diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index b29d16f9..25d7556e 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -47,9 +47,11 @@ jobs: submodules: recursive - name: Build FPP run: cargo build --manifest-path presence/fpp/fpp/Cargo.toml + - name: Build Bluetooth Module + run: cargo test --manifest-path fastpair/rust/bluetooth/Cargo.toml - name: Build Fast Pair - run: cargo build --manifest-path fastpair/rust/Cargo.toml - + run: cargo test --manifest-path fastpair/rust/demo/rust/Cargo.toml + build-rust-windows: name: Build Rust on Windows runs-on: windows-latest @@ -57,6 +59,8 @@ jobs: - uses: actions/checkout@v3 with: submodules: recursive + - name: Build Bluetooth Module + run: cargo test --manifest-path fastpair/rust/bluetooth/Cargo.toml - name: Build Fast Pair - run: cargo build --manifest-path fastpair/rust/Cargo.toml + run: cargo test --manifest-path fastpair/rust/demo/rust/Cargo.toml \ No newline at end of file diff --git a/compiled_proto/connections/implementation/proto/offline_wire_formats.pb.cc b/compiled_proto/connections/implementation/proto/offline_wire_formats.pb.cc index 33628b31..7e041c19 100644 --- a/compiled_proto/connections/implementation/proto/offline_wire_formats.pb.cc +++ b/compiled_proto/connections/implementation/proto/offline_wire_formats.pb.cc @@ -41,6 +41,8 @@ constexpr V1Frame::V1Frame( , paired_key_encryption_(nullptr) , authentication_message_(nullptr) , authentication_result_(nullptr) + , auto_resume_(nullptr) + , auto_reconnect_(nullptr) , type_(0) {} struct V1FrameDefaultTypeInternal { @@ -83,7 +85,8 @@ constexpr ConnectionResponseFrame::ConnectionResponseFrame( , response_(0) , multiplex_socket_bitmask_(0) - , nearby_connections_version_(0){} + , nearby_connections_version_(0) + , safe_to_disconnect_version_(0){} struct ConnectionResponseFrameDefaultTypeInternal { constexpr ConnectionResponseFrameDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} @@ -115,7 +118,8 @@ constexpr PayloadTransferFrame_PayloadChunk::PayloadTransferFrame_PayloadChunk( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : body_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) , offset_(int64_t{0}) - , flags_(0){} + , flags_(0) + , index_(0){} struct PayloadTransferFrame_PayloadChunkDefaultTypeInternal { constexpr PayloadTransferFrame_PayloadChunkDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} @@ -304,7 +308,8 @@ struct BandwidthUpgradeNegotiationFrameDefaultTypeInternal { PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT BandwidthUpgradeNegotiationFrameDefaultTypeInternal _BandwidthUpgradeNegotiationFrame_default_instance_; constexpr KeepAliveFrame::KeepAliveFrame( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) - : ack_(false){} + : ack_(false) + , seq_num_(0u){} struct KeepAliveFrameDefaultTypeInternal { constexpr KeepAliveFrameDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} @@ -363,6 +368,35 @@ struct AuthenticationResultFrameDefaultTypeInternal { }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT AuthenticationResultFrameDefaultTypeInternal _AuthenticationResultFrame_default_instance_; +constexpr AutoResumeFrame::AutoResumeFrame( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : pending_payload_id_(int64_t{0}) + , event_type_(0) + + , next_payload_chunk_index_(0){} +struct AutoResumeFrameDefaultTypeInternal { + constexpr AutoResumeFrameDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~AutoResumeFrameDefaultTypeInternal() {} + union { + AutoResumeFrame _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT AutoResumeFrameDefaultTypeInternal _AutoResumeFrame_default_instance_; +constexpr AutoReconnectFrame::AutoReconnectFrame( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : endpoint_id_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , event_type_(0) +{} +struct AutoReconnectFrameDefaultTypeInternal { + constexpr AutoReconnectFrameDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~AutoReconnectFrameDefaultTypeInternal() {} + union { + AutoReconnectFrame _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT AutoReconnectFrameDefaultTypeInternal _AutoReconnectFrame_default_instance_; constexpr MediumMetadata::MediumMetadata( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : bssid_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) @@ -606,17 +640,21 @@ bool V1Frame_FrameType_IsValid(int value) { case 7: case 8: case 9: + case 10: + case 11: return true; default: return false; } } -static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed V1Frame_FrameType_strings[10] = {}; +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed V1Frame_FrameType_strings[12] = {}; static const char V1Frame_FrameType_names[] = "AUTHENTICATION_MESSAGE" "AUTHENTICATION_RESULT" + "AUTO_RECONNECT" + "AUTO_RESUME" "BANDWIDTH_UPGRADE_NEGOTIATION" "CONNECTION_REQUEST" "CONNECTION_RESPONSE" @@ -629,27 +667,31 @@ static const char V1Frame_FrameType_names[] = static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry V1Frame_FrameType_entries[] = { { {V1Frame_FrameType_names + 0, 22}, 8 }, { {V1Frame_FrameType_names + 22, 21}, 9 }, - { {V1Frame_FrameType_names + 43, 29}, 4 }, - { {V1Frame_FrameType_names + 72, 18}, 1 }, - { {V1Frame_FrameType_names + 90, 19}, 2 }, - { {V1Frame_FrameType_names + 109, 13}, 6 }, - { {V1Frame_FrameType_names + 122, 10}, 5 }, - { {V1Frame_FrameType_names + 132, 21}, 7 }, - { {V1Frame_FrameType_names + 153, 16}, 3 }, - { {V1Frame_FrameType_names + 169, 18}, 0 }, + { {V1Frame_FrameType_names + 43, 14}, 11 }, + { {V1Frame_FrameType_names + 57, 11}, 10 }, + { {V1Frame_FrameType_names + 68, 29}, 4 }, + { {V1Frame_FrameType_names + 97, 18}, 1 }, + { {V1Frame_FrameType_names + 115, 19}, 2 }, + { {V1Frame_FrameType_names + 134, 13}, 6 }, + { {V1Frame_FrameType_names + 147, 10}, 5 }, + { {V1Frame_FrameType_names + 157, 21}, 7 }, + { {V1Frame_FrameType_names + 178, 16}, 3 }, + { {V1Frame_FrameType_names + 194, 18}, 0 }, }; static const int V1Frame_FrameType_entries_by_number[] = { - 9, // 0 -> UNKNOWN_FRAME_TYPE - 3, // 1 -> CONNECTION_REQUEST - 4, // 2 -> CONNECTION_RESPONSE - 8, // 3 -> PAYLOAD_TRANSFER - 2, // 4 -> BANDWIDTH_UPGRADE_NEGOTIATION - 6, // 5 -> KEEP_ALIVE - 5, // 6 -> DISCONNECTION - 7, // 7 -> PAIRED_KEY_ENCRYPTION + 11, // 0 -> UNKNOWN_FRAME_TYPE + 5, // 1 -> CONNECTION_REQUEST + 6, // 2 -> CONNECTION_RESPONSE + 10, // 3 -> PAYLOAD_TRANSFER + 4, // 4 -> BANDWIDTH_UPGRADE_NEGOTIATION + 8, // 5 -> KEEP_ALIVE + 7, // 6 -> DISCONNECTION + 9, // 7 -> PAIRED_KEY_ENCRYPTION 0, // 8 -> AUTHENTICATION_MESSAGE 1, // 9 -> AUTHENTICATION_RESULT + 3, // 10 -> AUTO_RESUME + 2, // 11 -> AUTO_RECONNECT }; const std::string& V1Frame_FrameType_Name( @@ -658,12 +700,12 @@ const std::string& V1Frame_FrameType_Name( ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( V1Frame_FrameType_entries, V1Frame_FrameType_entries_by_number, - 10, V1Frame_FrameType_strings); + 12, V1Frame_FrameType_strings); (void) dummy; int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( V1Frame_FrameType_entries, V1Frame_FrameType_entries_by_number, - 10, value); + 12, value); return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : V1Frame_FrameType_strings[idx].get(); } @@ -671,7 +713,7 @@ bool V1Frame_FrameType_Parse( ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, V1Frame_FrameType* value) { int int_value; bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( - V1Frame_FrameType_entries, 10, name, &int_value); + V1Frame_FrameType_entries, 12, name, &int_value); if (success) { *value = static_cast(int_value); } @@ -688,6 +730,8 @@ constexpr V1Frame_FrameType V1Frame::DISCONNECTION; constexpr V1Frame_FrameType V1Frame::PAIRED_KEY_ENCRYPTION; constexpr V1Frame_FrameType V1Frame::AUTHENTICATION_MESSAGE; constexpr V1Frame_FrameType V1Frame::AUTHENTICATION_RESULT; +constexpr V1Frame_FrameType V1Frame::AUTO_RESUME; +constexpr V1Frame_FrameType V1Frame::AUTO_RECONNECT; constexpr V1Frame_FrameType V1Frame::FrameType_MIN; constexpr V1Frame_FrameType V1Frame::FrameType_MAX; constexpr int V1Frame::FrameType_ARRAYSIZE; @@ -1301,6 +1345,132 @@ constexpr BandwidthUpgradeNegotiationFrame_EventType BandwidthUpgradeNegotiation constexpr BandwidthUpgradeNegotiationFrame_EventType BandwidthUpgradeNegotiationFrame::EventType_MAX; constexpr int BandwidthUpgradeNegotiationFrame::EventType_ARRAYSIZE; #endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) +bool AutoResumeFrame_EventType_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed AutoResumeFrame_EventType_strings[3] = {}; + +static const char AutoResumeFrame_EventType_names[] = + "PAYLOAD_RESUME_TRANSFER_ACK" + "PAYLOAD_RESUME_TRANSFER_START" + "UNKNOWN_AUTO_RESUME_EVENT_TYPE"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry AutoResumeFrame_EventType_entries[] = { + { {AutoResumeFrame_EventType_names + 0, 27}, 2 }, + { {AutoResumeFrame_EventType_names + 27, 29}, 1 }, + { {AutoResumeFrame_EventType_names + 56, 30}, 0 }, +}; + +static const int AutoResumeFrame_EventType_entries_by_number[] = { + 2, // 0 -> UNKNOWN_AUTO_RESUME_EVENT_TYPE + 1, // 1 -> PAYLOAD_RESUME_TRANSFER_START + 0, // 2 -> PAYLOAD_RESUME_TRANSFER_ACK +}; + +const std::string& AutoResumeFrame_EventType_Name( + AutoResumeFrame_EventType value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + AutoResumeFrame_EventType_entries, + AutoResumeFrame_EventType_entries_by_number, + 3, AutoResumeFrame_EventType_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + AutoResumeFrame_EventType_entries, + AutoResumeFrame_EventType_entries_by_number, + 3, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + AutoResumeFrame_EventType_strings[idx].get(); +} +bool AutoResumeFrame_EventType_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, AutoResumeFrame_EventType* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + AutoResumeFrame_EventType_entries, 3, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} +#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) +constexpr AutoResumeFrame_EventType AutoResumeFrame::UNKNOWN_AUTO_RESUME_EVENT_TYPE; +constexpr AutoResumeFrame_EventType AutoResumeFrame::PAYLOAD_RESUME_TRANSFER_START; +constexpr AutoResumeFrame_EventType AutoResumeFrame::PAYLOAD_RESUME_TRANSFER_ACK; +constexpr AutoResumeFrame_EventType AutoResumeFrame::EventType_MIN; +constexpr AutoResumeFrame_EventType AutoResumeFrame::EventType_MAX; +constexpr int AutoResumeFrame::EventType_ARRAYSIZE; +#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) +bool AutoReconnectFrame_EventType_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed AutoReconnectFrame_EventType_strings[3] = {}; + +static const char AutoReconnectFrame_EventType_names[] = + "CLIENT_INTRODUCTION" + "CLIENT_INTRODUCTION_ACK" + "UNKNOWN_EVENT_TYPE"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry AutoReconnectFrame_EventType_entries[] = { + { {AutoReconnectFrame_EventType_names + 0, 19}, 1 }, + { {AutoReconnectFrame_EventType_names + 19, 23}, 2 }, + { {AutoReconnectFrame_EventType_names + 42, 18}, 0 }, +}; + +static const int AutoReconnectFrame_EventType_entries_by_number[] = { + 2, // 0 -> UNKNOWN_EVENT_TYPE + 0, // 1 -> CLIENT_INTRODUCTION + 1, // 2 -> CLIENT_INTRODUCTION_ACK +}; + +const std::string& AutoReconnectFrame_EventType_Name( + AutoReconnectFrame_EventType value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + AutoReconnectFrame_EventType_entries, + AutoReconnectFrame_EventType_entries_by_number, + 3, AutoReconnectFrame_EventType_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + AutoReconnectFrame_EventType_entries, + AutoReconnectFrame_EventType_entries_by_number, + 3, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + AutoReconnectFrame_EventType_strings[idx].get(); +} +bool AutoReconnectFrame_EventType_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, AutoReconnectFrame_EventType* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + AutoReconnectFrame_EventType_entries, 3, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} +#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) +constexpr AutoReconnectFrame_EventType AutoReconnectFrame::UNKNOWN_EVENT_TYPE; +constexpr AutoReconnectFrame_EventType AutoReconnectFrame::CLIENT_INTRODUCTION; +constexpr AutoReconnectFrame_EventType AutoReconnectFrame::CLIENT_INTRODUCTION_ACK; +constexpr AutoReconnectFrame_EventType AutoReconnectFrame::EventType_MIN; +constexpr AutoReconnectFrame_EventType AutoReconnectFrame::EventType_MAX; +constexpr int AutoReconnectFrame::EventType_ARRAYSIZE; +#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) bool LocationStandard_Format_IsValid(int value) { switch (value) { case 0: @@ -1839,7 +2009,7 @@ class V1Frame::_Internal { public: using HasBits = decltype(std::declval()._has_bits_); static void set_has_type(HasBits* has_bits) { - (*has_bits)[0] |= 512u; + (*has_bits)[0] |= 2048u; } static const ::location::nearby::connections::ConnectionRequestFrame& connection_request(const V1Frame* msg); static void set_has_connection_request(HasBits* has_bits) { @@ -1877,6 +2047,14 @@ class V1Frame::_Internal { static void set_has_authentication_result(HasBits* has_bits) { (*has_bits)[0] |= 256u; } + static const ::location::nearby::connections::AutoResumeFrame& auto_resume(const V1Frame* msg); + static void set_has_auto_resume(HasBits* has_bits) { + (*has_bits)[0] |= 512u; + } + static const ::location::nearby::connections::AutoReconnectFrame& auto_reconnect(const V1Frame* msg); + static void set_has_auto_reconnect(HasBits* has_bits) { + (*has_bits)[0] |= 1024u; + } }; const ::location::nearby::connections::ConnectionRequestFrame& @@ -1915,6 +2093,14 @@ const ::location::nearby::connections::AuthenticationResultFrame& V1Frame::_Internal::authentication_result(const V1Frame* msg) { return *msg->authentication_result_; } +const ::location::nearby::connections::AutoResumeFrame& +V1Frame::_Internal::auto_resume(const V1Frame* msg) { + return *msg->auto_resume_; +} +const ::location::nearby::connections::AutoReconnectFrame& +V1Frame::_Internal::auto_reconnect(const V1Frame* msg) { + return *msg->auto_reconnect_; +} V1Frame::V1Frame(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned) : ::PROTOBUF_NAMESPACE_ID::MessageLite(arena, is_message_owned) { @@ -1973,6 +2159,16 @@ V1Frame::V1Frame(const V1Frame& from) } else { authentication_result_ = nullptr; } + if (from._internal_has_auto_resume()) { + auto_resume_ = new ::location::nearby::connections::AutoResumeFrame(*from.auto_resume_); + } else { + auto_resume_ = nullptr; + } + if (from._internal_has_auto_reconnect()) { + auto_reconnect_ = new ::location::nearby::connections::AutoReconnectFrame(*from.auto_reconnect_); + } else { + auto_reconnect_ = nullptr; + } type_ = from.type_; // @@protoc_insertion_point(copy_constructor:location.nearby.connections.V1Frame) } @@ -2002,6 +2198,8 @@ inline void V1Frame::SharedDtor() { if (this != internal_default_instance()) delete paired_key_encryption_; if (this != internal_default_instance()) delete authentication_message_; if (this != internal_default_instance()) delete authentication_result_; + if (this != internal_default_instance()) delete auto_resume_; + if (this != internal_default_instance()) delete auto_reconnect_; } void V1Frame::ArenaDtor(void* object) { @@ -2055,9 +2253,19 @@ void V1Frame::Clear() { authentication_message_->Clear(); } } - if (cached_has_bits & 0x00000100u) { - GOOGLE_DCHECK(authentication_result_ != nullptr); - authentication_result_->Clear(); + if (cached_has_bits & 0x00000700u) { + if (cached_has_bits & 0x00000100u) { + GOOGLE_DCHECK(authentication_result_ != nullptr); + authentication_result_->Clear(); + } + if (cached_has_bits & 0x00000200u) { + GOOGLE_DCHECK(auto_resume_ != nullptr); + auto_resume_->Clear(); + } + if (cached_has_bits & 0x00000400u) { + GOOGLE_DCHECK(auto_reconnect_ != nullptr); + auto_reconnect_->Clear(); + } } type_ = 0; _has_bits_.Clear(); @@ -2156,6 +2364,22 @@ const char* V1Frame::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::in } else goto handle_unusual; continue; + // optional .location.nearby.connections.AutoResumeFrame auto_resume = 11; + case 11: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 90)) { + ptr = ctx->ParseMessage(_internal_mutable_auto_resume(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional .location.nearby.connections.AutoReconnectFrame auto_reconnect = 12; + case 12: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 98)) { + ptr = ctx->ParseMessage(_internal_mutable_auto_reconnect(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; default: goto handle_unusual; } // switch @@ -2188,7 +2412,7 @@ uint8_t* V1Frame::_InternalSerialize( cached_has_bits = _has_bits_[0]; // optional .location.nearby.connections.V1Frame.FrameType type = 1; - if (cached_has_bits & 0x00000200u) { + if (cached_has_bits & 0x00000800u) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray( 1, this->_internal_type(), target); @@ -2266,6 +2490,22 @@ uint8_t* V1Frame::_InternalSerialize( 10, _Internal::authentication_result(this), target, stream); } + // optional .location.nearby.connections.AutoResumeFrame auto_resume = 11; + if (cached_has_bits & 0x00000200u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 11, _Internal::auto_resume(this), target, stream); + } + + // optional .location.nearby.connections.AutoReconnectFrame auto_reconnect = 12; + if (cached_has_bits & 0x00000400u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 12, _Internal::auto_reconnect(this), target, stream); + } + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = stream->WriteRaw(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).data(), static_cast(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size()), target); @@ -2341,7 +2581,7 @@ size_t V1Frame::ByteSizeLong() const { } } - if (cached_has_bits & 0x00000300u) { + if (cached_has_bits & 0x00000f00u) { // optional .location.nearby.connections.AuthenticationResultFrame authentication_result = 10; if (cached_has_bits & 0x00000100u) { total_size += 1 + @@ -2349,8 +2589,22 @@ size_t V1Frame::ByteSizeLong() const { *authentication_result_); } - // optional .location.nearby.connections.V1Frame.FrameType type = 1; + // optional .location.nearby.connections.AutoResumeFrame auto_resume = 11; if (cached_has_bits & 0x00000200u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *auto_resume_); + } + + // optional .location.nearby.connections.AutoReconnectFrame auto_reconnect = 12; + if (cached_has_bits & 0x00000400u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *auto_reconnect_); + } + + // optional .location.nearby.connections.V1Frame.FrameType type = 1; + if (cached_has_bits & 0x00000800u) { total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_type()); } @@ -2403,11 +2657,17 @@ void V1Frame::MergeFrom(const V1Frame& from) { _internal_mutable_authentication_message()->::location::nearby::connections::AuthenticationMessageFrame::MergeFrom(from._internal_authentication_message()); } } - if (cached_has_bits & 0x00000300u) { + if (cached_has_bits & 0x00000f00u) { if (cached_has_bits & 0x00000100u) { _internal_mutable_authentication_result()->::location::nearby::connections::AuthenticationResultFrame::MergeFrom(from._internal_authentication_result()); } if (cached_has_bits & 0x00000200u) { + _internal_mutable_auto_resume()->::location::nearby::connections::AutoResumeFrame::MergeFrom(from._internal_auto_resume()); + } + if (cached_has_bits & 0x00000400u) { + _internal_mutable_auto_reconnect()->::location::nearby::connections::AutoReconnectFrame::MergeFrom(from._internal_auto_reconnect()); + } + if (cached_has_bits & 0x00000800u) { type_ = from.type_; } _has_bits_[0] |= cached_has_bits; @@ -3248,6 +3508,9 @@ class ConnectionResponseFrame::_Internal { static void set_has_nearby_connections_version(HasBits* has_bits) { (*has_bits)[0] |= 32u; } + static void set_has_safe_to_disconnect_version(HasBits* has_bits) { + (*has_bits)[0] |= 64u; + } }; const ::location::nearby::connections::OsInfo& @@ -3281,8 +3544,8 @@ ConnectionResponseFrame::ConnectionResponseFrame(const ConnectionResponseFrame& os_info_ = nullptr; } ::memcpy(&status_, &from.status_, - static_cast(reinterpret_cast(&nearby_connections_version_) - - reinterpret_cast(&status_)) + sizeof(nearby_connections_version_)); + static_cast(reinterpret_cast(&safe_to_disconnect_version_) - + reinterpret_cast(&status_)) + sizeof(safe_to_disconnect_version_)); // @@protoc_insertion_point(copy_constructor:location.nearby.connections.ConnectionResponseFrame) } @@ -3293,8 +3556,8 @@ handshake_data_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStr #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING ::memset(reinterpret_cast(this) + static_cast( reinterpret_cast(&os_info_) - reinterpret_cast(this)), - 0, static_cast(reinterpret_cast(&nearby_connections_version_) - - reinterpret_cast(&os_info_)) + sizeof(nearby_connections_version_)); + 0, static_cast(reinterpret_cast(&safe_to_disconnect_version_) - + reinterpret_cast(&os_info_)) + sizeof(safe_to_disconnect_version_)); } ConnectionResponseFrame::~ConnectionResponseFrame() { @@ -3336,10 +3599,10 @@ void ConnectionResponseFrame::Clear() { os_info_->Clear(); } } - if (cached_has_bits & 0x0000003cu) { + if (cached_has_bits & 0x0000007cu) { ::memset(&status_, 0, static_cast( - reinterpret_cast(&nearby_connections_version_) - - reinterpret_cast(&status_)) + sizeof(nearby_connections_version_)); + reinterpret_cast(&safe_to_disconnect_version_) - + reinterpret_cast(&status_)) + sizeof(safe_to_disconnect_version_)); } _has_bits_.Clear(); _internal_metadata_.Clear(); @@ -3400,7 +3663,7 @@ const char* ConnectionResponseFrame::_InternalParse(const char* ptr, ::PROTOBUF_ } else goto handle_unusual; continue; - // optional int32 nearby_connections_version = 6; + // optional int32 nearby_connections_version = 6 [deprecated = true]; case 6: if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 48)) { _Internal::set_has_nearby_connections_version(&has_bits); @@ -3409,6 +3672,15 @@ const char* ConnectionResponseFrame::_InternalParse(const char* ptr, ::PROTOBUF_ } else goto handle_unusual; continue; + // optional int32 safe_to_disconnect_version = 7; + case 7: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 56)) { + _Internal::set_has_safe_to_disconnect_version(&has_bits); + safe_to_disconnect_version_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; default: goto handle_unusual; } // switch @@ -3473,12 +3745,18 @@ uint8_t* ConnectionResponseFrame::_InternalSerialize( target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(5, this->_internal_multiplex_socket_bitmask(), target); } - // optional int32 nearby_connections_version = 6; + // optional int32 nearby_connections_version = 6 [deprecated = true]; if (cached_has_bits & 0x00000020u) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(6, this->_internal_nearby_connections_version(), target); } + // optional int32 safe_to_disconnect_version = 7; + if (cached_has_bits & 0x00000040u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(7, this->_internal_safe_to_disconnect_version(), target); + } + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = stream->WriteRaw(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).data(), static_cast(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size()), target); @@ -3496,7 +3774,7 @@ size_t ConnectionResponseFrame::ByteSizeLong() const { (void) cached_has_bits; cached_has_bits = _has_bits_[0]; - if (cached_has_bits & 0x0000003fu) { + if (cached_has_bits & 0x0000007fu) { // optional bytes handshake_data = 2; if (cached_has_bits & 0x00000001u) { total_size += 1 + @@ -3527,11 +3805,16 @@ size_t ConnectionResponseFrame::ByteSizeLong() const { total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_multiplex_socket_bitmask()); } - // optional int32 nearby_connections_version = 6; + // optional int32 nearby_connections_version = 6 [deprecated = true]; if (cached_has_bits & 0x00000020u) { total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_nearby_connections_version()); } + // optional int32 safe_to_disconnect_version = 7; + if (cached_has_bits & 0x00000040u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_safe_to_disconnect_version()); + } + } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { total_size += _internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size(); @@ -3554,7 +3837,7 @@ void ConnectionResponseFrame::MergeFrom(const ConnectionResponseFrame& from) { (void) cached_has_bits; cached_has_bits = from._has_bits_[0]; - if (cached_has_bits & 0x0000003fu) { + if (cached_has_bits & 0x0000007fu) { if (cached_has_bits & 0x00000001u) { _internal_set_handshake_data(from._internal_handshake_data()); } @@ -3573,6 +3856,9 @@ void ConnectionResponseFrame::MergeFrom(const ConnectionResponseFrame& from) { if (cached_has_bits & 0x00000020u) { nearby_connections_version_ = from.nearby_connections_version_; } + if (cached_has_bits & 0x00000040u) { + safe_to_disconnect_version_ = from.safe_to_disconnect_version_; + } _has_bits_[0] |= cached_has_bits; } _internal_metadata_.MergeFrom(from._internal_metadata_); @@ -3601,8 +3887,8 @@ void ConnectionResponseFrame::InternalSwap(ConnectionResponseFrame* other) { &other->handshake_data_, rhs_arena ); ::PROTOBUF_NAMESPACE_ID::internal::memswap< - PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, nearby_connections_version_) - + sizeof(ConnectionResponseFrame::nearby_connections_version_) + PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, safe_to_disconnect_version_) + + sizeof(ConnectionResponseFrame::safe_to_disconnect_version_) - PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, os_info_)>( reinterpret_cast(&os_info_), reinterpret_cast(&other->os_info_)); @@ -4021,6 +4307,9 @@ class PayloadTransferFrame_PayloadChunk::_Internal { static void set_has_body(HasBits* has_bits) { (*has_bits)[0] |= 1u; } + static void set_has_index(HasBits* has_bits) { + (*has_bits)[0] |= 8u; + } }; PayloadTransferFrame_PayloadChunk::PayloadTransferFrame_PayloadChunk(::PROTOBUF_NAMESPACE_ID::Arena* arena, @@ -4045,8 +4334,8 @@ PayloadTransferFrame_PayloadChunk::PayloadTransferFrame_PayloadChunk(const Paylo GetArenaForAllocation()); } ::memcpy(&offset_, &from.offset_, - static_cast(reinterpret_cast(&flags_) - - reinterpret_cast(&offset_)) + sizeof(flags_)); + static_cast(reinterpret_cast(&index_) - + reinterpret_cast(&offset_)) + sizeof(index_)); // @@protoc_insertion_point(copy_constructor:location.nearby.connections.PayloadTransferFrame.PayloadChunk) } @@ -4057,8 +4346,8 @@ body_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlready #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING ::memset(reinterpret_cast(this) + static_cast( reinterpret_cast(&offset_) - reinterpret_cast(this)), - 0, static_cast(reinterpret_cast(&flags_) - - reinterpret_cast(&offset_)) + sizeof(flags_)); + 0, static_cast(reinterpret_cast(&index_) - + reinterpret_cast(&offset_)) + sizeof(index_)); } PayloadTransferFrame_PayloadChunk::~PayloadTransferFrame_PayloadChunk() { @@ -4093,10 +4382,10 @@ void PayloadTransferFrame_PayloadChunk::Clear() { if (cached_has_bits & 0x00000001u) { body_.ClearNonDefaultToEmpty(); } - if (cached_has_bits & 0x00000006u) { + if (cached_has_bits & 0x0000000eu) { ::memset(&offset_, 0, static_cast( - reinterpret_cast(&flags_) - - reinterpret_cast(&offset_)) + sizeof(flags_)); + reinterpret_cast(&index_) - + reinterpret_cast(&offset_)) + sizeof(index_)); } _has_bits_.Clear(); _internal_metadata_.Clear(); @@ -4136,6 +4425,15 @@ const char* PayloadTransferFrame_PayloadChunk::_InternalParse(const char* ptr, : } else goto handle_unusual; continue; + // optional int32 index = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 32)) { + _Internal::set_has_index(&has_bits); + index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; default: goto handle_unusual; } // switch @@ -4185,6 +4483,12 @@ uint8_t* PayloadTransferFrame_PayloadChunk::_InternalSerialize( 3, this->_internal_body(), target); } + // optional int32 index = 4; + if (cached_has_bits & 0x00000008u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(4, this->_internal_index(), target); + } + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = stream->WriteRaw(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).data(), static_cast(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size()), target); @@ -4202,7 +4506,7 @@ size_t PayloadTransferFrame_PayloadChunk::ByteSizeLong() const { (void) cached_has_bits; cached_has_bits = _has_bits_[0]; - if (cached_has_bits & 0x00000007u) { + if (cached_has_bits & 0x0000000fu) { // optional bytes body = 3; if (cached_has_bits & 0x00000001u) { total_size += 1 + @@ -4220,6 +4524,11 @@ size_t PayloadTransferFrame_PayloadChunk::ByteSizeLong() const { total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_flags()); } + // optional int32 index = 4; + if (cached_has_bits & 0x00000008u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_index()); + } + } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { total_size += _internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size(); @@ -4242,7 +4551,7 @@ void PayloadTransferFrame_PayloadChunk::MergeFrom(const PayloadTransferFrame_Pay (void) cached_has_bits; cached_has_bits = from._has_bits_[0]; - if (cached_has_bits & 0x00000007u) { + if (cached_has_bits & 0x0000000fu) { if (cached_has_bits & 0x00000001u) { _internal_set_body(from._internal_body()); } @@ -4252,6 +4561,9 @@ void PayloadTransferFrame_PayloadChunk::MergeFrom(const PayloadTransferFrame_Pay if (cached_has_bits & 0x00000004u) { flags_ = from.flags_; } + if (cached_has_bits & 0x00000008u) { + index_ = from.index_; + } _has_bits_[0] |= cached_has_bits; } _internal_metadata_.MergeFrom(from._internal_metadata_); @@ -4280,8 +4592,8 @@ void PayloadTransferFrame_PayloadChunk::InternalSwap(PayloadTransferFrame_Payloa &other->body_, rhs_arena ); ::PROTOBUF_NAMESPACE_ID::internal::memswap< - PROTOBUF_FIELD_OFFSET(PayloadTransferFrame_PayloadChunk, flags_) - + sizeof(PayloadTransferFrame_PayloadChunk::flags_) + PROTOBUF_FIELD_OFFSET(PayloadTransferFrame_PayloadChunk, index_) + + sizeof(PayloadTransferFrame_PayloadChunk::index_) - PROTOBUF_FIELD_OFFSET(PayloadTransferFrame_PayloadChunk, offset_)>( reinterpret_cast(&offset_), reinterpret_cast(&other->offset_)); @@ -8034,6 +8346,9 @@ class KeepAliveFrame::_Internal { static void set_has_ack(HasBits* has_bits) { (*has_bits)[0] |= 1u; } + static void set_has_seq_num(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } }; KeepAliveFrame::KeepAliveFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, @@ -8049,12 +8364,17 @@ KeepAliveFrame::KeepAliveFrame(const KeepAliveFrame& from) : ::PROTOBUF_NAMESPACE_ID::MessageLite(), _has_bits_(from._has_bits_) { _internal_metadata_.MergeFrom(from._internal_metadata_); - ack_ = from.ack_; + ::memcpy(&ack_, &from.ack_, + static_cast(reinterpret_cast(&seq_num_) - + reinterpret_cast(&ack_)) + sizeof(seq_num_)); // @@protoc_insertion_point(copy_constructor:location.nearby.connections.KeepAliveFrame) } inline void KeepAliveFrame::SharedCtor() { -ack_ = false; +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&ack_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&seq_num_) - + reinterpret_cast(&ack_)) + sizeof(seq_num_)); } KeepAliveFrame::~KeepAliveFrame() { @@ -8084,7 +8404,12 @@ void KeepAliveFrame::Clear() { // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; - ack_ = false; + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + ::memset(&ack_, 0, static_cast( + reinterpret_cast(&seq_num_) - + reinterpret_cast(&ack_)) + sizeof(seq_num_)); + } _has_bits_.Clear(); _internal_metadata_.Clear(); } @@ -8105,6 +8430,15 @@ const char* KeepAliveFrame::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE } else goto handle_unusual; continue; + // optional uint32 seq_num = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 16)) { + _Internal::set_has_seq_num(&has_bits); + seq_num_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; default: goto handle_unusual; } // switch @@ -8142,6 +8476,12 @@ uint8_t* KeepAliveFrame::_InternalSerialize( target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(1, this->_internal_ack(), target); } + // optional uint32 seq_num = 2; + if (cached_has_bits & 0x00000002u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32ToArray(2, this->_internal_seq_num(), target); + } + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = stream->WriteRaw(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).data(), static_cast(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size()), target); @@ -8158,12 +8498,19 @@ size_t KeepAliveFrame::ByteSizeLong() const { // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; - // optional bool ack = 1; cached_has_bits = _has_bits_[0]; - if (cached_has_bits & 0x00000001u) { - total_size += 1 + 1; - } + if (cached_has_bits & 0x00000003u) { + // optional bool ack = 1; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + 1; + } + // optional uint32 seq_num = 2; + if (cached_has_bits & 0x00000002u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32SizePlusOne(this->_internal_seq_num()); + } + + } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { total_size += _internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size(); } @@ -8184,8 +8531,15 @@ void KeepAliveFrame::MergeFrom(const KeepAliveFrame& from) { uint32_t cached_has_bits = 0; (void) cached_has_bits; - if (from._internal_has_ack()) { - _internal_set_ack(from._internal_ack()); + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000001u) { + ack_ = from.ack_; + } + if (cached_has_bits & 0x00000002u) { + seq_num_ = from.seq_num_; + } + _has_bits_[0] |= cached_has_bits; } _internal_metadata_.MergeFrom(from._internal_metadata_); } @@ -8205,7 +8559,12 @@ void KeepAliveFrame::InternalSwap(KeepAliveFrame* other) { using std::swap; _internal_metadata_.InternalSwap(&other->_internal_metadata_); swap(_has_bits_[0], other->_has_bits_[0]); - swap(ack_, other->ack_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(KeepAliveFrame, seq_num_) + + sizeof(KeepAliveFrame::seq_num_) + - PROTOBUF_FIELD_OFFSET(KeepAliveFrame, ack_)>( + reinterpret_cast(&ack_), + reinterpret_cast(&other->ack_)); } std::string KeepAliveFrame::GetTypeName() const { @@ -9049,6 +9408,523 @@ std::string AuthenticationResultFrame::GetTypeName() const { } +// =================================================================== + +class AutoResumeFrame::_Internal { + public: + using HasBits = decltype(std::declval()._has_bits_); + static void set_has_event_type(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } + static void set_has_pending_payload_id(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static void set_has_next_payload_chunk_index(HasBits* has_bits) { + (*has_bits)[0] |= 4u; + } +}; + +AutoResumeFrame::AutoResumeFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::MessageLite(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:location.nearby.connections.AutoResumeFrame) +} +AutoResumeFrame::AutoResumeFrame(const AutoResumeFrame& from) + : ::PROTOBUF_NAMESPACE_ID::MessageLite(), + _has_bits_(from._has_bits_) { + _internal_metadata_.MergeFrom(from._internal_metadata_); + ::memcpy(&pending_payload_id_, &from.pending_payload_id_, + static_cast(reinterpret_cast(&next_payload_chunk_index_) - + reinterpret_cast(&pending_payload_id_)) + sizeof(next_payload_chunk_index_)); + // @@protoc_insertion_point(copy_constructor:location.nearby.connections.AutoResumeFrame) +} + +inline void AutoResumeFrame::SharedCtor() { +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&pending_payload_id_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&next_payload_chunk_index_) - + reinterpret_cast(&pending_payload_id_)) + sizeof(next_payload_chunk_index_)); +} + +AutoResumeFrame::~AutoResumeFrame() { + // @@protoc_insertion_point(destructor:location.nearby.connections.AutoResumeFrame) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete(); +} + +inline void AutoResumeFrame::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); +} + +void AutoResumeFrame::ArenaDtor(void* object) { + AutoResumeFrame* _this = reinterpret_cast< AutoResumeFrame* >(object); + (void)_this; +} +void AutoResumeFrame::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void AutoResumeFrame::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void AutoResumeFrame::Clear() { +// @@protoc_insertion_point(message_clear_start:location.nearby.connections.AutoResumeFrame) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000007u) { + ::memset(&pending_payload_id_, 0, static_cast( + reinterpret_cast(&next_payload_chunk_index_) - + reinterpret_cast(&pending_payload_id_)) + sizeof(next_payload_chunk_index_)); + } + _has_bits_.Clear(); + _internal_metadata_.Clear(); +} + +const char* AutoResumeFrame::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional .location.nearby.connections.AutoResumeFrame.EventType event_type = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 8)) { + uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + if (PROTOBUF_PREDICT_TRUE(::location::nearby::connections::AutoResumeFrame_EventType_IsValid(val))) { + _internal_set_event_type(static_cast<::location::nearby::connections::AutoResumeFrame_EventType>(val)); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(1, val, mutable_unknown_fields()); + } + } else + goto handle_unusual; + continue; + // optional int64 pending_payload_id = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 16)) { + _Internal::set_has_pending_payload_id(&has_bits); + pending_payload_id_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 next_payload_chunk_index = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 24)) { + _Internal::set_has_next_payload_chunk_index(&has_bits); + next_payload_chunk_index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* AutoResumeFrame::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:location.nearby.connections.AutoResumeFrame) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional .location.nearby.connections.AutoResumeFrame.EventType event_type = 1; + if (cached_has_bits & 0x00000002u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray( + 1, this->_internal_event_type(), target); + } + + // optional int64 pending_payload_id = 2; + if (cached_has_bits & 0x00000001u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64ToArray(2, this->_internal_pending_payload_id(), target); + } + + // optional int32 next_payload_chunk_index = 3; + if (cached_has_bits & 0x00000004u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->_internal_next_payload_chunk_index(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = stream->WriteRaw(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).data(), + static_cast(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size()), target); + } + // @@protoc_insertion_point(serialize_to_array_end:location.nearby.connections.AutoResumeFrame) + return target; +} + +size_t AutoResumeFrame::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:location.nearby.connections.AutoResumeFrame) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000007u) { + // optional int64 pending_payload_id = 2; + if (cached_has_bits & 0x00000001u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64SizePlusOne(this->_internal_pending_payload_id()); + } + + // optional .location.nearby.connections.AutoResumeFrame.EventType event_type = 1; + if (cached_has_bits & 0x00000002u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_event_type()); + } + + // optional int32 next_payload_chunk_index = 3; + if (cached_has_bits & 0x00000004u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_next_payload_chunk_index()); + } + + } + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + total_size += _internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size(); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); + SetCachedSize(cached_size); + return total_size; +} + +void AutoResumeFrame::CheckTypeAndMergeFrom( + const ::PROTOBUF_NAMESPACE_ID::MessageLite& from) { + MergeFrom(*::PROTOBUF_NAMESPACE_ID::internal::DownCast( + &from)); +} + +void AutoResumeFrame::MergeFrom(const AutoResumeFrame& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:location.nearby.connections.AutoResumeFrame) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x00000007u) { + if (cached_has_bits & 0x00000001u) { + pending_payload_id_ = from.pending_payload_id_; + } + if (cached_has_bits & 0x00000002u) { + event_type_ = from.event_type_; + } + if (cached_has_bits & 0x00000004u) { + next_payload_chunk_index_ = from.next_payload_chunk_index_; + } + _has_bits_[0] |= cached_has_bits; + } + _internal_metadata_.MergeFrom(from._internal_metadata_); +} + +void AutoResumeFrame::CopyFrom(const AutoResumeFrame& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:location.nearby.connections.AutoResumeFrame) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool AutoResumeFrame::IsInitialized() const { + return true; +} + +void AutoResumeFrame::InternalSwap(AutoResumeFrame* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(AutoResumeFrame, next_payload_chunk_index_) + + sizeof(AutoResumeFrame::next_payload_chunk_index_) + - PROTOBUF_FIELD_OFFSET(AutoResumeFrame, pending_payload_id_)>( + reinterpret_cast(&pending_payload_id_), + reinterpret_cast(&other->pending_payload_id_)); +} + +std::string AutoResumeFrame::GetTypeName() const { + return "location.nearby.connections.AutoResumeFrame"; +} + + +// =================================================================== + +class AutoReconnectFrame::_Internal { + public: + using HasBits = decltype(std::declval()._has_bits_); + static void set_has_endpoint_id(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static void set_has_event_type(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } +}; + +AutoReconnectFrame::AutoReconnectFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::MessageLite(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:location.nearby.connections.AutoReconnectFrame) +} +AutoReconnectFrame::AutoReconnectFrame(const AutoReconnectFrame& from) + : ::PROTOBUF_NAMESPACE_ID::MessageLite(), + _has_bits_(from._has_bits_) { + _internal_metadata_.MergeFrom(from._internal_metadata_); + endpoint_id_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + endpoint_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_endpoint_id()) { + endpoint_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_endpoint_id(), + GetArenaForAllocation()); + } + event_type_ = from.event_type_; + // @@protoc_insertion_point(copy_constructor:location.nearby.connections.AutoReconnectFrame) +} + +inline void AutoReconnectFrame::SharedCtor() { +endpoint_id_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + endpoint_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +event_type_ = 0; +} + +AutoReconnectFrame::~AutoReconnectFrame() { + // @@protoc_insertion_point(destructor:location.nearby.connections.AutoReconnectFrame) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete(); +} + +inline void AutoReconnectFrame::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + endpoint_id_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void AutoReconnectFrame::ArenaDtor(void* object) { + AutoReconnectFrame* _this = reinterpret_cast< AutoReconnectFrame* >(object); + (void)_this; +} +void AutoReconnectFrame::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void AutoReconnectFrame::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void AutoReconnectFrame::Clear() { +// @@protoc_insertion_point(message_clear_start:location.nearby.connections.AutoReconnectFrame) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000001u) { + endpoint_id_.ClearNonDefaultToEmpty(); + } + event_type_ = 0; + _has_bits_.Clear(); + _internal_metadata_.Clear(); +} + +const char* AutoReconnectFrame::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional string endpoint_id = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + auto str = _internal_mutable_endpoint_id(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional .location.nearby.connections.AutoReconnectFrame.EventType event_type = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 16)) { + uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + if (PROTOBUF_PREDICT_TRUE(::location::nearby::connections::AutoReconnectFrame_EventType_IsValid(val))) { + _internal_set_event_type(static_cast<::location::nearby::connections::AutoReconnectFrame_EventType>(val)); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(2, val, mutable_unknown_fields()); + } + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* AutoReconnectFrame::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:location.nearby.connections.AutoReconnectFrame) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional string endpoint_id = 1; + if (cached_has_bits & 0x00000001u) { + target = stream->WriteStringMaybeAliased( + 1, this->_internal_endpoint_id(), target); + } + + // optional .location.nearby.connections.AutoReconnectFrame.EventType event_type = 2; + if (cached_has_bits & 0x00000002u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray( + 2, this->_internal_event_type(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = stream->WriteRaw(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).data(), + static_cast(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size()), target); + } + // @@protoc_insertion_point(serialize_to_array_end:location.nearby.connections.AutoReconnectFrame) + return target; +} + +size_t AutoReconnectFrame::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:location.nearby.connections.AutoReconnectFrame) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + // optional string endpoint_id = 1; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_endpoint_id()); + } + + // optional .location.nearby.connections.AutoReconnectFrame.EventType event_type = 2; + if (cached_has_bits & 0x00000002u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_event_type()); + } + + } + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + total_size += _internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size(); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); + SetCachedSize(cached_size); + return total_size; +} + +void AutoReconnectFrame::CheckTypeAndMergeFrom( + const ::PROTOBUF_NAMESPACE_ID::MessageLite& from) { + MergeFrom(*::PROTOBUF_NAMESPACE_ID::internal::DownCast( + &from)); +} + +void AutoReconnectFrame::MergeFrom(const AutoReconnectFrame& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:location.nearby.connections.AutoReconnectFrame) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000001u) { + _internal_set_endpoint_id(from._internal_endpoint_id()); + } + if (cached_has_bits & 0x00000002u) { + event_type_ = from.event_type_; + } + _has_bits_[0] |= cached_has_bits; + } + _internal_metadata_.MergeFrom(from._internal_metadata_); +} + +void AutoReconnectFrame::CopyFrom(const AutoReconnectFrame& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:location.nearby.connections.AutoReconnectFrame) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool AutoReconnectFrame::IsInitialized() const { + return true; +} + +void AutoReconnectFrame::InternalSwap(AutoReconnectFrame* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &endpoint_id_, lhs_arena, + &other->endpoint_id_, rhs_arena + ); + swap(event_type_, other->event_type_); +} + +std::string AutoReconnectFrame::GetTypeName() const { + return "location.nearby.connections.AutoReconnectFrame"; +} + + // =================================================================== class MediumMetadata::_Internal { @@ -12222,6 +13098,12 @@ template<> PROTOBUF_NOINLINE ::location::nearby::connections::AuthenticationMess template<> PROTOBUF_NOINLINE ::location::nearby::connections::AuthenticationResultFrame* Arena::CreateMaybeMessage< ::location::nearby::connections::AuthenticationResultFrame >(Arena* arena) { return Arena::CreateMessageInternal< ::location::nearby::connections::AuthenticationResultFrame >(arena); } +template<> PROTOBUF_NOINLINE ::location::nearby::connections::AutoResumeFrame* Arena::CreateMaybeMessage< ::location::nearby::connections::AutoResumeFrame >(Arena* arena) { + return Arena::CreateMessageInternal< ::location::nearby::connections::AutoResumeFrame >(arena); +} +template<> PROTOBUF_NOINLINE ::location::nearby::connections::AutoReconnectFrame* Arena::CreateMaybeMessage< ::location::nearby::connections::AutoReconnectFrame >(Arena* arena) { + return Arena::CreateMessageInternal< ::location::nearby::connections::AutoReconnectFrame >(arena); +} template<> PROTOBUF_NOINLINE ::location::nearby::connections::MediumMetadata* Arena::CreateMaybeMessage< ::location::nearby::connections::MediumMetadata >(Arena* arena) { return Arena::CreateMessageInternal< ::location::nearby::connections::MediumMetadata >(arena); } diff --git a/compiled_proto/connections/implementation/proto/offline_wire_formats.pb.h b/compiled_proto/connections/implementation/proto/offline_wire_formats.pb.h index c75669f6..22ca5e23 100644 --- a/compiled_proto/connections/implementation/proto/offline_wire_formats.pb.h +++ b/compiled_proto/connections/implementation/proto/offline_wire_formats.pb.h @@ -45,7 +45,7 @@ struct TableStruct_connections_2fimplementation_2fproto_2foffline_5fwire_5fforma PROTOBUF_SECTION_VARIABLE(protodesc_cold); static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[] PROTOBUF_SECTION_VARIABLE(protodesc_cold); - static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[34] + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[36] PROTOBUF_SECTION_VARIABLE(protodesc_cold); static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; @@ -60,6 +60,12 @@ extern AuthenticationMessageFrameDefaultTypeInternal _AuthenticationMessageFrame class AuthenticationResultFrame; struct AuthenticationResultFrameDefaultTypeInternal; extern AuthenticationResultFrameDefaultTypeInternal _AuthenticationResultFrame_default_instance_; +class AutoReconnectFrame; +struct AutoReconnectFrameDefaultTypeInternal; +extern AutoReconnectFrameDefaultTypeInternal _AutoReconnectFrame_default_instance_; +class AutoResumeFrame; +struct AutoResumeFrameDefaultTypeInternal; +extern AutoResumeFrameDefaultTypeInternal _AutoResumeFrame_default_instance_; class AvailableChannels; struct AvailableChannelsDefaultTypeInternal; extern AvailableChannelsDefaultTypeInternal _AvailableChannels_default_instance_; @@ -162,6 +168,8 @@ extern WifiLanUsableChannelsDefaultTypeInternal _WifiLanUsableChannels_default_i PROTOBUF_NAMESPACE_OPEN template<> ::location::nearby::connections::AuthenticationMessageFrame* Arena::CreateMaybeMessage<::location::nearby::connections::AuthenticationMessageFrame>(Arena*); template<> ::location::nearby::connections::AuthenticationResultFrame* Arena::CreateMaybeMessage<::location::nearby::connections::AuthenticationResultFrame>(Arena*); +template<> ::location::nearby::connections::AutoReconnectFrame* Arena::CreateMaybeMessage<::location::nearby::connections::AutoReconnectFrame>(Arena*); +template<> ::location::nearby::connections::AutoResumeFrame* Arena::CreateMaybeMessage<::location::nearby::connections::AutoResumeFrame>(Arena*); template<> ::location::nearby::connections::AvailableChannels* Arena::CreateMaybeMessage<::location::nearby::connections::AvailableChannels>(Arena*); template<> ::location::nearby::connections::BandwidthUpgradeNegotiationFrame* Arena::CreateMaybeMessage<::location::nearby::connections::BandwidthUpgradeNegotiationFrame>(Arena*); template<> ::location::nearby::connections::BandwidthUpgradeNegotiationFrame_ClientIntroduction* Arena::CreateMaybeMessage<::location::nearby::connections::BandwidthUpgradeNegotiationFrame_ClientIntroduction>(Arena*); @@ -228,11 +236,13 @@ enum V1Frame_FrameType : int { V1Frame_FrameType_DISCONNECTION = 6, V1Frame_FrameType_PAIRED_KEY_ENCRYPTION = 7, V1Frame_FrameType_AUTHENTICATION_MESSAGE = 8, - V1Frame_FrameType_AUTHENTICATION_RESULT = 9 + V1Frame_FrameType_AUTHENTICATION_RESULT = 9, + V1Frame_FrameType_AUTO_RESUME = 10, + V1Frame_FrameType_AUTO_RECONNECT = 11 }; bool V1Frame_FrameType_IsValid(int value); constexpr V1Frame_FrameType V1Frame_FrameType_FrameType_MIN = V1Frame_FrameType_UNKNOWN_FRAME_TYPE; -constexpr V1Frame_FrameType V1Frame_FrameType_FrameType_MAX = V1Frame_FrameType_AUTHENTICATION_RESULT; +constexpr V1Frame_FrameType V1Frame_FrameType_FrameType_MAX = V1Frame_FrameType_AUTO_RECONNECT; constexpr int V1Frame_FrameType_FrameType_ARRAYSIZE = V1Frame_FrameType_FrameType_MAX + 1; const std::string& V1Frame_FrameType_Name(V1Frame_FrameType value); @@ -426,6 +436,46 @@ inline const std::string& BandwidthUpgradeNegotiationFrame_EventType_Name(T enum } bool BandwidthUpgradeNegotiationFrame_EventType_Parse( ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, BandwidthUpgradeNegotiationFrame_EventType* value); +enum AutoResumeFrame_EventType : int { + AutoResumeFrame_EventType_UNKNOWN_AUTO_RESUME_EVENT_TYPE = 0, + AutoResumeFrame_EventType_PAYLOAD_RESUME_TRANSFER_START = 1, + AutoResumeFrame_EventType_PAYLOAD_RESUME_TRANSFER_ACK = 2 +}; +bool AutoResumeFrame_EventType_IsValid(int value); +constexpr AutoResumeFrame_EventType AutoResumeFrame_EventType_EventType_MIN = AutoResumeFrame_EventType_UNKNOWN_AUTO_RESUME_EVENT_TYPE; +constexpr AutoResumeFrame_EventType AutoResumeFrame_EventType_EventType_MAX = AutoResumeFrame_EventType_PAYLOAD_RESUME_TRANSFER_ACK; +constexpr int AutoResumeFrame_EventType_EventType_ARRAYSIZE = AutoResumeFrame_EventType_EventType_MAX + 1; + +const std::string& AutoResumeFrame_EventType_Name(AutoResumeFrame_EventType value); +template +inline const std::string& AutoResumeFrame_EventType_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function AutoResumeFrame_EventType_Name."); + return AutoResumeFrame_EventType_Name(static_cast(enum_t_value)); +} +bool AutoResumeFrame_EventType_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, AutoResumeFrame_EventType* value); +enum AutoReconnectFrame_EventType : int { + AutoReconnectFrame_EventType_UNKNOWN_EVENT_TYPE = 0, + AutoReconnectFrame_EventType_CLIENT_INTRODUCTION = 1, + AutoReconnectFrame_EventType_CLIENT_INTRODUCTION_ACK = 2 +}; +bool AutoReconnectFrame_EventType_IsValid(int value); +constexpr AutoReconnectFrame_EventType AutoReconnectFrame_EventType_EventType_MIN = AutoReconnectFrame_EventType_UNKNOWN_EVENT_TYPE; +constexpr AutoReconnectFrame_EventType AutoReconnectFrame_EventType_EventType_MAX = AutoReconnectFrame_EventType_CLIENT_INTRODUCTION_ACK; +constexpr int AutoReconnectFrame_EventType_EventType_ARRAYSIZE = AutoReconnectFrame_EventType_EventType_MAX + 1; + +const std::string& AutoReconnectFrame_EventType_Name(AutoReconnectFrame_EventType value); +template +inline const std::string& AutoReconnectFrame_EventType_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function AutoReconnectFrame_EventType_Name."); + return AutoReconnectFrame_EventType_Name(static_cast(enum_t_value)); +} +bool AutoReconnectFrame_EventType_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, AutoReconnectFrame_EventType* value); enum LocationStandard_Format : int { LocationStandard_Format_UNKNOWN = 0, LocationStandard_Format_E164_CALLING = 1, @@ -834,6 +884,10 @@ class V1Frame final : V1Frame_FrameType_AUTHENTICATION_MESSAGE; static constexpr FrameType AUTHENTICATION_RESULT = V1Frame_FrameType_AUTHENTICATION_RESULT; + static constexpr FrameType AUTO_RESUME = + V1Frame_FrameType_AUTO_RESUME; + static constexpr FrameType AUTO_RECONNECT = + V1Frame_FrameType_AUTO_RECONNECT; static inline bool FrameType_IsValid(int value) { return V1Frame_FrameType_IsValid(value); } @@ -867,6 +921,8 @@ class V1Frame final : kPairedKeyEncryptionFieldNumber = 8, kAuthenticationMessageFieldNumber = 9, kAuthenticationResultFieldNumber = 10, + kAutoResumeFieldNumber = 11, + kAutoReconnectFieldNumber = 12, kTypeFieldNumber = 1, }; // optional .location.nearby.connections.ConnectionRequestFrame connection_request = 2; @@ -1031,6 +1087,42 @@ class V1Frame final : ::location::nearby::connections::AuthenticationResultFrame* authentication_result); ::location::nearby::connections::AuthenticationResultFrame* unsafe_arena_release_authentication_result(); + // optional .location.nearby.connections.AutoResumeFrame auto_resume = 11; + bool has_auto_resume() const; + private: + bool _internal_has_auto_resume() const; + public: + void clear_auto_resume(); + const ::location::nearby::connections::AutoResumeFrame& auto_resume() const; + PROTOBUF_NODISCARD ::location::nearby::connections::AutoResumeFrame* release_auto_resume(); + ::location::nearby::connections::AutoResumeFrame* mutable_auto_resume(); + void set_allocated_auto_resume(::location::nearby::connections::AutoResumeFrame* auto_resume); + private: + const ::location::nearby::connections::AutoResumeFrame& _internal_auto_resume() const; + ::location::nearby::connections::AutoResumeFrame* _internal_mutable_auto_resume(); + public: + void unsafe_arena_set_allocated_auto_resume( + ::location::nearby::connections::AutoResumeFrame* auto_resume); + ::location::nearby::connections::AutoResumeFrame* unsafe_arena_release_auto_resume(); + + // optional .location.nearby.connections.AutoReconnectFrame auto_reconnect = 12; + bool has_auto_reconnect() const; + private: + bool _internal_has_auto_reconnect() const; + public: + void clear_auto_reconnect(); + const ::location::nearby::connections::AutoReconnectFrame& auto_reconnect() const; + PROTOBUF_NODISCARD ::location::nearby::connections::AutoReconnectFrame* release_auto_reconnect(); + ::location::nearby::connections::AutoReconnectFrame* mutable_auto_reconnect(); + void set_allocated_auto_reconnect(::location::nearby::connections::AutoReconnectFrame* auto_reconnect); + private: + const ::location::nearby::connections::AutoReconnectFrame& _internal_auto_reconnect() const; + ::location::nearby::connections::AutoReconnectFrame* _internal_mutable_auto_reconnect(); + public: + void unsafe_arena_set_allocated_auto_reconnect( + ::location::nearby::connections::AutoReconnectFrame* auto_reconnect); + ::location::nearby::connections::AutoReconnectFrame* unsafe_arena_release_auto_reconnect(); + // optional .location.nearby.connections.V1Frame.FrameType type = 1; bool has_type() const; private: @@ -1062,6 +1154,8 @@ class V1Frame final : ::location::nearby::connections::PairedKeyEncryptionFrame* paired_key_encryption_; ::location::nearby::connections::AuthenticationMessageFrame* authentication_message_; ::location::nearby::connections::AuthenticationResultFrame* authentication_result_; + ::location::nearby::connections::AutoResumeFrame* auto_resume_; + ::location::nearby::connections::AutoReconnectFrame* auto_reconnect_; int type_; friend struct ::TableStruct_connections_2fimplementation_2fproto_2foffline_5fwire_5fformats_2eproto; }; @@ -1645,6 +1739,7 @@ class ConnectionResponseFrame final : kResponseFieldNumber = 3, kMultiplexSocketBitmaskFieldNumber = 5, kNearbyConnectionsVersionFieldNumber = 6, + kSafeToDisconnectVersionFieldNumber = 7, }; // optional bytes handshake_data = 2; bool has_handshake_data() const; @@ -1721,19 +1816,32 @@ class ConnectionResponseFrame final : void _internal_set_multiplex_socket_bitmask(int32_t value); public: - // optional int32 nearby_connections_version = 6; - bool has_nearby_connections_version() const; + // optional int32 nearby_connections_version = 6 [deprecated = true]; + PROTOBUF_DEPRECATED bool has_nearby_connections_version() const; private: bool _internal_has_nearby_connections_version() const; public: - void clear_nearby_connections_version(); - int32_t nearby_connections_version() const; - void set_nearby_connections_version(int32_t value); + PROTOBUF_DEPRECATED void clear_nearby_connections_version(); + PROTOBUF_DEPRECATED int32_t nearby_connections_version() const; + PROTOBUF_DEPRECATED void set_nearby_connections_version(int32_t value); private: int32_t _internal_nearby_connections_version() const; void _internal_set_nearby_connections_version(int32_t value); public: + // optional int32 safe_to_disconnect_version = 7; + bool has_safe_to_disconnect_version() const; + private: + bool _internal_has_safe_to_disconnect_version() const; + public: + void clear_safe_to_disconnect_version(); + int32_t safe_to_disconnect_version() const; + void set_safe_to_disconnect_version(int32_t value); + private: + int32_t _internal_safe_to_disconnect_version() const; + void _internal_set_safe_to_disconnect_version(int32_t value); + public: + // @@protoc_insertion_point(class_scope:location.nearby.connections.ConnectionResponseFrame) private: class _Internal; @@ -1749,6 +1857,7 @@ class ConnectionResponseFrame final : int response_; int32_t multiplex_socket_bitmask_; int32_t nearby_connections_version_; + int32_t safe_to_disconnect_version_; friend struct ::TableStruct_connections_2fimplementation_2fproto_2foffline_5fwire_5fformats_2eproto; }; // ------------------------------------------------------------------- @@ -2150,6 +2259,7 @@ class PayloadTransferFrame_PayloadChunk final : kBodyFieldNumber = 3, kOffsetFieldNumber = 2, kFlagsFieldNumber = 1, + kIndexFieldNumber = 4, }; // optional bytes body = 3; bool has_body() const; @@ -2195,6 +2305,19 @@ class PayloadTransferFrame_PayloadChunk final : void _internal_set_flags(int32_t value); public: + // optional int32 index = 4; + bool has_index() const; + private: + bool _internal_has_index() const; + public: + void clear_index(); + int32_t index() const; + void set_index(int32_t value); + private: + int32_t _internal_index() const; + void _internal_set_index(int32_t value); + public: + // @@protoc_insertion_point(class_scope:location.nearby.connections.PayloadTransferFrame.PayloadChunk) private: class _Internal; @@ -2207,6 +2330,7 @@ class PayloadTransferFrame_PayloadChunk final : ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr body_; int64_t offset_; int32_t flags_; + int32_t index_; friend struct ::TableStruct_connections_2fimplementation_2fproto_2foffline_5fwire_5fformats_2eproto; }; // ------------------------------------------------------------------- @@ -4756,6 +4880,7 @@ class KeepAliveFrame final : enum : int { kAckFieldNumber = 1, + kSeqNumFieldNumber = 2, }; // optional bool ack = 1; bool has_ack() const; @@ -4770,6 +4895,19 @@ class KeepAliveFrame final : void _internal_set_ack(bool value); public: + // optional uint32 seq_num = 2; + bool has_seq_num() const; + private: + bool _internal_has_seq_num() const; + public: + void clear_seq_num(); + uint32_t seq_num() const; + void set_seq_num(uint32_t value); + private: + uint32_t _internal_seq_num() const; + void _internal_set_seq_num(uint32_t value); + public: + // @@protoc_insertion_point(class_scope:location.nearby.connections.KeepAliveFrame) private: class _Internal; @@ -4780,6 +4918,7 @@ class KeepAliveFrame final : ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; bool ack_; + uint32_t seq_num_; friend struct ::TableStruct_connections_2fimplementation_2fproto_2foffline_5fwire_5fformats_2eproto; }; // ------------------------------------------------------------------- @@ -5377,6 +5516,396 @@ class AuthenticationResultFrame final : }; // ------------------------------------------------------------------- +class AutoResumeFrame final : + public ::PROTOBUF_NAMESPACE_ID::MessageLite /* @@protoc_insertion_point(class_definition:location.nearby.connections.AutoResumeFrame) */ { + public: + inline AutoResumeFrame() : AutoResumeFrame(nullptr) {} + ~AutoResumeFrame() override; + explicit constexpr AutoResumeFrame(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + AutoResumeFrame(const AutoResumeFrame& from); + AutoResumeFrame(AutoResumeFrame&& from) noexcept + : AutoResumeFrame() { + *this = ::std::move(from); + } + + inline AutoResumeFrame& operator=(const AutoResumeFrame& from) { + CopyFrom(from); + return *this; + } + inline AutoResumeFrame& operator=(AutoResumeFrame&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const std::string& unknown_fields() const { + return _internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString); + } + inline std::string* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields(); + } + + static const AutoResumeFrame& default_instance() { + return *internal_default_instance(); + } + static inline const AutoResumeFrame* internal_default_instance() { + return reinterpret_cast( + &_AutoResumeFrame_default_instance_); + } + static constexpr int kIndexInFileMessages = + 23; + + friend void swap(AutoResumeFrame& a, AutoResumeFrame& b) { + a.Swap(&b); + } + inline void Swap(AutoResumeFrame* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(AutoResumeFrame* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + AutoResumeFrame* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + void CheckTypeAndMergeFrom(const ::PROTOBUF_NAMESPACE_ID::MessageLite& from) final; + void CopyFrom(const AutoResumeFrame& from); + void MergeFrom(const AutoResumeFrame& from); + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + void InternalSwap(AutoResumeFrame* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "location.nearby.connections.AutoResumeFrame"; + } + protected: + explicit AutoResumeFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + std::string GetTypeName() const final; + + // nested types ---------------------------------------------------- + + typedef AutoResumeFrame_EventType EventType; + static constexpr EventType UNKNOWN_AUTO_RESUME_EVENT_TYPE = + AutoResumeFrame_EventType_UNKNOWN_AUTO_RESUME_EVENT_TYPE; + static constexpr EventType PAYLOAD_RESUME_TRANSFER_START = + AutoResumeFrame_EventType_PAYLOAD_RESUME_TRANSFER_START; + static constexpr EventType PAYLOAD_RESUME_TRANSFER_ACK = + AutoResumeFrame_EventType_PAYLOAD_RESUME_TRANSFER_ACK; + static inline bool EventType_IsValid(int value) { + return AutoResumeFrame_EventType_IsValid(value); + } + static constexpr EventType EventType_MIN = + AutoResumeFrame_EventType_EventType_MIN; + static constexpr EventType EventType_MAX = + AutoResumeFrame_EventType_EventType_MAX; + static constexpr int EventType_ARRAYSIZE = + AutoResumeFrame_EventType_EventType_ARRAYSIZE; + template + static inline const std::string& EventType_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function EventType_Name."); + return AutoResumeFrame_EventType_Name(enum_t_value); + } + static inline bool EventType_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name, + EventType* value) { + return AutoResumeFrame_EventType_Parse(name, value); + } + + // accessors ------------------------------------------------------- + + enum : int { + kPendingPayloadIdFieldNumber = 2, + kEventTypeFieldNumber = 1, + kNextPayloadChunkIndexFieldNumber = 3, + }; + // optional int64 pending_payload_id = 2; + bool has_pending_payload_id() const; + private: + bool _internal_has_pending_payload_id() const; + public: + void clear_pending_payload_id(); + int64_t pending_payload_id() const; + void set_pending_payload_id(int64_t value); + private: + int64_t _internal_pending_payload_id() const; + void _internal_set_pending_payload_id(int64_t value); + public: + + // optional .location.nearby.connections.AutoResumeFrame.EventType event_type = 1; + bool has_event_type() const; + private: + bool _internal_has_event_type() const; + public: + void clear_event_type(); + ::location::nearby::connections::AutoResumeFrame_EventType event_type() const; + void set_event_type(::location::nearby::connections::AutoResumeFrame_EventType value); + private: + ::location::nearby::connections::AutoResumeFrame_EventType _internal_event_type() const; + void _internal_set_event_type(::location::nearby::connections::AutoResumeFrame_EventType value); + public: + + // optional int32 next_payload_chunk_index = 3; + bool has_next_payload_chunk_index() const; + private: + bool _internal_has_next_payload_chunk_index() const; + public: + void clear_next_payload_chunk_index(); + int32_t next_payload_chunk_index() const; + void set_next_payload_chunk_index(int32_t value); + private: + int32_t _internal_next_payload_chunk_index() const; + void _internal_set_next_payload_chunk_index(int32_t value); + public: + + // @@protoc_insertion_point(class_scope:location.nearby.connections.AutoResumeFrame) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + int64_t pending_payload_id_; + int event_type_; + int32_t next_payload_chunk_index_; + friend struct ::TableStruct_connections_2fimplementation_2fproto_2foffline_5fwire_5fformats_2eproto; +}; +// ------------------------------------------------------------------- + +class AutoReconnectFrame final : + public ::PROTOBUF_NAMESPACE_ID::MessageLite /* @@protoc_insertion_point(class_definition:location.nearby.connections.AutoReconnectFrame) */ { + public: + inline AutoReconnectFrame() : AutoReconnectFrame(nullptr) {} + ~AutoReconnectFrame() override; + explicit constexpr AutoReconnectFrame(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + AutoReconnectFrame(const AutoReconnectFrame& from); + AutoReconnectFrame(AutoReconnectFrame&& from) noexcept + : AutoReconnectFrame() { + *this = ::std::move(from); + } + + inline AutoReconnectFrame& operator=(const AutoReconnectFrame& from) { + CopyFrom(from); + return *this; + } + inline AutoReconnectFrame& operator=(AutoReconnectFrame&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const std::string& unknown_fields() const { + return _internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString); + } + inline std::string* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields(); + } + + static const AutoReconnectFrame& default_instance() { + return *internal_default_instance(); + } + static inline const AutoReconnectFrame* internal_default_instance() { + return reinterpret_cast( + &_AutoReconnectFrame_default_instance_); + } + static constexpr int kIndexInFileMessages = + 24; + + friend void swap(AutoReconnectFrame& a, AutoReconnectFrame& b) { + a.Swap(&b); + } + inline void Swap(AutoReconnectFrame* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(AutoReconnectFrame* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + AutoReconnectFrame* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + void CheckTypeAndMergeFrom(const ::PROTOBUF_NAMESPACE_ID::MessageLite& from) final; + void CopyFrom(const AutoReconnectFrame& from); + void MergeFrom(const AutoReconnectFrame& from); + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + void InternalSwap(AutoReconnectFrame* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "location.nearby.connections.AutoReconnectFrame"; + } + protected: + explicit AutoReconnectFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + std::string GetTypeName() const final; + + // nested types ---------------------------------------------------- + + typedef AutoReconnectFrame_EventType EventType; + static constexpr EventType UNKNOWN_EVENT_TYPE = + AutoReconnectFrame_EventType_UNKNOWN_EVENT_TYPE; + static constexpr EventType CLIENT_INTRODUCTION = + AutoReconnectFrame_EventType_CLIENT_INTRODUCTION; + static constexpr EventType CLIENT_INTRODUCTION_ACK = + AutoReconnectFrame_EventType_CLIENT_INTRODUCTION_ACK; + static inline bool EventType_IsValid(int value) { + return AutoReconnectFrame_EventType_IsValid(value); + } + static constexpr EventType EventType_MIN = + AutoReconnectFrame_EventType_EventType_MIN; + static constexpr EventType EventType_MAX = + AutoReconnectFrame_EventType_EventType_MAX; + static constexpr int EventType_ARRAYSIZE = + AutoReconnectFrame_EventType_EventType_ARRAYSIZE; + template + static inline const std::string& EventType_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function EventType_Name."); + return AutoReconnectFrame_EventType_Name(enum_t_value); + } + static inline bool EventType_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name, + EventType* value) { + return AutoReconnectFrame_EventType_Parse(name, value); + } + + // accessors ------------------------------------------------------- + + enum : int { + kEndpointIdFieldNumber = 1, + kEventTypeFieldNumber = 2, + }; + // optional string endpoint_id = 1; + bool has_endpoint_id() const; + private: + bool _internal_has_endpoint_id() const; + public: + void clear_endpoint_id(); + const std::string& endpoint_id() const; + template + void set_endpoint_id(ArgT0&& arg0, ArgT... args); + std::string* mutable_endpoint_id(); + PROTOBUF_NODISCARD std::string* release_endpoint_id(); + void set_allocated_endpoint_id(std::string* endpoint_id); + private: + const std::string& _internal_endpoint_id() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_endpoint_id(const std::string& value); + std::string* _internal_mutable_endpoint_id(); + public: + + // optional .location.nearby.connections.AutoReconnectFrame.EventType event_type = 2; + bool has_event_type() const; + private: + bool _internal_has_event_type() const; + public: + void clear_event_type(); + ::location::nearby::connections::AutoReconnectFrame_EventType event_type() const; + void set_event_type(::location::nearby::connections::AutoReconnectFrame_EventType value); + private: + ::location::nearby::connections::AutoReconnectFrame_EventType _internal_event_type() const; + void _internal_set_event_type(::location::nearby::connections::AutoReconnectFrame_EventType value); + public: + + // @@protoc_insertion_point(class_scope:location.nearby.connections.AutoReconnectFrame) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr endpoint_id_; + int event_type_; + friend struct ::TableStruct_connections_2fimplementation_2fproto_2foffline_5fwire_5fformats_2eproto; +}; +// ------------------------------------------------------------------- + class MediumMetadata final : public ::PROTOBUF_NAMESPACE_ID::MessageLite /* @@protoc_insertion_point(class_definition:location.nearby.connections.MediumMetadata) */ { public: @@ -5423,7 +5952,7 @@ class MediumMetadata final : &_MediumMetadata_default_instance_); } static constexpr int kIndexInFileMessages = - 23; + 25; friend void swap(MediumMetadata& a, MediumMetadata& b) { a.Swap(&b); @@ -5750,7 +6279,7 @@ class AvailableChannels final : &_AvailableChannels_default_instance_); } static constexpr int kIndexInFileMessages = - 24; + 26; friend void swap(AvailableChannels& a, AvailableChannels& b) { a.Swap(&b); @@ -5901,7 +6430,7 @@ class WifiDirectCliUsableChannels final : &_WifiDirectCliUsableChannels_default_instance_); } static constexpr int kIndexInFileMessages = - 25; + 27; friend void swap(WifiDirectCliUsableChannels& a, WifiDirectCliUsableChannels& b) { a.Swap(&b); @@ -6052,7 +6581,7 @@ class WifiLanUsableChannels final : &_WifiLanUsableChannels_default_instance_); } static constexpr int kIndexInFileMessages = - 26; + 28; friend void swap(WifiLanUsableChannels& a, WifiLanUsableChannels& b) { a.Swap(&b); @@ -6203,7 +6732,7 @@ class WifiAwareUsableChannels final : &_WifiAwareUsableChannels_default_instance_); } static constexpr int kIndexInFileMessages = - 27; + 29; friend void swap(WifiAwareUsableChannels& a, WifiAwareUsableChannels& b) { a.Swap(&b); @@ -6354,7 +6883,7 @@ class WifiHotspotStaUsableChannels final : &_WifiHotspotStaUsableChannels_default_instance_); } static constexpr int kIndexInFileMessages = - 28; + 30; friend void swap(WifiHotspotStaUsableChannels& a, WifiHotspotStaUsableChannels& b) { a.Swap(&b); @@ -6505,7 +7034,7 @@ class LocationHint final : &_LocationHint_default_instance_); } static constexpr int kIndexInFileMessages = - 29; + 31; friend void swap(LocationHint& a, LocationHint& b) { a.Swap(&b); @@ -6667,7 +7196,7 @@ class LocationStandard final : &_LocationStandard_default_instance_); } static constexpr int kIndexInFileMessages = - 30; + 32; friend void swap(LocationStandard& a, LocationStandard& b) { a.Swap(&b); @@ -6819,7 +7348,7 @@ class OsInfo final : &_OsInfo_default_instance_); } static constexpr int kIndexInFileMessages = - 31; + 33; friend void swap(OsInfo& a, OsInfo& b) { a.Swap(&b); @@ -6995,7 +7524,7 @@ class ConnectionsDevice final : &_ConnectionsDevice_default_instance_); } static constexpr int kIndexInFileMessages = - 32; + 34; friend void swap(ConnectionsDevice& a, ConnectionsDevice& b) { a.Swap(&b); @@ -7197,7 +7726,7 @@ class PresenceDevice final : &_PresenceDevice_default_instance_); } static constexpr int kIndexInFileMessages = - 33; + 35; friend void swap(PresenceDevice& a, PresenceDevice& b) { a.Swap(&b); @@ -7643,7 +8172,7 @@ inline void OfflineFrame::set_allocated_v1(::location::nearby::connections::V1Fr // optional .location.nearby.connections.V1Frame.FrameType type = 1; inline bool V1Frame::_internal_has_type() const { - bool value = (_has_bits_[0] & 0x00000200u) != 0; + bool value = (_has_bits_[0] & 0x00000800u) != 0; return value; } inline bool V1Frame::has_type() const { @@ -7651,7 +8180,7 @@ inline bool V1Frame::has_type() const { } inline void V1Frame::clear_type() { type_ = 0; - _has_bits_[0] &= ~0x00000200u; + _has_bits_[0] &= ~0x00000800u; } inline ::location::nearby::connections::V1Frame_FrameType V1Frame::_internal_type() const { return static_cast< ::location::nearby::connections::V1Frame_FrameType >(type_); @@ -7662,7 +8191,7 @@ inline ::location::nearby::connections::V1Frame_FrameType V1Frame::type() const } inline void V1Frame::_internal_set_type(::location::nearby::connections::V1Frame_FrameType value) { assert(::location::nearby::connections::V1Frame_FrameType_IsValid(value)); - _has_bits_[0] |= 0x00000200u; + _has_bits_[0] |= 0x00000800u; type_ = value; } inline void V1Frame::set_type(::location::nearby::connections::V1Frame_FrameType value) { @@ -8480,6 +9009,186 @@ inline void V1Frame::set_allocated_authentication_result(::location::nearby::con // @@protoc_insertion_point(field_set_allocated:location.nearby.connections.V1Frame.authentication_result) } +// optional .location.nearby.connections.AutoResumeFrame auto_resume = 11; +inline bool V1Frame::_internal_has_auto_resume() const { + bool value = (_has_bits_[0] & 0x00000200u) != 0; + PROTOBUF_ASSUME(!value || auto_resume_ != nullptr); + return value; +} +inline bool V1Frame::has_auto_resume() const { + return _internal_has_auto_resume(); +} +inline void V1Frame::clear_auto_resume() { + if (auto_resume_ != nullptr) auto_resume_->Clear(); + _has_bits_[0] &= ~0x00000200u; +} +inline const ::location::nearby::connections::AutoResumeFrame& V1Frame::_internal_auto_resume() const { + const ::location::nearby::connections::AutoResumeFrame* p = auto_resume_; + return p != nullptr ? *p : reinterpret_cast( + ::location::nearby::connections::_AutoResumeFrame_default_instance_); +} +inline const ::location::nearby::connections::AutoResumeFrame& V1Frame::auto_resume() const { + // @@protoc_insertion_point(field_get:location.nearby.connections.V1Frame.auto_resume) + return _internal_auto_resume(); +} +inline void V1Frame::unsafe_arena_set_allocated_auto_resume( + ::location::nearby::connections::AutoResumeFrame* auto_resume) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(auto_resume_); + } + auto_resume_ = auto_resume; + if (auto_resume) { + _has_bits_[0] |= 0x00000200u; + } else { + _has_bits_[0] &= ~0x00000200u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:location.nearby.connections.V1Frame.auto_resume) +} +inline ::location::nearby::connections::AutoResumeFrame* V1Frame::release_auto_resume() { + _has_bits_[0] &= ~0x00000200u; + ::location::nearby::connections::AutoResumeFrame* temp = auto_resume_; + auto_resume_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::location::nearby::connections::AutoResumeFrame* V1Frame::unsafe_arena_release_auto_resume() { + // @@protoc_insertion_point(field_release:location.nearby.connections.V1Frame.auto_resume) + _has_bits_[0] &= ~0x00000200u; + ::location::nearby::connections::AutoResumeFrame* temp = auto_resume_; + auto_resume_ = nullptr; + return temp; +} +inline ::location::nearby::connections::AutoResumeFrame* V1Frame::_internal_mutable_auto_resume() { + _has_bits_[0] |= 0x00000200u; + if (auto_resume_ == nullptr) { + auto* p = CreateMaybeMessage<::location::nearby::connections::AutoResumeFrame>(GetArenaForAllocation()); + auto_resume_ = p; + } + return auto_resume_; +} +inline ::location::nearby::connections::AutoResumeFrame* V1Frame::mutable_auto_resume() { + ::location::nearby::connections::AutoResumeFrame* _msg = _internal_mutable_auto_resume(); + // @@protoc_insertion_point(field_mutable:location.nearby.connections.V1Frame.auto_resume) + return _msg; +} +inline void V1Frame::set_allocated_auto_resume(::location::nearby::connections::AutoResumeFrame* auto_resume) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete auto_resume_; + } + if (auto_resume) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::location::nearby::connections::AutoResumeFrame>::GetOwningArena(auto_resume); + if (message_arena != submessage_arena) { + auto_resume = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, auto_resume, submessage_arena); + } + _has_bits_[0] |= 0x00000200u; + } else { + _has_bits_[0] &= ~0x00000200u; + } + auto_resume_ = auto_resume; + // @@protoc_insertion_point(field_set_allocated:location.nearby.connections.V1Frame.auto_resume) +} + +// optional .location.nearby.connections.AutoReconnectFrame auto_reconnect = 12; +inline bool V1Frame::_internal_has_auto_reconnect() const { + bool value = (_has_bits_[0] & 0x00000400u) != 0; + PROTOBUF_ASSUME(!value || auto_reconnect_ != nullptr); + return value; +} +inline bool V1Frame::has_auto_reconnect() const { + return _internal_has_auto_reconnect(); +} +inline void V1Frame::clear_auto_reconnect() { + if (auto_reconnect_ != nullptr) auto_reconnect_->Clear(); + _has_bits_[0] &= ~0x00000400u; +} +inline const ::location::nearby::connections::AutoReconnectFrame& V1Frame::_internal_auto_reconnect() const { + const ::location::nearby::connections::AutoReconnectFrame* p = auto_reconnect_; + return p != nullptr ? *p : reinterpret_cast( + ::location::nearby::connections::_AutoReconnectFrame_default_instance_); +} +inline const ::location::nearby::connections::AutoReconnectFrame& V1Frame::auto_reconnect() const { + // @@protoc_insertion_point(field_get:location.nearby.connections.V1Frame.auto_reconnect) + return _internal_auto_reconnect(); +} +inline void V1Frame::unsafe_arena_set_allocated_auto_reconnect( + ::location::nearby::connections::AutoReconnectFrame* auto_reconnect) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(auto_reconnect_); + } + auto_reconnect_ = auto_reconnect; + if (auto_reconnect) { + _has_bits_[0] |= 0x00000400u; + } else { + _has_bits_[0] &= ~0x00000400u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:location.nearby.connections.V1Frame.auto_reconnect) +} +inline ::location::nearby::connections::AutoReconnectFrame* V1Frame::release_auto_reconnect() { + _has_bits_[0] &= ~0x00000400u; + ::location::nearby::connections::AutoReconnectFrame* temp = auto_reconnect_; + auto_reconnect_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::location::nearby::connections::AutoReconnectFrame* V1Frame::unsafe_arena_release_auto_reconnect() { + // @@protoc_insertion_point(field_release:location.nearby.connections.V1Frame.auto_reconnect) + _has_bits_[0] &= ~0x00000400u; + ::location::nearby::connections::AutoReconnectFrame* temp = auto_reconnect_; + auto_reconnect_ = nullptr; + return temp; +} +inline ::location::nearby::connections::AutoReconnectFrame* V1Frame::_internal_mutable_auto_reconnect() { + _has_bits_[0] |= 0x00000400u; + if (auto_reconnect_ == nullptr) { + auto* p = CreateMaybeMessage<::location::nearby::connections::AutoReconnectFrame>(GetArenaForAllocation()); + auto_reconnect_ = p; + } + return auto_reconnect_; +} +inline ::location::nearby::connections::AutoReconnectFrame* V1Frame::mutable_auto_reconnect() { + ::location::nearby::connections::AutoReconnectFrame* _msg = _internal_mutable_auto_reconnect(); + // @@protoc_insertion_point(field_mutable:location.nearby.connections.V1Frame.auto_reconnect) + return _msg; +} +inline void V1Frame::set_allocated_auto_reconnect(::location::nearby::connections::AutoReconnectFrame* auto_reconnect) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete auto_reconnect_; + } + if (auto_reconnect) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::location::nearby::connections::AutoReconnectFrame>::GetOwningArena(auto_reconnect); + if (message_arena != submessage_arena) { + auto_reconnect = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, auto_reconnect, submessage_arena); + } + _has_bits_[0] |= 0x00000400u; + } else { + _has_bits_[0] &= ~0x00000400u; + } + auto_reconnect_ = auto_reconnect; + // @@protoc_insertion_point(field_set_allocated:location.nearby.connections.V1Frame.auto_reconnect) +} + // ------------------------------------------------------------------- // ConnectionRequestFrame @@ -9481,7 +10190,7 @@ inline void ConnectionResponseFrame::set_multiplex_socket_bitmask(int32_t value) // @@protoc_insertion_point(field_set:location.nearby.connections.ConnectionResponseFrame.multiplex_socket_bitmask) } -// optional int32 nearby_connections_version = 6; +// optional int32 nearby_connections_version = 6 [deprecated = true]; inline bool ConnectionResponseFrame::_internal_has_nearby_connections_version() const { bool value = (_has_bits_[0] & 0x00000020u) != 0; return value; @@ -9509,6 +10218,34 @@ inline void ConnectionResponseFrame::set_nearby_connections_version(int32_t valu // @@protoc_insertion_point(field_set:location.nearby.connections.ConnectionResponseFrame.nearby_connections_version) } +// optional int32 safe_to_disconnect_version = 7; +inline bool ConnectionResponseFrame::_internal_has_safe_to_disconnect_version() const { + bool value = (_has_bits_[0] & 0x00000040u) != 0; + return value; +} +inline bool ConnectionResponseFrame::has_safe_to_disconnect_version() const { + return _internal_has_safe_to_disconnect_version(); +} +inline void ConnectionResponseFrame::clear_safe_to_disconnect_version() { + safe_to_disconnect_version_ = 0; + _has_bits_[0] &= ~0x00000040u; +} +inline int32_t ConnectionResponseFrame::_internal_safe_to_disconnect_version() const { + return safe_to_disconnect_version_; +} +inline int32_t ConnectionResponseFrame::safe_to_disconnect_version() const { + // @@protoc_insertion_point(field_get:location.nearby.connections.ConnectionResponseFrame.safe_to_disconnect_version) + return _internal_safe_to_disconnect_version(); +} +inline void ConnectionResponseFrame::_internal_set_safe_to_disconnect_version(int32_t value) { + _has_bits_[0] |= 0x00000040u; + safe_to_disconnect_version_ = value; +} +inline void ConnectionResponseFrame::set_safe_to_disconnect_version(int32_t value) { + _internal_set_safe_to_disconnect_version(value); + // @@protoc_insertion_point(field_set:location.nearby.connections.ConnectionResponseFrame.safe_to_disconnect_version) +} + // ------------------------------------------------------------------- // PayloadTransferFrame_PayloadHeader @@ -9893,6 +10630,34 @@ inline void PayloadTransferFrame_PayloadChunk::set_allocated_body(std::string* b // @@protoc_insertion_point(field_set_allocated:location.nearby.connections.PayloadTransferFrame.PayloadChunk.body) } +// optional int32 index = 4; +inline bool PayloadTransferFrame_PayloadChunk::_internal_has_index() const { + bool value = (_has_bits_[0] & 0x00000008u) != 0; + return value; +} +inline bool PayloadTransferFrame_PayloadChunk::has_index() const { + return _internal_has_index(); +} +inline void PayloadTransferFrame_PayloadChunk::clear_index() { + index_ = 0; + _has_bits_[0] &= ~0x00000008u; +} +inline int32_t PayloadTransferFrame_PayloadChunk::_internal_index() const { + return index_; +} +inline int32_t PayloadTransferFrame_PayloadChunk::index() const { + // @@protoc_insertion_point(field_get:location.nearby.connections.PayloadTransferFrame.PayloadChunk.index) + return _internal_index(); +} +inline void PayloadTransferFrame_PayloadChunk::_internal_set_index(int32_t value) { + _has_bits_[0] |= 0x00000008u; + index_ = value; +} +inline void PayloadTransferFrame_PayloadChunk::set_index(int32_t value) { + _internal_set_index(value); + // @@protoc_insertion_point(field_set:location.nearby.connections.PayloadTransferFrame.PayloadChunk.index) +} + // ------------------------------------------------------------------- // PayloadTransferFrame_ControlMessage @@ -12528,6 +13293,34 @@ inline void KeepAliveFrame::set_ack(bool value) { // @@protoc_insertion_point(field_set:location.nearby.connections.KeepAliveFrame.ack) } +// optional uint32 seq_num = 2; +inline bool KeepAliveFrame::_internal_has_seq_num() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool KeepAliveFrame::has_seq_num() const { + return _internal_has_seq_num(); +} +inline void KeepAliveFrame::clear_seq_num() { + seq_num_ = 0u; + _has_bits_[0] &= ~0x00000002u; +} +inline uint32_t KeepAliveFrame::_internal_seq_num() const { + return seq_num_; +} +inline uint32_t KeepAliveFrame::seq_num() const { + // @@protoc_insertion_point(field_get:location.nearby.connections.KeepAliveFrame.seq_num) + return _internal_seq_num(); +} +inline void KeepAliveFrame::_internal_set_seq_num(uint32_t value) { + _has_bits_[0] |= 0x00000002u; + seq_num_ = value; +} +inline void KeepAliveFrame::set_seq_num(uint32_t value) { + _internal_set_seq_num(value); + // @@protoc_insertion_point(field_set:location.nearby.connections.KeepAliveFrame.seq_num) +} + // ------------------------------------------------------------------- // DisconnectionFrame @@ -12768,6 +13561,197 @@ inline void AuthenticationResultFrame::set_result(int32_t value) { // ------------------------------------------------------------------- +// AutoResumeFrame + +// optional .location.nearby.connections.AutoResumeFrame.EventType event_type = 1; +inline bool AutoResumeFrame::_internal_has_event_type() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool AutoResumeFrame::has_event_type() const { + return _internal_has_event_type(); +} +inline void AutoResumeFrame::clear_event_type() { + event_type_ = 0; + _has_bits_[0] &= ~0x00000002u; +} +inline ::location::nearby::connections::AutoResumeFrame_EventType AutoResumeFrame::_internal_event_type() const { + return static_cast< ::location::nearby::connections::AutoResumeFrame_EventType >(event_type_); +} +inline ::location::nearby::connections::AutoResumeFrame_EventType AutoResumeFrame::event_type() const { + // @@protoc_insertion_point(field_get:location.nearby.connections.AutoResumeFrame.event_type) + return _internal_event_type(); +} +inline void AutoResumeFrame::_internal_set_event_type(::location::nearby::connections::AutoResumeFrame_EventType value) { + assert(::location::nearby::connections::AutoResumeFrame_EventType_IsValid(value)); + _has_bits_[0] |= 0x00000002u; + event_type_ = value; +} +inline void AutoResumeFrame::set_event_type(::location::nearby::connections::AutoResumeFrame_EventType value) { + _internal_set_event_type(value); + // @@protoc_insertion_point(field_set:location.nearby.connections.AutoResumeFrame.event_type) +} + +// optional int64 pending_payload_id = 2; +inline bool AutoResumeFrame::_internal_has_pending_payload_id() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool AutoResumeFrame::has_pending_payload_id() const { + return _internal_has_pending_payload_id(); +} +inline void AutoResumeFrame::clear_pending_payload_id() { + pending_payload_id_ = int64_t{0}; + _has_bits_[0] &= ~0x00000001u; +} +inline int64_t AutoResumeFrame::_internal_pending_payload_id() const { + return pending_payload_id_; +} +inline int64_t AutoResumeFrame::pending_payload_id() const { + // @@protoc_insertion_point(field_get:location.nearby.connections.AutoResumeFrame.pending_payload_id) + return _internal_pending_payload_id(); +} +inline void AutoResumeFrame::_internal_set_pending_payload_id(int64_t value) { + _has_bits_[0] |= 0x00000001u; + pending_payload_id_ = value; +} +inline void AutoResumeFrame::set_pending_payload_id(int64_t value) { + _internal_set_pending_payload_id(value); + // @@protoc_insertion_point(field_set:location.nearby.connections.AutoResumeFrame.pending_payload_id) +} + +// optional int32 next_payload_chunk_index = 3; +inline bool AutoResumeFrame::_internal_has_next_payload_chunk_index() const { + bool value = (_has_bits_[0] & 0x00000004u) != 0; + return value; +} +inline bool AutoResumeFrame::has_next_payload_chunk_index() const { + return _internal_has_next_payload_chunk_index(); +} +inline void AutoResumeFrame::clear_next_payload_chunk_index() { + next_payload_chunk_index_ = 0; + _has_bits_[0] &= ~0x00000004u; +} +inline int32_t AutoResumeFrame::_internal_next_payload_chunk_index() const { + return next_payload_chunk_index_; +} +inline int32_t AutoResumeFrame::next_payload_chunk_index() const { + // @@protoc_insertion_point(field_get:location.nearby.connections.AutoResumeFrame.next_payload_chunk_index) + return _internal_next_payload_chunk_index(); +} +inline void AutoResumeFrame::_internal_set_next_payload_chunk_index(int32_t value) { + _has_bits_[0] |= 0x00000004u; + next_payload_chunk_index_ = value; +} +inline void AutoResumeFrame::set_next_payload_chunk_index(int32_t value) { + _internal_set_next_payload_chunk_index(value); + // @@protoc_insertion_point(field_set:location.nearby.connections.AutoResumeFrame.next_payload_chunk_index) +} + +// ------------------------------------------------------------------- + +// AutoReconnectFrame + +// optional string endpoint_id = 1; +inline bool AutoReconnectFrame::_internal_has_endpoint_id() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool AutoReconnectFrame::has_endpoint_id() const { + return _internal_has_endpoint_id(); +} +inline void AutoReconnectFrame::clear_endpoint_id() { + endpoint_id_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000001u; +} +inline const std::string& AutoReconnectFrame::endpoint_id() const { + // @@protoc_insertion_point(field_get:location.nearby.connections.AutoReconnectFrame.endpoint_id) + return _internal_endpoint_id(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void AutoReconnectFrame::set_endpoint_id(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000001u; + endpoint_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:location.nearby.connections.AutoReconnectFrame.endpoint_id) +} +inline std::string* AutoReconnectFrame::mutable_endpoint_id() { + std::string* _s = _internal_mutable_endpoint_id(); + // @@protoc_insertion_point(field_mutable:location.nearby.connections.AutoReconnectFrame.endpoint_id) + return _s; +} +inline const std::string& AutoReconnectFrame::_internal_endpoint_id() const { + return endpoint_id_.Get(); +} +inline void AutoReconnectFrame::_internal_set_endpoint_id(const std::string& value) { + _has_bits_[0] |= 0x00000001u; + endpoint_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* AutoReconnectFrame::_internal_mutable_endpoint_id() { + _has_bits_[0] |= 0x00000001u; + return endpoint_id_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* AutoReconnectFrame::release_endpoint_id() { + // @@protoc_insertion_point(field_release:location.nearby.connections.AutoReconnectFrame.endpoint_id) + if (!_internal_has_endpoint_id()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000001u; + auto* p = endpoint_id_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (endpoint_id_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + endpoint_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void AutoReconnectFrame::set_allocated_endpoint_id(std::string* endpoint_id) { + if (endpoint_id != nullptr) { + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + endpoint_id_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), endpoint_id, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (endpoint_id_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + endpoint_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:location.nearby.connections.AutoReconnectFrame.endpoint_id) +} + +// optional .location.nearby.connections.AutoReconnectFrame.EventType event_type = 2; +inline bool AutoReconnectFrame::_internal_has_event_type() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool AutoReconnectFrame::has_event_type() const { + return _internal_has_event_type(); +} +inline void AutoReconnectFrame::clear_event_type() { + event_type_ = 0; + _has_bits_[0] &= ~0x00000002u; +} +inline ::location::nearby::connections::AutoReconnectFrame_EventType AutoReconnectFrame::_internal_event_type() const { + return static_cast< ::location::nearby::connections::AutoReconnectFrame_EventType >(event_type_); +} +inline ::location::nearby::connections::AutoReconnectFrame_EventType AutoReconnectFrame::event_type() const { + // @@protoc_insertion_point(field_get:location.nearby.connections.AutoReconnectFrame.event_type) + return _internal_event_type(); +} +inline void AutoReconnectFrame::_internal_set_event_type(::location::nearby::connections::AutoReconnectFrame_EventType value) { + assert(::location::nearby::connections::AutoReconnectFrame_EventType_IsValid(value)); + _has_bits_[0] |= 0x00000002u; + event_type_ = value; +} +inline void AutoReconnectFrame::set_event_type(::location::nearby::connections::AutoReconnectFrame_EventType value) { + _internal_set_event_type(value); + // @@protoc_insertion_point(field_set:location.nearby.connections.AutoReconnectFrame.event_type) +} + +// ------------------------------------------------------------------- + // MediumMetadata // optional bool supports_5_ghz = 1; @@ -14678,6 +15662,10 @@ PresenceDevice::mutable_identity_type() { // ------------------------------------------------------------------- +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + // @@protoc_insertion_point(namespace_scope) @@ -14697,6 +15685,8 @@ template <> struct is_proto_enum< ::location::nearby::connections::PayloadTransf template <> struct is_proto_enum< ::location::nearby::connections::PayloadTransferFrame_PacketType> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::connections::BandwidthUpgradeNegotiationFrame_UpgradePathInfo_Medium> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::connections::BandwidthUpgradeNegotiationFrame_EventType> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::connections::AutoResumeFrame_EventType> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::connections::AutoReconnectFrame_EventType> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::connections::LocationStandard_Format> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::connections::OsInfo_OsType> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::connections::PresenceDevice_DeviceType> : ::std::true_type {}; diff --git a/compiled_proto/presence/proto/presence_frame.pb.cc b/compiled_proto/presence/proto/presence_frame.pb.cc new file mode 100644 index 00000000..f1340dee --- /dev/null +++ b/compiled_proto/presence/proto/presence_frame.pb.cc @@ -0,0 +1,4258 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: presence/proto/presence_frame.proto + +#include "presence/proto/presence_frame.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) +#include + +PROTOBUF_PRAGMA_INIT_SEG +namespace nearby { +namespace presence { +constexpr PresenceFrame::PresenceFrame( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : v1_frame_(nullptr){} +struct PresenceFrameDefaultTypeInternal { + constexpr PresenceFrameDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~PresenceFrameDefaultTypeInternal() {} + union { + PresenceFrame _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PresenceFrameDefaultTypeInternal _PresenceFrame_default_instance_; +constexpr V1Frame::V1Frame( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : _oneof_case_{}{} +struct V1FrameDefaultTypeInternal { + constexpr V1FrameDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~V1FrameDefaultTypeInternal() {} + union { + V1Frame _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT V1FrameDefaultTypeInternal _V1Frame_default_instance_; +constexpr DeviceIdentityFrame::DeviceIdentityFrame( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : action_() + , _action_cached_byte_size_(0) + , device_name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , bluetooth_mac_address_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , device_image_url_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , model_id_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , device_model_name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , device_type_(0){} +struct DeviceIdentityFrameDefaultTypeInternal { + constexpr DeviceIdentityFrameDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~DeviceIdentityFrameDefaultTypeInternal() {} + union { + DeviceIdentityFrame _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT DeviceIdentityFrameDefaultTypeInternal _DeviceIdentityFrame_default_instance_; +constexpr ConnectionInitFrame::ConnectionInitFrame( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : actions_() + , _actions_cached_byte_size_(0) + , identity_type_(0) + , uwb_enable_(false) + , device_unique_id_(int64_t{0}){} +struct ConnectionInitFrameDefaultTypeInternal { + constexpr ConnectionInitFrameDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~ConnectionInitFrameDefaultTypeInternal() {} + union { + ConnectionInitFrame _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ConnectionInitFrameDefaultTypeInternal _ConnectionInitFrame_default_instance_; +constexpr UwbControleeCapabilities::UwbControleeCapabilities( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : supported_config_ids_() + , _supported_config_ids_cached_byte_size_(0) + , supported_channels_() + , _supported_channels_cached_byte_size_(0) + , supported_ntf_configs_() + , _supported_ntf_configs_cached_byte_size_(0) + , supported_slot_durations_() + , _supported_slot_durations_cached_byte_size_(0) + , supported_ranging_update_rates_() + , _supported_ranging_update_rates_cached_byte_size_(0) + , multi_chip_info_() + , controlee_address_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , sub_session_id_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , sub_session_key_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , device_unique_id_(int64_t{0}) + , min_ranging_interval_ms_(0) + , ranging_disabled_(false) + , is_elevation_supported_(false) + , is_ranging_interval_reconfigure_supported_(false) + , chip_count_(1) + , is_distance_supported_(true) + , is_azimuth_supported_(true) + , min_slot_duration_ms_(2){} +struct UwbControleeCapabilitiesDefaultTypeInternal { + constexpr UwbControleeCapabilitiesDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~UwbControleeCapabilitiesDefaultTypeInternal() {} + union { + UwbControleeCapabilities _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT UwbControleeCapabilitiesDefaultTypeInternal _UwbControleeCapabilities_default_instance_; +constexpr UwbMultiChipInfo::UwbMultiChipInfo( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : controlee_address_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , chip_id_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string){} +struct UwbMultiChipInfoDefaultTypeInternal { + constexpr UwbMultiChipInfoDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~UwbMultiChipInfoDefaultTypeInternal() {} + union { + UwbMultiChipInfo _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT UwbMultiChipInfoDefaultTypeInternal _UwbMultiChipInfo_default_instance_; +constexpr UwbConnectionInfo::UwbConnectionInfo( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : controller_address_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , vendor_id_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , static_sts_iv_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , session_key_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , channel_(0) + , preamble_index_(0) + , config_id_(0) + , ranging_interval_ms_(0) + , session_id_(0) + , ranging_disabled_(false){} +struct UwbConnectionInfoDefaultTypeInternal { + constexpr UwbConnectionInfoDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~UwbConnectionInfoDefaultTypeInternal() {} + union { + UwbConnectionInfo _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT UwbConnectionInfoDefaultTypeInternal _UwbConnectionInfo_default_instance_; +constexpr ControlFrame::ControlFrame( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : type_(0) +{} +struct ControlFrameDefaultTypeInternal { + constexpr ControlFrameDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~ControlFrameDefaultTypeInternal() {} + union { + ControlFrame _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ControlFrameDefaultTypeInternal _ControlFrame_default_instance_; +constexpr PresenceAuthenticationFrame::PresenceAuthenticationFrame( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : private_key_signature_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , shared_credential_id_hash_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , credential_id_hash_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , version_(0){} +struct PresenceAuthenticationFrameDefaultTypeInternal { + constexpr PresenceAuthenticationFrameDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~PresenceAuthenticationFrameDefaultTypeInternal() {} + union { + PresenceAuthenticationFrame _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PresenceAuthenticationFrameDefaultTypeInternal _PresenceAuthenticationFrame_default_instance_; +} // namespace presence +} // namespace nearby +static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_presence_2fproto_2fpresence_5fframe_2eproto[9]; +static const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* file_level_enum_descriptors_presence_2fproto_2fpresence_5fframe_2eproto[2]; +static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_presence_2fproto_2fpresence_5fframe_2eproto = nullptr; + +const uint32_t TableStruct_presence_2fproto_2fpresence_5fframe_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + PROTOBUF_FIELD_OFFSET(::nearby::presence::PresenceFrame, _has_bits_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::PresenceFrame, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::nearby::presence::PresenceFrame, v1_frame_), + 0, + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::nearby::presence::V1Frame, _internal_metadata_), + ~0u, // no _extensions_ + PROTOBUF_FIELD_OFFSET(::nearby::presence::V1Frame, _oneof_case_[0]), + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + PROTOBUF_FIELD_OFFSET(::nearby::presence::V1Frame, Message_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::DeviceIdentityFrame, _has_bits_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::DeviceIdentityFrame, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::nearby::presence::DeviceIdentityFrame, device_name_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::DeviceIdentityFrame, bluetooth_mac_address_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::DeviceIdentityFrame, device_image_url_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::DeviceIdentityFrame, model_id_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::DeviceIdentityFrame, action_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::DeviceIdentityFrame, device_model_name_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::DeviceIdentityFrame, device_type_), + 0, + 1, + 2, + 3, + ~0u, + 4, + 5, + PROTOBUF_FIELD_OFFSET(::nearby::presence::ConnectionInitFrame, _has_bits_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::ConnectionInitFrame, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::nearby::presence::ConnectionInitFrame, actions_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::ConnectionInitFrame, identity_type_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::ConnectionInitFrame, uwb_enable_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::ConnectionInitFrame, device_unique_id_), + ~0u, + 0, + 1, + 2, + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, _has_bits_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, controlee_address_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, supported_config_ids_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, supported_channels_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, min_ranging_interval_ms_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, sub_session_id_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, sub_session_key_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, ranging_disabled_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, device_unique_id_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, is_distance_supported_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, is_azimuth_supported_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, is_elevation_supported_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, min_slot_duration_ms_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, supported_ntf_configs_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, is_ranging_interval_reconfigure_supported_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, supported_slot_durations_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, supported_ranging_update_rates_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, chip_count_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbControleeCapabilities, multi_chip_info_), + 0, + ~0u, + ~0u, + 4, + 1, + 2, + 5, + 3, + 9, + 10, + 6, + 11, + ~0u, + 7, + ~0u, + ~0u, + 8, + ~0u, + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbMultiChipInfo, _has_bits_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbMultiChipInfo, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbMultiChipInfo, controlee_address_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbMultiChipInfo, chip_id_), + 0, + 1, + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, _has_bits_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, controller_address_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, channel_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, preamble_index_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, config_id_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, ranging_interval_ms_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, session_id_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, vendor_id_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, static_sts_iv_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, session_key_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::UwbConnectionInfo, ranging_disabled_), + 0, + 4, + 5, + 6, + 7, + 8, + 1, + 2, + 3, + 9, + PROTOBUF_FIELD_OFFSET(::nearby::presence::ControlFrame, _has_bits_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::ControlFrame, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::nearby::presence::ControlFrame, type_), + 0, + PROTOBUF_FIELD_OFFSET(::nearby::presence::PresenceAuthenticationFrame, _has_bits_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::PresenceAuthenticationFrame, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::nearby::presence::PresenceAuthenticationFrame, version_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::PresenceAuthenticationFrame, private_key_signature_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::PresenceAuthenticationFrame, shared_credential_id_hash_), + PROTOBUF_FIELD_OFFSET(::nearby::presence::PresenceAuthenticationFrame, credential_id_hash_), + 3, + 0, + 1, + 2, +}; +static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + { 0, 7, -1, sizeof(::nearby::presence::PresenceFrame)}, + { 8, -1, -1, sizeof(::nearby::presence::V1Frame)}, + { 21, 34, -1, sizeof(::nearby::presence::DeviceIdentityFrame)}, + { 41, 51, -1, sizeof(::nearby::presence::ConnectionInitFrame)}, + { 55, 79, -1, sizeof(::nearby::presence::UwbControleeCapabilities)}, + { 97, 105, -1, sizeof(::nearby::presence::UwbMultiChipInfo)}, + { 107, 123, -1, sizeof(::nearby::presence::UwbConnectionInfo)}, + { 133, 140, -1, sizeof(::nearby::presence::ControlFrame)}, + { 141, 151, -1, sizeof(::nearby::presence::PresenceAuthenticationFrame)}, +}; + +static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = { + reinterpret_cast(&::nearby::presence::_PresenceFrame_default_instance_), + reinterpret_cast(&::nearby::presence::_V1Frame_default_instance_), + reinterpret_cast(&::nearby::presence::_DeviceIdentityFrame_default_instance_), + reinterpret_cast(&::nearby::presence::_ConnectionInitFrame_default_instance_), + reinterpret_cast(&::nearby::presence::_UwbControleeCapabilities_default_instance_), + reinterpret_cast(&::nearby::presence::_UwbMultiChipInfo_default_instance_), + reinterpret_cast(&::nearby::presence::_UwbConnectionInfo_default_instance_), + reinterpret_cast(&::nearby::presence::_ControlFrame_default_instance_), + reinterpret_cast(&::nearby::presence::_PresenceAuthenticationFrame_default_instance_), +}; + +const char descriptor_table_protodef_presence_2fproto_2fpresence_5fframe_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = + "\n#presence/proto/presence_frame.proto\022\017n" + "earby.presence\"j\n\rPresenceFrame\022*\n\010v1_fr" + "ame\030\001 \001(\0132\030.nearby.presence.V1Frame\"-\n\007V" + "ersion\022\023\n\017UNKNOWN_VERSION\020\000\022\r\n\tVERSION_1" + "\020\001\"\302\003\n\007V1Frame\0226\n\rcontrol_frame\030\001 \001(\0132\035." + "nearby.presence.ControlFrameH\000\022E\n\025device" + "_identity_frame\030\002 \001(\0132$.nearby.presence." + "DeviceIdentityFrameH\000\022E\n\025connection_init" + "_frame\030\003 \001(\0132$.nearby.presence.Connectio" + "nInitFrameH\000\022U\n uwb_controlee_capabiliti" + "es_frame\030\004 \001(\0132).nearby.presence.UwbCont" + "roleeCapabilitiesH\000\022A\n\023uwb_connection_in" + "fo\030\005 \001(\0132\".nearby.presence.UwbConnection" + "InfoH\000\022L\n\024authentication_frame\030\006 \001(\0132,.n" + "earby.presence.PresenceAuthenticationFra" + "meH\000B\t\n\007Message\"\271\001\n\023DeviceIdentityFrame\022" + "\023\n\013device_name\030\001 \001(\t\022\035\n\025bluetooth_mac_ad" + "dress\030\002 \001(\014\022\030\n\020device_image_url\030\003 \001(\t\022\020\n" + "\010model_id\030\004 \001(\t\022\022\n\006action\030\005 \003(\005B\002\020\001\022\031\n\021d" + "evice_model_name\030\006 \001(\t\022\023\n\013device_type\030\007 " + "\001(\005\"o\n\023ConnectionInitFrame\022\023\n\007actions\030\001 " + "\003(\005B\002\020\001\022\025\n\ridentity_type\030\002 \001(\005\022\022\n\nuwb_en" + "able\030\003 \001(\010\022\030\n\020device_unique_id\030\004 \001(\003\"\220\005\n" + "\030UwbControleeCapabilities\022\031\n\021controlee_a" + "ddress\030\001 \001(\014\022 \n\024supported_config_ids\030\002 \003" + "(\005B\002\020\001\022\036\n\022supported_channels\030\003 \003(\005B\002\020\001\022\037" + "\n\027min_ranging_interval_ms\030\004 \001(\005\022\026\n\016sub_s" + "ession_id\030\005 \001(\014\022\027\n\017sub_session_key\030\006 \001(\014" + "\022\030\n\020ranging_disabled\030\007 \001(\010\022\030\n\020device_uni" + "que_id\030\010 \001(\003\022#\n\025is_distance_supported\030\t " + "\001(\010:\004true\022\"\n\024is_azimuth_supported\030\n \001(\010:" + "\004true\022%\n\026is_elevation_supported\030\013 \001(\010:\005f" + "alse\022\037\n\024min_slot_duration_ms\030\014 \001(\002:\0012\022!\n" + "\025supported_ntf_configs\030\r \003(\005B\002\020\001\0228\n)is_r" + "anging_interval_reconfigure_supported\030\016 " + "\001(\010:\005false\022$\n\030supported_slot_durations\030\017" + " \003(\005B\002\020\001\022*\n\036supported_ranging_update_rat" + "es\030\020 \003(\005B\002\020\001\022\025\n\nchip_count\030\021 \001(\005:\0011\022:\n\017m" + "ulti_chip_info\030\022 \003(\0132!.nearby.presence.U" + "wbMultiChipInfo\">\n\020UwbMultiChipInfo\022\031\n\021c" + "ontrolee_address\030\001 \001(\014\022\017\n\007chip_id\030\002 \001(\t\"" + "\365\001\n\021UwbConnectionInfo\022\032\n\022controller_addr" + "ess\030\001 \001(\014\022\017\n\007channel\030\002 \001(\005\022\026\n\016preamble_i" + "ndex\030\003 \001(\005\022\021\n\tconfig_id\030\004 \001(\005\022\033\n\023ranging" + "_interval_ms\030\005 \001(\005\022\022\n\nsession_id\030\006 \001(\005\022\021" + "\n\tvendor_id\030\007 \001(\014\022\025\n\rstatic_sts_iv\030\010 \001(\014" + "\022\023\n\013session_key\030\t \001(\014\022\030\n\020ranging_disable" + "d\030\n \001(\010\"\210\001\n\014ControlFrame\0227\n\004type\030\001 \001(\0162)" + ".nearby.presence.ControlFrame.ControlTyp" + "e\"\?\n\013ControlType\022\020\n\014UNKNOWN_TYPE\020\000\022\016\n\nKE" + "EP_ALIVE\020\001\022\016\n\nDISCONNECT\020\002\"\220\001\n\033PresenceA" + "uthenticationFrame\022\017\n\007version\030\001 \001(\005\022\035\n\025p" + "rivate_key_signature\030\002 \001(\014\022!\n\031shared_cre" + "dential_id_hash\030\003 \001(\014\022\036\n\022credential_id_h" + "ash\030\004 \001(\014B\002\030\001B\?\n&com.google.android.gms." + "nearby.presenceB\025PresenceFrameProtocol" + ; +static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_once; +const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto = { + false, false, 2238, descriptor_table_protodef_presence_2fproto_2fpresence_5fframe_2eproto, "presence/proto/presence_frame.proto", + &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_once, nullptr, 0, 9, + schemas, file_default_instances, TableStruct_presence_2fproto_2fpresence_5fframe_2eproto::offsets, + file_level_metadata_presence_2fproto_2fpresence_5fframe_2eproto, file_level_enum_descriptors_presence_2fproto_2fpresence_5fframe_2eproto, file_level_service_descriptors_presence_2fproto_2fpresence_5fframe_2eproto, +}; +PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_getter() { + return &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto; +} + +// Force running AddDescriptors() at dynamic initialization time. +PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_presence_2fproto_2fpresence_5fframe_2eproto(&descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto); +namespace nearby { +namespace presence { +const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* PresenceFrame_Version_descriptor() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto); + return file_level_enum_descriptors_presence_2fproto_2fpresence_5fframe_2eproto[0]; +} +bool PresenceFrame_Version_IsValid(int value) { + switch (value) { + case 0: + case 1: + return true; + default: + return false; + } +} + +#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) +constexpr PresenceFrame_Version PresenceFrame::UNKNOWN_VERSION; +constexpr PresenceFrame_Version PresenceFrame::VERSION_1; +constexpr PresenceFrame_Version PresenceFrame::Version_MIN; +constexpr PresenceFrame_Version PresenceFrame::Version_MAX; +constexpr int PresenceFrame::Version_ARRAYSIZE; +#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) +const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* ControlFrame_ControlType_descriptor() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto); + return file_level_enum_descriptors_presence_2fproto_2fpresence_5fframe_2eproto[1]; +} +bool ControlFrame_ControlType_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) +constexpr ControlFrame_ControlType ControlFrame::UNKNOWN_TYPE; +constexpr ControlFrame_ControlType ControlFrame::KEEP_ALIVE; +constexpr ControlFrame_ControlType ControlFrame::DISCONNECT; +constexpr ControlFrame_ControlType ControlFrame::ControlType_MIN; +constexpr ControlFrame_ControlType ControlFrame::ControlType_MAX; +constexpr int ControlFrame::ControlType_ARRAYSIZE; +#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + +// =================================================================== + +class PresenceFrame::_Internal { + public: + using HasBits = decltype(std::declval()._has_bits_); + static const ::nearby::presence::V1Frame& v1_frame(const PresenceFrame* msg); + static void set_has_v1_frame(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } +}; + +const ::nearby::presence::V1Frame& +PresenceFrame::_Internal::v1_frame(const PresenceFrame* msg) { + return *msg->v1_frame_; +} +PresenceFrame::PresenceFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:nearby.presence.PresenceFrame) +} +PresenceFrame::PresenceFrame(const PresenceFrame& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + if (from._internal_has_v1_frame()) { + v1_frame_ = new ::nearby::presence::V1Frame(*from.v1_frame_); + } else { + v1_frame_ = nullptr; + } + // @@protoc_insertion_point(copy_constructor:nearby.presence.PresenceFrame) +} + +inline void PresenceFrame::SharedCtor() { +v1_frame_ = nullptr; +} + +PresenceFrame::~PresenceFrame() { + // @@protoc_insertion_point(destructor:nearby.presence.PresenceFrame) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void PresenceFrame::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + if (this != internal_default_instance()) delete v1_frame_; +} + +void PresenceFrame::ArenaDtor(void* object) { + PresenceFrame* _this = reinterpret_cast< PresenceFrame* >(object); + (void)_this; +} +void PresenceFrame::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void PresenceFrame::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void PresenceFrame::Clear() { +// @@protoc_insertion_point(message_clear_start:nearby.presence.PresenceFrame) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000001u) { + GOOGLE_DCHECK(v1_frame_ != nullptr); + v1_frame_->Clear(); + } + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* PresenceFrame::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional .nearby.presence.V1Frame v1_frame = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + ptr = ctx->ParseMessage(_internal_mutable_v1_frame(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* PresenceFrame::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:nearby.presence.PresenceFrame) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional .nearby.presence.V1Frame v1_frame = 1; + if (cached_has_bits & 0x00000001u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 1, _Internal::v1_frame(this), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:nearby.presence.PresenceFrame) + return target; +} + +size_t PresenceFrame::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:nearby.presence.PresenceFrame) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // optional .nearby.presence.V1Frame v1_frame = 1; + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *v1_frame_); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData PresenceFrame::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + PresenceFrame::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*PresenceFrame::GetClassData() const { return &_class_data_; } + +void PresenceFrame::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void PresenceFrame::MergeFrom(const PresenceFrame& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:nearby.presence.PresenceFrame) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_has_v1_frame()) { + _internal_mutable_v1_frame()->::nearby::presence::V1Frame::MergeFrom(from._internal_v1_frame()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void PresenceFrame::CopyFrom(const PresenceFrame& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:nearby.presence.PresenceFrame) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool PresenceFrame::IsInitialized() const { + return true; +} + +void PresenceFrame::InternalSwap(PresenceFrame* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + swap(v1_frame_, other->v1_frame_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata PresenceFrame::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_getter, &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_once, + file_level_metadata_presence_2fproto_2fpresence_5fframe_2eproto[0]); +} + +// =================================================================== + +class V1Frame::_Internal { + public: + static const ::nearby::presence::ControlFrame& control_frame(const V1Frame* msg); + static const ::nearby::presence::DeviceIdentityFrame& device_identity_frame(const V1Frame* msg); + static const ::nearby::presence::ConnectionInitFrame& connection_init_frame(const V1Frame* msg); + static const ::nearby::presence::UwbControleeCapabilities& uwb_controlee_capabilities_frame(const V1Frame* msg); + static const ::nearby::presence::UwbConnectionInfo& uwb_connection_info(const V1Frame* msg); + static const ::nearby::presence::PresenceAuthenticationFrame& authentication_frame(const V1Frame* msg); +}; + +const ::nearby::presence::ControlFrame& +V1Frame::_Internal::control_frame(const V1Frame* msg) { + return *msg->Message_.control_frame_; +} +const ::nearby::presence::DeviceIdentityFrame& +V1Frame::_Internal::device_identity_frame(const V1Frame* msg) { + return *msg->Message_.device_identity_frame_; +} +const ::nearby::presence::ConnectionInitFrame& +V1Frame::_Internal::connection_init_frame(const V1Frame* msg) { + return *msg->Message_.connection_init_frame_; +} +const ::nearby::presence::UwbControleeCapabilities& +V1Frame::_Internal::uwb_controlee_capabilities_frame(const V1Frame* msg) { + return *msg->Message_.uwb_controlee_capabilities_frame_; +} +const ::nearby::presence::UwbConnectionInfo& +V1Frame::_Internal::uwb_connection_info(const V1Frame* msg) { + return *msg->Message_.uwb_connection_info_; +} +const ::nearby::presence::PresenceAuthenticationFrame& +V1Frame::_Internal::authentication_frame(const V1Frame* msg) { + return *msg->Message_.authentication_frame_; +} +void V1Frame::set_allocated_control_frame(::nearby::presence::ControlFrame* control_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_Message(); + if (control_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::nearby::presence::ControlFrame>::GetOwningArena(control_frame); + if (message_arena != submessage_arena) { + control_frame = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, control_frame, submessage_arena); + } + set_has_control_frame(); + Message_.control_frame_ = control_frame; + } + // @@protoc_insertion_point(field_set_allocated:nearby.presence.V1Frame.control_frame) +} +void V1Frame::set_allocated_device_identity_frame(::nearby::presence::DeviceIdentityFrame* device_identity_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_Message(); + if (device_identity_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::nearby::presence::DeviceIdentityFrame>::GetOwningArena(device_identity_frame); + if (message_arena != submessage_arena) { + device_identity_frame = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, device_identity_frame, submessage_arena); + } + set_has_device_identity_frame(); + Message_.device_identity_frame_ = device_identity_frame; + } + // @@protoc_insertion_point(field_set_allocated:nearby.presence.V1Frame.device_identity_frame) +} +void V1Frame::set_allocated_connection_init_frame(::nearby::presence::ConnectionInitFrame* connection_init_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_Message(); + if (connection_init_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::nearby::presence::ConnectionInitFrame>::GetOwningArena(connection_init_frame); + if (message_arena != submessage_arena) { + connection_init_frame = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, connection_init_frame, submessage_arena); + } + set_has_connection_init_frame(); + Message_.connection_init_frame_ = connection_init_frame; + } + // @@protoc_insertion_point(field_set_allocated:nearby.presence.V1Frame.connection_init_frame) +} +void V1Frame::set_allocated_uwb_controlee_capabilities_frame(::nearby::presence::UwbControleeCapabilities* uwb_controlee_capabilities_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_Message(); + if (uwb_controlee_capabilities_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::nearby::presence::UwbControleeCapabilities>::GetOwningArena(uwb_controlee_capabilities_frame); + if (message_arena != submessage_arena) { + uwb_controlee_capabilities_frame = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, uwb_controlee_capabilities_frame, submessage_arena); + } + set_has_uwb_controlee_capabilities_frame(); + Message_.uwb_controlee_capabilities_frame_ = uwb_controlee_capabilities_frame; + } + // @@protoc_insertion_point(field_set_allocated:nearby.presence.V1Frame.uwb_controlee_capabilities_frame) +} +void V1Frame::set_allocated_uwb_connection_info(::nearby::presence::UwbConnectionInfo* uwb_connection_info) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_Message(); + if (uwb_connection_info) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::nearby::presence::UwbConnectionInfo>::GetOwningArena(uwb_connection_info); + if (message_arena != submessage_arena) { + uwb_connection_info = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, uwb_connection_info, submessage_arena); + } + set_has_uwb_connection_info(); + Message_.uwb_connection_info_ = uwb_connection_info; + } + // @@protoc_insertion_point(field_set_allocated:nearby.presence.V1Frame.uwb_connection_info) +} +void V1Frame::set_allocated_authentication_frame(::nearby::presence::PresenceAuthenticationFrame* authentication_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_Message(); + if (authentication_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::nearby::presence::PresenceAuthenticationFrame>::GetOwningArena(authentication_frame); + if (message_arena != submessage_arena) { + authentication_frame = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, authentication_frame, submessage_arena); + } + set_has_authentication_frame(); + Message_.authentication_frame_ = authentication_frame; + } + // @@protoc_insertion_point(field_set_allocated:nearby.presence.V1Frame.authentication_frame) +} +V1Frame::V1Frame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:nearby.presence.V1Frame) +} +V1Frame::V1Frame(const V1Frame& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + clear_has_Message(); + switch (from.Message_case()) { + case kControlFrame: { + _internal_mutable_control_frame()->::nearby::presence::ControlFrame::MergeFrom(from._internal_control_frame()); + break; + } + case kDeviceIdentityFrame: { + _internal_mutable_device_identity_frame()->::nearby::presence::DeviceIdentityFrame::MergeFrom(from._internal_device_identity_frame()); + break; + } + case kConnectionInitFrame: { + _internal_mutable_connection_init_frame()->::nearby::presence::ConnectionInitFrame::MergeFrom(from._internal_connection_init_frame()); + break; + } + case kUwbControleeCapabilitiesFrame: { + _internal_mutable_uwb_controlee_capabilities_frame()->::nearby::presence::UwbControleeCapabilities::MergeFrom(from._internal_uwb_controlee_capabilities_frame()); + break; + } + case kUwbConnectionInfo: { + _internal_mutable_uwb_connection_info()->::nearby::presence::UwbConnectionInfo::MergeFrom(from._internal_uwb_connection_info()); + break; + } + case kAuthenticationFrame: { + _internal_mutable_authentication_frame()->::nearby::presence::PresenceAuthenticationFrame::MergeFrom(from._internal_authentication_frame()); + break; + } + case MESSAGE_NOT_SET: { + break; + } + } + // @@protoc_insertion_point(copy_constructor:nearby.presence.V1Frame) +} + +inline void V1Frame::SharedCtor() { +clear_has_Message(); +} + +V1Frame::~V1Frame() { + // @@protoc_insertion_point(destructor:nearby.presence.V1Frame) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void V1Frame::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + if (has_Message()) { + clear_Message(); + } +} + +void V1Frame::ArenaDtor(void* object) { + V1Frame* _this = reinterpret_cast< V1Frame* >(object); + (void)_this; +} +void V1Frame::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void V1Frame::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void V1Frame::clear_Message() { +// @@protoc_insertion_point(one_of_clear_start:nearby.presence.V1Frame) + switch (Message_case()) { + case kControlFrame: { + if (GetArenaForAllocation() == nullptr) { + delete Message_.control_frame_; + } + break; + } + case kDeviceIdentityFrame: { + if (GetArenaForAllocation() == nullptr) { + delete Message_.device_identity_frame_; + } + break; + } + case kConnectionInitFrame: { + if (GetArenaForAllocation() == nullptr) { + delete Message_.connection_init_frame_; + } + break; + } + case kUwbControleeCapabilitiesFrame: { + if (GetArenaForAllocation() == nullptr) { + delete Message_.uwb_controlee_capabilities_frame_; + } + break; + } + case kUwbConnectionInfo: { + if (GetArenaForAllocation() == nullptr) { + delete Message_.uwb_connection_info_; + } + break; + } + case kAuthenticationFrame: { + if (GetArenaForAllocation() == nullptr) { + delete Message_.authentication_frame_; + } + break; + } + case MESSAGE_NOT_SET: { + break; + } + } + _oneof_case_[0] = MESSAGE_NOT_SET; +} + + +void V1Frame::Clear() { +// @@protoc_insertion_point(message_clear_start:nearby.presence.V1Frame) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + clear_Message(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* V1Frame::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // .nearby.presence.ControlFrame control_frame = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + ptr = ctx->ParseMessage(_internal_mutable_control_frame(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .nearby.presence.DeviceIdentityFrame device_identity_frame = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + ptr = ctx->ParseMessage(_internal_mutable_device_identity_frame(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .nearby.presence.ConnectionInitFrame connection_init_frame = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 26)) { + ptr = ctx->ParseMessage(_internal_mutable_connection_init_frame(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .nearby.presence.UwbControleeCapabilities uwb_controlee_capabilities_frame = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 34)) { + ptr = ctx->ParseMessage(_internal_mutable_uwb_controlee_capabilities_frame(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .nearby.presence.UwbConnectionInfo uwb_connection_info = 5; + case 5: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 42)) { + ptr = ctx->ParseMessage(_internal_mutable_uwb_connection_info(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .nearby.presence.PresenceAuthenticationFrame authentication_frame = 6; + case 6: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 50)) { + ptr = ctx->ParseMessage(_internal_mutable_authentication_frame(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* V1Frame::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:nearby.presence.V1Frame) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + switch (Message_case()) { + case kControlFrame: { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 1, _Internal::control_frame(this), target, stream); + break; + } + case kDeviceIdentityFrame: { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 2, _Internal::device_identity_frame(this), target, stream); + break; + } + case kConnectionInitFrame: { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 3, _Internal::connection_init_frame(this), target, stream); + break; + } + case kUwbControleeCapabilitiesFrame: { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 4, _Internal::uwb_controlee_capabilities_frame(this), target, stream); + break; + } + case kUwbConnectionInfo: { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 5, _Internal::uwb_connection_info(this), target, stream); + break; + } + case kAuthenticationFrame: { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 6, _Internal::authentication_frame(this), target, stream); + break; + } + default: ; + } + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:nearby.presence.V1Frame) + return target; +} + +size_t V1Frame::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:nearby.presence.V1Frame) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + switch (Message_case()) { + // .nearby.presence.ControlFrame control_frame = 1; + case kControlFrame: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *Message_.control_frame_); + break; + } + // .nearby.presence.DeviceIdentityFrame device_identity_frame = 2; + case kDeviceIdentityFrame: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *Message_.device_identity_frame_); + break; + } + // .nearby.presence.ConnectionInitFrame connection_init_frame = 3; + case kConnectionInitFrame: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *Message_.connection_init_frame_); + break; + } + // .nearby.presence.UwbControleeCapabilities uwb_controlee_capabilities_frame = 4; + case kUwbControleeCapabilitiesFrame: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *Message_.uwb_controlee_capabilities_frame_); + break; + } + // .nearby.presence.UwbConnectionInfo uwb_connection_info = 5; + case kUwbConnectionInfo: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *Message_.uwb_connection_info_); + break; + } + // .nearby.presence.PresenceAuthenticationFrame authentication_frame = 6; + case kAuthenticationFrame: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *Message_.authentication_frame_); + break; + } + case MESSAGE_NOT_SET: { + break; + } + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData V1Frame::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + V1Frame::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*V1Frame::GetClassData() const { return &_class_data_; } + +void V1Frame::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void V1Frame::MergeFrom(const V1Frame& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:nearby.presence.V1Frame) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + switch (from.Message_case()) { + case kControlFrame: { + _internal_mutable_control_frame()->::nearby::presence::ControlFrame::MergeFrom(from._internal_control_frame()); + break; + } + case kDeviceIdentityFrame: { + _internal_mutable_device_identity_frame()->::nearby::presence::DeviceIdentityFrame::MergeFrom(from._internal_device_identity_frame()); + break; + } + case kConnectionInitFrame: { + _internal_mutable_connection_init_frame()->::nearby::presence::ConnectionInitFrame::MergeFrom(from._internal_connection_init_frame()); + break; + } + case kUwbControleeCapabilitiesFrame: { + _internal_mutable_uwb_controlee_capabilities_frame()->::nearby::presence::UwbControleeCapabilities::MergeFrom(from._internal_uwb_controlee_capabilities_frame()); + break; + } + case kUwbConnectionInfo: { + _internal_mutable_uwb_connection_info()->::nearby::presence::UwbConnectionInfo::MergeFrom(from._internal_uwb_connection_info()); + break; + } + case kAuthenticationFrame: { + _internal_mutable_authentication_frame()->::nearby::presence::PresenceAuthenticationFrame::MergeFrom(from._internal_authentication_frame()); + break; + } + case MESSAGE_NOT_SET: { + break; + } + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void V1Frame::CopyFrom(const V1Frame& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:nearby.presence.V1Frame) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool V1Frame::IsInitialized() const { + return true; +} + +void V1Frame::InternalSwap(V1Frame* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(Message_, other->Message_); + swap(_oneof_case_[0], other->_oneof_case_[0]); +} + +::PROTOBUF_NAMESPACE_ID::Metadata V1Frame::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_getter, &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_once, + file_level_metadata_presence_2fproto_2fpresence_5fframe_2eproto[1]); +} + +// =================================================================== + +class DeviceIdentityFrame::_Internal { + public: + using HasBits = decltype(std::declval()._has_bits_); + static void set_has_device_name(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static void set_has_bluetooth_mac_address(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } + static void set_has_device_image_url(HasBits* has_bits) { + (*has_bits)[0] |= 4u; + } + static void set_has_model_id(HasBits* has_bits) { + (*has_bits)[0] |= 8u; + } + static void set_has_device_model_name(HasBits* has_bits) { + (*has_bits)[0] |= 16u; + } + static void set_has_device_type(HasBits* has_bits) { + (*has_bits)[0] |= 32u; + } +}; + +DeviceIdentityFrame::DeviceIdentityFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned), + action_(arena) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:nearby.presence.DeviceIdentityFrame) +} +DeviceIdentityFrame::DeviceIdentityFrame(const DeviceIdentityFrame& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_), + action_(from.action_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + device_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + device_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_device_name()) { + device_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_device_name(), + GetArenaForAllocation()); + } + bluetooth_mac_address_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + bluetooth_mac_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_bluetooth_mac_address()) { + bluetooth_mac_address_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_bluetooth_mac_address(), + GetArenaForAllocation()); + } + device_image_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + device_image_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_device_image_url()) { + device_image_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_device_image_url(), + GetArenaForAllocation()); + } + model_id_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + model_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_model_id()) { + model_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_model_id(), + GetArenaForAllocation()); + } + device_model_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + device_model_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_device_model_name()) { + device_model_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_device_model_name(), + GetArenaForAllocation()); + } + device_type_ = from.device_type_; + // @@protoc_insertion_point(copy_constructor:nearby.presence.DeviceIdentityFrame) +} + +inline void DeviceIdentityFrame::SharedCtor() { +device_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + device_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +bluetooth_mac_address_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + bluetooth_mac_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +device_image_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + device_image_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +model_id_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + model_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +device_model_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + device_model_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +device_type_ = 0; +} + +DeviceIdentityFrame::~DeviceIdentityFrame() { + // @@protoc_insertion_point(destructor:nearby.presence.DeviceIdentityFrame) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void DeviceIdentityFrame::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + device_name_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + bluetooth_mac_address_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + device_image_url_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + model_id_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + device_model_name_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void DeviceIdentityFrame::ArenaDtor(void* object) { + DeviceIdentityFrame* _this = reinterpret_cast< DeviceIdentityFrame* >(object); + (void)_this; +} +void DeviceIdentityFrame::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void DeviceIdentityFrame::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void DeviceIdentityFrame::Clear() { +// @@protoc_insertion_point(message_clear_start:nearby.presence.DeviceIdentityFrame) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + action_.Clear(); + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x0000001fu) { + if (cached_has_bits & 0x00000001u) { + device_name_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000002u) { + bluetooth_mac_address_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000004u) { + device_image_url_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000008u) { + model_id_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000010u) { + device_model_name_.ClearNonDefaultToEmpty(); + } + } + device_type_ = 0; + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* DeviceIdentityFrame::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional string device_name = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + auto str = _internal_mutable_device_name(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "nearby.presence.DeviceIdentityFrame.device_name"); + #endif // !NDEBUG + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bytes bluetooth_mac_address = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + auto str = _internal_mutable_bluetooth_mac_address(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional string device_image_url = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 26)) { + auto str = _internal_mutable_device_image_url(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "nearby.presence.DeviceIdentityFrame.device_image_url"); + #endif // !NDEBUG + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional string model_id = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 34)) { + auto str = _internal_mutable_model_id(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "nearby.presence.DeviceIdentityFrame.model_id"); + #endif // !NDEBUG + CHK_(ptr); + } else + goto handle_unusual; + continue; + // repeated int32 action = 5 [packed = true]; + case 5: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 42)) { + ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_action(), ptr, ctx); + CHK_(ptr); + } else if (static_cast(tag) == 40) { + _internal_add_action(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr)); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional string device_model_name = 6; + case 6: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 50)) { + auto str = _internal_mutable_device_model_name(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "nearby.presence.DeviceIdentityFrame.device_model_name"); + #endif // !NDEBUG + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 device_type = 7; + case 7: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 56)) { + _Internal::set_has_device_type(&has_bits); + device_type_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* DeviceIdentityFrame::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:nearby.presence.DeviceIdentityFrame) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional string device_name = 1; + if (cached_has_bits & 0x00000001u) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + this->_internal_device_name().data(), static_cast(this->_internal_device_name().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "nearby.presence.DeviceIdentityFrame.device_name"); + target = stream->WriteStringMaybeAliased( + 1, this->_internal_device_name(), target); + } + + // optional bytes bluetooth_mac_address = 2; + if (cached_has_bits & 0x00000002u) { + target = stream->WriteBytesMaybeAliased( + 2, this->_internal_bluetooth_mac_address(), target); + } + + // optional string device_image_url = 3; + if (cached_has_bits & 0x00000004u) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + this->_internal_device_image_url().data(), static_cast(this->_internal_device_image_url().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "nearby.presence.DeviceIdentityFrame.device_image_url"); + target = stream->WriteStringMaybeAliased( + 3, this->_internal_device_image_url(), target); + } + + // optional string model_id = 4; + if (cached_has_bits & 0x00000008u) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + this->_internal_model_id().data(), static_cast(this->_internal_model_id().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "nearby.presence.DeviceIdentityFrame.model_id"); + target = stream->WriteStringMaybeAliased( + 4, this->_internal_model_id(), target); + } + + // repeated int32 action = 5 [packed = true]; + { + int byte_size = _action_cached_byte_size_.load(std::memory_order_relaxed); + if (byte_size > 0) { + target = stream->WriteInt32Packed( + 5, _internal_action(), byte_size, target); + } + } + + // optional string device_model_name = 6; + if (cached_has_bits & 0x00000010u) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + this->_internal_device_model_name().data(), static_cast(this->_internal_device_model_name().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "nearby.presence.DeviceIdentityFrame.device_model_name"); + target = stream->WriteStringMaybeAliased( + 6, this->_internal_device_model_name(), target); + } + + // optional int32 device_type = 7; + if (cached_has_bits & 0x00000020u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(7, this->_internal_device_type(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:nearby.presence.DeviceIdentityFrame) + return target; +} + +size_t DeviceIdentityFrame::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:nearby.presence.DeviceIdentityFrame) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // repeated int32 action = 5 [packed = true]; + { + size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + Int32Size(this->action_); + if (data_size > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size( + static_cast(data_size)); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size); + _action_cached_byte_size_.store(cached_size, + std::memory_order_relaxed); + total_size += data_size; + } + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x0000003fu) { + // optional string device_name = 1; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_device_name()); + } + + // optional bytes bluetooth_mac_address = 2; + if (cached_has_bits & 0x00000002u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_bluetooth_mac_address()); + } + + // optional string device_image_url = 3; + if (cached_has_bits & 0x00000004u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_device_image_url()); + } + + // optional string model_id = 4; + if (cached_has_bits & 0x00000008u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_model_id()); + } + + // optional string device_model_name = 6; + if (cached_has_bits & 0x00000010u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_device_model_name()); + } + + // optional int32 device_type = 7; + if (cached_has_bits & 0x00000020u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_device_type()); + } + + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DeviceIdentityFrame::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + DeviceIdentityFrame::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DeviceIdentityFrame::GetClassData() const { return &_class_data_; } + +void DeviceIdentityFrame::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void DeviceIdentityFrame::MergeFrom(const DeviceIdentityFrame& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:nearby.presence.DeviceIdentityFrame) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + action_.MergeFrom(from.action_); + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x0000003fu) { + if (cached_has_bits & 0x00000001u) { + _internal_set_device_name(from._internal_device_name()); + } + if (cached_has_bits & 0x00000002u) { + _internal_set_bluetooth_mac_address(from._internal_bluetooth_mac_address()); + } + if (cached_has_bits & 0x00000004u) { + _internal_set_device_image_url(from._internal_device_image_url()); + } + if (cached_has_bits & 0x00000008u) { + _internal_set_model_id(from._internal_model_id()); + } + if (cached_has_bits & 0x00000010u) { + _internal_set_device_model_name(from._internal_device_model_name()); + } + if (cached_has_bits & 0x00000020u) { + device_type_ = from.device_type_; + } + _has_bits_[0] |= cached_has_bits; + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void DeviceIdentityFrame::CopyFrom(const DeviceIdentityFrame& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:nearby.presence.DeviceIdentityFrame) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool DeviceIdentityFrame::IsInitialized() const { + return true; +} + +void DeviceIdentityFrame::InternalSwap(DeviceIdentityFrame* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + action_.InternalSwap(&other->action_); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &device_name_, lhs_arena, + &other->device_name_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &bluetooth_mac_address_, lhs_arena, + &other->bluetooth_mac_address_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &device_image_url_, lhs_arena, + &other->device_image_url_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &model_id_, lhs_arena, + &other->model_id_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &device_model_name_, lhs_arena, + &other->device_model_name_, rhs_arena + ); + swap(device_type_, other->device_type_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata DeviceIdentityFrame::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_getter, &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_once, + file_level_metadata_presence_2fproto_2fpresence_5fframe_2eproto[2]); +} + +// =================================================================== + +class ConnectionInitFrame::_Internal { + public: + using HasBits = decltype(std::declval()._has_bits_); + static void set_has_identity_type(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static void set_has_uwb_enable(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } + static void set_has_device_unique_id(HasBits* has_bits) { + (*has_bits)[0] |= 4u; + } +}; + +ConnectionInitFrame::ConnectionInitFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned), + actions_(arena) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:nearby.presence.ConnectionInitFrame) +} +ConnectionInitFrame::ConnectionInitFrame(const ConnectionInitFrame& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_), + actions_(from.actions_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::memcpy(&identity_type_, &from.identity_type_, + static_cast(reinterpret_cast(&device_unique_id_) - + reinterpret_cast(&identity_type_)) + sizeof(device_unique_id_)); + // @@protoc_insertion_point(copy_constructor:nearby.presence.ConnectionInitFrame) +} + +inline void ConnectionInitFrame::SharedCtor() { +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&identity_type_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&device_unique_id_) - + reinterpret_cast(&identity_type_)) + sizeof(device_unique_id_)); +} + +ConnectionInitFrame::~ConnectionInitFrame() { + // @@protoc_insertion_point(destructor:nearby.presence.ConnectionInitFrame) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void ConnectionInitFrame::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); +} + +void ConnectionInitFrame::ArenaDtor(void* object) { + ConnectionInitFrame* _this = reinterpret_cast< ConnectionInitFrame* >(object); + (void)_this; +} +void ConnectionInitFrame::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void ConnectionInitFrame::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void ConnectionInitFrame::Clear() { +// @@protoc_insertion_point(message_clear_start:nearby.presence.ConnectionInitFrame) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + actions_.Clear(); + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000007u) { + ::memset(&identity_type_, 0, static_cast( + reinterpret_cast(&device_unique_id_) - + reinterpret_cast(&identity_type_)) + sizeof(device_unique_id_)); + } + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* ConnectionInitFrame::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // repeated int32 actions = 1 [packed = true]; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_actions(), ptr, ctx); + CHK_(ptr); + } else if (static_cast(tag) == 8) { + _internal_add_actions(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr)); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 identity_type = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 16)) { + _Internal::set_has_identity_type(&has_bits); + identity_type_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bool uwb_enable = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 24)) { + _Internal::set_has_uwb_enable(&has_bits); + uwb_enable_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int64 device_unique_id = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 32)) { + _Internal::set_has_device_unique_id(&has_bits); + device_unique_id_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* ConnectionInitFrame::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:nearby.presence.ConnectionInitFrame) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // repeated int32 actions = 1 [packed = true]; + { + int byte_size = _actions_cached_byte_size_.load(std::memory_order_relaxed); + if (byte_size > 0) { + target = stream->WriteInt32Packed( + 1, _internal_actions(), byte_size, target); + } + } + + cached_has_bits = _has_bits_[0]; + // optional int32 identity_type = 2; + if (cached_has_bits & 0x00000001u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_identity_type(), target); + } + + // optional bool uwb_enable = 3; + if (cached_has_bits & 0x00000002u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(3, this->_internal_uwb_enable(), target); + } + + // optional int64 device_unique_id = 4; + if (cached_has_bits & 0x00000004u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64ToArray(4, this->_internal_device_unique_id(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:nearby.presence.ConnectionInitFrame) + return target; +} + +size_t ConnectionInitFrame::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:nearby.presence.ConnectionInitFrame) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // repeated int32 actions = 1 [packed = true]; + { + size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + Int32Size(this->actions_); + if (data_size > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size( + static_cast(data_size)); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size); + _actions_cached_byte_size_.store(cached_size, + std::memory_order_relaxed); + total_size += data_size; + } + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000007u) { + // optional int32 identity_type = 2; + if (cached_has_bits & 0x00000001u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_identity_type()); + } + + // optional bool uwb_enable = 3; + if (cached_has_bits & 0x00000002u) { + total_size += 1 + 1; + } + + // optional int64 device_unique_id = 4; + if (cached_has_bits & 0x00000004u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64SizePlusOne(this->_internal_device_unique_id()); + } + + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ConnectionInitFrame::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + ConnectionInitFrame::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ConnectionInitFrame::GetClassData() const { return &_class_data_; } + +void ConnectionInitFrame::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void ConnectionInitFrame::MergeFrom(const ConnectionInitFrame& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:nearby.presence.ConnectionInitFrame) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + actions_.MergeFrom(from.actions_); + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x00000007u) { + if (cached_has_bits & 0x00000001u) { + identity_type_ = from.identity_type_; + } + if (cached_has_bits & 0x00000002u) { + uwb_enable_ = from.uwb_enable_; + } + if (cached_has_bits & 0x00000004u) { + device_unique_id_ = from.device_unique_id_; + } + _has_bits_[0] |= cached_has_bits; + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void ConnectionInitFrame::CopyFrom(const ConnectionInitFrame& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:nearby.presence.ConnectionInitFrame) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool ConnectionInitFrame::IsInitialized() const { + return true; +} + +void ConnectionInitFrame::InternalSwap(ConnectionInitFrame* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + actions_.InternalSwap(&other->actions_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(ConnectionInitFrame, device_unique_id_) + + sizeof(ConnectionInitFrame::device_unique_id_) + - PROTOBUF_FIELD_OFFSET(ConnectionInitFrame, identity_type_)>( + reinterpret_cast(&identity_type_), + reinterpret_cast(&other->identity_type_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata ConnectionInitFrame::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_getter, &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_once, + file_level_metadata_presence_2fproto_2fpresence_5fframe_2eproto[3]); +} + +// =================================================================== + +class UwbControleeCapabilities::_Internal { + public: + using HasBits = decltype(std::declval()._has_bits_); + static void set_has_controlee_address(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static void set_has_min_ranging_interval_ms(HasBits* has_bits) { + (*has_bits)[0] |= 16u; + } + static void set_has_sub_session_id(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } + static void set_has_sub_session_key(HasBits* has_bits) { + (*has_bits)[0] |= 4u; + } + static void set_has_ranging_disabled(HasBits* has_bits) { + (*has_bits)[0] |= 32u; + } + static void set_has_device_unique_id(HasBits* has_bits) { + (*has_bits)[0] |= 8u; + } + static void set_has_is_distance_supported(HasBits* has_bits) { + (*has_bits)[0] |= 512u; + } + static void set_has_is_azimuth_supported(HasBits* has_bits) { + (*has_bits)[0] |= 1024u; + } + static void set_has_is_elevation_supported(HasBits* has_bits) { + (*has_bits)[0] |= 64u; + } + static void set_has_min_slot_duration_ms(HasBits* has_bits) { + (*has_bits)[0] |= 2048u; + } + static void set_has_is_ranging_interval_reconfigure_supported(HasBits* has_bits) { + (*has_bits)[0] |= 128u; + } + static void set_has_chip_count(HasBits* has_bits) { + (*has_bits)[0] |= 256u; + } +}; + +UwbControleeCapabilities::UwbControleeCapabilities(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned), + supported_config_ids_(arena), + supported_channels_(arena), + supported_ntf_configs_(arena), + supported_slot_durations_(arena), + supported_ranging_update_rates_(arena), + multi_chip_info_(arena) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:nearby.presence.UwbControleeCapabilities) +} +UwbControleeCapabilities::UwbControleeCapabilities(const UwbControleeCapabilities& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_), + supported_config_ids_(from.supported_config_ids_), + supported_channels_(from.supported_channels_), + supported_ntf_configs_(from.supported_ntf_configs_), + supported_slot_durations_(from.supported_slot_durations_), + supported_ranging_update_rates_(from.supported_ranging_update_rates_), + multi_chip_info_(from.multi_chip_info_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + controlee_address_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + controlee_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_controlee_address()) { + controlee_address_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_controlee_address(), + GetArenaForAllocation()); + } + sub_session_id_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + sub_session_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_sub_session_id()) { + sub_session_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_sub_session_id(), + GetArenaForAllocation()); + } + sub_session_key_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + sub_session_key_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_sub_session_key()) { + sub_session_key_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_sub_session_key(), + GetArenaForAllocation()); + } + ::memcpy(&device_unique_id_, &from.device_unique_id_, + static_cast(reinterpret_cast(&min_slot_duration_ms_) - + reinterpret_cast(&device_unique_id_)) + sizeof(min_slot_duration_ms_)); + // @@protoc_insertion_point(copy_constructor:nearby.presence.UwbControleeCapabilities) +} + +inline void UwbControleeCapabilities::SharedCtor() { +controlee_address_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + controlee_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +sub_session_id_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + sub_session_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +sub_session_key_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + sub_session_key_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&device_unique_id_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&is_ranging_interval_reconfigure_supported_) - + reinterpret_cast(&device_unique_id_)) + sizeof(is_ranging_interval_reconfigure_supported_)); +chip_count_ = 1; +is_distance_supported_ = true; +is_azimuth_supported_ = true; +min_slot_duration_ms_ = 2; +} + +UwbControleeCapabilities::~UwbControleeCapabilities() { + // @@protoc_insertion_point(destructor:nearby.presence.UwbControleeCapabilities) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void UwbControleeCapabilities::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + controlee_address_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + sub_session_id_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + sub_session_key_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void UwbControleeCapabilities::ArenaDtor(void* object) { + UwbControleeCapabilities* _this = reinterpret_cast< UwbControleeCapabilities* >(object); + (void)_this; +} +void UwbControleeCapabilities::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void UwbControleeCapabilities::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void UwbControleeCapabilities::Clear() { +// @@protoc_insertion_point(message_clear_start:nearby.presence.UwbControleeCapabilities) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + supported_config_ids_.Clear(); + supported_channels_.Clear(); + supported_ntf_configs_.Clear(); + supported_slot_durations_.Clear(); + supported_ranging_update_rates_.Clear(); + multi_chip_info_.Clear(); + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000007u) { + if (cached_has_bits & 0x00000001u) { + controlee_address_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000002u) { + sub_session_id_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000004u) { + sub_session_key_.ClearNonDefaultToEmpty(); + } + } + if (cached_has_bits & 0x000000f8u) { + ::memset(&device_unique_id_, 0, static_cast( + reinterpret_cast(&is_ranging_interval_reconfigure_supported_) - + reinterpret_cast(&device_unique_id_)) + sizeof(is_ranging_interval_reconfigure_supported_)); + } + if (cached_has_bits & 0x00000f00u) { + chip_count_ = 1; + is_distance_supported_ = true; + is_azimuth_supported_ = true; + min_slot_duration_ms_ = 2; + } + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* UwbControleeCapabilities::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional bytes controlee_address = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + auto str = _internal_mutable_controlee_address(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // repeated int32 supported_config_ids = 2 [packed = true]; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_supported_config_ids(), ptr, ctx); + CHK_(ptr); + } else if (static_cast(tag) == 16) { + _internal_add_supported_config_ids(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr)); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // repeated int32 supported_channels = 3 [packed = true]; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 26)) { + ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_supported_channels(), ptr, ctx); + CHK_(ptr); + } else if (static_cast(tag) == 24) { + _internal_add_supported_channels(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr)); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 min_ranging_interval_ms = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 32)) { + _Internal::set_has_min_ranging_interval_ms(&has_bits); + min_ranging_interval_ms_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bytes sub_session_id = 5; + case 5: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 42)) { + auto str = _internal_mutable_sub_session_id(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bytes sub_session_key = 6; + case 6: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 50)) { + auto str = _internal_mutable_sub_session_key(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bool ranging_disabled = 7; + case 7: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 56)) { + _Internal::set_has_ranging_disabled(&has_bits); + ranging_disabled_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int64 device_unique_id = 8; + case 8: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 64)) { + _Internal::set_has_device_unique_id(&has_bits); + device_unique_id_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bool is_distance_supported = 9 [default = true]; + case 9: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 72)) { + _Internal::set_has_is_distance_supported(&has_bits); + is_distance_supported_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bool is_azimuth_supported = 10 [default = true]; + case 10: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 80)) { + _Internal::set_has_is_azimuth_supported(&has_bits); + is_azimuth_supported_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bool is_elevation_supported = 11 [default = false]; + case 11: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 88)) { + _Internal::set_has_is_elevation_supported(&has_bits); + is_elevation_supported_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional float min_slot_duration_ms = 12 [default = 2]; + case 12: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 101)) { + _Internal::set_has_min_slot_duration_ms(&has_bits); + min_slot_duration_ms_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad(ptr); + ptr += sizeof(float); + } else + goto handle_unusual; + continue; + // repeated int32 supported_ntf_configs = 13 [packed = true]; + case 13: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 106)) { + ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_supported_ntf_configs(), ptr, ctx); + CHK_(ptr); + } else if (static_cast(tag) == 104) { + _internal_add_supported_ntf_configs(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr)); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bool is_ranging_interval_reconfigure_supported = 14 [default = false]; + case 14: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 112)) { + _Internal::set_has_is_ranging_interval_reconfigure_supported(&has_bits); + is_ranging_interval_reconfigure_supported_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // repeated int32 supported_slot_durations = 15 [packed = true]; + case 15: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 122)) { + ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_supported_slot_durations(), ptr, ctx); + CHK_(ptr); + } else if (static_cast(tag) == 120) { + _internal_add_supported_slot_durations(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr)); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // repeated int32 supported_ranging_update_rates = 16 [packed = true]; + case 16: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 130)) { + ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_supported_ranging_update_rates(), ptr, ctx); + CHK_(ptr); + } else if (static_cast(tag) == 128) { + _internal_add_supported_ranging_update_rates(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr)); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 chip_count = 17 [default = 1]; + case 17: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 136)) { + _Internal::set_has_chip_count(&has_bits); + chip_count_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // repeated .nearby.presence.UwbMultiChipInfo multi_chip_info = 18; + case 18: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 146)) { + ptr -= 2; + do { + ptr += 2; + ptr = ctx->ParseMessage(_internal_add_multi_chip_info(), ptr); + CHK_(ptr); + if (!ctx->DataAvailable(ptr)) break; + } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<146>(ptr)); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* UwbControleeCapabilities::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:nearby.presence.UwbControleeCapabilities) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional bytes controlee_address = 1; + if (cached_has_bits & 0x00000001u) { + target = stream->WriteBytesMaybeAliased( + 1, this->_internal_controlee_address(), target); + } + + // repeated int32 supported_config_ids = 2 [packed = true]; + { + int byte_size = _supported_config_ids_cached_byte_size_.load(std::memory_order_relaxed); + if (byte_size > 0) { + target = stream->WriteInt32Packed( + 2, _internal_supported_config_ids(), byte_size, target); + } + } + + // repeated int32 supported_channels = 3 [packed = true]; + { + int byte_size = _supported_channels_cached_byte_size_.load(std::memory_order_relaxed); + if (byte_size > 0) { + target = stream->WriteInt32Packed( + 3, _internal_supported_channels(), byte_size, target); + } + } + + // optional int32 min_ranging_interval_ms = 4; + if (cached_has_bits & 0x00000010u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(4, this->_internal_min_ranging_interval_ms(), target); + } + + // optional bytes sub_session_id = 5; + if (cached_has_bits & 0x00000002u) { + target = stream->WriteBytesMaybeAliased( + 5, this->_internal_sub_session_id(), target); + } + + // optional bytes sub_session_key = 6; + if (cached_has_bits & 0x00000004u) { + target = stream->WriteBytesMaybeAliased( + 6, this->_internal_sub_session_key(), target); + } + + // optional bool ranging_disabled = 7; + if (cached_has_bits & 0x00000020u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(7, this->_internal_ranging_disabled(), target); + } + + // optional int64 device_unique_id = 8; + if (cached_has_bits & 0x00000008u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64ToArray(8, this->_internal_device_unique_id(), target); + } + + // optional bool is_distance_supported = 9 [default = true]; + if (cached_has_bits & 0x00000200u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(9, this->_internal_is_distance_supported(), target); + } + + // optional bool is_azimuth_supported = 10 [default = true]; + if (cached_has_bits & 0x00000400u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(10, this->_internal_is_azimuth_supported(), target); + } + + // optional bool is_elevation_supported = 11 [default = false]; + if (cached_has_bits & 0x00000040u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(11, this->_internal_is_elevation_supported(), target); + } + + // optional float min_slot_duration_ms = 12 [default = 2]; + if (cached_has_bits & 0x00000800u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloatToArray(12, this->_internal_min_slot_duration_ms(), target); + } + + // repeated int32 supported_ntf_configs = 13 [packed = true]; + { + int byte_size = _supported_ntf_configs_cached_byte_size_.load(std::memory_order_relaxed); + if (byte_size > 0) { + target = stream->WriteInt32Packed( + 13, _internal_supported_ntf_configs(), byte_size, target); + } + } + + // optional bool is_ranging_interval_reconfigure_supported = 14 [default = false]; + if (cached_has_bits & 0x00000080u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(14, this->_internal_is_ranging_interval_reconfigure_supported(), target); + } + + // repeated int32 supported_slot_durations = 15 [packed = true]; + { + int byte_size = _supported_slot_durations_cached_byte_size_.load(std::memory_order_relaxed); + if (byte_size > 0) { + target = stream->WriteInt32Packed( + 15, _internal_supported_slot_durations(), byte_size, target); + } + } + + // repeated int32 supported_ranging_update_rates = 16 [packed = true]; + { + int byte_size = _supported_ranging_update_rates_cached_byte_size_.load(std::memory_order_relaxed); + if (byte_size > 0) { + target = stream->WriteInt32Packed( + 16, _internal_supported_ranging_update_rates(), byte_size, target); + } + } + + // optional int32 chip_count = 17 [default = 1]; + if (cached_has_bits & 0x00000100u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(17, this->_internal_chip_count(), target); + } + + // repeated .nearby.presence.UwbMultiChipInfo multi_chip_info = 18; + for (unsigned int i = 0, + n = static_cast(this->_internal_multi_chip_info_size()); i < n; i++) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage(18, this->_internal_multi_chip_info(i), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:nearby.presence.UwbControleeCapabilities) + return target; +} + +size_t UwbControleeCapabilities::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:nearby.presence.UwbControleeCapabilities) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // repeated int32 supported_config_ids = 2 [packed = true]; + { + size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + Int32Size(this->supported_config_ids_); + if (data_size > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size( + static_cast(data_size)); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size); + _supported_config_ids_cached_byte_size_.store(cached_size, + std::memory_order_relaxed); + total_size += data_size; + } + + // repeated int32 supported_channels = 3 [packed = true]; + { + size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + Int32Size(this->supported_channels_); + if (data_size > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size( + static_cast(data_size)); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size); + _supported_channels_cached_byte_size_.store(cached_size, + std::memory_order_relaxed); + total_size += data_size; + } + + // repeated int32 supported_ntf_configs = 13 [packed = true]; + { + size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + Int32Size(this->supported_ntf_configs_); + if (data_size > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size( + static_cast(data_size)); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size); + _supported_ntf_configs_cached_byte_size_.store(cached_size, + std::memory_order_relaxed); + total_size += data_size; + } + + // repeated int32 supported_slot_durations = 15 [packed = true]; + { + size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + Int32Size(this->supported_slot_durations_); + if (data_size > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size( + static_cast(data_size)); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size); + _supported_slot_durations_cached_byte_size_.store(cached_size, + std::memory_order_relaxed); + total_size += data_size; + } + + // repeated int32 supported_ranging_update_rates = 16 [packed = true]; + { + size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + Int32Size(this->supported_ranging_update_rates_); + if (data_size > 0) { + total_size += 2 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size( + static_cast(data_size)); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size); + _supported_ranging_update_rates_cached_byte_size_.store(cached_size, + std::memory_order_relaxed); + total_size += data_size; + } + + // repeated .nearby.presence.UwbMultiChipInfo multi_chip_info = 18; + total_size += 2UL * this->_internal_multi_chip_info_size(); + for (const auto& msg : this->multi_chip_info_) { + total_size += + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg); + } + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x000000ffu) { + // optional bytes controlee_address = 1; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_controlee_address()); + } + + // optional bytes sub_session_id = 5; + if (cached_has_bits & 0x00000002u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_sub_session_id()); + } + + // optional bytes sub_session_key = 6; + if (cached_has_bits & 0x00000004u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_sub_session_key()); + } + + // optional int64 device_unique_id = 8; + if (cached_has_bits & 0x00000008u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64SizePlusOne(this->_internal_device_unique_id()); + } + + // optional int32 min_ranging_interval_ms = 4; + if (cached_has_bits & 0x00000010u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_min_ranging_interval_ms()); + } + + // optional bool ranging_disabled = 7; + if (cached_has_bits & 0x00000020u) { + total_size += 1 + 1; + } + + // optional bool is_elevation_supported = 11 [default = false]; + if (cached_has_bits & 0x00000040u) { + total_size += 1 + 1; + } + + // optional bool is_ranging_interval_reconfigure_supported = 14 [default = false]; + if (cached_has_bits & 0x00000080u) { + total_size += 1 + 1; + } + + } + if (cached_has_bits & 0x00000f00u) { + // optional int32 chip_count = 17 [default = 1]; + if (cached_has_bits & 0x00000100u) { + total_size += 2 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size( + this->_internal_chip_count()); + } + + // optional bool is_distance_supported = 9 [default = true]; + if (cached_has_bits & 0x00000200u) { + total_size += 1 + 1; + } + + // optional bool is_azimuth_supported = 10 [default = true]; + if (cached_has_bits & 0x00000400u) { + total_size += 1 + 1; + } + + // optional float min_slot_duration_ms = 12 [default = 2]; + if (cached_has_bits & 0x00000800u) { + total_size += 1 + 4; + } + + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UwbControleeCapabilities::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + UwbControleeCapabilities::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UwbControleeCapabilities::GetClassData() const { return &_class_data_; } + +void UwbControleeCapabilities::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void UwbControleeCapabilities::MergeFrom(const UwbControleeCapabilities& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:nearby.presence.UwbControleeCapabilities) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + supported_config_ids_.MergeFrom(from.supported_config_ids_); + supported_channels_.MergeFrom(from.supported_channels_); + supported_ntf_configs_.MergeFrom(from.supported_ntf_configs_); + supported_slot_durations_.MergeFrom(from.supported_slot_durations_); + supported_ranging_update_rates_.MergeFrom(from.supported_ranging_update_rates_); + multi_chip_info_.MergeFrom(from.multi_chip_info_); + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x000000ffu) { + if (cached_has_bits & 0x00000001u) { + _internal_set_controlee_address(from._internal_controlee_address()); + } + if (cached_has_bits & 0x00000002u) { + _internal_set_sub_session_id(from._internal_sub_session_id()); + } + if (cached_has_bits & 0x00000004u) { + _internal_set_sub_session_key(from._internal_sub_session_key()); + } + if (cached_has_bits & 0x00000008u) { + device_unique_id_ = from.device_unique_id_; + } + if (cached_has_bits & 0x00000010u) { + min_ranging_interval_ms_ = from.min_ranging_interval_ms_; + } + if (cached_has_bits & 0x00000020u) { + ranging_disabled_ = from.ranging_disabled_; + } + if (cached_has_bits & 0x00000040u) { + is_elevation_supported_ = from.is_elevation_supported_; + } + if (cached_has_bits & 0x00000080u) { + is_ranging_interval_reconfigure_supported_ = from.is_ranging_interval_reconfigure_supported_; + } + _has_bits_[0] |= cached_has_bits; + } + if (cached_has_bits & 0x00000f00u) { + if (cached_has_bits & 0x00000100u) { + chip_count_ = from.chip_count_; + } + if (cached_has_bits & 0x00000200u) { + is_distance_supported_ = from.is_distance_supported_; + } + if (cached_has_bits & 0x00000400u) { + is_azimuth_supported_ = from.is_azimuth_supported_; + } + if (cached_has_bits & 0x00000800u) { + min_slot_duration_ms_ = from.min_slot_duration_ms_; + } + _has_bits_[0] |= cached_has_bits; + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void UwbControleeCapabilities::CopyFrom(const UwbControleeCapabilities& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:nearby.presence.UwbControleeCapabilities) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool UwbControleeCapabilities::IsInitialized() const { + return true; +} + +void UwbControleeCapabilities::InternalSwap(UwbControleeCapabilities* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + supported_config_ids_.InternalSwap(&other->supported_config_ids_); + supported_channels_.InternalSwap(&other->supported_channels_); + supported_ntf_configs_.InternalSwap(&other->supported_ntf_configs_); + supported_slot_durations_.InternalSwap(&other->supported_slot_durations_); + supported_ranging_update_rates_.InternalSwap(&other->supported_ranging_update_rates_); + multi_chip_info_.InternalSwap(&other->multi_chip_info_); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &controlee_address_, lhs_arena, + &other->controlee_address_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &sub_session_id_, lhs_arena, + &other->sub_session_id_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &sub_session_key_, lhs_arena, + &other->sub_session_key_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(UwbControleeCapabilities, is_ranging_interval_reconfigure_supported_) + + sizeof(UwbControleeCapabilities::is_ranging_interval_reconfigure_supported_) + - PROTOBUF_FIELD_OFFSET(UwbControleeCapabilities, device_unique_id_)>( + reinterpret_cast(&device_unique_id_), + reinterpret_cast(&other->device_unique_id_)); + swap(chip_count_, other->chip_count_); + swap(is_distance_supported_, other->is_distance_supported_); + swap(is_azimuth_supported_, other->is_azimuth_supported_); + swap(min_slot_duration_ms_, other->min_slot_duration_ms_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata UwbControleeCapabilities::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_getter, &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_once, + file_level_metadata_presence_2fproto_2fpresence_5fframe_2eproto[4]); +} + +// =================================================================== + +class UwbMultiChipInfo::_Internal { + public: + using HasBits = decltype(std::declval()._has_bits_); + static void set_has_controlee_address(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static void set_has_chip_id(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } +}; + +UwbMultiChipInfo::UwbMultiChipInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:nearby.presence.UwbMultiChipInfo) +} +UwbMultiChipInfo::UwbMultiChipInfo(const UwbMultiChipInfo& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + controlee_address_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + controlee_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_controlee_address()) { + controlee_address_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_controlee_address(), + GetArenaForAllocation()); + } + chip_id_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + chip_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_chip_id()) { + chip_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_chip_id(), + GetArenaForAllocation()); + } + // @@protoc_insertion_point(copy_constructor:nearby.presence.UwbMultiChipInfo) +} + +inline void UwbMultiChipInfo::SharedCtor() { +controlee_address_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + controlee_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +chip_id_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + chip_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +} + +UwbMultiChipInfo::~UwbMultiChipInfo() { + // @@protoc_insertion_point(destructor:nearby.presence.UwbMultiChipInfo) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void UwbMultiChipInfo::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + controlee_address_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + chip_id_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void UwbMultiChipInfo::ArenaDtor(void* object) { + UwbMultiChipInfo* _this = reinterpret_cast< UwbMultiChipInfo* >(object); + (void)_this; +} +void UwbMultiChipInfo::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void UwbMultiChipInfo::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void UwbMultiChipInfo::Clear() { +// @@protoc_insertion_point(message_clear_start:nearby.presence.UwbMultiChipInfo) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000001u) { + controlee_address_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000002u) { + chip_id_.ClearNonDefaultToEmpty(); + } + } + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* UwbMultiChipInfo::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional bytes controlee_address = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + auto str = _internal_mutable_controlee_address(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional string chip_id = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + auto str = _internal_mutable_chip_id(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + #ifndef NDEBUG + ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "nearby.presence.UwbMultiChipInfo.chip_id"); + #endif // !NDEBUG + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* UwbMultiChipInfo::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:nearby.presence.UwbMultiChipInfo) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional bytes controlee_address = 1; + if (cached_has_bits & 0x00000001u) { + target = stream->WriteBytesMaybeAliased( + 1, this->_internal_controlee_address(), target); + } + + // optional string chip_id = 2; + if (cached_has_bits & 0x00000002u) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField( + this->_internal_chip_id().data(), static_cast(this->_internal_chip_id().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE, + "nearby.presence.UwbMultiChipInfo.chip_id"); + target = stream->WriteStringMaybeAliased( + 2, this->_internal_chip_id(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:nearby.presence.UwbMultiChipInfo) + return target; +} + +size_t UwbMultiChipInfo::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:nearby.presence.UwbMultiChipInfo) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + // optional bytes controlee_address = 1; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_controlee_address()); + } + + // optional string chip_id = 2; + if (cached_has_bits & 0x00000002u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_chip_id()); + } + + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UwbMultiChipInfo::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + UwbMultiChipInfo::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UwbMultiChipInfo::GetClassData() const { return &_class_data_; } + +void UwbMultiChipInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void UwbMultiChipInfo::MergeFrom(const UwbMultiChipInfo& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:nearby.presence.UwbMultiChipInfo) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000001u) { + _internal_set_controlee_address(from._internal_controlee_address()); + } + if (cached_has_bits & 0x00000002u) { + _internal_set_chip_id(from._internal_chip_id()); + } + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void UwbMultiChipInfo::CopyFrom(const UwbMultiChipInfo& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:nearby.presence.UwbMultiChipInfo) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool UwbMultiChipInfo::IsInitialized() const { + return true; +} + +void UwbMultiChipInfo::InternalSwap(UwbMultiChipInfo* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &controlee_address_, lhs_arena, + &other->controlee_address_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &chip_id_, lhs_arena, + &other->chip_id_, rhs_arena + ); +} + +::PROTOBUF_NAMESPACE_ID::Metadata UwbMultiChipInfo::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_getter, &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_once, + file_level_metadata_presence_2fproto_2fpresence_5fframe_2eproto[5]); +} + +// =================================================================== + +class UwbConnectionInfo::_Internal { + public: + using HasBits = decltype(std::declval()._has_bits_); + static void set_has_controller_address(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static void set_has_channel(HasBits* has_bits) { + (*has_bits)[0] |= 16u; + } + static void set_has_preamble_index(HasBits* has_bits) { + (*has_bits)[0] |= 32u; + } + static void set_has_config_id(HasBits* has_bits) { + (*has_bits)[0] |= 64u; + } + static void set_has_ranging_interval_ms(HasBits* has_bits) { + (*has_bits)[0] |= 128u; + } + static void set_has_session_id(HasBits* has_bits) { + (*has_bits)[0] |= 256u; + } + static void set_has_vendor_id(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } + static void set_has_static_sts_iv(HasBits* has_bits) { + (*has_bits)[0] |= 4u; + } + static void set_has_session_key(HasBits* has_bits) { + (*has_bits)[0] |= 8u; + } + static void set_has_ranging_disabled(HasBits* has_bits) { + (*has_bits)[0] |= 512u; + } +}; + +UwbConnectionInfo::UwbConnectionInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:nearby.presence.UwbConnectionInfo) +} +UwbConnectionInfo::UwbConnectionInfo(const UwbConnectionInfo& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + controller_address_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + controller_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_controller_address()) { + controller_address_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_controller_address(), + GetArenaForAllocation()); + } + vendor_id_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + vendor_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_vendor_id()) { + vendor_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_vendor_id(), + GetArenaForAllocation()); + } + static_sts_iv_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + static_sts_iv_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_static_sts_iv()) { + static_sts_iv_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_static_sts_iv(), + GetArenaForAllocation()); + } + session_key_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + session_key_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_session_key()) { + session_key_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_session_key(), + GetArenaForAllocation()); + } + ::memcpy(&channel_, &from.channel_, + static_cast(reinterpret_cast(&ranging_disabled_) - + reinterpret_cast(&channel_)) + sizeof(ranging_disabled_)); + // @@protoc_insertion_point(copy_constructor:nearby.presence.UwbConnectionInfo) +} + +inline void UwbConnectionInfo::SharedCtor() { +controller_address_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + controller_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +vendor_id_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + vendor_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +static_sts_iv_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + static_sts_iv_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +session_key_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + session_key_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&channel_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&ranging_disabled_) - + reinterpret_cast(&channel_)) + sizeof(ranging_disabled_)); +} + +UwbConnectionInfo::~UwbConnectionInfo() { + // @@protoc_insertion_point(destructor:nearby.presence.UwbConnectionInfo) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void UwbConnectionInfo::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + controller_address_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + vendor_id_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + static_sts_iv_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + session_key_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void UwbConnectionInfo::ArenaDtor(void* object) { + UwbConnectionInfo* _this = reinterpret_cast< UwbConnectionInfo* >(object); + (void)_this; +} +void UwbConnectionInfo::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void UwbConnectionInfo::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void UwbConnectionInfo::Clear() { +// @@protoc_insertion_point(message_clear_start:nearby.presence.UwbConnectionInfo) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x0000000fu) { + if (cached_has_bits & 0x00000001u) { + controller_address_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000002u) { + vendor_id_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000004u) { + static_sts_iv_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000008u) { + session_key_.ClearNonDefaultToEmpty(); + } + } + if (cached_has_bits & 0x000000f0u) { + ::memset(&channel_, 0, static_cast( + reinterpret_cast(&ranging_interval_ms_) - + reinterpret_cast(&channel_)) + sizeof(ranging_interval_ms_)); + } + if (cached_has_bits & 0x00000300u) { + ::memset(&session_id_, 0, static_cast( + reinterpret_cast(&ranging_disabled_) - + reinterpret_cast(&session_id_)) + sizeof(ranging_disabled_)); + } + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* UwbConnectionInfo::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional bytes controller_address = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + auto str = _internal_mutable_controller_address(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 channel = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 16)) { + _Internal::set_has_channel(&has_bits); + channel_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 preamble_index = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 24)) { + _Internal::set_has_preamble_index(&has_bits); + preamble_index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 config_id = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 32)) { + _Internal::set_has_config_id(&has_bits); + config_id_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 ranging_interval_ms = 5; + case 5: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 40)) { + _Internal::set_has_ranging_interval_ms(&has_bits); + ranging_interval_ms_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional int32 session_id = 6; + case 6: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 48)) { + _Internal::set_has_session_id(&has_bits); + session_id_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bytes vendor_id = 7; + case 7: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 58)) { + auto str = _internal_mutable_vendor_id(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bytes static_sts_iv = 8; + case 8: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 66)) { + auto str = _internal_mutable_static_sts_iv(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bytes session_key = 9; + case 9: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 74)) { + auto str = _internal_mutable_session_key(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bool ranging_disabled = 10; + case 10: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 80)) { + _Internal::set_has_ranging_disabled(&has_bits); + ranging_disabled_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* UwbConnectionInfo::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:nearby.presence.UwbConnectionInfo) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional bytes controller_address = 1; + if (cached_has_bits & 0x00000001u) { + target = stream->WriteBytesMaybeAliased( + 1, this->_internal_controller_address(), target); + } + + // optional int32 channel = 2; + if (cached_has_bits & 0x00000010u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_channel(), target); + } + + // optional int32 preamble_index = 3; + if (cached_has_bits & 0x00000020u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->_internal_preamble_index(), target); + } + + // optional int32 config_id = 4; + if (cached_has_bits & 0x00000040u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(4, this->_internal_config_id(), target); + } + + // optional int32 ranging_interval_ms = 5; + if (cached_has_bits & 0x00000080u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(5, this->_internal_ranging_interval_ms(), target); + } + + // optional int32 session_id = 6; + if (cached_has_bits & 0x00000100u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(6, this->_internal_session_id(), target); + } + + // optional bytes vendor_id = 7; + if (cached_has_bits & 0x00000002u) { + target = stream->WriteBytesMaybeAliased( + 7, this->_internal_vendor_id(), target); + } + + // optional bytes static_sts_iv = 8; + if (cached_has_bits & 0x00000004u) { + target = stream->WriteBytesMaybeAliased( + 8, this->_internal_static_sts_iv(), target); + } + + // optional bytes session_key = 9; + if (cached_has_bits & 0x00000008u) { + target = stream->WriteBytesMaybeAliased( + 9, this->_internal_session_key(), target); + } + + // optional bool ranging_disabled = 10; + if (cached_has_bits & 0x00000200u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(10, this->_internal_ranging_disabled(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:nearby.presence.UwbConnectionInfo) + return target; +} + +size_t UwbConnectionInfo::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:nearby.presence.UwbConnectionInfo) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x000000ffu) { + // optional bytes controller_address = 1; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_controller_address()); + } + + // optional bytes vendor_id = 7; + if (cached_has_bits & 0x00000002u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_vendor_id()); + } + + // optional bytes static_sts_iv = 8; + if (cached_has_bits & 0x00000004u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_static_sts_iv()); + } + + // optional bytes session_key = 9; + if (cached_has_bits & 0x00000008u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_session_key()); + } + + // optional int32 channel = 2; + if (cached_has_bits & 0x00000010u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_channel()); + } + + // optional int32 preamble_index = 3; + if (cached_has_bits & 0x00000020u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_preamble_index()); + } + + // optional int32 config_id = 4; + if (cached_has_bits & 0x00000040u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_config_id()); + } + + // optional int32 ranging_interval_ms = 5; + if (cached_has_bits & 0x00000080u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_ranging_interval_ms()); + } + + } + if (cached_has_bits & 0x00000300u) { + // optional int32 session_id = 6; + if (cached_has_bits & 0x00000100u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_session_id()); + } + + // optional bool ranging_disabled = 10; + if (cached_has_bits & 0x00000200u) { + total_size += 1 + 1; + } + + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UwbConnectionInfo::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + UwbConnectionInfo::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UwbConnectionInfo::GetClassData() const { return &_class_data_; } + +void UwbConnectionInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void UwbConnectionInfo::MergeFrom(const UwbConnectionInfo& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:nearby.presence.UwbConnectionInfo) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x000000ffu) { + if (cached_has_bits & 0x00000001u) { + _internal_set_controller_address(from._internal_controller_address()); + } + if (cached_has_bits & 0x00000002u) { + _internal_set_vendor_id(from._internal_vendor_id()); + } + if (cached_has_bits & 0x00000004u) { + _internal_set_static_sts_iv(from._internal_static_sts_iv()); + } + if (cached_has_bits & 0x00000008u) { + _internal_set_session_key(from._internal_session_key()); + } + if (cached_has_bits & 0x00000010u) { + channel_ = from.channel_; + } + if (cached_has_bits & 0x00000020u) { + preamble_index_ = from.preamble_index_; + } + if (cached_has_bits & 0x00000040u) { + config_id_ = from.config_id_; + } + if (cached_has_bits & 0x00000080u) { + ranging_interval_ms_ = from.ranging_interval_ms_; + } + _has_bits_[0] |= cached_has_bits; + } + if (cached_has_bits & 0x00000300u) { + if (cached_has_bits & 0x00000100u) { + session_id_ = from.session_id_; + } + if (cached_has_bits & 0x00000200u) { + ranging_disabled_ = from.ranging_disabled_; + } + _has_bits_[0] |= cached_has_bits; + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void UwbConnectionInfo::CopyFrom(const UwbConnectionInfo& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:nearby.presence.UwbConnectionInfo) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool UwbConnectionInfo::IsInitialized() const { + return true; +} + +void UwbConnectionInfo::InternalSwap(UwbConnectionInfo* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &controller_address_, lhs_arena, + &other->controller_address_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &vendor_id_, lhs_arena, + &other->vendor_id_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &static_sts_iv_, lhs_arena, + &other->static_sts_iv_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &session_key_, lhs_arena, + &other->session_key_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(UwbConnectionInfo, ranging_disabled_) + + sizeof(UwbConnectionInfo::ranging_disabled_) + - PROTOBUF_FIELD_OFFSET(UwbConnectionInfo, channel_)>( + reinterpret_cast(&channel_), + reinterpret_cast(&other->channel_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata UwbConnectionInfo::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_getter, &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_once, + file_level_metadata_presence_2fproto_2fpresence_5fframe_2eproto[6]); +} + +// =================================================================== + +class ControlFrame::_Internal { + public: + using HasBits = decltype(std::declval()._has_bits_); + static void set_has_type(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } +}; + +ControlFrame::ControlFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:nearby.presence.ControlFrame) +} +ControlFrame::ControlFrame(const ControlFrame& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + type_ = from.type_; + // @@protoc_insertion_point(copy_constructor:nearby.presence.ControlFrame) +} + +inline void ControlFrame::SharedCtor() { +type_ = 0; +} + +ControlFrame::~ControlFrame() { + // @@protoc_insertion_point(destructor:nearby.presence.ControlFrame) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void ControlFrame::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); +} + +void ControlFrame::ArenaDtor(void* object) { + ControlFrame* _this = reinterpret_cast< ControlFrame* >(object); + (void)_this; +} +void ControlFrame::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void ControlFrame::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void ControlFrame::Clear() { +// @@protoc_insertion_point(message_clear_start:nearby.presence.ControlFrame) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + type_ = 0; + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* ControlFrame::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional .nearby.presence.ControlFrame.ControlType type = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 8)) { + uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + if (PROTOBUF_PREDICT_TRUE(::nearby::presence::ControlFrame_ControlType_IsValid(val))) { + _internal_set_type(static_cast<::nearby::presence::ControlFrame_ControlType>(val)); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(1, val, mutable_unknown_fields()); + } + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* ControlFrame::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:nearby.presence.ControlFrame) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional .nearby.presence.ControlFrame.ControlType type = 1; + if (cached_has_bits & 0x00000001u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray( + 1, this->_internal_type(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:nearby.presence.ControlFrame) + return target; +} + +size_t ControlFrame::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:nearby.presence.ControlFrame) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // optional .nearby.presence.ControlFrame.ControlType type = 1; + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_type()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ControlFrame::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + ControlFrame::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ControlFrame::GetClassData() const { return &_class_data_; } + +void ControlFrame::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void ControlFrame::MergeFrom(const ControlFrame& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:nearby.presence.ControlFrame) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_has_type()) { + _internal_set_type(from._internal_type()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void ControlFrame::CopyFrom(const ControlFrame& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:nearby.presence.ControlFrame) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool ControlFrame::IsInitialized() const { + return true; +} + +void ControlFrame::InternalSwap(ControlFrame* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + swap(type_, other->type_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata ControlFrame::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_getter, &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_once, + file_level_metadata_presence_2fproto_2fpresence_5fframe_2eproto[7]); +} + +// =================================================================== + +class PresenceAuthenticationFrame::_Internal { + public: + using HasBits = decltype(std::declval()._has_bits_); + static void set_has_version(HasBits* has_bits) { + (*has_bits)[0] |= 8u; + } + static void set_has_private_key_signature(HasBits* has_bits) { + (*has_bits)[0] |= 1u; + } + static void set_has_shared_credential_id_hash(HasBits* has_bits) { + (*has_bits)[0] |= 2u; + } + static void set_has_credential_id_hash(HasBits* has_bits) { + (*has_bits)[0] |= 4u; + } +}; + +PresenceAuthenticationFrame::PresenceAuthenticationFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:nearby.presence.PresenceAuthenticationFrame) +} +PresenceAuthenticationFrame::PresenceAuthenticationFrame(const PresenceAuthenticationFrame& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + _has_bits_(from._has_bits_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + private_key_signature_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + private_key_signature_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_private_key_signature()) { + private_key_signature_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_private_key_signature(), + GetArenaForAllocation()); + } + shared_credential_id_hash_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + shared_credential_id_hash_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_shared_credential_id_hash()) { + shared_credential_id_hash_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_shared_credential_id_hash(), + GetArenaForAllocation()); + } + credential_id_hash_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + credential_id_hash_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_credential_id_hash()) { + credential_id_hash_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_credential_id_hash(), + GetArenaForAllocation()); + } + version_ = from.version_; + // @@protoc_insertion_point(copy_constructor:nearby.presence.PresenceAuthenticationFrame) +} + +inline void PresenceAuthenticationFrame::SharedCtor() { +private_key_signature_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + private_key_signature_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +shared_credential_id_hash_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + shared_credential_id_hash_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +credential_id_hash_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + credential_id_hash_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +version_ = 0; +} + +PresenceAuthenticationFrame::~PresenceAuthenticationFrame() { + // @@protoc_insertion_point(destructor:nearby.presence.PresenceAuthenticationFrame) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void PresenceAuthenticationFrame::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + private_key_signature_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + shared_credential_id_hash_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + credential_id_hash_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void PresenceAuthenticationFrame::ArenaDtor(void* object) { + PresenceAuthenticationFrame* _this = reinterpret_cast< PresenceAuthenticationFrame* >(object); + (void)_this; +} +void PresenceAuthenticationFrame::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void PresenceAuthenticationFrame::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void PresenceAuthenticationFrame::Clear() { +// @@protoc_insertion_point(message_clear_start:nearby.presence.PresenceAuthenticationFrame) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x00000007u) { + if (cached_has_bits & 0x00000001u) { + private_key_signature_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000002u) { + shared_credential_id_hash_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000004u) { + credential_id_hash_.ClearNonDefaultToEmpty(); + } + } + version_ = 0; + _has_bits_.Clear(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* PresenceAuthenticationFrame::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + _Internal::HasBits has_bits{}; + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // optional int32 version = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 8)) { + _Internal::set_has_version(&has_bits); + version_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bytes private_key_signature = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + auto str = _internal_mutable_private_key_signature(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bytes shared_credential_id_hash = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 26)) { + auto str = _internal_mutable_shared_credential_id_hash(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // optional bytes credential_id_hash = 4 [deprecated = true]; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 34)) { + auto str = _internal_mutable_credential_id_hash(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + _has_bits_.Or(has_bits); + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* PresenceAuthenticationFrame::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:nearby.presence.PresenceAuthenticationFrame) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + // optional int32 version = 1; + if (cached_has_bits & 0x00000008u) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->_internal_version(), target); + } + + // optional bytes private_key_signature = 2; + if (cached_has_bits & 0x00000001u) { + target = stream->WriteBytesMaybeAliased( + 2, this->_internal_private_key_signature(), target); + } + + // optional bytes shared_credential_id_hash = 3; + if (cached_has_bits & 0x00000002u) { + target = stream->WriteBytesMaybeAliased( + 3, this->_internal_shared_credential_id_hash(), target); + } + + // optional bytes credential_id_hash = 4 [deprecated = true]; + if (cached_has_bits & 0x00000004u) { + target = stream->WriteBytesMaybeAliased( + 4, this->_internal_credential_id_hash(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:nearby.presence.PresenceAuthenticationFrame) + return target; +} + +size_t PresenceAuthenticationFrame::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:nearby.presence.PresenceAuthenticationFrame) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + cached_has_bits = _has_bits_[0]; + if (cached_has_bits & 0x0000000fu) { + // optional bytes private_key_signature = 2; + if (cached_has_bits & 0x00000001u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_private_key_signature()); + } + + // optional bytes shared_credential_id_hash = 3; + if (cached_has_bits & 0x00000002u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_shared_credential_id_hash()); + } + + // optional bytes credential_id_hash = 4 [deprecated = true]; + if (cached_has_bits & 0x00000004u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( + this->_internal_credential_id_hash()); + } + + // optional int32 version = 1; + if (cached_has_bits & 0x00000008u) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_version()); + } + + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData PresenceAuthenticationFrame::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + PresenceAuthenticationFrame::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*PresenceAuthenticationFrame::GetClassData() const { return &_class_data_; } + +void PresenceAuthenticationFrame::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void PresenceAuthenticationFrame::MergeFrom(const PresenceAuthenticationFrame& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:nearby.presence.PresenceAuthenticationFrame) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + cached_has_bits = from._has_bits_[0]; + if (cached_has_bits & 0x0000000fu) { + if (cached_has_bits & 0x00000001u) { + _internal_set_private_key_signature(from._internal_private_key_signature()); + } + if (cached_has_bits & 0x00000002u) { + _internal_set_shared_credential_id_hash(from._internal_shared_credential_id_hash()); + } + if (cached_has_bits & 0x00000004u) { + _internal_set_credential_id_hash(from._internal_credential_id_hash()); + } + if (cached_has_bits & 0x00000008u) { + version_ = from.version_; + } + _has_bits_[0] |= cached_has_bits; + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void PresenceAuthenticationFrame::CopyFrom(const PresenceAuthenticationFrame& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:nearby.presence.PresenceAuthenticationFrame) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool PresenceAuthenticationFrame::IsInitialized() const { + return true; +} + +void PresenceAuthenticationFrame::InternalSwap(PresenceAuthenticationFrame* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(_has_bits_[0], other->_has_bits_[0]); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &private_key_signature_, lhs_arena, + &other->private_key_signature_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &shared_credential_id_hash_, lhs_arena, + &other->shared_credential_id_hash_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &credential_id_hash_, lhs_arena, + &other->credential_id_hash_, rhs_arena + ); + swap(version_, other->version_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata PresenceAuthenticationFrame::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_getter, &descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto_once, + file_level_metadata_presence_2fproto_2fpresence_5fframe_2eproto[8]); +} + +// @@protoc_insertion_point(namespace_scope) +} // namespace presence +} // namespace nearby +PROTOBUF_NAMESPACE_OPEN +template<> PROTOBUF_NOINLINE ::nearby::presence::PresenceFrame* Arena::CreateMaybeMessage< ::nearby::presence::PresenceFrame >(Arena* arena) { + return Arena::CreateMessageInternal< ::nearby::presence::PresenceFrame >(arena); +} +template<> PROTOBUF_NOINLINE ::nearby::presence::V1Frame* Arena::CreateMaybeMessage< ::nearby::presence::V1Frame >(Arena* arena) { + return Arena::CreateMessageInternal< ::nearby::presence::V1Frame >(arena); +} +template<> PROTOBUF_NOINLINE ::nearby::presence::DeviceIdentityFrame* Arena::CreateMaybeMessage< ::nearby::presence::DeviceIdentityFrame >(Arena* arena) { + return Arena::CreateMessageInternal< ::nearby::presence::DeviceIdentityFrame >(arena); +} +template<> PROTOBUF_NOINLINE ::nearby::presence::ConnectionInitFrame* Arena::CreateMaybeMessage< ::nearby::presence::ConnectionInitFrame >(Arena* arena) { + return Arena::CreateMessageInternal< ::nearby::presence::ConnectionInitFrame >(arena); +} +template<> PROTOBUF_NOINLINE ::nearby::presence::UwbControleeCapabilities* Arena::CreateMaybeMessage< ::nearby::presence::UwbControleeCapabilities >(Arena* arena) { + return Arena::CreateMessageInternal< ::nearby::presence::UwbControleeCapabilities >(arena); +} +template<> PROTOBUF_NOINLINE ::nearby::presence::UwbMultiChipInfo* Arena::CreateMaybeMessage< ::nearby::presence::UwbMultiChipInfo >(Arena* arena) { + return Arena::CreateMessageInternal< ::nearby::presence::UwbMultiChipInfo >(arena); +} +template<> PROTOBUF_NOINLINE ::nearby::presence::UwbConnectionInfo* Arena::CreateMaybeMessage< ::nearby::presence::UwbConnectionInfo >(Arena* arena) { + return Arena::CreateMessageInternal< ::nearby::presence::UwbConnectionInfo >(arena); +} +template<> PROTOBUF_NOINLINE ::nearby::presence::ControlFrame* Arena::CreateMaybeMessage< ::nearby::presence::ControlFrame >(Arena* arena) { + return Arena::CreateMessageInternal< ::nearby::presence::ControlFrame >(arena); +} +template<> PROTOBUF_NOINLINE ::nearby::presence::PresenceAuthenticationFrame* Arena::CreateMaybeMessage< ::nearby::presence::PresenceAuthenticationFrame >(Arena* arena) { + return Arena::CreateMessageInternal< ::nearby::presence::PresenceAuthenticationFrame >(arena); +} +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) +#include diff --git a/compiled_proto/presence/proto/presence_frame.pb.h b/compiled_proto/presence/proto/presence_frame.pb.h new file mode 100644 index 00000000..ce177b23 --- /dev/null +++ b/compiled_proto/presence/proto/presence_frame.pb.h @@ -0,0 +1,5274 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: presence/proto/presence_frame.proto + +#ifndef GOOGLE_PROTOBUF_INCLUDED_presence_2fproto_2fpresence_5fframe_2eproto +#define GOOGLE_PROTOBUF_INCLUDED_presence_2fproto_2fpresence_5fframe_2eproto + +#include +#include + +#include +#if PROTOBUF_VERSION < 3019000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3019001 < PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export +#include // IWYU pragma: export +#include +#include +// @@protoc_insertion_point(includes) +#include +#define PROTOBUF_INTERNAL_EXPORT_presence_2fproto_2fpresence_5fframe_2eproto +PROTOBUF_NAMESPACE_OPEN +namespace internal { +class AnyMetadata; +} // namespace internal +PROTOBUF_NAMESPACE_CLOSE + +// Internal implementation detail -- do not use these members. +struct TableStruct_presence_2fproto_2fpresence_5fframe_2eproto { + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[9] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; + static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; + static const uint32_t offsets[]; +}; +extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_presence_2fproto_2fpresence_5fframe_2eproto; +namespace nearby { +namespace presence { +class ConnectionInitFrame; +struct ConnectionInitFrameDefaultTypeInternal; +extern ConnectionInitFrameDefaultTypeInternal _ConnectionInitFrame_default_instance_; +class ControlFrame; +struct ControlFrameDefaultTypeInternal; +extern ControlFrameDefaultTypeInternal _ControlFrame_default_instance_; +class DeviceIdentityFrame; +struct DeviceIdentityFrameDefaultTypeInternal; +extern DeviceIdentityFrameDefaultTypeInternal _DeviceIdentityFrame_default_instance_; +class PresenceAuthenticationFrame; +struct PresenceAuthenticationFrameDefaultTypeInternal; +extern PresenceAuthenticationFrameDefaultTypeInternal _PresenceAuthenticationFrame_default_instance_; +class PresenceFrame; +struct PresenceFrameDefaultTypeInternal; +extern PresenceFrameDefaultTypeInternal _PresenceFrame_default_instance_; +class UwbConnectionInfo; +struct UwbConnectionInfoDefaultTypeInternal; +extern UwbConnectionInfoDefaultTypeInternal _UwbConnectionInfo_default_instance_; +class UwbControleeCapabilities; +struct UwbControleeCapabilitiesDefaultTypeInternal; +extern UwbControleeCapabilitiesDefaultTypeInternal _UwbControleeCapabilities_default_instance_; +class UwbMultiChipInfo; +struct UwbMultiChipInfoDefaultTypeInternal; +extern UwbMultiChipInfoDefaultTypeInternal _UwbMultiChipInfo_default_instance_; +class V1Frame; +struct V1FrameDefaultTypeInternal; +extern V1FrameDefaultTypeInternal _V1Frame_default_instance_; +} // namespace presence +} // namespace nearby +PROTOBUF_NAMESPACE_OPEN +template<> ::nearby::presence::ConnectionInitFrame* Arena::CreateMaybeMessage<::nearby::presence::ConnectionInitFrame>(Arena*); +template<> ::nearby::presence::ControlFrame* Arena::CreateMaybeMessage<::nearby::presence::ControlFrame>(Arena*); +template<> ::nearby::presence::DeviceIdentityFrame* Arena::CreateMaybeMessage<::nearby::presence::DeviceIdentityFrame>(Arena*); +template<> ::nearby::presence::PresenceAuthenticationFrame* Arena::CreateMaybeMessage<::nearby::presence::PresenceAuthenticationFrame>(Arena*); +template<> ::nearby::presence::PresenceFrame* Arena::CreateMaybeMessage<::nearby::presence::PresenceFrame>(Arena*); +template<> ::nearby::presence::UwbConnectionInfo* Arena::CreateMaybeMessage<::nearby::presence::UwbConnectionInfo>(Arena*); +template<> ::nearby::presence::UwbControleeCapabilities* Arena::CreateMaybeMessage<::nearby::presence::UwbControleeCapabilities>(Arena*); +template<> ::nearby::presence::UwbMultiChipInfo* Arena::CreateMaybeMessage<::nearby::presence::UwbMultiChipInfo>(Arena*); +template<> ::nearby::presence::V1Frame* Arena::CreateMaybeMessage<::nearby::presence::V1Frame>(Arena*); +PROTOBUF_NAMESPACE_CLOSE +namespace nearby { +namespace presence { + +enum PresenceFrame_Version : int { + PresenceFrame_Version_UNKNOWN_VERSION = 0, + PresenceFrame_Version_VERSION_1 = 1 +}; +bool PresenceFrame_Version_IsValid(int value); +constexpr PresenceFrame_Version PresenceFrame_Version_Version_MIN = PresenceFrame_Version_UNKNOWN_VERSION; +constexpr PresenceFrame_Version PresenceFrame_Version_Version_MAX = PresenceFrame_Version_VERSION_1; +constexpr int PresenceFrame_Version_Version_ARRAYSIZE = PresenceFrame_Version_Version_MAX + 1; + +const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* PresenceFrame_Version_descriptor(); +template +inline const std::string& PresenceFrame_Version_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function PresenceFrame_Version_Name."); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum( + PresenceFrame_Version_descriptor(), enum_t_value); +} +inline bool PresenceFrame_Version_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, PresenceFrame_Version* value) { + return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( + PresenceFrame_Version_descriptor(), name, value); +} +enum ControlFrame_ControlType : int { + ControlFrame_ControlType_UNKNOWN_TYPE = 0, + ControlFrame_ControlType_KEEP_ALIVE = 1, + ControlFrame_ControlType_DISCONNECT = 2 +}; +bool ControlFrame_ControlType_IsValid(int value); +constexpr ControlFrame_ControlType ControlFrame_ControlType_ControlType_MIN = ControlFrame_ControlType_UNKNOWN_TYPE; +constexpr ControlFrame_ControlType ControlFrame_ControlType_ControlType_MAX = ControlFrame_ControlType_DISCONNECT; +constexpr int ControlFrame_ControlType_ControlType_ARRAYSIZE = ControlFrame_ControlType_ControlType_MAX + 1; + +const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* ControlFrame_ControlType_descriptor(); +template +inline const std::string& ControlFrame_ControlType_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function ControlFrame_ControlType_Name."); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum( + ControlFrame_ControlType_descriptor(), enum_t_value); +} +inline bool ControlFrame_ControlType_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, ControlFrame_ControlType* value) { + return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( + ControlFrame_ControlType_descriptor(), name, value); +} +// =================================================================== + +class PresenceFrame final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:nearby.presence.PresenceFrame) */ { + public: + inline PresenceFrame() : PresenceFrame(nullptr) {} + ~PresenceFrame() override; + explicit constexpr PresenceFrame(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + PresenceFrame(const PresenceFrame& from); + PresenceFrame(PresenceFrame&& from) noexcept + : PresenceFrame() { + *this = ::std::move(from); + } + + inline PresenceFrame& operator=(const PresenceFrame& from) { + CopyFrom(from); + return *this; + } + inline PresenceFrame& operator=(PresenceFrame&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const PresenceFrame& default_instance() { + return *internal_default_instance(); + } + static inline const PresenceFrame* internal_default_instance() { + return reinterpret_cast( + &_PresenceFrame_default_instance_); + } + static constexpr int kIndexInFileMessages = + 0; + + friend void swap(PresenceFrame& a, PresenceFrame& b) { + a.Swap(&b); + } + inline void Swap(PresenceFrame* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(PresenceFrame* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + PresenceFrame* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const PresenceFrame& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const PresenceFrame& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(PresenceFrame* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "nearby.presence.PresenceFrame"; + } + protected: + explicit PresenceFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + typedef PresenceFrame_Version Version; + static constexpr Version UNKNOWN_VERSION = + PresenceFrame_Version_UNKNOWN_VERSION; + static constexpr Version VERSION_1 = + PresenceFrame_Version_VERSION_1; + static inline bool Version_IsValid(int value) { + return PresenceFrame_Version_IsValid(value); + } + static constexpr Version Version_MIN = + PresenceFrame_Version_Version_MIN; + static constexpr Version Version_MAX = + PresenceFrame_Version_Version_MAX; + static constexpr int Version_ARRAYSIZE = + PresenceFrame_Version_Version_ARRAYSIZE; + static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* + Version_descriptor() { + return PresenceFrame_Version_descriptor(); + } + template + static inline const std::string& Version_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function Version_Name."); + return PresenceFrame_Version_Name(enum_t_value); + } + static inline bool Version_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name, + Version* value) { + return PresenceFrame_Version_Parse(name, value); + } + + // accessors ------------------------------------------------------- + + enum : int { + kV1FrameFieldNumber = 1, + }; + // optional .nearby.presence.V1Frame v1_frame = 1; + bool has_v1_frame() const; + private: + bool _internal_has_v1_frame() const; + public: + void clear_v1_frame(); + const ::nearby::presence::V1Frame& v1_frame() const; + PROTOBUF_NODISCARD ::nearby::presence::V1Frame* release_v1_frame(); + ::nearby::presence::V1Frame* mutable_v1_frame(); + void set_allocated_v1_frame(::nearby::presence::V1Frame* v1_frame); + private: + const ::nearby::presence::V1Frame& _internal_v1_frame() const; + ::nearby::presence::V1Frame* _internal_mutable_v1_frame(); + public: + void unsafe_arena_set_allocated_v1_frame( + ::nearby::presence::V1Frame* v1_frame); + ::nearby::presence::V1Frame* unsafe_arena_release_v1_frame(); + + // @@protoc_insertion_point(class_scope:nearby.presence.PresenceFrame) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::nearby::presence::V1Frame* v1_frame_; + friend struct ::TableStruct_presence_2fproto_2fpresence_5fframe_2eproto; +}; +// ------------------------------------------------------------------- + +class V1Frame final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:nearby.presence.V1Frame) */ { + public: + inline V1Frame() : V1Frame(nullptr) {} + ~V1Frame() override; + explicit constexpr V1Frame(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + V1Frame(const V1Frame& from); + V1Frame(V1Frame&& from) noexcept + : V1Frame() { + *this = ::std::move(from); + } + + inline V1Frame& operator=(const V1Frame& from) { + CopyFrom(from); + return *this; + } + inline V1Frame& operator=(V1Frame&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const V1Frame& default_instance() { + return *internal_default_instance(); + } + enum MessageCase { + kControlFrame = 1, + kDeviceIdentityFrame = 2, + kConnectionInitFrame = 3, + kUwbControleeCapabilitiesFrame = 4, + kUwbConnectionInfo = 5, + kAuthenticationFrame = 6, + MESSAGE_NOT_SET = 0, + }; + + static inline const V1Frame* internal_default_instance() { + return reinterpret_cast( + &_V1Frame_default_instance_); + } + static constexpr int kIndexInFileMessages = + 1; + + friend void swap(V1Frame& a, V1Frame& b) { + a.Swap(&b); + } + inline void Swap(V1Frame* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(V1Frame* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + V1Frame* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const V1Frame& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const V1Frame& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(V1Frame* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "nearby.presence.V1Frame"; + } + protected: + explicit V1Frame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kControlFrameFieldNumber = 1, + kDeviceIdentityFrameFieldNumber = 2, + kConnectionInitFrameFieldNumber = 3, + kUwbControleeCapabilitiesFrameFieldNumber = 4, + kUwbConnectionInfoFieldNumber = 5, + kAuthenticationFrameFieldNumber = 6, + }; + // .nearby.presence.ControlFrame control_frame = 1; + bool has_control_frame() const; + private: + bool _internal_has_control_frame() const; + public: + void clear_control_frame(); + const ::nearby::presence::ControlFrame& control_frame() const; + PROTOBUF_NODISCARD ::nearby::presence::ControlFrame* release_control_frame(); + ::nearby::presence::ControlFrame* mutable_control_frame(); + void set_allocated_control_frame(::nearby::presence::ControlFrame* control_frame); + private: + const ::nearby::presence::ControlFrame& _internal_control_frame() const; + ::nearby::presence::ControlFrame* _internal_mutable_control_frame(); + public: + void unsafe_arena_set_allocated_control_frame( + ::nearby::presence::ControlFrame* control_frame); + ::nearby::presence::ControlFrame* unsafe_arena_release_control_frame(); + + // .nearby.presence.DeviceIdentityFrame device_identity_frame = 2; + bool has_device_identity_frame() const; + private: + bool _internal_has_device_identity_frame() const; + public: + void clear_device_identity_frame(); + const ::nearby::presence::DeviceIdentityFrame& device_identity_frame() const; + PROTOBUF_NODISCARD ::nearby::presence::DeviceIdentityFrame* release_device_identity_frame(); + ::nearby::presence::DeviceIdentityFrame* mutable_device_identity_frame(); + void set_allocated_device_identity_frame(::nearby::presence::DeviceIdentityFrame* device_identity_frame); + private: + const ::nearby::presence::DeviceIdentityFrame& _internal_device_identity_frame() const; + ::nearby::presence::DeviceIdentityFrame* _internal_mutable_device_identity_frame(); + public: + void unsafe_arena_set_allocated_device_identity_frame( + ::nearby::presence::DeviceIdentityFrame* device_identity_frame); + ::nearby::presence::DeviceIdentityFrame* unsafe_arena_release_device_identity_frame(); + + // .nearby.presence.ConnectionInitFrame connection_init_frame = 3; + bool has_connection_init_frame() const; + private: + bool _internal_has_connection_init_frame() const; + public: + void clear_connection_init_frame(); + const ::nearby::presence::ConnectionInitFrame& connection_init_frame() const; + PROTOBUF_NODISCARD ::nearby::presence::ConnectionInitFrame* release_connection_init_frame(); + ::nearby::presence::ConnectionInitFrame* mutable_connection_init_frame(); + void set_allocated_connection_init_frame(::nearby::presence::ConnectionInitFrame* connection_init_frame); + private: + const ::nearby::presence::ConnectionInitFrame& _internal_connection_init_frame() const; + ::nearby::presence::ConnectionInitFrame* _internal_mutable_connection_init_frame(); + public: + void unsafe_arena_set_allocated_connection_init_frame( + ::nearby::presence::ConnectionInitFrame* connection_init_frame); + ::nearby::presence::ConnectionInitFrame* unsafe_arena_release_connection_init_frame(); + + // .nearby.presence.UwbControleeCapabilities uwb_controlee_capabilities_frame = 4; + bool has_uwb_controlee_capabilities_frame() const; + private: + bool _internal_has_uwb_controlee_capabilities_frame() const; + public: + void clear_uwb_controlee_capabilities_frame(); + const ::nearby::presence::UwbControleeCapabilities& uwb_controlee_capabilities_frame() const; + PROTOBUF_NODISCARD ::nearby::presence::UwbControleeCapabilities* release_uwb_controlee_capabilities_frame(); + ::nearby::presence::UwbControleeCapabilities* mutable_uwb_controlee_capabilities_frame(); + void set_allocated_uwb_controlee_capabilities_frame(::nearby::presence::UwbControleeCapabilities* uwb_controlee_capabilities_frame); + private: + const ::nearby::presence::UwbControleeCapabilities& _internal_uwb_controlee_capabilities_frame() const; + ::nearby::presence::UwbControleeCapabilities* _internal_mutable_uwb_controlee_capabilities_frame(); + public: + void unsafe_arena_set_allocated_uwb_controlee_capabilities_frame( + ::nearby::presence::UwbControleeCapabilities* uwb_controlee_capabilities_frame); + ::nearby::presence::UwbControleeCapabilities* unsafe_arena_release_uwb_controlee_capabilities_frame(); + + // .nearby.presence.UwbConnectionInfo uwb_connection_info = 5; + bool has_uwb_connection_info() const; + private: + bool _internal_has_uwb_connection_info() const; + public: + void clear_uwb_connection_info(); + const ::nearby::presence::UwbConnectionInfo& uwb_connection_info() const; + PROTOBUF_NODISCARD ::nearby::presence::UwbConnectionInfo* release_uwb_connection_info(); + ::nearby::presence::UwbConnectionInfo* mutable_uwb_connection_info(); + void set_allocated_uwb_connection_info(::nearby::presence::UwbConnectionInfo* uwb_connection_info); + private: + const ::nearby::presence::UwbConnectionInfo& _internal_uwb_connection_info() const; + ::nearby::presence::UwbConnectionInfo* _internal_mutable_uwb_connection_info(); + public: + void unsafe_arena_set_allocated_uwb_connection_info( + ::nearby::presence::UwbConnectionInfo* uwb_connection_info); + ::nearby::presence::UwbConnectionInfo* unsafe_arena_release_uwb_connection_info(); + + // .nearby.presence.PresenceAuthenticationFrame authentication_frame = 6; + bool has_authentication_frame() const; + private: + bool _internal_has_authentication_frame() const; + public: + void clear_authentication_frame(); + const ::nearby::presence::PresenceAuthenticationFrame& authentication_frame() const; + PROTOBUF_NODISCARD ::nearby::presence::PresenceAuthenticationFrame* release_authentication_frame(); + ::nearby::presence::PresenceAuthenticationFrame* mutable_authentication_frame(); + void set_allocated_authentication_frame(::nearby::presence::PresenceAuthenticationFrame* authentication_frame); + private: + const ::nearby::presence::PresenceAuthenticationFrame& _internal_authentication_frame() const; + ::nearby::presence::PresenceAuthenticationFrame* _internal_mutable_authentication_frame(); + public: + void unsafe_arena_set_allocated_authentication_frame( + ::nearby::presence::PresenceAuthenticationFrame* authentication_frame); + ::nearby::presence::PresenceAuthenticationFrame* unsafe_arena_release_authentication_frame(); + + void clear_Message(); + MessageCase Message_case() const; + // @@protoc_insertion_point(class_scope:nearby.presence.V1Frame) + private: + class _Internal; + void set_has_control_frame(); + void set_has_device_identity_frame(); + void set_has_connection_init_frame(); + void set_has_uwb_controlee_capabilities_frame(); + void set_has_uwb_connection_info(); + void set_has_authentication_frame(); + + inline bool has_Message() const; + inline void clear_has_Message(); + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + union MessageUnion { + constexpr MessageUnion() : _constinit_{} {} + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized _constinit_; + ::nearby::presence::ControlFrame* control_frame_; + ::nearby::presence::DeviceIdentityFrame* device_identity_frame_; + ::nearby::presence::ConnectionInitFrame* connection_init_frame_; + ::nearby::presence::UwbControleeCapabilities* uwb_controlee_capabilities_frame_; + ::nearby::presence::UwbConnectionInfo* uwb_connection_info_; + ::nearby::presence::PresenceAuthenticationFrame* authentication_frame_; + } Message_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + uint32_t _oneof_case_[1]; + + friend struct ::TableStruct_presence_2fproto_2fpresence_5fframe_2eproto; +}; +// ------------------------------------------------------------------- + +class DeviceIdentityFrame final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:nearby.presence.DeviceIdentityFrame) */ { + public: + inline DeviceIdentityFrame() : DeviceIdentityFrame(nullptr) {} + ~DeviceIdentityFrame() override; + explicit constexpr DeviceIdentityFrame(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + DeviceIdentityFrame(const DeviceIdentityFrame& from); + DeviceIdentityFrame(DeviceIdentityFrame&& from) noexcept + : DeviceIdentityFrame() { + *this = ::std::move(from); + } + + inline DeviceIdentityFrame& operator=(const DeviceIdentityFrame& from) { + CopyFrom(from); + return *this; + } + inline DeviceIdentityFrame& operator=(DeviceIdentityFrame&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const DeviceIdentityFrame& default_instance() { + return *internal_default_instance(); + } + static inline const DeviceIdentityFrame* internal_default_instance() { + return reinterpret_cast( + &_DeviceIdentityFrame_default_instance_); + } + static constexpr int kIndexInFileMessages = + 2; + + friend void swap(DeviceIdentityFrame& a, DeviceIdentityFrame& b) { + a.Swap(&b); + } + inline void Swap(DeviceIdentityFrame* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(DeviceIdentityFrame* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + DeviceIdentityFrame* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const DeviceIdentityFrame& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const DeviceIdentityFrame& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(DeviceIdentityFrame* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "nearby.presence.DeviceIdentityFrame"; + } + protected: + explicit DeviceIdentityFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kActionFieldNumber = 5, + kDeviceNameFieldNumber = 1, + kBluetoothMacAddressFieldNumber = 2, + kDeviceImageUrlFieldNumber = 3, + kModelIdFieldNumber = 4, + kDeviceModelNameFieldNumber = 6, + kDeviceTypeFieldNumber = 7, + }; + // repeated int32 action = 5 [packed = true]; + int action_size() const; + private: + int _internal_action_size() const; + public: + void clear_action(); + private: + int32_t _internal_action(int index) const; + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + _internal_action() const; + void _internal_add_action(int32_t value); + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + _internal_mutable_action(); + public: + int32_t action(int index) const; + void set_action(int index, int32_t value); + void add_action(int32_t value); + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + action() const; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + mutable_action(); + + // optional string device_name = 1; + bool has_device_name() const; + private: + bool _internal_has_device_name() const; + public: + void clear_device_name(); + const std::string& device_name() const; + template + void set_device_name(ArgT0&& arg0, ArgT... args); + std::string* mutable_device_name(); + PROTOBUF_NODISCARD std::string* release_device_name(); + void set_allocated_device_name(std::string* device_name); + private: + const std::string& _internal_device_name() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_device_name(const std::string& value); + std::string* _internal_mutable_device_name(); + public: + + // optional bytes bluetooth_mac_address = 2; + bool has_bluetooth_mac_address() const; + private: + bool _internal_has_bluetooth_mac_address() const; + public: + void clear_bluetooth_mac_address(); + const std::string& bluetooth_mac_address() const; + template + void set_bluetooth_mac_address(ArgT0&& arg0, ArgT... args); + std::string* mutable_bluetooth_mac_address(); + PROTOBUF_NODISCARD std::string* release_bluetooth_mac_address(); + void set_allocated_bluetooth_mac_address(std::string* bluetooth_mac_address); + private: + const std::string& _internal_bluetooth_mac_address() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_bluetooth_mac_address(const std::string& value); + std::string* _internal_mutable_bluetooth_mac_address(); + public: + + // optional string device_image_url = 3; + bool has_device_image_url() const; + private: + bool _internal_has_device_image_url() const; + public: + void clear_device_image_url(); + const std::string& device_image_url() const; + template + void set_device_image_url(ArgT0&& arg0, ArgT... args); + std::string* mutable_device_image_url(); + PROTOBUF_NODISCARD std::string* release_device_image_url(); + void set_allocated_device_image_url(std::string* device_image_url); + private: + const std::string& _internal_device_image_url() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_device_image_url(const std::string& value); + std::string* _internal_mutable_device_image_url(); + public: + + // optional string model_id = 4; + bool has_model_id() const; + private: + bool _internal_has_model_id() const; + public: + void clear_model_id(); + const std::string& model_id() const; + template + void set_model_id(ArgT0&& arg0, ArgT... args); + std::string* mutable_model_id(); + PROTOBUF_NODISCARD std::string* release_model_id(); + void set_allocated_model_id(std::string* model_id); + private: + const std::string& _internal_model_id() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_model_id(const std::string& value); + std::string* _internal_mutable_model_id(); + public: + + // optional string device_model_name = 6; + bool has_device_model_name() const; + private: + bool _internal_has_device_model_name() const; + public: + void clear_device_model_name(); + const std::string& device_model_name() const; + template + void set_device_model_name(ArgT0&& arg0, ArgT... args); + std::string* mutable_device_model_name(); + PROTOBUF_NODISCARD std::string* release_device_model_name(); + void set_allocated_device_model_name(std::string* device_model_name); + private: + const std::string& _internal_device_model_name() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_device_model_name(const std::string& value); + std::string* _internal_mutable_device_model_name(); + public: + + // optional int32 device_type = 7; + bool has_device_type() const; + private: + bool _internal_has_device_type() const; + public: + void clear_device_type(); + int32_t device_type() const; + void set_device_type(int32_t value); + private: + int32_t _internal_device_type() const; + void _internal_set_device_type(int32_t value); + public: + + // @@protoc_insertion_point(class_scope:nearby.presence.DeviceIdentityFrame) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > action_; + mutable std::atomic _action_cached_byte_size_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr device_name_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr bluetooth_mac_address_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr device_image_url_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr model_id_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr device_model_name_; + int32_t device_type_; + friend struct ::TableStruct_presence_2fproto_2fpresence_5fframe_2eproto; +}; +// ------------------------------------------------------------------- + +class ConnectionInitFrame final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:nearby.presence.ConnectionInitFrame) */ { + public: + inline ConnectionInitFrame() : ConnectionInitFrame(nullptr) {} + ~ConnectionInitFrame() override; + explicit constexpr ConnectionInitFrame(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + ConnectionInitFrame(const ConnectionInitFrame& from); + ConnectionInitFrame(ConnectionInitFrame&& from) noexcept + : ConnectionInitFrame() { + *this = ::std::move(from); + } + + inline ConnectionInitFrame& operator=(const ConnectionInitFrame& from) { + CopyFrom(from); + return *this; + } + inline ConnectionInitFrame& operator=(ConnectionInitFrame&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const ConnectionInitFrame& default_instance() { + return *internal_default_instance(); + } + static inline const ConnectionInitFrame* internal_default_instance() { + return reinterpret_cast( + &_ConnectionInitFrame_default_instance_); + } + static constexpr int kIndexInFileMessages = + 3; + + friend void swap(ConnectionInitFrame& a, ConnectionInitFrame& b) { + a.Swap(&b); + } + inline void Swap(ConnectionInitFrame* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(ConnectionInitFrame* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + ConnectionInitFrame* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const ConnectionInitFrame& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const ConnectionInitFrame& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(ConnectionInitFrame* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "nearby.presence.ConnectionInitFrame"; + } + protected: + explicit ConnectionInitFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kActionsFieldNumber = 1, + kIdentityTypeFieldNumber = 2, + kUwbEnableFieldNumber = 3, + kDeviceUniqueIdFieldNumber = 4, + }; + // repeated int32 actions = 1 [packed = true]; + int actions_size() const; + private: + int _internal_actions_size() const; + public: + void clear_actions(); + private: + int32_t _internal_actions(int index) const; + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + _internal_actions() const; + void _internal_add_actions(int32_t value); + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + _internal_mutable_actions(); + public: + int32_t actions(int index) const; + void set_actions(int index, int32_t value); + void add_actions(int32_t value); + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + actions() const; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + mutable_actions(); + + // optional int32 identity_type = 2; + bool has_identity_type() const; + private: + bool _internal_has_identity_type() const; + public: + void clear_identity_type(); + int32_t identity_type() const; + void set_identity_type(int32_t value); + private: + int32_t _internal_identity_type() const; + void _internal_set_identity_type(int32_t value); + public: + + // optional bool uwb_enable = 3; + bool has_uwb_enable() const; + private: + bool _internal_has_uwb_enable() const; + public: + void clear_uwb_enable(); + bool uwb_enable() const; + void set_uwb_enable(bool value); + private: + bool _internal_uwb_enable() const; + void _internal_set_uwb_enable(bool value); + public: + + // optional int64 device_unique_id = 4; + bool has_device_unique_id() const; + private: + bool _internal_has_device_unique_id() const; + public: + void clear_device_unique_id(); + int64_t device_unique_id() const; + void set_device_unique_id(int64_t value); + private: + int64_t _internal_device_unique_id() const; + void _internal_set_device_unique_id(int64_t value); + public: + + // @@protoc_insertion_point(class_scope:nearby.presence.ConnectionInitFrame) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > actions_; + mutable std::atomic _actions_cached_byte_size_; + int32_t identity_type_; + bool uwb_enable_; + int64_t device_unique_id_; + friend struct ::TableStruct_presence_2fproto_2fpresence_5fframe_2eproto; +}; +// ------------------------------------------------------------------- + +class UwbControleeCapabilities final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:nearby.presence.UwbControleeCapabilities) */ { + public: + inline UwbControleeCapabilities() : UwbControleeCapabilities(nullptr) {} + ~UwbControleeCapabilities() override; + explicit constexpr UwbControleeCapabilities(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + UwbControleeCapabilities(const UwbControleeCapabilities& from); + UwbControleeCapabilities(UwbControleeCapabilities&& from) noexcept + : UwbControleeCapabilities() { + *this = ::std::move(from); + } + + inline UwbControleeCapabilities& operator=(const UwbControleeCapabilities& from) { + CopyFrom(from); + return *this; + } + inline UwbControleeCapabilities& operator=(UwbControleeCapabilities&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const UwbControleeCapabilities& default_instance() { + return *internal_default_instance(); + } + static inline const UwbControleeCapabilities* internal_default_instance() { + return reinterpret_cast( + &_UwbControleeCapabilities_default_instance_); + } + static constexpr int kIndexInFileMessages = + 4; + + friend void swap(UwbControleeCapabilities& a, UwbControleeCapabilities& b) { + a.Swap(&b); + } + inline void Swap(UwbControleeCapabilities* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(UwbControleeCapabilities* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + UwbControleeCapabilities* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const UwbControleeCapabilities& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const UwbControleeCapabilities& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(UwbControleeCapabilities* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "nearby.presence.UwbControleeCapabilities"; + } + protected: + explicit UwbControleeCapabilities(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kSupportedConfigIdsFieldNumber = 2, + kSupportedChannelsFieldNumber = 3, + kSupportedNtfConfigsFieldNumber = 13, + kSupportedSlotDurationsFieldNumber = 15, + kSupportedRangingUpdateRatesFieldNumber = 16, + kMultiChipInfoFieldNumber = 18, + kControleeAddressFieldNumber = 1, + kSubSessionIdFieldNumber = 5, + kSubSessionKeyFieldNumber = 6, + kDeviceUniqueIdFieldNumber = 8, + kMinRangingIntervalMsFieldNumber = 4, + kRangingDisabledFieldNumber = 7, + kIsElevationSupportedFieldNumber = 11, + kIsRangingIntervalReconfigureSupportedFieldNumber = 14, + kChipCountFieldNumber = 17, + kIsDistanceSupportedFieldNumber = 9, + kIsAzimuthSupportedFieldNumber = 10, + kMinSlotDurationMsFieldNumber = 12, + }; + // repeated int32 supported_config_ids = 2 [packed = true]; + int supported_config_ids_size() const; + private: + int _internal_supported_config_ids_size() const; + public: + void clear_supported_config_ids(); + private: + int32_t _internal_supported_config_ids(int index) const; + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + _internal_supported_config_ids() const; + void _internal_add_supported_config_ids(int32_t value); + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + _internal_mutable_supported_config_ids(); + public: + int32_t supported_config_ids(int index) const; + void set_supported_config_ids(int index, int32_t value); + void add_supported_config_ids(int32_t value); + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + supported_config_ids() const; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + mutable_supported_config_ids(); + + // repeated int32 supported_channels = 3 [packed = true]; + int supported_channels_size() const; + private: + int _internal_supported_channels_size() const; + public: + void clear_supported_channels(); + private: + int32_t _internal_supported_channels(int index) const; + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + _internal_supported_channels() const; + void _internal_add_supported_channels(int32_t value); + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + _internal_mutable_supported_channels(); + public: + int32_t supported_channels(int index) const; + void set_supported_channels(int index, int32_t value); + void add_supported_channels(int32_t value); + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + supported_channels() const; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + mutable_supported_channels(); + + // repeated int32 supported_ntf_configs = 13 [packed = true]; + int supported_ntf_configs_size() const; + private: + int _internal_supported_ntf_configs_size() const; + public: + void clear_supported_ntf_configs(); + private: + int32_t _internal_supported_ntf_configs(int index) const; + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + _internal_supported_ntf_configs() const; + void _internal_add_supported_ntf_configs(int32_t value); + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + _internal_mutable_supported_ntf_configs(); + public: + int32_t supported_ntf_configs(int index) const; + void set_supported_ntf_configs(int index, int32_t value); + void add_supported_ntf_configs(int32_t value); + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + supported_ntf_configs() const; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + mutable_supported_ntf_configs(); + + // repeated int32 supported_slot_durations = 15 [packed = true]; + int supported_slot_durations_size() const; + private: + int _internal_supported_slot_durations_size() const; + public: + void clear_supported_slot_durations(); + private: + int32_t _internal_supported_slot_durations(int index) const; + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + _internal_supported_slot_durations() const; + void _internal_add_supported_slot_durations(int32_t value); + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + _internal_mutable_supported_slot_durations(); + public: + int32_t supported_slot_durations(int index) const; + void set_supported_slot_durations(int index, int32_t value); + void add_supported_slot_durations(int32_t value); + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + supported_slot_durations() const; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + mutable_supported_slot_durations(); + + // repeated int32 supported_ranging_update_rates = 16 [packed = true]; + int supported_ranging_update_rates_size() const; + private: + int _internal_supported_ranging_update_rates_size() const; + public: + void clear_supported_ranging_update_rates(); + private: + int32_t _internal_supported_ranging_update_rates(int index) const; + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + _internal_supported_ranging_update_rates() const; + void _internal_add_supported_ranging_update_rates(int32_t value); + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + _internal_mutable_supported_ranging_update_rates(); + public: + int32_t supported_ranging_update_rates(int index) const; + void set_supported_ranging_update_rates(int index, int32_t value); + void add_supported_ranging_update_rates(int32_t value); + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& + supported_ranging_update_rates() const; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* + mutable_supported_ranging_update_rates(); + + // repeated .nearby.presence.UwbMultiChipInfo multi_chip_info = 18; + int multi_chip_info_size() const; + private: + int _internal_multi_chip_info_size() const; + public: + void clear_multi_chip_info(); + ::nearby::presence::UwbMultiChipInfo* mutable_multi_chip_info(int index); + ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::nearby::presence::UwbMultiChipInfo >* + mutable_multi_chip_info(); + private: + const ::nearby::presence::UwbMultiChipInfo& _internal_multi_chip_info(int index) const; + ::nearby::presence::UwbMultiChipInfo* _internal_add_multi_chip_info(); + public: + const ::nearby::presence::UwbMultiChipInfo& multi_chip_info(int index) const; + ::nearby::presence::UwbMultiChipInfo* add_multi_chip_info(); + const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::nearby::presence::UwbMultiChipInfo >& + multi_chip_info() const; + + // optional bytes controlee_address = 1; + bool has_controlee_address() const; + private: + bool _internal_has_controlee_address() const; + public: + void clear_controlee_address(); + const std::string& controlee_address() const; + template + void set_controlee_address(ArgT0&& arg0, ArgT... args); + std::string* mutable_controlee_address(); + PROTOBUF_NODISCARD std::string* release_controlee_address(); + void set_allocated_controlee_address(std::string* controlee_address); + private: + const std::string& _internal_controlee_address() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_controlee_address(const std::string& value); + std::string* _internal_mutable_controlee_address(); + public: + + // optional bytes sub_session_id = 5; + bool has_sub_session_id() const; + private: + bool _internal_has_sub_session_id() const; + public: + void clear_sub_session_id(); + const std::string& sub_session_id() const; + template + void set_sub_session_id(ArgT0&& arg0, ArgT... args); + std::string* mutable_sub_session_id(); + PROTOBUF_NODISCARD std::string* release_sub_session_id(); + void set_allocated_sub_session_id(std::string* sub_session_id); + private: + const std::string& _internal_sub_session_id() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_sub_session_id(const std::string& value); + std::string* _internal_mutable_sub_session_id(); + public: + + // optional bytes sub_session_key = 6; + bool has_sub_session_key() const; + private: + bool _internal_has_sub_session_key() const; + public: + void clear_sub_session_key(); + const std::string& sub_session_key() const; + template + void set_sub_session_key(ArgT0&& arg0, ArgT... args); + std::string* mutable_sub_session_key(); + PROTOBUF_NODISCARD std::string* release_sub_session_key(); + void set_allocated_sub_session_key(std::string* sub_session_key); + private: + const std::string& _internal_sub_session_key() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_sub_session_key(const std::string& value); + std::string* _internal_mutable_sub_session_key(); + public: + + // optional int64 device_unique_id = 8; + bool has_device_unique_id() const; + private: + bool _internal_has_device_unique_id() const; + public: + void clear_device_unique_id(); + int64_t device_unique_id() const; + void set_device_unique_id(int64_t value); + private: + int64_t _internal_device_unique_id() const; + void _internal_set_device_unique_id(int64_t value); + public: + + // optional int32 min_ranging_interval_ms = 4; + bool has_min_ranging_interval_ms() const; + private: + bool _internal_has_min_ranging_interval_ms() const; + public: + void clear_min_ranging_interval_ms(); + int32_t min_ranging_interval_ms() const; + void set_min_ranging_interval_ms(int32_t value); + private: + int32_t _internal_min_ranging_interval_ms() const; + void _internal_set_min_ranging_interval_ms(int32_t value); + public: + + // optional bool ranging_disabled = 7; + bool has_ranging_disabled() const; + private: + bool _internal_has_ranging_disabled() const; + public: + void clear_ranging_disabled(); + bool ranging_disabled() const; + void set_ranging_disabled(bool value); + private: + bool _internal_ranging_disabled() const; + void _internal_set_ranging_disabled(bool value); + public: + + // optional bool is_elevation_supported = 11 [default = false]; + bool has_is_elevation_supported() const; + private: + bool _internal_has_is_elevation_supported() const; + public: + void clear_is_elevation_supported(); + bool is_elevation_supported() const; + void set_is_elevation_supported(bool value); + private: + bool _internal_is_elevation_supported() const; + void _internal_set_is_elevation_supported(bool value); + public: + + // optional bool is_ranging_interval_reconfigure_supported = 14 [default = false]; + bool has_is_ranging_interval_reconfigure_supported() const; + private: + bool _internal_has_is_ranging_interval_reconfigure_supported() const; + public: + void clear_is_ranging_interval_reconfigure_supported(); + bool is_ranging_interval_reconfigure_supported() const; + void set_is_ranging_interval_reconfigure_supported(bool value); + private: + bool _internal_is_ranging_interval_reconfigure_supported() const; + void _internal_set_is_ranging_interval_reconfigure_supported(bool value); + public: + + // optional int32 chip_count = 17 [default = 1]; + bool has_chip_count() const; + private: + bool _internal_has_chip_count() const; + public: + void clear_chip_count(); + int32_t chip_count() const; + void set_chip_count(int32_t value); + private: + int32_t _internal_chip_count() const; + void _internal_set_chip_count(int32_t value); + public: + + // optional bool is_distance_supported = 9 [default = true]; + bool has_is_distance_supported() const; + private: + bool _internal_has_is_distance_supported() const; + public: + void clear_is_distance_supported(); + bool is_distance_supported() const; + void set_is_distance_supported(bool value); + private: + bool _internal_is_distance_supported() const; + void _internal_set_is_distance_supported(bool value); + public: + + // optional bool is_azimuth_supported = 10 [default = true]; + bool has_is_azimuth_supported() const; + private: + bool _internal_has_is_azimuth_supported() const; + public: + void clear_is_azimuth_supported(); + bool is_azimuth_supported() const; + void set_is_azimuth_supported(bool value); + private: + bool _internal_is_azimuth_supported() const; + void _internal_set_is_azimuth_supported(bool value); + public: + + // optional float min_slot_duration_ms = 12 [default = 2]; + bool has_min_slot_duration_ms() const; + private: + bool _internal_has_min_slot_duration_ms() const; + public: + void clear_min_slot_duration_ms(); + float min_slot_duration_ms() const; + void set_min_slot_duration_ms(float value); + private: + float _internal_min_slot_duration_ms() const; + void _internal_set_min_slot_duration_ms(float value); + public: + + // @@protoc_insertion_point(class_scope:nearby.presence.UwbControleeCapabilities) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > supported_config_ids_; + mutable std::atomic _supported_config_ids_cached_byte_size_; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > supported_channels_; + mutable std::atomic _supported_channels_cached_byte_size_; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > supported_ntf_configs_; + mutable std::atomic _supported_ntf_configs_cached_byte_size_; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > supported_slot_durations_; + mutable std::atomic _supported_slot_durations_cached_byte_size_; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > supported_ranging_update_rates_; + mutable std::atomic _supported_ranging_update_rates_cached_byte_size_; + ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::nearby::presence::UwbMultiChipInfo > multi_chip_info_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr controlee_address_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr sub_session_id_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr sub_session_key_; + int64_t device_unique_id_; + int32_t min_ranging_interval_ms_; + bool ranging_disabled_; + bool is_elevation_supported_; + bool is_ranging_interval_reconfigure_supported_; + int32_t chip_count_; + bool is_distance_supported_; + bool is_azimuth_supported_; + float min_slot_duration_ms_; + friend struct ::TableStruct_presence_2fproto_2fpresence_5fframe_2eproto; +}; +// ------------------------------------------------------------------- + +class UwbMultiChipInfo final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:nearby.presence.UwbMultiChipInfo) */ { + public: + inline UwbMultiChipInfo() : UwbMultiChipInfo(nullptr) {} + ~UwbMultiChipInfo() override; + explicit constexpr UwbMultiChipInfo(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + UwbMultiChipInfo(const UwbMultiChipInfo& from); + UwbMultiChipInfo(UwbMultiChipInfo&& from) noexcept + : UwbMultiChipInfo() { + *this = ::std::move(from); + } + + inline UwbMultiChipInfo& operator=(const UwbMultiChipInfo& from) { + CopyFrom(from); + return *this; + } + inline UwbMultiChipInfo& operator=(UwbMultiChipInfo&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const UwbMultiChipInfo& default_instance() { + return *internal_default_instance(); + } + static inline const UwbMultiChipInfo* internal_default_instance() { + return reinterpret_cast( + &_UwbMultiChipInfo_default_instance_); + } + static constexpr int kIndexInFileMessages = + 5; + + friend void swap(UwbMultiChipInfo& a, UwbMultiChipInfo& b) { + a.Swap(&b); + } + inline void Swap(UwbMultiChipInfo* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(UwbMultiChipInfo* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + UwbMultiChipInfo* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const UwbMultiChipInfo& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const UwbMultiChipInfo& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(UwbMultiChipInfo* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "nearby.presence.UwbMultiChipInfo"; + } + protected: + explicit UwbMultiChipInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kControleeAddressFieldNumber = 1, + kChipIdFieldNumber = 2, + }; + // optional bytes controlee_address = 1; + bool has_controlee_address() const; + private: + bool _internal_has_controlee_address() const; + public: + void clear_controlee_address(); + const std::string& controlee_address() const; + template + void set_controlee_address(ArgT0&& arg0, ArgT... args); + std::string* mutable_controlee_address(); + PROTOBUF_NODISCARD std::string* release_controlee_address(); + void set_allocated_controlee_address(std::string* controlee_address); + private: + const std::string& _internal_controlee_address() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_controlee_address(const std::string& value); + std::string* _internal_mutable_controlee_address(); + public: + + // optional string chip_id = 2; + bool has_chip_id() const; + private: + bool _internal_has_chip_id() const; + public: + void clear_chip_id(); + const std::string& chip_id() const; + template + void set_chip_id(ArgT0&& arg0, ArgT... args); + std::string* mutable_chip_id(); + PROTOBUF_NODISCARD std::string* release_chip_id(); + void set_allocated_chip_id(std::string* chip_id); + private: + const std::string& _internal_chip_id() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_chip_id(const std::string& value); + std::string* _internal_mutable_chip_id(); + public: + + // @@protoc_insertion_point(class_scope:nearby.presence.UwbMultiChipInfo) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr controlee_address_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr chip_id_; + friend struct ::TableStruct_presence_2fproto_2fpresence_5fframe_2eproto; +}; +// ------------------------------------------------------------------- + +class UwbConnectionInfo final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:nearby.presence.UwbConnectionInfo) */ { + public: + inline UwbConnectionInfo() : UwbConnectionInfo(nullptr) {} + ~UwbConnectionInfo() override; + explicit constexpr UwbConnectionInfo(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + UwbConnectionInfo(const UwbConnectionInfo& from); + UwbConnectionInfo(UwbConnectionInfo&& from) noexcept + : UwbConnectionInfo() { + *this = ::std::move(from); + } + + inline UwbConnectionInfo& operator=(const UwbConnectionInfo& from) { + CopyFrom(from); + return *this; + } + inline UwbConnectionInfo& operator=(UwbConnectionInfo&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const UwbConnectionInfo& default_instance() { + return *internal_default_instance(); + } + static inline const UwbConnectionInfo* internal_default_instance() { + return reinterpret_cast( + &_UwbConnectionInfo_default_instance_); + } + static constexpr int kIndexInFileMessages = + 6; + + friend void swap(UwbConnectionInfo& a, UwbConnectionInfo& b) { + a.Swap(&b); + } + inline void Swap(UwbConnectionInfo* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(UwbConnectionInfo* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + UwbConnectionInfo* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const UwbConnectionInfo& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const UwbConnectionInfo& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(UwbConnectionInfo* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "nearby.presence.UwbConnectionInfo"; + } + protected: + explicit UwbConnectionInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kControllerAddressFieldNumber = 1, + kVendorIdFieldNumber = 7, + kStaticStsIvFieldNumber = 8, + kSessionKeyFieldNumber = 9, + kChannelFieldNumber = 2, + kPreambleIndexFieldNumber = 3, + kConfigIdFieldNumber = 4, + kRangingIntervalMsFieldNumber = 5, + kSessionIdFieldNumber = 6, + kRangingDisabledFieldNumber = 10, + }; + // optional bytes controller_address = 1; + bool has_controller_address() const; + private: + bool _internal_has_controller_address() const; + public: + void clear_controller_address(); + const std::string& controller_address() const; + template + void set_controller_address(ArgT0&& arg0, ArgT... args); + std::string* mutable_controller_address(); + PROTOBUF_NODISCARD std::string* release_controller_address(); + void set_allocated_controller_address(std::string* controller_address); + private: + const std::string& _internal_controller_address() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_controller_address(const std::string& value); + std::string* _internal_mutable_controller_address(); + public: + + // optional bytes vendor_id = 7; + bool has_vendor_id() const; + private: + bool _internal_has_vendor_id() const; + public: + void clear_vendor_id(); + const std::string& vendor_id() const; + template + void set_vendor_id(ArgT0&& arg0, ArgT... args); + std::string* mutable_vendor_id(); + PROTOBUF_NODISCARD std::string* release_vendor_id(); + void set_allocated_vendor_id(std::string* vendor_id); + private: + const std::string& _internal_vendor_id() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_vendor_id(const std::string& value); + std::string* _internal_mutable_vendor_id(); + public: + + // optional bytes static_sts_iv = 8; + bool has_static_sts_iv() const; + private: + bool _internal_has_static_sts_iv() const; + public: + void clear_static_sts_iv(); + const std::string& static_sts_iv() const; + template + void set_static_sts_iv(ArgT0&& arg0, ArgT... args); + std::string* mutable_static_sts_iv(); + PROTOBUF_NODISCARD std::string* release_static_sts_iv(); + void set_allocated_static_sts_iv(std::string* static_sts_iv); + private: + const std::string& _internal_static_sts_iv() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_static_sts_iv(const std::string& value); + std::string* _internal_mutable_static_sts_iv(); + public: + + // optional bytes session_key = 9; + bool has_session_key() const; + private: + bool _internal_has_session_key() const; + public: + void clear_session_key(); + const std::string& session_key() const; + template + void set_session_key(ArgT0&& arg0, ArgT... args); + std::string* mutable_session_key(); + PROTOBUF_NODISCARD std::string* release_session_key(); + void set_allocated_session_key(std::string* session_key); + private: + const std::string& _internal_session_key() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_session_key(const std::string& value); + std::string* _internal_mutable_session_key(); + public: + + // optional int32 channel = 2; + bool has_channel() const; + private: + bool _internal_has_channel() const; + public: + void clear_channel(); + int32_t channel() const; + void set_channel(int32_t value); + private: + int32_t _internal_channel() const; + void _internal_set_channel(int32_t value); + public: + + // optional int32 preamble_index = 3; + bool has_preamble_index() const; + private: + bool _internal_has_preamble_index() const; + public: + void clear_preamble_index(); + int32_t preamble_index() const; + void set_preamble_index(int32_t value); + private: + int32_t _internal_preamble_index() const; + void _internal_set_preamble_index(int32_t value); + public: + + // optional int32 config_id = 4; + bool has_config_id() const; + private: + bool _internal_has_config_id() const; + public: + void clear_config_id(); + int32_t config_id() const; + void set_config_id(int32_t value); + private: + int32_t _internal_config_id() const; + void _internal_set_config_id(int32_t value); + public: + + // optional int32 ranging_interval_ms = 5; + bool has_ranging_interval_ms() const; + private: + bool _internal_has_ranging_interval_ms() const; + public: + void clear_ranging_interval_ms(); + int32_t ranging_interval_ms() const; + void set_ranging_interval_ms(int32_t value); + private: + int32_t _internal_ranging_interval_ms() const; + void _internal_set_ranging_interval_ms(int32_t value); + public: + + // optional int32 session_id = 6; + bool has_session_id() const; + private: + bool _internal_has_session_id() const; + public: + void clear_session_id(); + int32_t session_id() const; + void set_session_id(int32_t value); + private: + int32_t _internal_session_id() const; + void _internal_set_session_id(int32_t value); + public: + + // optional bool ranging_disabled = 10; + bool has_ranging_disabled() const; + private: + bool _internal_has_ranging_disabled() const; + public: + void clear_ranging_disabled(); + bool ranging_disabled() const; + void set_ranging_disabled(bool value); + private: + bool _internal_ranging_disabled() const; + void _internal_set_ranging_disabled(bool value); + public: + + // @@protoc_insertion_point(class_scope:nearby.presence.UwbConnectionInfo) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr controller_address_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr vendor_id_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr static_sts_iv_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr session_key_; + int32_t channel_; + int32_t preamble_index_; + int32_t config_id_; + int32_t ranging_interval_ms_; + int32_t session_id_; + bool ranging_disabled_; + friend struct ::TableStruct_presence_2fproto_2fpresence_5fframe_2eproto; +}; +// ------------------------------------------------------------------- + +class ControlFrame final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:nearby.presence.ControlFrame) */ { + public: + inline ControlFrame() : ControlFrame(nullptr) {} + ~ControlFrame() override; + explicit constexpr ControlFrame(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + ControlFrame(const ControlFrame& from); + ControlFrame(ControlFrame&& from) noexcept + : ControlFrame() { + *this = ::std::move(from); + } + + inline ControlFrame& operator=(const ControlFrame& from) { + CopyFrom(from); + return *this; + } + inline ControlFrame& operator=(ControlFrame&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const ControlFrame& default_instance() { + return *internal_default_instance(); + } + static inline const ControlFrame* internal_default_instance() { + return reinterpret_cast( + &_ControlFrame_default_instance_); + } + static constexpr int kIndexInFileMessages = + 7; + + friend void swap(ControlFrame& a, ControlFrame& b) { + a.Swap(&b); + } + inline void Swap(ControlFrame* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(ControlFrame* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + ControlFrame* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const ControlFrame& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const ControlFrame& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(ControlFrame* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "nearby.presence.ControlFrame"; + } + protected: + explicit ControlFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + typedef ControlFrame_ControlType ControlType; + static constexpr ControlType UNKNOWN_TYPE = + ControlFrame_ControlType_UNKNOWN_TYPE; + static constexpr ControlType KEEP_ALIVE = + ControlFrame_ControlType_KEEP_ALIVE; + static constexpr ControlType DISCONNECT = + ControlFrame_ControlType_DISCONNECT; + static inline bool ControlType_IsValid(int value) { + return ControlFrame_ControlType_IsValid(value); + } + static constexpr ControlType ControlType_MIN = + ControlFrame_ControlType_ControlType_MIN; + static constexpr ControlType ControlType_MAX = + ControlFrame_ControlType_ControlType_MAX; + static constexpr int ControlType_ARRAYSIZE = + ControlFrame_ControlType_ControlType_ARRAYSIZE; + static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* + ControlType_descriptor() { + return ControlFrame_ControlType_descriptor(); + } + template + static inline const std::string& ControlType_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function ControlType_Name."); + return ControlFrame_ControlType_Name(enum_t_value); + } + static inline bool ControlType_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name, + ControlType* value) { + return ControlFrame_ControlType_Parse(name, value); + } + + // accessors ------------------------------------------------------- + + enum : int { + kTypeFieldNumber = 1, + }; + // optional .nearby.presence.ControlFrame.ControlType type = 1; + bool has_type() const; + private: + bool _internal_has_type() const; + public: + void clear_type(); + ::nearby::presence::ControlFrame_ControlType type() const; + void set_type(::nearby::presence::ControlFrame_ControlType value); + private: + ::nearby::presence::ControlFrame_ControlType _internal_type() const; + void _internal_set_type(::nearby::presence::ControlFrame_ControlType value); + public: + + // @@protoc_insertion_point(class_scope:nearby.presence.ControlFrame) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + int type_; + friend struct ::TableStruct_presence_2fproto_2fpresence_5fframe_2eproto; +}; +// ------------------------------------------------------------------- + +class PresenceAuthenticationFrame final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:nearby.presence.PresenceAuthenticationFrame) */ { + public: + inline PresenceAuthenticationFrame() : PresenceAuthenticationFrame(nullptr) {} + ~PresenceAuthenticationFrame() override; + explicit constexpr PresenceAuthenticationFrame(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + PresenceAuthenticationFrame(const PresenceAuthenticationFrame& from); + PresenceAuthenticationFrame(PresenceAuthenticationFrame&& from) noexcept + : PresenceAuthenticationFrame() { + *this = ::std::move(from); + } + + inline PresenceAuthenticationFrame& operator=(const PresenceAuthenticationFrame& from) { + CopyFrom(from); + return *this; + } + inline PresenceAuthenticationFrame& operator=(PresenceAuthenticationFrame&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance); + } + inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const PresenceAuthenticationFrame& default_instance() { + return *internal_default_instance(); + } + static inline const PresenceAuthenticationFrame* internal_default_instance() { + return reinterpret_cast( + &_PresenceAuthenticationFrame_default_instance_); + } + static constexpr int kIndexInFileMessages = + 8; + + friend void swap(PresenceAuthenticationFrame& a, PresenceAuthenticationFrame& b) { + a.Swap(&b); + } + inline void Swap(PresenceAuthenticationFrame* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(PresenceAuthenticationFrame* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + PresenceAuthenticationFrame* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const PresenceAuthenticationFrame& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const PresenceAuthenticationFrame& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(PresenceAuthenticationFrame* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "nearby.presence.PresenceAuthenticationFrame"; + } + protected: + explicit PresenceAuthenticationFrame(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kPrivateKeySignatureFieldNumber = 2, + kSharedCredentialIdHashFieldNumber = 3, + kCredentialIdHashFieldNumber = 4, + kVersionFieldNumber = 1, + }; + // optional bytes private_key_signature = 2; + bool has_private_key_signature() const; + private: + bool _internal_has_private_key_signature() const; + public: + void clear_private_key_signature(); + const std::string& private_key_signature() const; + template + void set_private_key_signature(ArgT0&& arg0, ArgT... args); + std::string* mutable_private_key_signature(); + PROTOBUF_NODISCARD std::string* release_private_key_signature(); + void set_allocated_private_key_signature(std::string* private_key_signature); + private: + const std::string& _internal_private_key_signature() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_private_key_signature(const std::string& value); + std::string* _internal_mutable_private_key_signature(); + public: + + // optional bytes shared_credential_id_hash = 3; + bool has_shared_credential_id_hash() const; + private: + bool _internal_has_shared_credential_id_hash() const; + public: + void clear_shared_credential_id_hash(); + const std::string& shared_credential_id_hash() const; + template + void set_shared_credential_id_hash(ArgT0&& arg0, ArgT... args); + std::string* mutable_shared_credential_id_hash(); + PROTOBUF_NODISCARD std::string* release_shared_credential_id_hash(); + void set_allocated_shared_credential_id_hash(std::string* shared_credential_id_hash); + private: + const std::string& _internal_shared_credential_id_hash() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_shared_credential_id_hash(const std::string& value); + std::string* _internal_mutable_shared_credential_id_hash(); + public: + + // optional bytes credential_id_hash = 4 [deprecated = true]; + PROTOBUF_DEPRECATED bool has_credential_id_hash() const; + private: + bool _internal_has_credential_id_hash() const; + public: + PROTOBUF_DEPRECATED void clear_credential_id_hash(); + PROTOBUF_DEPRECATED const std::string& credential_id_hash() const; + template + PROTOBUF_DEPRECATED void set_credential_id_hash(ArgT0&& arg0, ArgT... args); + PROTOBUF_DEPRECATED std::string* mutable_credential_id_hash(); + PROTOBUF_NODISCARD PROTOBUF_DEPRECATED std::string* release_credential_id_hash(); + PROTOBUF_DEPRECATED void set_allocated_credential_id_hash(std::string* credential_id_hash); + private: + const std::string& _internal_credential_id_hash() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_credential_id_hash(const std::string& value); + std::string* _internal_mutable_credential_id_hash(); + public: + + // optional int32 version = 1; + bool has_version() const; + private: + bool _internal_has_version() const; + public: + void clear_version(); + int32_t version() const; + void set_version(int32_t value); + private: + int32_t _internal_version() const; + void _internal_set_version(int32_t value); + public: + + // @@protoc_insertion_point(class_scope:nearby.presence.PresenceAuthenticationFrame) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr private_key_signature_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr shared_credential_id_hash_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr credential_id_hash_; + int32_t version_; + friend struct ::TableStruct_presence_2fproto_2fpresence_5fframe_2eproto; +}; +// =================================================================== + + +// =================================================================== + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// PresenceFrame + +// optional .nearby.presence.V1Frame v1_frame = 1; +inline bool PresenceFrame::_internal_has_v1_frame() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + PROTOBUF_ASSUME(!value || v1_frame_ != nullptr); + return value; +} +inline bool PresenceFrame::has_v1_frame() const { + return _internal_has_v1_frame(); +} +inline void PresenceFrame::clear_v1_frame() { + if (v1_frame_ != nullptr) v1_frame_->Clear(); + _has_bits_[0] &= ~0x00000001u; +} +inline const ::nearby::presence::V1Frame& PresenceFrame::_internal_v1_frame() const { + const ::nearby::presence::V1Frame* p = v1_frame_; + return p != nullptr ? *p : reinterpret_cast( + ::nearby::presence::_V1Frame_default_instance_); +} +inline const ::nearby::presence::V1Frame& PresenceFrame::v1_frame() const { + // @@protoc_insertion_point(field_get:nearby.presence.PresenceFrame.v1_frame) + return _internal_v1_frame(); +} +inline void PresenceFrame::unsafe_arena_set_allocated_v1_frame( + ::nearby::presence::V1Frame* v1_frame) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(v1_frame_); + } + v1_frame_ = v1_frame; + if (v1_frame) { + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:nearby.presence.PresenceFrame.v1_frame) +} +inline ::nearby::presence::V1Frame* PresenceFrame::release_v1_frame() { + _has_bits_[0] &= ~0x00000001u; + ::nearby::presence::V1Frame* temp = v1_frame_; + v1_frame_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::nearby::presence::V1Frame* PresenceFrame::unsafe_arena_release_v1_frame() { + // @@protoc_insertion_point(field_release:nearby.presence.PresenceFrame.v1_frame) + _has_bits_[0] &= ~0x00000001u; + ::nearby::presence::V1Frame* temp = v1_frame_; + v1_frame_ = nullptr; + return temp; +} +inline ::nearby::presence::V1Frame* PresenceFrame::_internal_mutable_v1_frame() { + _has_bits_[0] |= 0x00000001u; + if (v1_frame_ == nullptr) { + auto* p = CreateMaybeMessage<::nearby::presence::V1Frame>(GetArenaForAllocation()); + v1_frame_ = p; + } + return v1_frame_; +} +inline ::nearby::presence::V1Frame* PresenceFrame::mutable_v1_frame() { + ::nearby::presence::V1Frame* _msg = _internal_mutable_v1_frame(); + // @@protoc_insertion_point(field_mutable:nearby.presence.PresenceFrame.v1_frame) + return _msg; +} +inline void PresenceFrame::set_allocated_v1_frame(::nearby::presence::V1Frame* v1_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete v1_frame_; + } + if (v1_frame) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::nearby::presence::V1Frame>::GetOwningArena(v1_frame); + if (message_arena != submessage_arena) { + v1_frame = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, v1_frame, submessage_arena); + } + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + v1_frame_ = v1_frame; + // @@protoc_insertion_point(field_set_allocated:nearby.presence.PresenceFrame.v1_frame) +} + +// ------------------------------------------------------------------- + +// V1Frame + +// .nearby.presence.ControlFrame control_frame = 1; +inline bool V1Frame::_internal_has_control_frame() const { + return Message_case() == kControlFrame; +} +inline bool V1Frame::has_control_frame() const { + return _internal_has_control_frame(); +} +inline void V1Frame::set_has_control_frame() { + _oneof_case_[0] = kControlFrame; +} +inline void V1Frame::clear_control_frame() { + if (_internal_has_control_frame()) { + if (GetArenaForAllocation() == nullptr) { + delete Message_.control_frame_; + } + clear_has_Message(); + } +} +inline ::nearby::presence::ControlFrame* V1Frame::release_control_frame() { + // @@protoc_insertion_point(field_release:nearby.presence.V1Frame.control_frame) + if (_internal_has_control_frame()) { + clear_has_Message(); + ::nearby::presence::ControlFrame* temp = Message_.control_frame_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + Message_.control_frame_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::nearby::presence::ControlFrame& V1Frame::_internal_control_frame() const { + return _internal_has_control_frame() + ? *Message_.control_frame_ + : reinterpret_cast< ::nearby::presence::ControlFrame&>(::nearby::presence::_ControlFrame_default_instance_); +} +inline const ::nearby::presence::ControlFrame& V1Frame::control_frame() const { + // @@protoc_insertion_point(field_get:nearby.presence.V1Frame.control_frame) + return _internal_control_frame(); +} +inline ::nearby::presence::ControlFrame* V1Frame::unsafe_arena_release_control_frame() { + // @@protoc_insertion_point(field_unsafe_arena_release:nearby.presence.V1Frame.control_frame) + if (_internal_has_control_frame()) { + clear_has_Message(); + ::nearby::presence::ControlFrame* temp = Message_.control_frame_; + Message_.control_frame_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void V1Frame::unsafe_arena_set_allocated_control_frame(::nearby::presence::ControlFrame* control_frame) { + clear_Message(); + if (control_frame) { + set_has_control_frame(); + Message_.control_frame_ = control_frame; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:nearby.presence.V1Frame.control_frame) +} +inline ::nearby::presence::ControlFrame* V1Frame::_internal_mutable_control_frame() { + if (!_internal_has_control_frame()) { + clear_Message(); + set_has_control_frame(); + Message_.control_frame_ = CreateMaybeMessage< ::nearby::presence::ControlFrame >(GetArenaForAllocation()); + } + return Message_.control_frame_; +} +inline ::nearby::presence::ControlFrame* V1Frame::mutable_control_frame() { + ::nearby::presence::ControlFrame* _msg = _internal_mutable_control_frame(); + // @@protoc_insertion_point(field_mutable:nearby.presence.V1Frame.control_frame) + return _msg; +} + +// .nearby.presence.DeviceIdentityFrame device_identity_frame = 2; +inline bool V1Frame::_internal_has_device_identity_frame() const { + return Message_case() == kDeviceIdentityFrame; +} +inline bool V1Frame::has_device_identity_frame() const { + return _internal_has_device_identity_frame(); +} +inline void V1Frame::set_has_device_identity_frame() { + _oneof_case_[0] = kDeviceIdentityFrame; +} +inline void V1Frame::clear_device_identity_frame() { + if (_internal_has_device_identity_frame()) { + if (GetArenaForAllocation() == nullptr) { + delete Message_.device_identity_frame_; + } + clear_has_Message(); + } +} +inline ::nearby::presence::DeviceIdentityFrame* V1Frame::release_device_identity_frame() { + // @@protoc_insertion_point(field_release:nearby.presence.V1Frame.device_identity_frame) + if (_internal_has_device_identity_frame()) { + clear_has_Message(); + ::nearby::presence::DeviceIdentityFrame* temp = Message_.device_identity_frame_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + Message_.device_identity_frame_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::nearby::presence::DeviceIdentityFrame& V1Frame::_internal_device_identity_frame() const { + return _internal_has_device_identity_frame() + ? *Message_.device_identity_frame_ + : reinterpret_cast< ::nearby::presence::DeviceIdentityFrame&>(::nearby::presence::_DeviceIdentityFrame_default_instance_); +} +inline const ::nearby::presence::DeviceIdentityFrame& V1Frame::device_identity_frame() const { + // @@protoc_insertion_point(field_get:nearby.presence.V1Frame.device_identity_frame) + return _internal_device_identity_frame(); +} +inline ::nearby::presence::DeviceIdentityFrame* V1Frame::unsafe_arena_release_device_identity_frame() { + // @@protoc_insertion_point(field_unsafe_arena_release:nearby.presence.V1Frame.device_identity_frame) + if (_internal_has_device_identity_frame()) { + clear_has_Message(); + ::nearby::presence::DeviceIdentityFrame* temp = Message_.device_identity_frame_; + Message_.device_identity_frame_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void V1Frame::unsafe_arena_set_allocated_device_identity_frame(::nearby::presence::DeviceIdentityFrame* device_identity_frame) { + clear_Message(); + if (device_identity_frame) { + set_has_device_identity_frame(); + Message_.device_identity_frame_ = device_identity_frame; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:nearby.presence.V1Frame.device_identity_frame) +} +inline ::nearby::presence::DeviceIdentityFrame* V1Frame::_internal_mutable_device_identity_frame() { + if (!_internal_has_device_identity_frame()) { + clear_Message(); + set_has_device_identity_frame(); + Message_.device_identity_frame_ = CreateMaybeMessage< ::nearby::presence::DeviceIdentityFrame >(GetArenaForAllocation()); + } + return Message_.device_identity_frame_; +} +inline ::nearby::presence::DeviceIdentityFrame* V1Frame::mutable_device_identity_frame() { + ::nearby::presence::DeviceIdentityFrame* _msg = _internal_mutable_device_identity_frame(); + // @@protoc_insertion_point(field_mutable:nearby.presence.V1Frame.device_identity_frame) + return _msg; +} + +// .nearby.presence.ConnectionInitFrame connection_init_frame = 3; +inline bool V1Frame::_internal_has_connection_init_frame() const { + return Message_case() == kConnectionInitFrame; +} +inline bool V1Frame::has_connection_init_frame() const { + return _internal_has_connection_init_frame(); +} +inline void V1Frame::set_has_connection_init_frame() { + _oneof_case_[0] = kConnectionInitFrame; +} +inline void V1Frame::clear_connection_init_frame() { + if (_internal_has_connection_init_frame()) { + if (GetArenaForAllocation() == nullptr) { + delete Message_.connection_init_frame_; + } + clear_has_Message(); + } +} +inline ::nearby::presence::ConnectionInitFrame* V1Frame::release_connection_init_frame() { + // @@protoc_insertion_point(field_release:nearby.presence.V1Frame.connection_init_frame) + if (_internal_has_connection_init_frame()) { + clear_has_Message(); + ::nearby::presence::ConnectionInitFrame* temp = Message_.connection_init_frame_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + Message_.connection_init_frame_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::nearby::presence::ConnectionInitFrame& V1Frame::_internal_connection_init_frame() const { + return _internal_has_connection_init_frame() + ? *Message_.connection_init_frame_ + : reinterpret_cast< ::nearby::presence::ConnectionInitFrame&>(::nearby::presence::_ConnectionInitFrame_default_instance_); +} +inline const ::nearby::presence::ConnectionInitFrame& V1Frame::connection_init_frame() const { + // @@protoc_insertion_point(field_get:nearby.presence.V1Frame.connection_init_frame) + return _internal_connection_init_frame(); +} +inline ::nearby::presence::ConnectionInitFrame* V1Frame::unsafe_arena_release_connection_init_frame() { + // @@protoc_insertion_point(field_unsafe_arena_release:nearby.presence.V1Frame.connection_init_frame) + if (_internal_has_connection_init_frame()) { + clear_has_Message(); + ::nearby::presence::ConnectionInitFrame* temp = Message_.connection_init_frame_; + Message_.connection_init_frame_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void V1Frame::unsafe_arena_set_allocated_connection_init_frame(::nearby::presence::ConnectionInitFrame* connection_init_frame) { + clear_Message(); + if (connection_init_frame) { + set_has_connection_init_frame(); + Message_.connection_init_frame_ = connection_init_frame; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:nearby.presence.V1Frame.connection_init_frame) +} +inline ::nearby::presence::ConnectionInitFrame* V1Frame::_internal_mutable_connection_init_frame() { + if (!_internal_has_connection_init_frame()) { + clear_Message(); + set_has_connection_init_frame(); + Message_.connection_init_frame_ = CreateMaybeMessage< ::nearby::presence::ConnectionInitFrame >(GetArenaForAllocation()); + } + return Message_.connection_init_frame_; +} +inline ::nearby::presence::ConnectionInitFrame* V1Frame::mutable_connection_init_frame() { + ::nearby::presence::ConnectionInitFrame* _msg = _internal_mutable_connection_init_frame(); + // @@protoc_insertion_point(field_mutable:nearby.presence.V1Frame.connection_init_frame) + return _msg; +} + +// .nearby.presence.UwbControleeCapabilities uwb_controlee_capabilities_frame = 4; +inline bool V1Frame::_internal_has_uwb_controlee_capabilities_frame() const { + return Message_case() == kUwbControleeCapabilitiesFrame; +} +inline bool V1Frame::has_uwb_controlee_capabilities_frame() const { + return _internal_has_uwb_controlee_capabilities_frame(); +} +inline void V1Frame::set_has_uwb_controlee_capabilities_frame() { + _oneof_case_[0] = kUwbControleeCapabilitiesFrame; +} +inline void V1Frame::clear_uwb_controlee_capabilities_frame() { + if (_internal_has_uwb_controlee_capabilities_frame()) { + if (GetArenaForAllocation() == nullptr) { + delete Message_.uwb_controlee_capabilities_frame_; + } + clear_has_Message(); + } +} +inline ::nearby::presence::UwbControleeCapabilities* V1Frame::release_uwb_controlee_capabilities_frame() { + // @@protoc_insertion_point(field_release:nearby.presence.V1Frame.uwb_controlee_capabilities_frame) + if (_internal_has_uwb_controlee_capabilities_frame()) { + clear_has_Message(); + ::nearby::presence::UwbControleeCapabilities* temp = Message_.uwb_controlee_capabilities_frame_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + Message_.uwb_controlee_capabilities_frame_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::nearby::presence::UwbControleeCapabilities& V1Frame::_internal_uwb_controlee_capabilities_frame() const { + return _internal_has_uwb_controlee_capabilities_frame() + ? *Message_.uwb_controlee_capabilities_frame_ + : reinterpret_cast< ::nearby::presence::UwbControleeCapabilities&>(::nearby::presence::_UwbControleeCapabilities_default_instance_); +} +inline const ::nearby::presence::UwbControleeCapabilities& V1Frame::uwb_controlee_capabilities_frame() const { + // @@protoc_insertion_point(field_get:nearby.presence.V1Frame.uwb_controlee_capabilities_frame) + return _internal_uwb_controlee_capabilities_frame(); +} +inline ::nearby::presence::UwbControleeCapabilities* V1Frame::unsafe_arena_release_uwb_controlee_capabilities_frame() { + // @@protoc_insertion_point(field_unsafe_arena_release:nearby.presence.V1Frame.uwb_controlee_capabilities_frame) + if (_internal_has_uwb_controlee_capabilities_frame()) { + clear_has_Message(); + ::nearby::presence::UwbControleeCapabilities* temp = Message_.uwb_controlee_capabilities_frame_; + Message_.uwb_controlee_capabilities_frame_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void V1Frame::unsafe_arena_set_allocated_uwb_controlee_capabilities_frame(::nearby::presence::UwbControleeCapabilities* uwb_controlee_capabilities_frame) { + clear_Message(); + if (uwb_controlee_capabilities_frame) { + set_has_uwb_controlee_capabilities_frame(); + Message_.uwb_controlee_capabilities_frame_ = uwb_controlee_capabilities_frame; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:nearby.presence.V1Frame.uwb_controlee_capabilities_frame) +} +inline ::nearby::presence::UwbControleeCapabilities* V1Frame::_internal_mutable_uwb_controlee_capabilities_frame() { + if (!_internal_has_uwb_controlee_capabilities_frame()) { + clear_Message(); + set_has_uwb_controlee_capabilities_frame(); + Message_.uwb_controlee_capabilities_frame_ = CreateMaybeMessage< ::nearby::presence::UwbControleeCapabilities >(GetArenaForAllocation()); + } + return Message_.uwb_controlee_capabilities_frame_; +} +inline ::nearby::presence::UwbControleeCapabilities* V1Frame::mutable_uwb_controlee_capabilities_frame() { + ::nearby::presence::UwbControleeCapabilities* _msg = _internal_mutable_uwb_controlee_capabilities_frame(); + // @@protoc_insertion_point(field_mutable:nearby.presence.V1Frame.uwb_controlee_capabilities_frame) + return _msg; +} + +// .nearby.presence.UwbConnectionInfo uwb_connection_info = 5; +inline bool V1Frame::_internal_has_uwb_connection_info() const { + return Message_case() == kUwbConnectionInfo; +} +inline bool V1Frame::has_uwb_connection_info() const { + return _internal_has_uwb_connection_info(); +} +inline void V1Frame::set_has_uwb_connection_info() { + _oneof_case_[0] = kUwbConnectionInfo; +} +inline void V1Frame::clear_uwb_connection_info() { + if (_internal_has_uwb_connection_info()) { + if (GetArenaForAllocation() == nullptr) { + delete Message_.uwb_connection_info_; + } + clear_has_Message(); + } +} +inline ::nearby::presence::UwbConnectionInfo* V1Frame::release_uwb_connection_info() { + // @@protoc_insertion_point(field_release:nearby.presence.V1Frame.uwb_connection_info) + if (_internal_has_uwb_connection_info()) { + clear_has_Message(); + ::nearby::presence::UwbConnectionInfo* temp = Message_.uwb_connection_info_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + Message_.uwb_connection_info_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::nearby::presence::UwbConnectionInfo& V1Frame::_internal_uwb_connection_info() const { + return _internal_has_uwb_connection_info() + ? *Message_.uwb_connection_info_ + : reinterpret_cast< ::nearby::presence::UwbConnectionInfo&>(::nearby::presence::_UwbConnectionInfo_default_instance_); +} +inline const ::nearby::presence::UwbConnectionInfo& V1Frame::uwb_connection_info() const { + // @@protoc_insertion_point(field_get:nearby.presence.V1Frame.uwb_connection_info) + return _internal_uwb_connection_info(); +} +inline ::nearby::presence::UwbConnectionInfo* V1Frame::unsafe_arena_release_uwb_connection_info() { + // @@protoc_insertion_point(field_unsafe_arena_release:nearby.presence.V1Frame.uwb_connection_info) + if (_internal_has_uwb_connection_info()) { + clear_has_Message(); + ::nearby::presence::UwbConnectionInfo* temp = Message_.uwb_connection_info_; + Message_.uwb_connection_info_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void V1Frame::unsafe_arena_set_allocated_uwb_connection_info(::nearby::presence::UwbConnectionInfo* uwb_connection_info) { + clear_Message(); + if (uwb_connection_info) { + set_has_uwb_connection_info(); + Message_.uwb_connection_info_ = uwb_connection_info; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:nearby.presence.V1Frame.uwb_connection_info) +} +inline ::nearby::presence::UwbConnectionInfo* V1Frame::_internal_mutable_uwb_connection_info() { + if (!_internal_has_uwb_connection_info()) { + clear_Message(); + set_has_uwb_connection_info(); + Message_.uwb_connection_info_ = CreateMaybeMessage< ::nearby::presence::UwbConnectionInfo >(GetArenaForAllocation()); + } + return Message_.uwb_connection_info_; +} +inline ::nearby::presence::UwbConnectionInfo* V1Frame::mutable_uwb_connection_info() { + ::nearby::presence::UwbConnectionInfo* _msg = _internal_mutable_uwb_connection_info(); + // @@protoc_insertion_point(field_mutable:nearby.presence.V1Frame.uwb_connection_info) + return _msg; +} + +// .nearby.presence.PresenceAuthenticationFrame authentication_frame = 6; +inline bool V1Frame::_internal_has_authentication_frame() const { + return Message_case() == kAuthenticationFrame; +} +inline bool V1Frame::has_authentication_frame() const { + return _internal_has_authentication_frame(); +} +inline void V1Frame::set_has_authentication_frame() { + _oneof_case_[0] = kAuthenticationFrame; +} +inline void V1Frame::clear_authentication_frame() { + if (_internal_has_authentication_frame()) { + if (GetArenaForAllocation() == nullptr) { + delete Message_.authentication_frame_; + } + clear_has_Message(); + } +} +inline ::nearby::presence::PresenceAuthenticationFrame* V1Frame::release_authentication_frame() { + // @@protoc_insertion_point(field_release:nearby.presence.V1Frame.authentication_frame) + if (_internal_has_authentication_frame()) { + clear_has_Message(); + ::nearby::presence::PresenceAuthenticationFrame* temp = Message_.authentication_frame_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + Message_.authentication_frame_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::nearby::presence::PresenceAuthenticationFrame& V1Frame::_internal_authentication_frame() const { + return _internal_has_authentication_frame() + ? *Message_.authentication_frame_ + : reinterpret_cast< ::nearby::presence::PresenceAuthenticationFrame&>(::nearby::presence::_PresenceAuthenticationFrame_default_instance_); +} +inline const ::nearby::presence::PresenceAuthenticationFrame& V1Frame::authentication_frame() const { + // @@protoc_insertion_point(field_get:nearby.presence.V1Frame.authentication_frame) + return _internal_authentication_frame(); +} +inline ::nearby::presence::PresenceAuthenticationFrame* V1Frame::unsafe_arena_release_authentication_frame() { + // @@protoc_insertion_point(field_unsafe_arena_release:nearby.presence.V1Frame.authentication_frame) + if (_internal_has_authentication_frame()) { + clear_has_Message(); + ::nearby::presence::PresenceAuthenticationFrame* temp = Message_.authentication_frame_; + Message_.authentication_frame_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void V1Frame::unsafe_arena_set_allocated_authentication_frame(::nearby::presence::PresenceAuthenticationFrame* authentication_frame) { + clear_Message(); + if (authentication_frame) { + set_has_authentication_frame(); + Message_.authentication_frame_ = authentication_frame; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:nearby.presence.V1Frame.authentication_frame) +} +inline ::nearby::presence::PresenceAuthenticationFrame* V1Frame::_internal_mutable_authentication_frame() { + if (!_internal_has_authentication_frame()) { + clear_Message(); + set_has_authentication_frame(); + Message_.authentication_frame_ = CreateMaybeMessage< ::nearby::presence::PresenceAuthenticationFrame >(GetArenaForAllocation()); + } + return Message_.authentication_frame_; +} +inline ::nearby::presence::PresenceAuthenticationFrame* V1Frame::mutable_authentication_frame() { + ::nearby::presence::PresenceAuthenticationFrame* _msg = _internal_mutable_authentication_frame(); + // @@protoc_insertion_point(field_mutable:nearby.presence.V1Frame.authentication_frame) + return _msg; +} + +inline bool V1Frame::has_Message() const { + return Message_case() != MESSAGE_NOT_SET; +} +inline void V1Frame::clear_has_Message() { + _oneof_case_[0] = MESSAGE_NOT_SET; +} +inline V1Frame::MessageCase V1Frame::Message_case() const { + return V1Frame::MessageCase(_oneof_case_[0]); +} +// ------------------------------------------------------------------- + +// DeviceIdentityFrame + +// optional string device_name = 1; +inline bool DeviceIdentityFrame::_internal_has_device_name() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool DeviceIdentityFrame::has_device_name() const { + return _internal_has_device_name(); +} +inline void DeviceIdentityFrame::clear_device_name() { + device_name_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000001u; +} +inline const std::string& DeviceIdentityFrame::device_name() const { + // @@protoc_insertion_point(field_get:nearby.presence.DeviceIdentityFrame.device_name) + return _internal_device_name(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void DeviceIdentityFrame::set_device_name(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000001u; + device_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.DeviceIdentityFrame.device_name) +} +inline std::string* DeviceIdentityFrame::mutable_device_name() { + std::string* _s = _internal_mutable_device_name(); + // @@protoc_insertion_point(field_mutable:nearby.presence.DeviceIdentityFrame.device_name) + return _s; +} +inline const std::string& DeviceIdentityFrame::_internal_device_name() const { + return device_name_.Get(); +} +inline void DeviceIdentityFrame::_internal_set_device_name(const std::string& value) { + _has_bits_[0] |= 0x00000001u; + device_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* DeviceIdentityFrame::_internal_mutable_device_name() { + _has_bits_[0] |= 0x00000001u; + return device_name_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* DeviceIdentityFrame::release_device_name() { + // @@protoc_insertion_point(field_release:nearby.presence.DeviceIdentityFrame.device_name) + if (!_internal_has_device_name()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000001u; + auto* p = device_name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (device_name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + device_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void DeviceIdentityFrame::set_allocated_device_name(std::string* device_name) { + if (device_name != nullptr) { + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + device_name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), device_name, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (device_name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + device_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.DeviceIdentityFrame.device_name) +} + +// optional bytes bluetooth_mac_address = 2; +inline bool DeviceIdentityFrame::_internal_has_bluetooth_mac_address() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool DeviceIdentityFrame::has_bluetooth_mac_address() const { + return _internal_has_bluetooth_mac_address(); +} +inline void DeviceIdentityFrame::clear_bluetooth_mac_address() { + bluetooth_mac_address_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000002u; +} +inline const std::string& DeviceIdentityFrame::bluetooth_mac_address() const { + // @@protoc_insertion_point(field_get:nearby.presence.DeviceIdentityFrame.bluetooth_mac_address) + return _internal_bluetooth_mac_address(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void DeviceIdentityFrame::set_bluetooth_mac_address(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000002u; + bluetooth_mac_address_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.DeviceIdentityFrame.bluetooth_mac_address) +} +inline std::string* DeviceIdentityFrame::mutable_bluetooth_mac_address() { + std::string* _s = _internal_mutable_bluetooth_mac_address(); + // @@protoc_insertion_point(field_mutable:nearby.presence.DeviceIdentityFrame.bluetooth_mac_address) + return _s; +} +inline const std::string& DeviceIdentityFrame::_internal_bluetooth_mac_address() const { + return bluetooth_mac_address_.Get(); +} +inline void DeviceIdentityFrame::_internal_set_bluetooth_mac_address(const std::string& value) { + _has_bits_[0] |= 0x00000002u; + bluetooth_mac_address_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* DeviceIdentityFrame::_internal_mutable_bluetooth_mac_address() { + _has_bits_[0] |= 0x00000002u; + return bluetooth_mac_address_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* DeviceIdentityFrame::release_bluetooth_mac_address() { + // @@protoc_insertion_point(field_release:nearby.presence.DeviceIdentityFrame.bluetooth_mac_address) + if (!_internal_has_bluetooth_mac_address()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000002u; + auto* p = bluetooth_mac_address_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (bluetooth_mac_address_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + bluetooth_mac_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void DeviceIdentityFrame::set_allocated_bluetooth_mac_address(std::string* bluetooth_mac_address) { + if (bluetooth_mac_address != nullptr) { + _has_bits_[0] |= 0x00000002u; + } else { + _has_bits_[0] &= ~0x00000002u; + } + bluetooth_mac_address_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), bluetooth_mac_address, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (bluetooth_mac_address_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + bluetooth_mac_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.DeviceIdentityFrame.bluetooth_mac_address) +} + +// optional string device_image_url = 3; +inline bool DeviceIdentityFrame::_internal_has_device_image_url() const { + bool value = (_has_bits_[0] & 0x00000004u) != 0; + return value; +} +inline bool DeviceIdentityFrame::has_device_image_url() const { + return _internal_has_device_image_url(); +} +inline void DeviceIdentityFrame::clear_device_image_url() { + device_image_url_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000004u; +} +inline const std::string& DeviceIdentityFrame::device_image_url() const { + // @@protoc_insertion_point(field_get:nearby.presence.DeviceIdentityFrame.device_image_url) + return _internal_device_image_url(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void DeviceIdentityFrame::set_device_image_url(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000004u; + device_image_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.DeviceIdentityFrame.device_image_url) +} +inline std::string* DeviceIdentityFrame::mutable_device_image_url() { + std::string* _s = _internal_mutable_device_image_url(); + // @@protoc_insertion_point(field_mutable:nearby.presence.DeviceIdentityFrame.device_image_url) + return _s; +} +inline const std::string& DeviceIdentityFrame::_internal_device_image_url() const { + return device_image_url_.Get(); +} +inline void DeviceIdentityFrame::_internal_set_device_image_url(const std::string& value) { + _has_bits_[0] |= 0x00000004u; + device_image_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* DeviceIdentityFrame::_internal_mutable_device_image_url() { + _has_bits_[0] |= 0x00000004u; + return device_image_url_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* DeviceIdentityFrame::release_device_image_url() { + // @@protoc_insertion_point(field_release:nearby.presence.DeviceIdentityFrame.device_image_url) + if (!_internal_has_device_image_url()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000004u; + auto* p = device_image_url_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (device_image_url_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + device_image_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void DeviceIdentityFrame::set_allocated_device_image_url(std::string* device_image_url) { + if (device_image_url != nullptr) { + _has_bits_[0] |= 0x00000004u; + } else { + _has_bits_[0] &= ~0x00000004u; + } + device_image_url_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), device_image_url, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (device_image_url_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + device_image_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.DeviceIdentityFrame.device_image_url) +} + +// optional string model_id = 4; +inline bool DeviceIdentityFrame::_internal_has_model_id() const { + bool value = (_has_bits_[0] & 0x00000008u) != 0; + return value; +} +inline bool DeviceIdentityFrame::has_model_id() const { + return _internal_has_model_id(); +} +inline void DeviceIdentityFrame::clear_model_id() { + model_id_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000008u; +} +inline const std::string& DeviceIdentityFrame::model_id() const { + // @@protoc_insertion_point(field_get:nearby.presence.DeviceIdentityFrame.model_id) + return _internal_model_id(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void DeviceIdentityFrame::set_model_id(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000008u; + model_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.DeviceIdentityFrame.model_id) +} +inline std::string* DeviceIdentityFrame::mutable_model_id() { + std::string* _s = _internal_mutable_model_id(); + // @@protoc_insertion_point(field_mutable:nearby.presence.DeviceIdentityFrame.model_id) + return _s; +} +inline const std::string& DeviceIdentityFrame::_internal_model_id() const { + return model_id_.Get(); +} +inline void DeviceIdentityFrame::_internal_set_model_id(const std::string& value) { + _has_bits_[0] |= 0x00000008u; + model_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* DeviceIdentityFrame::_internal_mutable_model_id() { + _has_bits_[0] |= 0x00000008u; + return model_id_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* DeviceIdentityFrame::release_model_id() { + // @@protoc_insertion_point(field_release:nearby.presence.DeviceIdentityFrame.model_id) + if (!_internal_has_model_id()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000008u; + auto* p = model_id_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (model_id_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + model_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void DeviceIdentityFrame::set_allocated_model_id(std::string* model_id) { + if (model_id != nullptr) { + _has_bits_[0] |= 0x00000008u; + } else { + _has_bits_[0] &= ~0x00000008u; + } + model_id_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), model_id, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (model_id_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + model_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.DeviceIdentityFrame.model_id) +} + +// repeated int32 action = 5 [packed = true]; +inline int DeviceIdentityFrame::_internal_action_size() const { + return action_.size(); +} +inline int DeviceIdentityFrame::action_size() const { + return _internal_action_size(); +} +inline void DeviceIdentityFrame::clear_action() { + action_.Clear(); +} +inline int32_t DeviceIdentityFrame::_internal_action(int index) const { + return action_.Get(index); +} +inline int32_t DeviceIdentityFrame::action(int index) const { + // @@protoc_insertion_point(field_get:nearby.presence.DeviceIdentityFrame.action) + return _internal_action(index); +} +inline void DeviceIdentityFrame::set_action(int index, int32_t value) { + action_.Set(index, value); + // @@protoc_insertion_point(field_set:nearby.presence.DeviceIdentityFrame.action) +} +inline void DeviceIdentityFrame::_internal_add_action(int32_t value) { + action_.Add(value); +} +inline void DeviceIdentityFrame::add_action(int32_t value) { + _internal_add_action(value); + // @@protoc_insertion_point(field_add:nearby.presence.DeviceIdentityFrame.action) +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +DeviceIdentityFrame::_internal_action() const { + return action_; +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +DeviceIdentityFrame::action() const { + // @@protoc_insertion_point(field_list:nearby.presence.DeviceIdentityFrame.action) + return _internal_action(); +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +DeviceIdentityFrame::_internal_mutable_action() { + return &action_; +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +DeviceIdentityFrame::mutable_action() { + // @@protoc_insertion_point(field_mutable_list:nearby.presence.DeviceIdentityFrame.action) + return _internal_mutable_action(); +} + +// optional string device_model_name = 6; +inline bool DeviceIdentityFrame::_internal_has_device_model_name() const { + bool value = (_has_bits_[0] & 0x00000010u) != 0; + return value; +} +inline bool DeviceIdentityFrame::has_device_model_name() const { + return _internal_has_device_model_name(); +} +inline void DeviceIdentityFrame::clear_device_model_name() { + device_model_name_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000010u; +} +inline const std::string& DeviceIdentityFrame::device_model_name() const { + // @@protoc_insertion_point(field_get:nearby.presence.DeviceIdentityFrame.device_model_name) + return _internal_device_model_name(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void DeviceIdentityFrame::set_device_model_name(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000010u; + device_model_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.DeviceIdentityFrame.device_model_name) +} +inline std::string* DeviceIdentityFrame::mutable_device_model_name() { + std::string* _s = _internal_mutable_device_model_name(); + // @@protoc_insertion_point(field_mutable:nearby.presence.DeviceIdentityFrame.device_model_name) + return _s; +} +inline const std::string& DeviceIdentityFrame::_internal_device_model_name() const { + return device_model_name_.Get(); +} +inline void DeviceIdentityFrame::_internal_set_device_model_name(const std::string& value) { + _has_bits_[0] |= 0x00000010u; + device_model_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* DeviceIdentityFrame::_internal_mutable_device_model_name() { + _has_bits_[0] |= 0x00000010u; + return device_model_name_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* DeviceIdentityFrame::release_device_model_name() { + // @@protoc_insertion_point(field_release:nearby.presence.DeviceIdentityFrame.device_model_name) + if (!_internal_has_device_model_name()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000010u; + auto* p = device_model_name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (device_model_name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + device_model_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void DeviceIdentityFrame::set_allocated_device_model_name(std::string* device_model_name) { + if (device_model_name != nullptr) { + _has_bits_[0] |= 0x00000010u; + } else { + _has_bits_[0] &= ~0x00000010u; + } + device_model_name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), device_model_name, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (device_model_name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + device_model_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.DeviceIdentityFrame.device_model_name) +} + +// optional int32 device_type = 7; +inline bool DeviceIdentityFrame::_internal_has_device_type() const { + bool value = (_has_bits_[0] & 0x00000020u) != 0; + return value; +} +inline bool DeviceIdentityFrame::has_device_type() const { + return _internal_has_device_type(); +} +inline void DeviceIdentityFrame::clear_device_type() { + device_type_ = 0; + _has_bits_[0] &= ~0x00000020u; +} +inline int32_t DeviceIdentityFrame::_internal_device_type() const { + return device_type_; +} +inline int32_t DeviceIdentityFrame::device_type() const { + // @@protoc_insertion_point(field_get:nearby.presence.DeviceIdentityFrame.device_type) + return _internal_device_type(); +} +inline void DeviceIdentityFrame::_internal_set_device_type(int32_t value) { + _has_bits_[0] |= 0x00000020u; + device_type_ = value; +} +inline void DeviceIdentityFrame::set_device_type(int32_t value) { + _internal_set_device_type(value); + // @@protoc_insertion_point(field_set:nearby.presence.DeviceIdentityFrame.device_type) +} + +// ------------------------------------------------------------------- + +// ConnectionInitFrame + +// repeated int32 actions = 1 [packed = true]; +inline int ConnectionInitFrame::_internal_actions_size() const { + return actions_.size(); +} +inline int ConnectionInitFrame::actions_size() const { + return _internal_actions_size(); +} +inline void ConnectionInitFrame::clear_actions() { + actions_.Clear(); +} +inline int32_t ConnectionInitFrame::_internal_actions(int index) const { + return actions_.Get(index); +} +inline int32_t ConnectionInitFrame::actions(int index) const { + // @@protoc_insertion_point(field_get:nearby.presence.ConnectionInitFrame.actions) + return _internal_actions(index); +} +inline void ConnectionInitFrame::set_actions(int index, int32_t value) { + actions_.Set(index, value); + // @@protoc_insertion_point(field_set:nearby.presence.ConnectionInitFrame.actions) +} +inline void ConnectionInitFrame::_internal_add_actions(int32_t value) { + actions_.Add(value); +} +inline void ConnectionInitFrame::add_actions(int32_t value) { + _internal_add_actions(value); + // @@protoc_insertion_point(field_add:nearby.presence.ConnectionInitFrame.actions) +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +ConnectionInitFrame::_internal_actions() const { + return actions_; +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +ConnectionInitFrame::actions() const { + // @@protoc_insertion_point(field_list:nearby.presence.ConnectionInitFrame.actions) + return _internal_actions(); +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +ConnectionInitFrame::_internal_mutable_actions() { + return &actions_; +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +ConnectionInitFrame::mutable_actions() { + // @@protoc_insertion_point(field_mutable_list:nearby.presence.ConnectionInitFrame.actions) + return _internal_mutable_actions(); +} + +// optional int32 identity_type = 2; +inline bool ConnectionInitFrame::_internal_has_identity_type() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool ConnectionInitFrame::has_identity_type() const { + return _internal_has_identity_type(); +} +inline void ConnectionInitFrame::clear_identity_type() { + identity_type_ = 0; + _has_bits_[0] &= ~0x00000001u; +} +inline int32_t ConnectionInitFrame::_internal_identity_type() const { + return identity_type_; +} +inline int32_t ConnectionInitFrame::identity_type() const { + // @@protoc_insertion_point(field_get:nearby.presence.ConnectionInitFrame.identity_type) + return _internal_identity_type(); +} +inline void ConnectionInitFrame::_internal_set_identity_type(int32_t value) { + _has_bits_[0] |= 0x00000001u; + identity_type_ = value; +} +inline void ConnectionInitFrame::set_identity_type(int32_t value) { + _internal_set_identity_type(value); + // @@protoc_insertion_point(field_set:nearby.presence.ConnectionInitFrame.identity_type) +} + +// optional bool uwb_enable = 3; +inline bool ConnectionInitFrame::_internal_has_uwb_enable() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool ConnectionInitFrame::has_uwb_enable() const { + return _internal_has_uwb_enable(); +} +inline void ConnectionInitFrame::clear_uwb_enable() { + uwb_enable_ = false; + _has_bits_[0] &= ~0x00000002u; +} +inline bool ConnectionInitFrame::_internal_uwb_enable() const { + return uwb_enable_; +} +inline bool ConnectionInitFrame::uwb_enable() const { + // @@protoc_insertion_point(field_get:nearby.presence.ConnectionInitFrame.uwb_enable) + return _internal_uwb_enable(); +} +inline void ConnectionInitFrame::_internal_set_uwb_enable(bool value) { + _has_bits_[0] |= 0x00000002u; + uwb_enable_ = value; +} +inline void ConnectionInitFrame::set_uwb_enable(bool value) { + _internal_set_uwb_enable(value); + // @@protoc_insertion_point(field_set:nearby.presence.ConnectionInitFrame.uwb_enable) +} + +// optional int64 device_unique_id = 4; +inline bool ConnectionInitFrame::_internal_has_device_unique_id() const { + bool value = (_has_bits_[0] & 0x00000004u) != 0; + return value; +} +inline bool ConnectionInitFrame::has_device_unique_id() const { + return _internal_has_device_unique_id(); +} +inline void ConnectionInitFrame::clear_device_unique_id() { + device_unique_id_ = int64_t{0}; + _has_bits_[0] &= ~0x00000004u; +} +inline int64_t ConnectionInitFrame::_internal_device_unique_id() const { + return device_unique_id_; +} +inline int64_t ConnectionInitFrame::device_unique_id() const { + // @@protoc_insertion_point(field_get:nearby.presence.ConnectionInitFrame.device_unique_id) + return _internal_device_unique_id(); +} +inline void ConnectionInitFrame::_internal_set_device_unique_id(int64_t value) { + _has_bits_[0] |= 0x00000004u; + device_unique_id_ = value; +} +inline void ConnectionInitFrame::set_device_unique_id(int64_t value) { + _internal_set_device_unique_id(value); + // @@protoc_insertion_point(field_set:nearby.presence.ConnectionInitFrame.device_unique_id) +} + +// ------------------------------------------------------------------- + +// UwbControleeCapabilities + +// optional bytes controlee_address = 1; +inline bool UwbControleeCapabilities::_internal_has_controlee_address() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_controlee_address() const { + return _internal_has_controlee_address(); +} +inline void UwbControleeCapabilities::clear_controlee_address() { + controlee_address_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000001u; +} +inline const std::string& UwbControleeCapabilities::controlee_address() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.controlee_address) + return _internal_controlee_address(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void UwbControleeCapabilities::set_controlee_address(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000001u; + controlee_address_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.controlee_address) +} +inline std::string* UwbControleeCapabilities::mutable_controlee_address() { + std::string* _s = _internal_mutable_controlee_address(); + // @@protoc_insertion_point(field_mutable:nearby.presence.UwbControleeCapabilities.controlee_address) + return _s; +} +inline const std::string& UwbControleeCapabilities::_internal_controlee_address() const { + return controlee_address_.Get(); +} +inline void UwbControleeCapabilities::_internal_set_controlee_address(const std::string& value) { + _has_bits_[0] |= 0x00000001u; + controlee_address_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* UwbControleeCapabilities::_internal_mutable_controlee_address() { + _has_bits_[0] |= 0x00000001u; + return controlee_address_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* UwbControleeCapabilities::release_controlee_address() { + // @@protoc_insertion_point(field_release:nearby.presence.UwbControleeCapabilities.controlee_address) + if (!_internal_has_controlee_address()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000001u; + auto* p = controlee_address_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (controlee_address_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + controlee_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void UwbControleeCapabilities::set_allocated_controlee_address(std::string* controlee_address) { + if (controlee_address != nullptr) { + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + controlee_address_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), controlee_address, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (controlee_address_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + controlee_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.UwbControleeCapabilities.controlee_address) +} + +// repeated int32 supported_config_ids = 2 [packed = true]; +inline int UwbControleeCapabilities::_internal_supported_config_ids_size() const { + return supported_config_ids_.size(); +} +inline int UwbControleeCapabilities::supported_config_ids_size() const { + return _internal_supported_config_ids_size(); +} +inline void UwbControleeCapabilities::clear_supported_config_ids() { + supported_config_ids_.Clear(); +} +inline int32_t UwbControleeCapabilities::_internal_supported_config_ids(int index) const { + return supported_config_ids_.Get(index); +} +inline int32_t UwbControleeCapabilities::supported_config_ids(int index) const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.supported_config_ids) + return _internal_supported_config_ids(index); +} +inline void UwbControleeCapabilities::set_supported_config_ids(int index, int32_t value) { + supported_config_ids_.Set(index, value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.supported_config_ids) +} +inline void UwbControleeCapabilities::_internal_add_supported_config_ids(int32_t value) { + supported_config_ids_.Add(value); +} +inline void UwbControleeCapabilities::add_supported_config_ids(int32_t value) { + _internal_add_supported_config_ids(value); + // @@protoc_insertion_point(field_add:nearby.presence.UwbControleeCapabilities.supported_config_ids) +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +UwbControleeCapabilities::_internal_supported_config_ids() const { + return supported_config_ids_; +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +UwbControleeCapabilities::supported_config_ids() const { + // @@protoc_insertion_point(field_list:nearby.presence.UwbControleeCapabilities.supported_config_ids) + return _internal_supported_config_ids(); +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +UwbControleeCapabilities::_internal_mutable_supported_config_ids() { + return &supported_config_ids_; +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +UwbControleeCapabilities::mutable_supported_config_ids() { + // @@protoc_insertion_point(field_mutable_list:nearby.presence.UwbControleeCapabilities.supported_config_ids) + return _internal_mutable_supported_config_ids(); +} + +// repeated int32 supported_channels = 3 [packed = true]; +inline int UwbControleeCapabilities::_internal_supported_channels_size() const { + return supported_channels_.size(); +} +inline int UwbControleeCapabilities::supported_channels_size() const { + return _internal_supported_channels_size(); +} +inline void UwbControleeCapabilities::clear_supported_channels() { + supported_channels_.Clear(); +} +inline int32_t UwbControleeCapabilities::_internal_supported_channels(int index) const { + return supported_channels_.Get(index); +} +inline int32_t UwbControleeCapabilities::supported_channels(int index) const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.supported_channels) + return _internal_supported_channels(index); +} +inline void UwbControleeCapabilities::set_supported_channels(int index, int32_t value) { + supported_channels_.Set(index, value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.supported_channels) +} +inline void UwbControleeCapabilities::_internal_add_supported_channels(int32_t value) { + supported_channels_.Add(value); +} +inline void UwbControleeCapabilities::add_supported_channels(int32_t value) { + _internal_add_supported_channels(value); + // @@protoc_insertion_point(field_add:nearby.presence.UwbControleeCapabilities.supported_channels) +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +UwbControleeCapabilities::_internal_supported_channels() const { + return supported_channels_; +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +UwbControleeCapabilities::supported_channels() const { + // @@protoc_insertion_point(field_list:nearby.presence.UwbControleeCapabilities.supported_channels) + return _internal_supported_channels(); +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +UwbControleeCapabilities::_internal_mutable_supported_channels() { + return &supported_channels_; +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +UwbControleeCapabilities::mutable_supported_channels() { + // @@protoc_insertion_point(field_mutable_list:nearby.presence.UwbControleeCapabilities.supported_channels) + return _internal_mutable_supported_channels(); +} + +// optional int32 min_ranging_interval_ms = 4; +inline bool UwbControleeCapabilities::_internal_has_min_ranging_interval_ms() const { + bool value = (_has_bits_[0] & 0x00000010u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_min_ranging_interval_ms() const { + return _internal_has_min_ranging_interval_ms(); +} +inline void UwbControleeCapabilities::clear_min_ranging_interval_ms() { + min_ranging_interval_ms_ = 0; + _has_bits_[0] &= ~0x00000010u; +} +inline int32_t UwbControleeCapabilities::_internal_min_ranging_interval_ms() const { + return min_ranging_interval_ms_; +} +inline int32_t UwbControleeCapabilities::min_ranging_interval_ms() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.min_ranging_interval_ms) + return _internal_min_ranging_interval_ms(); +} +inline void UwbControleeCapabilities::_internal_set_min_ranging_interval_ms(int32_t value) { + _has_bits_[0] |= 0x00000010u; + min_ranging_interval_ms_ = value; +} +inline void UwbControleeCapabilities::set_min_ranging_interval_ms(int32_t value) { + _internal_set_min_ranging_interval_ms(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.min_ranging_interval_ms) +} + +// optional bytes sub_session_id = 5; +inline bool UwbControleeCapabilities::_internal_has_sub_session_id() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_sub_session_id() const { + return _internal_has_sub_session_id(); +} +inline void UwbControleeCapabilities::clear_sub_session_id() { + sub_session_id_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000002u; +} +inline const std::string& UwbControleeCapabilities::sub_session_id() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.sub_session_id) + return _internal_sub_session_id(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void UwbControleeCapabilities::set_sub_session_id(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000002u; + sub_session_id_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.sub_session_id) +} +inline std::string* UwbControleeCapabilities::mutable_sub_session_id() { + std::string* _s = _internal_mutable_sub_session_id(); + // @@protoc_insertion_point(field_mutable:nearby.presence.UwbControleeCapabilities.sub_session_id) + return _s; +} +inline const std::string& UwbControleeCapabilities::_internal_sub_session_id() const { + return sub_session_id_.Get(); +} +inline void UwbControleeCapabilities::_internal_set_sub_session_id(const std::string& value) { + _has_bits_[0] |= 0x00000002u; + sub_session_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* UwbControleeCapabilities::_internal_mutable_sub_session_id() { + _has_bits_[0] |= 0x00000002u; + return sub_session_id_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* UwbControleeCapabilities::release_sub_session_id() { + // @@protoc_insertion_point(field_release:nearby.presence.UwbControleeCapabilities.sub_session_id) + if (!_internal_has_sub_session_id()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000002u; + auto* p = sub_session_id_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (sub_session_id_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + sub_session_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void UwbControleeCapabilities::set_allocated_sub_session_id(std::string* sub_session_id) { + if (sub_session_id != nullptr) { + _has_bits_[0] |= 0x00000002u; + } else { + _has_bits_[0] &= ~0x00000002u; + } + sub_session_id_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), sub_session_id, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (sub_session_id_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + sub_session_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.UwbControleeCapabilities.sub_session_id) +} + +// optional bytes sub_session_key = 6; +inline bool UwbControleeCapabilities::_internal_has_sub_session_key() const { + bool value = (_has_bits_[0] & 0x00000004u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_sub_session_key() const { + return _internal_has_sub_session_key(); +} +inline void UwbControleeCapabilities::clear_sub_session_key() { + sub_session_key_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000004u; +} +inline const std::string& UwbControleeCapabilities::sub_session_key() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.sub_session_key) + return _internal_sub_session_key(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void UwbControleeCapabilities::set_sub_session_key(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000004u; + sub_session_key_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.sub_session_key) +} +inline std::string* UwbControleeCapabilities::mutable_sub_session_key() { + std::string* _s = _internal_mutable_sub_session_key(); + // @@protoc_insertion_point(field_mutable:nearby.presence.UwbControleeCapabilities.sub_session_key) + return _s; +} +inline const std::string& UwbControleeCapabilities::_internal_sub_session_key() const { + return sub_session_key_.Get(); +} +inline void UwbControleeCapabilities::_internal_set_sub_session_key(const std::string& value) { + _has_bits_[0] |= 0x00000004u; + sub_session_key_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* UwbControleeCapabilities::_internal_mutable_sub_session_key() { + _has_bits_[0] |= 0x00000004u; + return sub_session_key_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* UwbControleeCapabilities::release_sub_session_key() { + // @@protoc_insertion_point(field_release:nearby.presence.UwbControleeCapabilities.sub_session_key) + if (!_internal_has_sub_session_key()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000004u; + auto* p = sub_session_key_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (sub_session_key_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + sub_session_key_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void UwbControleeCapabilities::set_allocated_sub_session_key(std::string* sub_session_key) { + if (sub_session_key != nullptr) { + _has_bits_[0] |= 0x00000004u; + } else { + _has_bits_[0] &= ~0x00000004u; + } + sub_session_key_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), sub_session_key, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (sub_session_key_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + sub_session_key_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.UwbControleeCapabilities.sub_session_key) +} + +// optional bool ranging_disabled = 7; +inline bool UwbControleeCapabilities::_internal_has_ranging_disabled() const { + bool value = (_has_bits_[0] & 0x00000020u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_ranging_disabled() const { + return _internal_has_ranging_disabled(); +} +inline void UwbControleeCapabilities::clear_ranging_disabled() { + ranging_disabled_ = false; + _has_bits_[0] &= ~0x00000020u; +} +inline bool UwbControleeCapabilities::_internal_ranging_disabled() const { + return ranging_disabled_; +} +inline bool UwbControleeCapabilities::ranging_disabled() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.ranging_disabled) + return _internal_ranging_disabled(); +} +inline void UwbControleeCapabilities::_internal_set_ranging_disabled(bool value) { + _has_bits_[0] |= 0x00000020u; + ranging_disabled_ = value; +} +inline void UwbControleeCapabilities::set_ranging_disabled(bool value) { + _internal_set_ranging_disabled(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.ranging_disabled) +} + +// optional int64 device_unique_id = 8; +inline bool UwbControleeCapabilities::_internal_has_device_unique_id() const { + bool value = (_has_bits_[0] & 0x00000008u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_device_unique_id() const { + return _internal_has_device_unique_id(); +} +inline void UwbControleeCapabilities::clear_device_unique_id() { + device_unique_id_ = int64_t{0}; + _has_bits_[0] &= ~0x00000008u; +} +inline int64_t UwbControleeCapabilities::_internal_device_unique_id() const { + return device_unique_id_; +} +inline int64_t UwbControleeCapabilities::device_unique_id() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.device_unique_id) + return _internal_device_unique_id(); +} +inline void UwbControleeCapabilities::_internal_set_device_unique_id(int64_t value) { + _has_bits_[0] |= 0x00000008u; + device_unique_id_ = value; +} +inline void UwbControleeCapabilities::set_device_unique_id(int64_t value) { + _internal_set_device_unique_id(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.device_unique_id) +} + +// optional bool is_distance_supported = 9 [default = true]; +inline bool UwbControleeCapabilities::_internal_has_is_distance_supported() const { + bool value = (_has_bits_[0] & 0x00000200u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_is_distance_supported() const { + return _internal_has_is_distance_supported(); +} +inline void UwbControleeCapabilities::clear_is_distance_supported() { + is_distance_supported_ = true; + _has_bits_[0] &= ~0x00000200u; +} +inline bool UwbControleeCapabilities::_internal_is_distance_supported() const { + return is_distance_supported_; +} +inline bool UwbControleeCapabilities::is_distance_supported() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.is_distance_supported) + return _internal_is_distance_supported(); +} +inline void UwbControleeCapabilities::_internal_set_is_distance_supported(bool value) { + _has_bits_[0] |= 0x00000200u; + is_distance_supported_ = value; +} +inline void UwbControleeCapabilities::set_is_distance_supported(bool value) { + _internal_set_is_distance_supported(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.is_distance_supported) +} + +// optional bool is_azimuth_supported = 10 [default = true]; +inline bool UwbControleeCapabilities::_internal_has_is_azimuth_supported() const { + bool value = (_has_bits_[0] & 0x00000400u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_is_azimuth_supported() const { + return _internal_has_is_azimuth_supported(); +} +inline void UwbControleeCapabilities::clear_is_azimuth_supported() { + is_azimuth_supported_ = true; + _has_bits_[0] &= ~0x00000400u; +} +inline bool UwbControleeCapabilities::_internal_is_azimuth_supported() const { + return is_azimuth_supported_; +} +inline bool UwbControleeCapabilities::is_azimuth_supported() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.is_azimuth_supported) + return _internal_is_azimuth_supported(); +} +inline void UwbControleeCapabilities::_internal_set_is_azimuth_supported(bool value) { + _has_bits_[0] |= 0x00000400u; + is_azimuth_supported_ = value; +} +inline void UwbControleeCapabilities::set_is_azimuth_supported(bool value) { + _internal_set_is_azimuth_supported(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.is_azimuth_supported) +} + +// optional bool is_elevation_supported = 11 [default = false]; +inline bool UwbControleeCapabilities::_internal_has_is_elevation_supported() const { + bool value = (_has_bits_[0] & 0x00000040u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_is_elevation_supported() const { + return _internal_has_is_elevation_supported(); +} +inline void UwbControleeCapabilities::clear_is_elevation_supported() { + is_elevation_supported_ = false; + _has_bits_[0] &= ~0x00000040u; +} +inline bool UwbControleeCapabilities::_internal_is_elevation_supported() const { + return is_elevation_supported_; +} +inline bool UwbControleeCapabilities::is_elevation_supported() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.is_elevation_supported) + return _internal_is_elevation_supported(); +} +inline void UwbControleeCapabilities::_internal_set_is_elevation_supported(bool value) { + _has_bits_[0] |= 0x00000040u; + is_elevation_supported_ = value; +} +inline void UwbControleeCapabilities::set_is_elevation_supported(bool value) { + _internal_set_is_elevation_supported(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.is_elevation_supported) +} + +// optional float min_slot_duration_ms = 12 [default = 2]; +inline bool UwbControleeCapabilities::_internal_has_min_slot_duration_ms() const { + bool value = (_has_bits_[0] & 0x00000800u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_min_slot_duration_ms() const { + return _internal_has_min_slot_duration_ms(); +} +inline void UwbControleeCapabilities::clear_min_slot_duration_ms() { + min_slot_duration_ms_ = 2; + _has_bits_[0] &= ~0x00000800u; +} +inline float UwbControleeCapabilities::_internal_min_slot_duration_ms() const { + return min_slot_duration_ms_; +} +inline float UwbControleeCapabilities::min_slot_duration_ms() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.min_slot_duration_ms) + return _internal_min_slot_duration_ms(); +} +inline void UwbControleeCapabilities::_internal_set_min_slot_duration_ms(float value) { + _has_bits_[0] |= 0x00000800u; + min_slot_duration_ms_ = value; +} +inline void UwbControleeCapabilities::set_min_slot_duration_ms(float value) { + _internal_set_min_slot_duration_ms(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.min_slot_duration_ms) +} + +// repeated int32 supported_ntf_configs = 13 [packed = true]; +inline int UwbControleeCapabilities::_internal_supported_ntf_configs_size() const { + return supported_ntf_configs_.size(); +} +inline int UwbControleeCapabilities::supported_ntf_configs_size() const { + return _internal_supported_ntf_configs_size(); +} +inline void UwbControleeCapabilities::clear_supported_ntf_configs() { + supported_ntf_configs_.Clear(); +} +inline int32_t UwbControleeCapabilities::_internal_supported_ntf_configs(int index) const { + return supported_ntf_configs_.Get(index); +} +inline int32_t UwbControleeCapabilities::supported_ntf_configs(int index) const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.supported_ntf_configs) + return _internal_supported_ntf_configs(index); +} +inline void UwbControleeCapabilities::set_supported_ntf_configs(int index, int32_t value) { + supported_ntf_configs_.Set(index, value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.supported_ntf_configs) +} +inline void UwbControleeCapabilities::_internal_add_supported_ntf_configs(int32_t value) { + supported_ntf_configs_.Add(value); +} +inline void UwbControleeCapabilities::add_supported_ntf_configs(int32_t value) { + _internal_add_supported_ntf_configs(value); + // @@protoc_insertion_point(field_add:nearby.presence.UwbControleeCapabilities.supported_ntf_configs) +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +UwbControleeCapabilities::_internal_supported_ntf_configs() const { + return supported_ntf_configs_; +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +UwbControleeCapabilities::supported_ntf_configs() const { + // @@protoc_insertion_point(field_list:nearby.presence.UwbControleeCapabilities.supported_ntf_configs) + return _internal_supported_ntf_configs(); +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +UwbControleeCapabilities::_internal_mutable_supported_ntf_configs() { + return &supported_ntf_configs_; +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +UwbControleeCapabilities::mutable_supported_ntf_configs() { + // @@protoc_insertion_point(field_mutable_list:nearby.presence.UwbControleeCapabilities.supported_ntf_configs) + return _internal_mutable_supported_ntf_configs(); +} + +// optional bool is_ranging_interval_reconfigure_supported = 14 [default = false]; +inline bool UwbControleeCapabilities::_internal_has_is_ranging_interval_reconfigure_supported() const { + bool value = (_has_bits_[0] & 0x00000080u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_is_ranging_interval_reconfigure_supported() const { + return _internal_has_is_ranging_interval_reconfigure_supported(); +} +inline void UwbControleeCapabilities::clear_is_ranging_interval_reconfigure_supported() { + is_ranging_interval_reconfigure_supported_ = false; + _has_bits_[0] &= ~0x00000080u; +} +inline bool UwbControleeCapabilities::_internal_is_ranging_interval_reconfigure_supported() const { + return is_ranging_interval_reconfigure_supported_; +} +inline bool UwbControleeCapabilities::is_ranging_interval_reconfigure_supported() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.is_ranging_interval_reconfigure_supported) + return _internal_is_ranging_interval_reconfigure_supported(); +} +inline void UwbControleeCapabilities::_internal_set_is_ranging_interval_reconfigure_supported(bool value) { + _has_bits_[0] |= 0x00000080u; + is_ranging_interval_reconfigure_supported_ = value; +} +inline void UwbControleeCapabilities::set_is_ranging_interval_reconfigure_supported(bool value) { + _internal_set_is_ranging_interval_reconfigure_supported(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.is_ranging_interval_reconfigure_supported) +} + +// repeated int32 supported_slot_durations = 15 [packed = true]; +inline int UwbControleeCapabilities::_internal_supported_slot_durations_size() const { + return supported_slot_durations_.size(); +} +inline int UwbControleeCapabilities::supported_slot_durations_size() const { + return _internal_supported_slot_durations_size(); +} +inline void UwbControleeCapabilities::clear_supported_slot_durations() { + supported_slot_durations_.Clear(); +} +inline int32_t UwbControleeCapabilities::_internal_supported_slot_durations(int index) const { + return supported_slot_durations_.Get(index); +} +inline int32_t UwbControleeCapabilities::supported_slot_durations(int index) const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.supported_slot_durations) + return _internal_supported_slot_durations(index); +} +inline void UwbControleeCapabilities::set_supported_slot_durations(int index, int32_t value) { + supported_slot_durations_.Set(index, value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.supported_slot_durations) +} +inline void UwbControleeCapabilities::_internal_add_supported_slot_durations(int32_t value) { + supported_slot_durations_.Add(value); +} +inline void UwbControleeCapabilities::add_supported_slot_durations(int32_t value) { + _internal_add_supported_slot_durations(value); + // @@protoc_insertion_point(field_add:nearby.presence.UwbControleeCapabilities.supported_slot_durations) +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +UwbControleeCapabilities::_internal_supported_slot_durations() const { + return supported_slot_durations_; +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +UwbControleeCapabilities::supported_slot_durations() const { + // @@protoc_insertion_point(field_list:nearby.presence.UwbControleeCapabilities.supported_slot_durations) + return _internal_supported_slot_durations(); +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +UwbControleeCapabilities::_internal_mutable_supported_slot_durations() { + return &supported_slot_durations_; +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +UwbControleeCapabilities::mutable_supported_slot_durations() { + // @@protoc_insertion_point(field_mutable_list:nearby.presence.UwbControleeCapabilities.supported_slot_durations) + return _internal_mutable_supported_slot_durations(); +} + +// repeated int32 supported_ranging_update_rates = 16 [packed = true]; +inline int UwbControleeCapabilities::_internal_supported_ranging_update_rates_size() const { + return supported_ranging_update_rates_.size(); +} +inline int UwbControleeCapabilities::supported_ranging_update_rates_size() const { + return _internal_supported_ranging_update_rates_size(); +} +inline void UwbControleeCapabilities::clear_supported_ranging_update_rates() { + supported_ranging_update_rates_.Clear(); +} +inline int32_t UwbControleeCapabilities::_internal_supported_ranging_update_rates(int index) const { + return supported_ranging_update_rates_.Get(index); +} +inline int32_t UwbControleeCapabilities::supported_ranging_update_rates(int index) const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.supported_ranging_update_rates) + return _internal_supported_ranging_update_rates(index); +} +inline void UwbControleeCapabilities::set_supported_ranging_update_rates(int index, int32_t value) { + supported_ranging_update_rates_.Set(index, value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.supported_ranging_update_rates) +} +inline void UwbControleeCapabilities::_internal_add_supported_ranging_update_rates(int32_t value) { + supported_ranging_update_rates_.Add(value); +} +inline void UwbControleeCapabilities::add_supported_ranging_update_rates(int32_t value) { + _internal_add_supported_ranging_update_rates(value); + // @@protoc_insertion_point(field_add:nearby.presence.UwbControleeCapabilities.supported_ranging_update_rates) +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +UwbControleeCapabilities::_internal_supported_ranging_update_rates() const { + return supported_ranging_update_rates_; +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >& +UwbControleeCapabilities::supported_ranging_update_rates() const { + // @@protoc_insertion_point(field_list:nearby.presence.UwbControleeCapabilities.supported_ranging_update_rates) + return _internal_supported_ranging_update_rates(); +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +UwbControleeCapabilities::_internal_mutable_supported_ranging_update_rates() { + return &supported_ranging_update_rates_; +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >* +UwbControleeCapabilities::mutable_supported_ranging_update_rates() { + // @@protoc_insertion_point(field_mutable_list:nearby.presence.UwbControleeCapabilities.supported_ranging_update_rates) + return _internal_mutable_supported_ranging_update_rates(); +} + +// optional int32 chip_count = 17 [default = 1]; +inline bool UwbControleeCapabilities::_internal_has_chip_count() const { + bool value = (_has_bits_[0] & 0x00000100u) != 0; + return value; +} +inline bool UwbControleeCapabilities::has_chip_count() const { + return _internal_has_chip_count(); +} +inline void UwbControleeCapabilities::clear_chip_count() { + chip_count_ = 1; + _has_bits_[0] &= ~0x00000100u; +} +inline int32_t UwbControleeCapabilities::_internal_chip_count() const { + return chip_count_; +} +inline int32_t UwbControleeCapabilities::chip_count() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.chip_count) + return _internal_chip_count(); +} +inline void UwbControleeCapabilities::_internal_set_chip_count(int32_t value) { + _has_bits_[0] |= 0x00000100u; + chip_count_ = value; +} +inline void UwbControleeCapabilities::set_chip_count(int32_t value) { + _internal_set_chip_count(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbControleeCapabilities.chip_count) +} + +// repeated .nearby.presence.UwbMultiChipInfo multi_chip_info = 18; +inline int UwbControleeCapabilities::_internal_multi_chip_info_size() const { + return multi_chip_info_.size(); +} +inline int UwbControleeCapabilities::multi_chip_info_size() const { + return _internal_multi_chip_info_size(); +} +inline void UwbControleeCapabilities::clear_multi_chip_info() { + multi_chip_info_.Clear(); +} +inline ::nearby::presence::UwbMultiChipInfo* UwbControleeCapabilities::mutable_multi_chip_info(int index) { + // @@protoc_insertion_point(field_mutable:nearby.presence.UwbControleeCapabilities.multi_chip_info) + return multi_chip_info_.Mutable(index); +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::nearby::presence::UwbMultiChipInfo >* +UwbControleeCapabilities::mutable_multi_chip_info() { + // @@protoc_insertion_point(field_mutable_list:nearby.presence.UwbControleeCapabilities.multi_chip_info) + return &multi_chip_info_; +} +inline const ::nearby::presence::UwbMultiChipInfo& UwbControleeCapabilities::_internal_multi_chip_info(int index) const { + return multi_chip_info_.Get(index); +} +inline const ::nearby::presence::UwbMultiChipInfo& UwbControleeCapabilities::multi_chip_info(int index) const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbControleeCapabilities.multi_chip_info) + return _internal_multi_chip_info(index); +} +inline ::nearby::presence::UwbMultiChipInfo* UwbControleeCapabilities::_internal_add_multi_chip_info() { + return multi_chip_info_.Add(); +} +inline ::nearby::presence::UwbMultiChipInfo* UwbControleeCapabilities::add_multi_chip_info() { + ::nearby::presence::UwbMultiChipInfo* _add = _internal_add_multi_chip_info(); + // @@protoc_insertion_point(field_add:nearby.presence.UwbControleeCapabilities.multi_chip_info) + return _add; +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::nearby::presence::UwbMultiChipInfo >& +UwbControleeCapabilities::multi_chip_info() const { + // @@protoc_insertion_point(field_list:nearby.presence.UwbControleeCapabilities.multi_chip_info) + return multi_chip_info_; +} + +// ------------------------------------------------------------------- + +// UwbMultiChipInfo + +// optional bytes controlee_address = 1; +inline bool UwbMultiChipInfo::_internal_has_controlee_address() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool UwbMultiChipInfo::has_controlee_address() const { + return _internal_has_controlee_address(); +} +inline void UwbMultiChipInfo::clear_controlee_address() { + controlee_address_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000001u; +} +inline const std::string& UwbMultiChipInfo::controlee_address() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbMultiChipInfo.controlee_address) + return _internal_controlee_address(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void UwbMultiChipInfo::set_controlee_address(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000001u; + controlee_address_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.UwbMultiChipInfo.controlee_address) +} +inline std::string* UwbMultiChipInfo::mutable_controlee_address() { + std::string* _s = _internal_mutable_controlee_address(); + // @@protoc_insertion_point(field_mutable:nearby.presence.UwbMultiChipInfo.controlee_address) + return _s; +} +inline const std::string& UwbMultiChipInfo::_internal_controlee_address() const { + return controlee_address_.Get(); +} +inline void UwbMultiChipInfo::_internal_set_controlee_address(const std::string& value) { + _has_bits_[0] |= 0x00000001u; + controlee_address_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* UwbMultiChipInfo::_internal_mutable_controlee_address() { + _has_bits_[0] |= 0x00000001u; + return controlee_address_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* UwbMultiChipInfo::release_controlee_address() { + // @@protoc_insertion_point(field_release:nearby.presence.UwbMultiChipInfo.controlee_address) + if (!_internal_has_controlee_address()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000001u; + auto* p = controlee_address_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (controlee_address_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + controlee_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void UwbMultiChipInfo::set_allocated_controlee_address(std::string* controlee_address) { + if (controlee_address != nullptr) { + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + controlee_address_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), controlee_address, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (controlee_address_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + controlee_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.UwbMultiChipInfo.controlee_address) +} + +// optional string chip_id = 2; +inline bool UwbMultiChipInfo::_internal_has_chip_id() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool UwbMultiChipInfo::has_chip_id() const { + return _internal_has_chip_id(); +} +inline void UwbMultiChipInfo::clear_chip_id() { + chip_id_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000002u; +} +inline const std::string& UwbMultiChipInfo::chip_id() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbMultiChipInfo.chip_id) + return _internal_chip_id(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void UwbMultiChipInfo::set_chip_id(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000002u; + chip_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.UwbMultiChipInfo.chip_id) +} +inline std::string* UwbMultiChipInfo::mutable_chip_id() { + std::string* _s = _internal_mutable_chip_id(); + // @@protoc_insertion_point(field_mutable:nearby.presence.UwbMultiChipInfo.chip_id) + return _s; +} +inline const std::string& UwbMultiChipInfo::_internal_chip_id() const { + return chip_id_.Get(); +} +inline void UwbMultiChipInfo::_internal_set_chip_id(const std::string& value) { + _has_bits_[0] |= 0x00000002u; + chip_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* UwbMultiChipInfo::_internal_mutable_chip_id() { + _has_bits_[0] |= 0x00000002u; + return chip_id_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* UwbMultiChipInfo::release_chip_id() { + // @@protoc_insertion_point(field_release:nearby.presence.UwbMultiChipInfo.chip_id) + if (!_internal_has_chip_id()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000002u; + auto* p = chip_id_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (chip_id_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + chip_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void UwbMultiChipInfo::set_allocated_chip_id(std::string* chip_id) { + if (chip_id != nullptr) { + _has_bits_[0] |= 0x00000002u; + } else { + _has_bits_[0] &= ~0x00000002u; + } + chip_id_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), chip_id, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (chip_id_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + chip_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.UwbMultiChipInfo.chip_id) +} + +// ------------------------------------------------------------------- + +// UwbConnectionInfo + +// optional bytes controller_address = 1; +inline bool UwbConnectionInfo::_internal_has_controller_address() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool UwbConnectionInfo::has_controller_address() const { + return _internal_has_controller_address(); +} +inline void UwbConnectionInfo::clear_controller_address() { + controller_address_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000001u; +} +inline const std::string& UwbConnectionInfo::controller_address() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbConnectionInfo.controller_address) + return _internal_controller_address(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void UwbConnectionInfo::set_controller_address(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000001u; + controller_address_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.UwbConnectionInfo.controller_address) +} +inline std::string* UwbConnectionInfo::mutable_controller_address() { + std::string* _s = _internal_mutable_controller_address(); + // @@protoc_insertion_point(field_mutable:nearby.presence.UwbConnectionInfo.controller_address) + return _s; +} +inline const std::string& UwbConnectionInfo::_internal_controller_address() const { + return controller_address_.Get(); +} +inline void UwbConnectionInfo::_internal_set_controller_address(const std::string& value) { + _has_bits_[0] |= 0x00000001u; + controller_address_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* UwbConnectionInfo::_internal_mutable_controller_address() { + _has_bits_[0] |= 0x00000001u; + return controller_address_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* UwbConnectionInfo::release_controller_address() { + // @@protoc_insertion_point(field_release:nearby.presence.UwbConnectionInfo.controller_address) + if (!_internal_has_controller_address()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000001u; + auto* p = controller_address_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (controller_address_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + controller_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void UwbConnectionInfo::set_allocated_controller_address(std::string* controller_address) { + if (controller_address != nullptr) { + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + controller_address_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), controller_address, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (controller_address_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + controller_address_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.UwbConnectionInfo.controller_address) +} + +// optional int32 channel = 2; +inline bool UwbConnectionInfo::_internal_has_channel() const { + bool value = (_has_bits_[0] & 0x00000010u) != 0; + return value; +} +inline bool UwbConnectionInfo::has_channel() const { + return _internal_has_channel(); +} +inline void UwbConnectionInfo::clear_channel() { + channel_ = 0; + _has_bits_[0] &= ~0x00000010u; +} +inline int32_t UwbConnectionInfo::_internal_channel() const { + return channel_; +} +inline int32_t UwbConnectionInfo::channel() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbConnectionInfo.channel) + return _internal_channel(); +} +inline void UwbConnectionInfo::_internal_set_channel(int32_t value) { + _has_bits_[0] |= 0x00000010u; + channel_ = value; +} +inline void UwbConnectionInfo::set_channel(int32_t value) { + _internal_set_channel(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbConnectionInfo.channel) +} + +// optional int32 preamble_index = 3; +inline bool UwbConnectionInfo::_internal_has_preamble_index() const { + bool value = (_has_bits_[0] & 0x00000020u) != 0; + return value; +} +inline bool UwbConnectionInfo::has_preamble_index() const { + return _internal_has_preamble_index(); +} +inline void UwbConnectionInfo::clear_preamble_index() { + preamble_index_ = 0; + _has_bits_[0] &= ~0x00000020u; +} +inline int32_t UwbConnectionInfo::_internal_preamble_index() const { + return preamble_index_; +} +inline int32_t UwbConnectionInfo::preamble_index() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbConnectionInfo.preamble_index) + return _internal_preamble_index(); +} +inline void UwbConnectionInfo::_internal_set_preamble_index(int32_t value) { + _has_bits_[0] |= 0x00000020u; + preamble_index_ = value; +} +inline void UwbConnectionInfo::set_preamble_index(int32_t value) { + _internal_set_preamble_index(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbConnectionInfo.preamble_index) +} + +// optional int32 config_id = 4; +inline bool UwbConnectionInfo::_internal_has_config_id() const { + bool value = (_has_bits_[0] & 0x00000040u) != 0; + return value; +} +inline bool UwbConnectionInfo::has_config_id() const { + return _internal_has_config_id(); +} +inline void UwbConnectionInfo::clear_config_id() { + config_id_ = 0; + _has_bits_[0] &= ~0x00000040u; +} +inline int32_t UwbConnectionInfo::_internal_config_id() const { + return config_id_; +} +inline int32_t UwbConnectionInfo::config_id() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbConnectionInfo.config_id) + return _internal_config_id(); +} +inline void UwbConnectionInfo::_internal_set_config_id(int32_t value) { + _has_bits_[0] |= 0x00000040u; + config_id_ = value; +} +inline void UwbConnectionInfo::set_config_id(int32_t value) { + _internal_set_config_id(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbConnectionInfo.config_id) +} + +// optional int32 ranging_interval_ms = 5; +inline bool UwbConnectionInfo::_internal_has_ranging_interval_ms() const { + bool value = (_has_bits_[0] & 0x00000080u) != 0; + return value; +} +inline bool UwbConnectionInfo::has_ranging_interval_ms() const { + return _internal_has_ranging_interval_ms(); +} +inline void UwbConnectionInfo::clear_ranging_interval_ms() { + ranging_interval_ms_ = 0; + _has_bits_[0] &= ~0x00000080u; +} +inline int32_t UwbConnectionInfo::_internal_ranging_interval_ms() const { + return ranging_interval_ms_; +} +inline int32_t UwbConnectionInfo::ranging_interval_ms() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbConnectionInfo.ranging_interval_ms) + return _internal_ranging_interval_ms(); +} +inline void UwbConnectionInfo::_internal_set_ranging_interval_ms(int32_t value) { + _has_bits_[0] |= 0x00000080u; + ranging_interval_ms_ = value; +} +inline void UwbConnectionInfo::set_ranging_interval_ms(int32_t value) { + _internal_set_ranging_interval_ms(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbConnectionInfo.ranging_interval_ms) +} + +// optional int32 session_id = 6; +inline bool UwbConnectionInfo::_internal_has_session_id() const { + bool value = (_has_bits_[0] & 0x00000100u) != 0; + return value; +} +inline bool UwbConnectionInfo::has_session_id() const { + return _internal_has_session_id(); +} +inline void UwbConnectionInfo::clear_session_id() { + session_id_ = 0; + _has_bits_[0] &= ~0x00000100u; +} +inline int32_t UwbConnectionInfo::_internal_session_id() const { + return session_id_; +} +inline int32_t UwbConnectionInfo::session_id() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbConnectionInfo.session_id) + return _internal_session_id(); +} +inline void UwbConnectionInfo::_internal_set_session_id(int32_t value) { + _has_bits_[0] |= 0x00000100u; + session_id_ = value; +} +inline void UwbConnectionInfo::set_session_id(int32_t value) { + _internal_set_session_id(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbConnectionInfo.session_id) +} + +// optional bytes vendor_id = 7; +inline bool UwbConnectionInfo::_internal_has_vendor_id() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool UwbConnectionInfo::has_vendor_id() const { + return _internal_has_vendor_id(); +} +inline void UwbConnectionInfo::clear_vendor_id() { + vendor_id_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000002u; +} +inline const std::string& UwbConnectionInfo::vendor_id() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbConnectionInfo.vendor_id) + return _internal_vendor_id(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void UwbConnectionInfo::set_vendor_id(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000002u; + vendor_id_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.UwbConnectionInfo.vendor_id) +} +inline std::string* UwbConnectionInfo::mutable_vendor_id() { + std::string* _s = _internal_mutable_vendor_id(); + // @@protoc_insertion_point(field_mutable:nearby.presence.UwbConnectionInfo.vendor_id) + return _s; +} +inline const std::string& UwbConnectionInfo::_internal_vendor_id() const { + return vendor_id_.Get(); +} +inline void UwbConnectionInfo::_internal_set_vendor_id(const std::string& value) { + _has_bits_[0] |= 0x00000002u; + vendor_id_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* UwbConnectionInfo::_internal_mutable_vendor_id() { + _has_bits_[0] |= 0x00000002u; + return vendor_id_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* UwbConnectionInfo::release_vendor_id() { + // @@protoc_insertion_point(field_release:nearby.presence.UwbConnectionInfo.vendor_id) + if (!_internal_has_vendor_id()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000002u; + auto* p = vendor_id_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (vendor_id_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + vendor_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void UwbConnectionInfo::set_allocated_vendor_id(std::string* vendor_id) { + if (vendor_id != nullptr) { + _has_bits_[0] |= 0x00000002u; + } else { + _has_bits_[0] &= ~0x00000002u; + } + vendor_id_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), vendor_id, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (vendor_id_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + vendor_id_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.UwbConnectionInfo.vendor_id) +} + +// optional bytes static_sts_iv = 8; +inline bool UwbConnectionInfo::_internal_has_static_sts_iv() const { + bool value = (_has_bits_[0] & 0x00000004u) != 0; + return value; +} +inline bool UwbConnectionInfo::has_static_sts_iv() const { + return _internal_has_static_sts_iv(); +} +inline void UwbConnectionInfo::clear_static_sts_iv() { + static_sts_iv_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000004u; +} +inline const std::string& UwbConnectionInfo::static_sts_iv() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbConnectionInfo.static_sts_iv) + return _internal_static_sts_iv(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void UwbConnectionInfo::set_static_sts_iv(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000004u; + static_sts_iv_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.UwbConnectionInfo.static_sts_iv) +} +inline std::string* UwbConnectionInfo::mutable_static_sts_iv() { + std::string* _s = _internal_mutable_static_sts_iv(); + // @@protoc_insertion_point(field_mutable:nearby.presence.UwbConnectionInfo.static_sts_iv) + return _s; +} +inline const std::string& UwbConnectionInfo::_internal_static_sts_iv() const { + return static_sts_iv_.Get(); +} +inline void UwbConnectionInfo::_internal_set_static_sts_iv(const std::string& value) { + _has_bits_[0] |= 0x00000004u; + static_sts_iv_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* UwbConnectionInfo::_internal_mutable_static_sts_iv() { + _has_bits_[0] |= 0x00000004u; + return static_sts_iv_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* UwbConnectionInfo::release_static_sts_iv() { + // @@protoc_insertion_point(field_release:nearby.presence.UwbConnectionInfo.static_sts_iv) + if (!_internal_has_static_sts_iv()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000004u; + auto* p = static_sts_iv_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (static_sts_iv_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + static_sts_iv_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void UwbConnectionInfo::set_allocated_static_sts_iv(std::string* static_sts_iv) { + if (static_sts_iv != nullptr) { + _has_bits_[0] |= 0x00000004u; + } else { + _has_bits_[0] &= ~0x00000004u; + } + static_sts_iv_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), static_sts_iv, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (static_sts_iv_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + static_sts_iv_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.UwbConnectionInfo.static_sts_iv) +} + +// optional bytes session_key = 9; +inline bool UwbConnectionInfo::_internal_has_session_key() const { + bool value = (_has_bits_[0] & 0x00000008u) != 0; + return value; +} +inline bool UwbConnectionInfo::has_session_key() const { + return _internal_has_session_key(); +} +inline void UwbConnectionInfo::clear_session_key() { + session_key_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000008u; +} +inline const std::string& UwbConnectionInfo::session_key() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbConnectionInfo.session_key) + return _internal_session_key(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void UwbConnectionInfo::set_session_key(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000008u; + session_key_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.UwbConnectionInfo.session_key) +} +inline std::string* UwbConnectionInfo::mutable_session_key() { + std::string* _s = _internal_mutable_session_key(); + // @@protoc_insertion_point(field_mutable:nearby.presence.UwbConnectionInfo.session_key) + return _s; +} +inline const std::string& UwbConnectionInfo::_internal_session_key() const { + return session_key_.Get(); +} +inline void UwbConnectionInfo::_internal_set_session_key(const std::string& value) { + _has_bits_[0] |= 0x00000008u; + session_key_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* UwbConnectionInfo::_internal_mutable_session_key() { + _has_bits_[0] |= 0x00000008u; + return session_key_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* UwbConnectionInfo::release_session_key() { + // @@protoc_insertion_point(field_release:nearby.presence.UwbConnectionInfo.session_key) + if (!_internal_has_session_key()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000008u; + auto* p = session_key_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (session_key_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + session_key_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void UwbConnectionInfo::set_allocated_session_key(std::string* session_key) { + if (session_key != nullptr) { + _has_bits_[0] |= 0x00000008u; + } else { + _has_bits_[0] &= ~0x00000008u; + } + session_key_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), session_key, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (session_key_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + session_key_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.UwbConnectionInfo.session_key) +} + +// optional bool ranging_disabled = 10; +inline bool UwbConnectionInfo::_internal_has_ranging_disabled() const { + bool value = (_has_bits_[0] & 0x00000200u) != 0; + return value; +} +inline bool UwbConnectionInfo::has_ranging_disabled() const { + return _internal_has_ranging_disabled(); +} +inline void UwbConnectionInfo::clear_ranging_disabled() { + ranging_disabled_ = false; + _has_bits_[0] &= ~0x00000200u; +} +inline bool UwbConnectionInfo::_internal_ranging_disabled() const { + return ranging_disabled_; +} +inline bool UwbConnectionInfo::ranging_disabled() const { + // @@protoc_insertion_point(field_get:nearby.presence.UwbConnectionInfo.ranging_disabled) + return _internal_ranging_disabled(); +} +inline void UwbConnectionInfo::_internal_set_ranging_disabled(bool value) { + _has_bits_[0] |= 0x00000200u; + ranging_disabled_ = value; +} +inline void UwbConnectionInfo::set_ranging_disabled(bool value) { + _internal_set_ranging_disabled(value); + // @@protoc_insertion_point(field_set:nearby.presence.UwbConnectionInfo.ranging_disabled) +} + +// ------------------------------------------------------------------- + +// ControlFrame + +// optional .nearby.presence.ControlFrame.ControlType type = 1; +inline bool ControlFrame::_internal_has_type() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool ControlFrame::has_type() const { + return _internal_has_type(); +} +inline void ControlFrame::clear_type() { + type_ = 0; + _has_bits_[0] &= ~0x00000001u; +} +inline ::nearby::presence::ControlFrame_ControlType ControlFrame::_internal_type() const { + return static_cast< ::nearby::presence::ControlFrame_ControlType >(type_); +} +inline ::nearby::presence::ControlFrame_ControlType ControlFrame::type() const { + // @@protoc_insertion_point(field_get:nearby.presence.ControlFrame.type) + return _internal_type(); +} +inline void ControlFrame::_internal_set_type(::nearby::presence::ControlFrame_ControlType value) { + assert(::nearby::presence::ControlFrame_ControlType_IsValid(value)); + _has_bits_[0] |= 0x00000001u; + type_ = value; +} +inline void ControlFrame::set_type(::nearby::presence::ControlFrame_ControlType value) { + _internal_set_type(value); + // @@protoc_insertion_point(field_set:nearby.presence.ControlFrame.type) +} + +// ------------------------------------------------------------------- + +// PresenceAuthenticationFrame + +// optional int32 version = 1; +inline bool PresenceAuthenticationFrame::_internal_has_version() const { + bool value = (_has_bits_[0] & 0x00000008u) != 0; + return value; +} +inline bool PresenceAuthenticationFrame::has_version() const { + return _internal_has_version(); +} +inline void PresenceAuthenticationFrame::clear_version() { + version_ = 0; + _has_bits_[0] &= ~0x00000008u; +} +inline int32_t PresenceAuthenticationFrame::_internal_version() const { + return version_; +} +inline int32_t PresenceAuthenticationFrame::version() const { + // @@protoc_insertion_point(field_get:nearby.presence.PresenceAuthenticationFrame.version) + return _internal_version(); +} +inline void PresenceAuthenticationFrame::_internal_set_version(int32_t value) { + _has_bits_[0] |= 0x00000008u; + version_ = value; +} +inline void PresenceAuthenticationFrame::set_version(int32_t value) { + _internal_set_version(value); + // @@protoc_insertion_point(field_set:nearby.presence.PresenceAuthenticationFrame.version) +} + +// optional bytes private_key_signature = 2; +inline bool PresenceAuthenticationFrame::_internal_has_private_key_signature() const { + bool value = (_has_bits_[0] & 0x00000001u) != 0; + return value; +} +inline bool PresenceAuthenticationFrame::has_private_key_signature() const { + return _internal_has_private_key_signature(); +} +inline void PresenceAuthenticationFrame::clear_private_key_signature() { + private_key_signature_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000001u; +} +inline const std::string& PresenceAuthenticationFrame::private_key_signature() const { + // @@protoc_insertion_point(field_get:nearby.presence.PresenceAuthenticationFrame.private_key_signature) + return _internal_private_key_signature(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void PresenceAuthenticationFrame::set_private_key_signature(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000001u; + private_key_signature_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.PresenceAuthenticationFrame.private_key_signature) +} +inline std::string* PresenceAuthenticationFrame::mutable_private_key_signature() { + std::string* _s = _internal_mutable_private_key_signature(); + // @@protoc_insertion_point(field_mutable:nearby.presence.PresenceAuthenticationFrame.private_key_signature) + return _s; +} +inline const std::string& PresenceAuthenticationFrame::_internal_private_key_signature() const { + return private_key_signature_.Get(); +} +inline void PresenceAuthenticationFrame::_internal_set_private_key_signature(const std::string& value) { + _has_bits_[0] |= 0x00000001u; + private_key_signature_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* PresenceAuthenticationFrame::_internal_mutable_private_key_signature() { + _has_bits_[0] |= 0x00000001u; + return private_key_signature_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* PresenceAuthenticationFrame::release_private_key_signature() { + // @@protoc_insertion_point(field_release:nearby.presence.PresenceAuthenticationFrame.private_key_signature) + if (!_internal_has_private_key_signature()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000001u; + auto* p = private_key_signature_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (private_key_signature_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + private_key_signature_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void PresenceAuthenticationFrame::set_allocated_private_key_signature(std::string* private_key_signature) { + if (private_key_signature != nullptr) { + _has_bits_[0] |= 0x00000001u; + } else { + _has_bits_[0] &= ~0x00000001u; + } + private_key_signature_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), private_key_signature, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (private_key_signature_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + private_key_signature_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.PresenceAuthenticationFrame.private_key_signature) +} + +// optional bytes shared_credential_id_hash = 3; +inline bool PresenceAuthenticationFrame::_internal_has_shared_credential_id_hash() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool PresenceAuthenticationFrame::has_shared_credential_id_hash() const { + return _internal_has_shared_credential_id_hash(); +} +inline void PresenceAuthenticationFrame::clear_shared_credential_id_hash() { + shared_credential_id_hash_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000002u; +} +inline const std::string& PresenceAuthenticationFrame::shared_credential_id_hash() const { + // @@protoc_insertion_point(field_get:nearby.presence.PresenceAuthenticationFrame.shared_credential_id_hash) + return _internal_shared_credential_id_hash(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void PresenceAuthenticationFrame::set_shared_credential_id_hash(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000002u; + shared_credential_id_hash_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.PresenceAuthenticationFrame.shared_credential_id_hash) +} +inline std::string* PresenceAuthenticationFrame::mutable_shared_credential_id_hash() { + std::string* _s = _internal_mutable_shared_credential_id_hash(); + // @@protoc_insertion_point(field_mutable:nearby.presence.PresenceAuthenticationFrame.shared_credential_id_hash) + return _s; +} +inline const std::string& PresenceAuthenticationFrame::_internal_shared_credential_id_hash() const { + return shared_credential_id_hash_.Get(); +} +inline void PresenceAuthenticationFrame::_internal_set_shared_credential_id_hash(const std::string& value) { + _has_bits_[0] |= 0x00000002u; + shared_credential_id_hash_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* PresenceAuthenticationFrame::_internal_mutable_shared_credential_id_hash() { + _has_bits_[0] |= 0x00000002u; + return shared_credential_id_hash_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* PresenceAuthenticationFrame::release_shared_credential_id_hash() { + // @@protoc_insertion_point(field_release:nearby.presence.PresenceAuthenticationFrame.shared_credential_id_hash) + if (!_internal_has_shared_credential_id_hash()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000002u; + auto* p = shared_credential_id_hash_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (shared_credential_id_hash_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + shared_credential_id_hash_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void PresenceAuthenticationFrame::set_allocated_shared_credential_id_hash(std::string* shared_credential_id_hash) { + if (shared_credential_id_hash != nullptr) { + _has_bits_[0] |= 0x00000002u; + } else { + _has_bits_[0] &= ~0x00000002u; + } + shared_credential_id_hash_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), shared_credential_id_hash, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (shared_credential_id_hash_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + shared_credential_id_hash_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.PresenceAuthenticationFrame.shared_credential_id_hash) +} + +// optional bytes credential_id_hash = 4 [deprecated = true]; +inline bool PresenceAuthenticationFrame::_internal_has_credential_id_hash() const { + bool value = (_has_bits_[0] & 0x00000004u) != 0; + return value; +} +inline bool PresenceAuthenticationFrame::has_credential_id_hash() const { + return _internal_has_credential_id_hash(); +} +inline void PresenceAuthenticationFrame::clear_credential_id_hash() { + credential_id_hash_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000004u; +} +inline const std::string& PresenceAuthenticationFrame::credential_id_hash() const { + // @@protoc_insertion_point(field_get:nearby.presence.PresenceAuthenticationFrame.credential_id_hash) + return _internal_credential_id_hash(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void PresenceAuthenticationFrame::set_credential_id_hash(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000004u; + credential_id_hash_.SetBytes(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:nearby.presence.PresenceAuthenticationFrame.credential_id_hash) +} +inline std::string* PresenceAuthenticationFrame::mutable_credential_id_hash() { + std::string* _s = _internal_mutable_credential_id_hash(); + // @@protoc_insertion_point(field_mutable:nearby.presence.PresenceAuthenticationFrame.credential_id_hash) + return _s; +} +inline const std::string& PresenceAuthenticationFrame::_internal_credential_id_hash() const { + return credential_id_hash_.Get(); +} +inline void PresenceAuthenticationFrame::_internal_set_credential_id_hash(const std::string& value) { + _has_bits_[0] |= 0x00000004u; + credential_id_hash_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* PresenceAuthenticationFrame::_internal_mutable_credential_id_hash() { + _has_bits_[0] |= 0x00000004u; + return credential_id_hash_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* PresenceAuthenticationFrame::release_credential_id_hash() { + // @@protoc_insertion_point(field_release:nearby.presence.PresenceAuthenticationFrame.credential_id_hash) + if (!_internal_has_credential_id_hash()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000004u; + auto* p = credential_id_hash_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (credential_id_hash_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + credential_id_hash_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void PresenceAuthenticationFrame::set_allocated_credential_id_hash(std::string* credential_id_hash) { + if (credential_id_hash != nullptr) { + _has_bits_[0] |= 0x00000004u; + } else { + _has_bits_[0] &= ~0x00000004u; + } + credential_id_hash_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), credential_id_hash, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (credential_id_hash_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + credential_id_hash_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:nearby.presence.PresenceAuthenticationFrame.credential_id_hash) +} + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif // __GNUC__ +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace presence +} // namespace nearby + +PROTOBUF_NAMESPACE_OPEN + +template <> struct is_proto_enum< ::nearby::presence::PresenceFrame_Version> : ::std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::nearby::presence::PresenceFrame_Version>() { + return ::nearby::presence::PresenceFrame_Version_descriptor(); +} +template <> struct is_proto_enum< ::nearby::presence::ControlFrame_ControlType> : ::std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::nearby::presence::ControlFrame_ControlType>() { + return ::nearby::presence::ControlFrame_ControlType_descriptor(); +} + +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) + +#include +#endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_presence_2fproto_2fpresence_5fframe_2eproto diff --git a/compiled_proto/proto/connections_enums.pb.cc b/compiled_proto/proto/connections_enums.pb.cc index e5fac4cc..20cd2d6f 100644 --- a/compiled_proto/proto/connections_enums.pb.cc +++ b/compiled_proto/proto/connections_enums.pb.cc @@ -1414,6 +1414,1084 @@ bool PowerLevel_Parse( } return success; } +bool OperationResultCategory_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed OperationResultCategory_strings[10] = {}; + +static const char OperationResultCategory_names[] = + "CATEGORY_CLIENT_CANCELLATION" + "CATEGORY_CLIENT_ERROR" + "CATEGORY_CONNECTIVITY_ERROR" + "CATEGORY_DEVICE_STATE_ERROR" + "CATEGORY_IO_ERROR" + "CATEGORY_MEDIUM_UNAVAILABLE" + "CATEGORY_MISCELLANEOUS" + "CATEGORY_NEARBY_ERROR" + "CATEGORY_SUCCESS" + "CATEGORY_UNKNOWN"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry OperationResultCategory_entries[] = { + { {OperationResultCategory_names + 0, 28}, 2 }, + { {OperationResultCategory_names + 28, 21}, 5 }, + { {OperationResultCategory_names + 49, 27}, 7 }, + { {OperationResultCategory_names + 76, 27}, 4 }, + { {OperationResultCategory_names + 103, 17}, 9 }, + { {OperationResultCategory_names + 120, 27}, 3 }, + { {OperationResultCategory_names + 147, 22}, 8 }, + { {OperationResultCategory_names + 169, 21}, 6 }, + { {OperationResultCategory_names + 190, 16}, 1 }, + { {OperationResultCategory_names + 206, 16}, 0 }, +}; + +static const int OperationResultCategory_entries_by_number[] = { + 9, // 0 -> CATEGORY_UNKNOWN + 8, // 1 -> CATEGORY_SUCCESS + 0, // 2 -> CATEGORY_CLIENT_CANCELLATION + 5, // 3 -> CATEGORY_MEDIUM_UNAVAILABLE + 3, // 4 -> CATEGORY_DEVICE_STATE_ERROR + 1, // 5 -> CATEGORY_CLIENT_ERROR + 7, // 6 -> CATEGORY_NEARBY_ERROR + 2, // 7 -> CATEGORY_CONNECTIVITY_ERROR + 6, // 8 -> CATEGORY_MISCELLANEOUS + 4, // 9 -> CATEGORY_IO_ERROR +}; + +const std::string& OperationResultCategory_Name( + OperationResultCategory value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + OperationResultCategory_entries, + OperationResultCategory_entries_by_number, + 10, OperationResultCategory_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + OperationResultCategory_entries, + OperationResultCategory_entries_by_number, + 10, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + OperationResultCategory_strings[idx].get(); +} +bool OperationResultCategory_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, OperationResultCategory* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + OperationResultCategory_entries, 10, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} +bool OperationResultDetail_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 500: + case 501: + case 502: + case 503: + case 504: + case 505: + case 506: + case 507: + case 508: + case 509: + case 510: + case 511: + case 512: + case 513: + case 514: + case 515: + case 516: + case 517: + case 518: + case 519: + case 520: + case 521: + case 522: + case 523: + case 1000: + case 1001: + case 1002: + case 1003: + case 1004: + case 1500: + case 1501: + case 1502: + case 1503: + case 1504: + case 1505: + case 1506: + case 1507: + case 1508: + case 1509: + case 1510: + case 1511: + case 1512: + case 1513: + case 1514: + case 1515: + case 1516: + case 1517: + case 1518: + case 1519: + case 1520: + case 1521: + case 1522: + case 1523: + case 1524: + case 1525: + case 1526: + case 1527: + case 1528: + case 1529: + case 1530: + case 1531: + case 1532: + case 1533: + case 1534: + case 1535: + case 1536: + case 1537: + case 1538: + case 2000: + case 2001: + case 2002: + case 2003: + case 2004: + case 2005: + case 2006: + case 2007: + case 2008: + case 2009: + case 2010: + case 2011: + case 2012: + case 2013: + case 2014: + case 2015: + case 2016: + case 2500: + case 2501: + case 2502: + case 2503: + case 2504: + case 2505: + case 2506: + case 2507: + case 2508: + case 2509: + case 2510: + case 2511: + case 2512: + case 3000: + case 3001: + case 3002: + case 3003: + case 3004: + case 3005: + case 3006: + case 3007: + case 3008: + case 3009: + case 3010: + case 3011: + case 3012: + case 3013: + case 3014: + case 3500: + case 3501: + case 3502: + case 3503: + case 3504: + case 3505: + case 3506: + case 3507: + case 3508: + case 3509: + case 3510: + case 3511: + case 3512: + case 3513: + case 3514: + case 3515: + case 3516: + case 3517: + case 3518: + case 3519: + case 3520: + case 3521: + case 3522: + case 3523: + case 3524: + case 3525: + case 3526: + case 3527: + case 3528: + case 3529: + case 3530: + case 3531: + case 3532: + case 3533: + case 3534: + case 3535: + case 3536: + case 3537: + case 3538: + case 3539: + case 3540: + case 3541: + case 3542: + case 3543: + case 3544: + case 3545: + case 3546: + case 3547: + case 3548: + case 3549: + case 3550: + case 3551: + case 3552: + case 3553: + case 3554: + case 3555: + case 4500: + case 4501: + case 4502: + case 4503: + case 4504: + case 4505: + case 4506: + case 4507: + case 4508: + case 4509: + case 4510: + case 4511: + case 4512: + case 4513: + case 4514: + case 4515: + case 4516: + case 4517: + case 4518: + case 4519: + case 4520: + case 4521: + case 4522: + case 4523: + case 4524: + case 4525: + case 4526: + case 4527: + case 4528: + case 4529: + case 4530: + case 4531: + case 4532: + case 4533: + case 4534: + case 4535: + case 4536: + case 4537: + case 4538: + case 4539: + case 4540: + case 4541: + case 4542: + case 4543: + case 4544: + case 4545: + case 4546: + case 4547: + case 4548: + case 4549: + case 4550: + case 4551: + case 4552: + case 4553: + case 4554: + case 4555: + case 4556: + case 4557: + case 4558: + case 4559: + case 4560: + case 4561: + case 4562: + case 4563: + case 4564: + case 4565: + case 4566: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed OperationResultDetail_strings[238] = {}; + +static const char OperationResultDetail_names[] = + "CLIENT_CANCELLATION_BT_SERVER_SOCKET_CREATION" + "CLIENT_CANCELLATION_CANCEL_BLE_OUTGOING_CONNECTION" + "CLIENT_CANCELLATION_CANCEL_BT_OUTGOING_CONNECTION" + "CLIENT_CANCELLATION_CANCEL_INCOMING_CONNECTION" + "CLIENT_CANCELLATION_CANCEL_L2CAP_OUTGOING_CONNECTION" + "CLIENT_CANCELLATION_CANCEL_LAN_OUTGOING_CONNECTION" + "CLIENT_CANCELLATION_CANCEL_NFC_OUTGOING_CONNECTION" + "CLIENT_CANCELLATION_CANCEL_OUTGOING_CONNECTION" + "CLIENT_CANCELLATION_CANCEL_USB_OUTGOING_CONNECTION" + "CLIENT_CANCELLATION_CANCEL_WEB_RTC_OUTGOING_CONNECTION" + "CLIENT_CANCELLATION_CANCEL_WIFI_AWARE_OUTGOING_CONNECTION" + "CLIENT_CANCELLATION_CANCEL_WIFI_DIRECT_OUTGOING_CONNECTION" + "CLIENT_CANCELLATION_CANCEL_WIFI_HOTSPOT_OUTGOING_CONNECTION" + "CLIENT_CANCELLATION_LOCAL_CANCEL_PAYLOAD" + "CLIENT_CANCELLATION_LOCAL_DISCONNECT" + "CLIENT_CANCELLATION_REMOTE_CANCEL_PAYLOAD" + "CLIENT_CANCELLATION_REMOTE_DISCONNECT" + "CLIENT_CANCELLATION_REMOTE_IN_CANCELED_STATE" + "CLIENT_CANCELLATION_UPGRADE_CANCELED_BY_REMOTE" + "CLIENT_CANCELLATION_WEB_RTC_SERVER_SOCKET_CREATION" + "CLIENT_CANCELLATION_WIFI_AWARE_SERVER_SOCKET_CREATION" + "CLIENT_CANCELLATION_WIFI_DIRECT_SERVER_SOCKET_CREATION" + "CLIENT_CANCELLATION_WIFI_HOTSPOT_SERVER_SOCKET_CREATION" + "CLIENT_CANCELLATION_WIFI_LAN_SERVER_SOCKET_CREATION" + "CLIENT_DUPLICATE_ACCEPTING_BLE_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_ACCEPTING_BT_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_ACCEPTING_L2CAP_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_ACCEPTING_LAN_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_ACCEPTING_NFC_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_ACCEPTING_USB_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_ACCEPTING_WEB_RTC_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_ACCEPTING_WIFI_AWARE_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_ACCEPTING_WIFI_DIRECT_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_ACCEPTING_WIFI_HOTSPOT_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_WIFI_AWARE_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_WIFI_AWARE_SUBSCRIBING_REQUEST" + "CLIENT_DUPLICATE_WIFI_DIRECT_CONNECTION_REQUEST" + "CLIENT_DUPLICATE_WIFI_HOTSPOT_CONNECTION_REQUEST" + "CLIENT_UNSUPPORTED_USB_TO_BE_UPGRADE_MEDIUM" + "CLIENT_WIFI_DIRECT_ALREADY_HOSTING_DIRECT_GROUP_FOR_THIS_CLIENT" + "CLIENT_WIFI_HOTSPOT_ALREADY_HOSTING_HOTSPOT_FOR_THIS_CLIENT" + "CONNECTIVITY_BLE_CLIENT_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_BLE_CREATE_GATT_CONNECTION_FAILURE" + "CONNECTIVITY_BLE_SERVER_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_BLUETOOTH_DEVICE_OBTAIN_FAILURE" + "CONNECTIVITY_BLUETOOTH_INVALID_CREDENTIAL" + "CONNECTIVITY_BT_CLIENT_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_BT_SERVER_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_BT_SERVER_SOCKET_CREATION_SECURITY_EXCEPTION_FAILURE" + "CONNECTIVITY_GATT_SERVER_OPEN_FAILURE" + "CONNECTIVITY_GENERIC_PAYLOAD_SENT_ERROR" + "CONNECTIVITY_GENERIC_WRITE_CLIENT_INTRODUCTION_ACK_IO_ERROR" + "CONNECTIVITY_GENERIC_WRITING_CHANNEL_IO_ERROR" + "CONNECTIVITY_L2CAP_CLIENT_OBTAIN_FAIURE" + "CONNECTIVITY_L2CAP_CLIENT_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_L2CAP_DATA_CONNECTION_FAILURE" + "CONNECTIVITY_L2CAP_SERVER_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_L2CAP_SERVER_SOCKET_CREATION_SECURITY_EXCEPTION_FAILURE" + "CONNECTIVITY_LAN_CLIENT_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_LAN_GET_NETWORK_INTERFACES_FAILURE" + "CONNECTIVITY_LAN_SERVER_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_LAN_UNREACHABLE" + "CONNECTIVITY_NFC_CLIENT_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_NFC_SERVER_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_USB_CLIENT_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_WEB_RTC_CLIENT_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_WEB_RTC_CONNECT_TO_TACHYON_FAILURE" + "CONNECTIVITY_WEB_RTC_INVALID_CREDENTIAL" + "CONNECTIVITY_WEB_RTC_SERVER_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_WIFI_AWARE_ATTACH_FAILURE" + "CONNECTIVITY_WIFI_AWARE_CLIENT_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_WIFI_AWARE_DISCOVERED_PEER_NULL" + "CONNECTIVITY_WIFI_AWARE_GET_REMOTE_IP_ADDRESS_FAILURE" + "CONNECTIVITY_WIFI_AWARE_GET_REMOTE_IP_FRAME_FAILURE" + "CONNECTIVITY_WIFI_AWARE_INVALID_CREDENTIAL" + "CONNECTIVITY_WIFI_AWARE_L2MESSAGE_NETWORK_AVAILABLE_FRAME_NULL" + "CONNECTIVITY_WIFI_AWARE_L2MESSAGE_SEND_HOST_NETWORK_FRAME_FAILURE" + "CONNECTIVITY_WIFI_AWARE_SERVER_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_WIFI_AWARE_UPDATE_PUBLISH_FAILURE" + "CONNECTIVITY_WIFI_DIRECT_CLIENT_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_WIFI_DIRECT_GET_NETWORK_INTERFACES_FAILURE" + "CONNECTIVITY_WIFI_DIRECT_INCONSISTENT_HOSTED_WIFI_BAND" + "CONNECTIVITY_WIFI_DIRECT_INVALID_CREDENTIAL" + "CONNECTIVITY_WIFI_DIRECT_P2P_CHANNEL_INITIALIZE_FAILURE" + "CONNECTIVITY_WIFI_DIRECT_P2P_GROUP_CREATION_FAILURE" + "CONNECTIVITY_WIFI_DIRECT_SERVER_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_WIFI_HOTSPOT_CLIENT_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_WIFI_HOTSPOT_GET_NETWORK_INTERFACES_FAILURE" + "CONNECTIVITY_WIFI_HOTSPOT_INCONSISTENT_HOSTED_WIFI_BAND" + "CONNECTIVITY_WIFI_HOTSPOT_INVALID_CREDENTIAL" + "CONNECTIVITY_WIFI_HOTSPOT_LOHS_CREATION_FAILURE" + "CONNECTIVITY_WIFI_HOTSPOT_P2P_CHANNEL_INITIALIZE_FAILURE" + "CONNECTIVITY_WIFI_HOTSPOT_P2P_GROUP_CREATION_FAILURE" + "CONNECTIVITY_WIFI_HOTSPOT_SERVER_SOCKET_CREATION_FAILURE" + "CONNECTIVITY_WIFI_HOTSPOT_SOFT_AP_CREATION_FAILURE" + "CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL" + "CONNECTIVITY_WIFI_LAN_IP_ADDRESS_ERROR" + "DETAIL_SUCCESS" + "DETAIL_UNKNOWN" + "DEVICE_STATE_ERROR_UNFINISHED_UPGRADE_ATTEMPTS" + "DEVICE_STATE_ERROR_USER_HOTSPOT_ENABLED" + "DEVICE_STATE_LOCATION_DISABLED" + "DEVICE_STATE_RADIO_DISABLING_FAILURE" + "DEVICE_STATE_RADIO_ENABLING_FAILURE" + "IO_ENDPOINT_IO_ERROR_ON_BLE" + "IO_ENDPOINT_IO_ERROR_ON_BT" + "IO_ENDPOINT_IO_ERROR_ON_L2CAP" + "IO_ENDPOINT_IO_ERROR_ON_LAN" + "IO_ENDPOINT_IO_ERROR_ON_NFC" + "IO_ENDPOINT_IO_ERROR_ON_USB" + "IO_ENDPOINT_IO_ERROR_ON_WEB_RTC" + "IO_ENDPOINT_IO_ERROR_ON_WIFI_AWARE" + "IO_ENDPOINT_IO_ERROR_ON_WIFI_DIRECT" + "IO_ENDPOINT_IO_ERROR_ON_WIFI_HOTSPOT" + "IO_FILE_OPENING_ERROR" + "IO_FILE_READING_ERROR" + "IO_FILE_WRITING_ERROR" + "IO_FOLDER_CREATION_ERROR" + "IO_STREAM_CREATE_PIPE_FAILURE" + "MEDIUM_UNAVAILABLE_ALREADY_HAVE_A_WIFI_DIRECT_GROUP" + "MEDIUM_UNAVAILABLE_ALREADY_HOSTING_HOTSPOT_FOR_OTHER_CLIENTS" + "MEDIUM_UNAVAILABLE_BLE_NC_LOGICAL_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_BLE_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_BLUETOOTH_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_BT_NC_LOGICAL_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_DIRECT_HOTSPOT_NOT_SUPPORT" + "MEDIUM_UNAVAILABLE_L2CAP_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_LAN_NC_LOGICAL_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_LAN_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_LOCAL_ONLY_HOTSPOT_DISRUPTIVE_FALSE" + "MEDIUM_UNAVAILABLE_LOCAL_ONLY_HOTSPOT_NOT_SUPPORT" + "MEDIUM_UNAVAILABLE_LOCAL_ONLY_HOTSPOT_NOT_SUPPORT_5G" + "MEDIUM_UNAVAILABLE_NFC_NC_LOGICAL_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_NFC_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_REJECT_L2CAP_ON_GATT_MULTIPLEX_CONNECTION" + "MEDIUM_UNAVAILABLE_SOFT_AP_DISRUPTIVE_FALSE" + "MEDIUM_UNAVAILABLE_SOFT_AP_NOT_SUPPORT" + "MEDIUM_UNAVAILABLE_UPGRADE_ON_SAME_MEDIUM" + "MEDIUM_UNAVAILABLE_UPGRADE_SKIP_BLE_LOW_QUALITY_MEDIUMS" + "MEDIUM_UNAVAILABLE_UPGRADE_SKIP_BT_LOW_QUALITY_MEDIUMS" + "MEDIUM_UNAVAILABLE_UPGRADE_SKIP_L2CAP_LOW_QUALITY_MEDIUMS" + "MEDIUM_UNAVAILABLE_UPGRADE_SKIP_LAN_LOW_QUALITY_MEDIUMS" + "MEDIUM_UNAVAILABLE_UPGRADE_SKIP_USB_LOW_QUALITY_MEDIUMS" + "MEDIUM_UNAVAILABLE_UPGRADE_SKIP_WEB_RTC_LOW_QUALITY_MEDIUMS" + "MEDIUM_UNAVAILABLE_USB_NC_LOGICAL_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_USB_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_WEB_RTC_NC_LOGICAL_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_WEB_RTC_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_WEB_RTC_NO_INTERNET" + "MEDIUM_UNAVAILABLE_WIFI_AWARE_NC_LOGICAL_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_WIFI_AWARE_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_WIFI_AWARE_RESOURCE_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_WIFI_DIRECT_NC_LOGICAL_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_WIFI_DIRECT_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_WIFI_DIRECT_P2P_RESOURCE_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_WIFI_HOTSPOT_NC_LOGICAL_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_WIFI_HOTSPOT_NOT_AVAILABLE" + "MEDIUM_UNAVAILABLE_WIFI_HOTSPOT_P2P_RESOURCE_NOT_AVAILABLE" + "MISCELLEANEOUS_BLE_SYSTEM_SERVICE_NULL" + "MISCELLEANEOUS_BLUETOOTH_MAC_ADDRESS_NULL" + "MISCELLEANEOUS_BT_NOT_ACCEPTING_CONNECTION_FOR_WORK_PROFILE" + "MISCELLEANEOUS_BT_SYSTEM_SERVICE_NULL" + "MISCELLEANEOUS_L2CAP_SYSTEM_SERVICE_NULL" + "MISCELLEANEOUS_MOVE_TO_NEW_MEDIUM" + "MISCELLEANEOUS_WEB_RTC_GET_DROIDGUARD_RESULT_FAILURE" + "MISCELLEANEOUS_WEB_RTC_TACHYON_SIGNALING_MESSENGER_NULL" + "MISCELLEANEOUS_WIFI_AWARE_SYSTEM_SERVICE_NULL" + "MISCELLEANEOUS_WIFI_DIRECT_SYSTEM_SERVICE_NULL" + "MISCELLEANEOUS_WIFI_HOTSPOT_SOFT_AP_BLOCKED_BY_PROVISION" + "MISCELLEANEOUS_WIFI_HOTSPOT_SYSTEM_SERVICE_NULL" + "MISCELLEANEOUS_WIFI_LAN_SYSTEM_SERVICE_NULL" + "NEARBY_BLE_ADVERTISEMENT_MAPPING_TO_MAC_ERROR" + "NEARBY_BLE_ENDPOINT_CHANNEL_CREATION_FAILURE" + "NEARBY_BLE_GATT_ADVERTISEMENT_NULL_FOR_CONNECTION" + "NEARBY_BLE_GATT_NULL_CALLBACK" + "NEARBY_BLE_OPERATION_REGISTERED_FAILED" + "NEARBY_BLUETOOTH_MAC_ADDRESS_INVALID_FOR_CONNECT" + "NEARBY_BT_ENDPOINT_CHANNEL_CREATION_FAILURE" + "NEARBY_BT_MULTIPLEX_SOCKET_DISABLED" + "NEARBY_BT_NULL_CALLBACK" + "NEARBY_BT_OPERATION_REGISTERED_FAILED" + "NEARBY_BT_VIRTUAL_SOCKET_CREATION_FAILURE" + "NEARBY_GENERIC_CONNECTION_CLOSED" + "NEARBY_GENERIC_ENDPOINT_UNENCRYPTED" + "NEARBY_GENERIC_INCOMING_PAYLOAD_NOT_DATA_TYPE" + "NEARBY_GENERIC_NEW_ENDPOINT_CHANNEL_NULL" + "NEARBY_GENERIC_OLD_ENDPOINT_CHANNEL_NULL" + "NEARBY_GENERIC_OUTGOING_PAYLOAD_CREATION_FAILURE" + "NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_ACK_EVENT_TYPE_ERROR" + "NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_ACK_FORMAT_ERROR" + "NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_ACK_FRAME_TYPE_ERROR" + "NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_EVENT_TYPE_ERROR" + "NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_FORMAT_ERROR" + "NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_FRAME_TYPE_ERROR" + "NEARBY_GENERIC_REMOTE_ENDPOINT_STATUS_ERROR" + "NEARBY_GENERIC_REMOTE_REPORT_PAYLOADS_ERROR" + "NEARBY_GENERIC_REMOTE_UPGRADE_FAILURE" + "NEARBY_GENERIC_SEND_PAYLOAD_EXECUTOR_NULL" + "NEARBY_L2CAP_ENDPOINT_CHANNEL_CREATION_FAILURE" + "NEARBY_L2CAP_NULL_CALLBACK" + "NEARBY_L2CAP_OPERATION_REGISTERED_FAILED" + "NEARBY_L2CAP_PSM_NOT_POSITIVE" + "NEARBY_LAN_ENDPOINT_CHANNEL_CREATION_FAILURE" + "NEARBY_LAN_MULTIPLEX_SOCKET_DISABLED" + "NEARBY_LAN_NULL_CALLBACK" + "NEARBY_LAN_OPERATION_REGISTERED_FAILED" + "NEARBY_LAN_VIRTUAL_SOCKET_CREATION_FAILURE" + "NEARBY_NFC_ENDPOINT_CHANNEL_CREATION_FAILURE" + "NEARBY_NFC_NULL_CALLBACK" + "NEARBY_USB_ENDPOINT_CHANNEL_CREATION_FAILURE" + "NEARBY_USB_NULL_CALLBACK" + "NEARBY_WEB_RTC_CONNECTION_FLOW_NULL" + "NEARBY_WEB_RTC_ENDPOINT_CHANNEL_CREATION_FAILURE" + "NEARBY_WEB_RTC_NULL_CALLBACK" + "NEARBY_WEB_RTC_OPERATION_REGISTERED_FAILED" + "NEARBY_WIFI_AWARE_ENDPOINT_CHANNEL_CREATION_FAILURE" + "NEARBY_WIFI_AWARE_NULL_CALLBACK" + "NEARBY_WIFI_AWARE_OPERATION_REGISTERED_FAILED" + "NEARBY_WIFI_DIRECT_ENDPOINT_CHANNEL_CREATION_FAILURE" + "NEARBY_WIFI_DIRECT_HOST_ON_SRD_CHANNELS" + "NEARBY_WIFI_DIRECT_NO_GROUP_FOR_LISTENING" + "NEARBY_WIFI_DIRECT_NULL_CALLBACK" + "NEARBY_WIFI_DIRECT_NULL_PASSWORD" + "NEARBY_WIFI_DIRECT_NULL_SSID" + "NEARBY_WIFI_DIRECT_OPERATION_REGISTERED_FAILED" + "NEARBY_WIFI_DIRECT_P2P_NON_DBS_WANT_2G_BUT_AP_5G" + "NEARBY_WIFI_DIRECT_P2P_NON_DBS_WANT_5G_BUT_AP_2G" + "NEARBY_WIFI_HOTSPOT_CLIENT_OPERATION_REGISTERED_FAILED" + "NEARBY_WIFI_HOTSPOT_DIRECT_OPERATION_REGISTERED_FAILED" + "NEARBY_WIFI_HOTSPOT_ENDPOINT_CHANNEL_CREATION_FAILURE" + "NEARBY_WIFI_HOTSPOT_HOST_ON_SRD_CHANNELS" + "NEARBY_WIFI_HOTSPOT_LOHS_OPERATION_REGISTERED_FAILED" + "NEARBY_WIFI_HOTSPOT_NO_HOTSPOT_FOR_LISTENING" + "NEARBY_WIFI_HOTSPOT_NULL_CALLBACK" + "NEARBY_WIFI_HOTSPOT_P2P_NON_DBS_WANT_2G_BUT_AP_5G" + "NEARBY_WIFI_HOTSPOT_P2P_NON_DBS_WANT_5G_BUT_AP_2G" + "NEARBY_WIFI_HOTSPOT_SOFT_AP_OPERATION_REGISTERED_FAILED" + "NEARBY_WIFI_LAN_IP_ADDRESS_ERROR"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry OperationResultDetail_entries[] = { + { {OperationResultDetail_names + 0, 45}, 519 }, + { {OperationResultDetail_names + 45, 50}, 504 }, + { {OperationResultDetail_names + 95, 49}, 505 }, + { {OperationResultDetail_names + 144, 46}, 515 }, + { {OperationResultDetail_names + 190, 52}, 506 }, + { {OperationResultDetail_names + 242, 50}, 507 }, + { {OperationResultDetail_names + 292, 50}, 508 }, + { {OperationResultDetail_names + 342, 46}, 514 }, + { {OperationResultDetail_names + 388, 50}, 509 }, + { {OperationResultDetail_names + 438, 54}, 513 }, + { {OperationResultDetail_names + 492, 57}, 510 }, + { {OperationResultDetail_names + 549, 58}, 511 }, + { {OperationResultDetail_names + 607, 59}, 512 }, + { {OperationResultDetail_names + 666, 40}, 501 }, + { {OperationResultDetail_names + 706, 36}, 522 }, + { {OperationResultDetail_names + 742, 41}, 502 }, + { {OperationResultDetail_names + 783, 37}, 523 }, + { {OperationResultDetail_names + 820, 44}, 500 }, + { {OperationResultDetail_names + 864, 46}, 503 }, + { {OperationResultDetail_names + 910, 50}, 520 }, + { {OperationResultDetail_names + 960, 53}, 516 }, + { {OperationResultDetail_names + 1013, 54}, 517 }, + { {OperationResultDetail_names + 1067, 55}, 518 }, + { {OperationResultDetail_names + 1122, 51}, 521 }, + { {OperationResultDetail_names + 1173, 49}, 2002 }, + { {OperationResultDetail_names + 1222, 48}, 2004 }, + { {OperationResultDetail_names + 1270, 51}, 2003 }, + { {OperationResultDetail_names + 1321, 49}, 2005 }, + { {OperationResultDetail_names + 1370, 49}, 2006 }, + { {OperationResultDetail_names + 1419, 49}, 2011 }, + { {OperationResultDetail_names + 1468, 53}, 2007 }, + { {OperationResultDetail_names + 1521, 56}, 2008 }, + { {OperationResultDetail_names + 1577, 57}, 2010 }, + { {OperationResultDetail_names + 1634, 58}, 2009 }, + { {OperationResultDetail_names + 1692, 46}, 2012 }, + { {OperationResultDetail_names + 1738, 47}, 2015 }, + { {OperationResultDetail_names + 1785, 47}, 2013 }, + { {OperationResultDetail_names + 1832, 48}, 2014 }, + { {OperationResultDetail_names + 1880, 43}, 2016 }, + { {OperationResultDetail_names + 1923, 63}, 2000 }, + { {OperationResultDetail_names + 1986, 59}, 2001 }, + { {OperationResultDetail_names + 2045, 47}, 3502 }, + { {OperationResultDetail_names + 2092, 47}, 3513 }, + { {OperationResultDetail_names + 2139, 47}, 3539 }, + { {OperationResultDetail_names + 2186, 44}, 3501 }, + { {OperationResultDetail_names + 2230, 41}, 3518 }, + { {OperationResultDetail_names + 2271, 46}, 3504 }, + { {OperationResultDetail_names + 2317, 46}, 3541 }, + { {OperationResultDetail_names + 2363, 65}, 3555 }, + { {OperationResultDetail_names + 2428, 37}, 3538 }, + { {OperationResultDetail_names + 2465, 39}, 3553 }, + { {OperationResultDetail_names + 2504, 59}, 3551 }, + { {OperationResultDetail_names + 2563, 45}, 3550 }, + { {OperationResultDetail_names + 2608, 39}, 3525 }, + { {OperationResultDetail_names + 2647, 49}, 3503 }, + { {OperationResultDetail_names + 2696, 42}, 3526 }, + { {OperationResultDetail_names + 2738, 49}, 3540 }, + { {OperationResultDetail_names + 2787, 68}, 3554 }, + { {OperationResultDetail_names + 2855, 47}, 3505 }, + { {OperationResultDetail_names + 2902, 47}, 3531 }, + { {OperationResultDetail_names + 2949, 47}, 3542 }, + { {OperationResultDetail_names + 2996, 28}, 3529 }, + { {OperationResultDetail_names + 3024, 47}, 3506 }, + { {OperationResultDetail_names + 3071, 47}, 3547 }, + { {OperationResultDetail_names + 3118, 47}, 3511 }, + { {OperationResultDetail_names + 3165, 51}, 3507 }, + { {OperationResultDetail_names + 3216, 47}, 3512 }, + { {OperationResultDetail_names + 3263, 39}, 3523 }, + { {OperationResultDetail_names + 3302, 51}, 3543 }, + { {OperationResultDetail_names + 3353, 38}, 3500 }, + { {OperationResultDetail_names + 3391, 54}, 3508 }, + { {OperationResultDetail_names + 3445, 44}, 3552 }, + { {OperationResultDetail_names + 3489, 53}, 3515 }, + { {OperationResultDetail_names + 3542, 51}, 3514 }, + { {OperationResultDetail_names + 3593, 42}, 3522 }, + { {OperationResultDetail_names + 3635, 62}, 3527 }, + { {OperationResultDetail_names + 3697, 65}, 3528 }, + { {OperationResultDetail_names + 3762, 54}, 3544 }, + { {OperationResultDetail_names + 3816, 46}, 3549 }, + { {OperationResultDetail_names + 3862, 55}, 3510 }, + { {OperationResultDetail_names + 3917, 55}, 3532 }, + { {OperationResultDetail_names + 3972, 54}, 3516 }, + { {OperationResultDetail_names + 4026, 43}, 3520 }, + { {OperationResultDetail_names + 4069, 55}, 3535 }, + { {OperationResultDetail_names + 4124, 51}, 3537 }, + { {OperationResultDetail_names + 4175, 55}, 3546 }, + { {OperationResultDetail_names + 4230, 56}, 3509 }, + { {OperationResultDetail_names + 4286, 56}, 3533 }, + { {OperationResultDetail_names + 4342, 55}, 3517 }, + { {OperationResultDetail_names + 4397, 44}, 3521 }, + { {OperationResultDetail_names + 4441, 47}, 3530 }, + { {OperationResultDetail_names + 4488, 56}, 3534 }, + { {OperationResultDetail_names + 4544, 52}, 3536 }, + { {OperationResultDetail_names + 4596, 56}, 3545 }, + { {OperationResultDetail_names + 4652, 50}, 3548 }, + { {OperationResultDetail_names + 4702, 40}, 3519 }, + { {OperationResultDetail_names + 4742, 38}, 3524 }, + { {OperationResultDetail_names + 4780, 14}, 1 }, + { {OperationResultDetail_names + 4794, 14}, 0 }, + { {OperationResultDetail_names + 4808, 46}, 1000 }, + { {OperationResultDetail_names + 4854, 39}, 1001 }, + { {OperationResultDetail_names + 4893, 30}, 1002 }, + { {OperationResultDetail_names + 4923, 36}, 1003 }, + { {OperationResultDetail_names + 4959, 35}, 1004 }, + { {OperationResultDetail_names + 4994, 27}, 3005 }, + { {OperationResultDetail_names + 5021, 26}, 3007 }, + { {OperationResultDetail_names + 5047, 29}, 3006 }, + { {OperationResultDetail_names + 5076, 27}, 3009 }, + { {OperationResultDetail_names + 5103, 27}, 3013 }, + { {OperationResultDetail_names + 5130, 27}, 3014 }, + { {OperationResultDetail_names + 5157, 31}, 3008 }, + { {OperationResultDetail_names + 5188, 34}, 3012 }, + { {OperationResultDetail_names + 5222, 35}, 3010 }, + { {OperationResultDetail_names + 5257, 36}, 3011 }, + { {OperationResultDetail_names + 5293, 21}, 3000 }, + { {OperationResultDetail_names + 5314, 21}, 3001 }, + { {OperationResultDetail_names + 5335, 21}, 3002 }, + { {OperationResultDetail_names + 5356, 24}, 3003 }, + { {OperationResultDetail_names + 5380, 29}, 3004 }, + { {OperationResultDetail_names + 5409, 51}, 1534 }, + { {OperationResultDetail_names + 5460, 60}, 1535 }, + { {OperationResultDetail_names + 5520, 47}, 1515 }, + { {OperationResultDetail_names + 5567, 36}, 1505 }, + { {OperationResultDetail_names + 5603, 42}, 1507 }, + { {OperationResultDetail_names + 5645, 46}, 1516 }, + { {OperationResultDetail_names + 5691, 45}, 1501 }, + { {OperationResultDetail_names + 5736, 38}, 1506 }, + { {OperationResultDetail_names + 5774, 47}, 1517 }, + { {OperationResultDetail_names + 5821, 36}, 1513 }, + { {OperationResultDetail_names + 5857, 54}, 1532 }, + { {OperationResultDetail_names + 5911, 49}, 1503 }, + { {OperationResultDetail_names + 5960, 52}, 1504 }, + { {OperationResultDetail_names + 6012, 47}, 1518 }, + { {OperationResultDetail_names + 6059, 36}, 1512 }, + { {OperationResultDetail_names + 6095, 60}, 1536 }, + { {OperationResultDetail_names + 6155, 43}, 1533 }, + { {OperationResultDetail_names + 6198, 38}, 1502 }, + { {OperationResultDetail_names + 6236, 41}, 1537 }, + { {OperationResultDetail_names + 6277, 55}, 1526 }, + { {OperationResultDetail_names + 6332, 54}, 1530 }, + { {OperationResultDetail_names + 6386, 57}, 1527 }, + { {OperationResultDetail_names + 6443, 55}, 1529 }, + { {OperationResultDetail_names + 6498, 55}, 1531 }, + { {OperationResultDetail_names + 6553, 59}, 1528 }, + { {OperationResultDetail_names + 6612, 47}, 1519 }, + { {OperationResultDetail_names + 6659, 36}, 1514 }, + { {OperationResultDetail_names + 6695, 51}, 1520 }, + { {OperationResultDetail_names + 6746, 40}, 1508 }, + { {OperationResultDetail_names + 6786, 38}, 1538 }, + { {OperationResultDetail_names + 6824, 54}, 1521 }, + { {OperationResultDetail_names + 6878, 43}, 1509 }, + { {OperationResultDetail_names + 6921, 52}, 1500 }, + { {OperationResultDetail_names + 6973, 55}, 1523 }, + { {OperationResultDetail_names + 7028, 44}, 1511 }, + { {OperationResultDetail_names + 7072, 57}, 1525 }, + { {OperationResultDetail_names + 7129, 56}, 1522 }, + { {OperationResultDetail_names + 7185, 45}, 1510 }, + { {OperationResultDetail_names + 7230, 58}, 1524 }, + { {OperationResultDetail_names + 7288, 38}, 2503 }, + { {OperationResultDetail_names + 7326, 41}, 2500 }, + { {OperationResultDetail_names + 7367, 59}, 2510 }, + { {OperationResultDetail_names + 7426, 37}, 2505 }, + { {OperationResultDetail_names + 7463, 40}, 2504 }, + { {OperationResultDetail_names + 7503, 33}, 2501 }, + { {OperationResultDetail_names + 7536, 52}, 2511 }, + { {OperationResultDetail_names + 7588, 55}, 2512 }, + { {OperationResultDetail_names + 7643, 45}, 2506 }, + { {OperationResultDetail_names + 7688, 46}, 2507 }, + { {OperationResultDetail_names + 7734, 56}, 2502 }, + { {OperationResultDetail_names + 7790, 47}, 2509 }, + { {OperationResultDetail_names + 7837, 43}, 2508 }, + { {OperationResultDetail_names + 7880, 45}, 4500 }, + { {OperationResultDetail_names + 7925, 44}, 4504 }, + { {OperationResultDetail_names + 7969, 49}, 4515 }, + { {OperationResultDetail_names + 8018, 29}, 4518 }, + { {OperationResultDetail_names + 8047, 38}, 4536 }, + { {OperationResultDetail_names + 8085, 48}, 4501 }, + { {OperationResultDetail_names + 8133, 43}, 4506 }, + { {OperationResultDetail_names + 8176, 35}, 4530 }, + { {OperationResultDetail_names + 8211, 23}, 4520 }, + { {OperationResultDetail_names + 8234, 37}, 4538 }, + { {OperationResultDetail_names + 8271, 41}, 4563 }, + { {OperationResultDetail_names + 8312, 32}, 4503 }, + { {OperationResultDetail_names + 8344, 35}, 4514 }, + { {OperationResultDetail_names + 8379, 45}, 4552 }, + { {OperationResultDetail_names + 8424, 40}, 4532 }, + { {OperationResultDetail_names + 8464, 40}, 4535 }, + { {OperationResultDetail_names + 8504, 48}, 4547 }, + { {OperationResultDetail_names + 8552, 60}, 4556 }, + { {OperationResultDetail_names + 8612, 56}, 4558 }, + { {OperationResultDetail_names + 8668, 60}, 4557 }, + { {OperationResultDetail_names + 8728, 56}, 4553 }, + { {OperationResultDetail_names + 8784, 52}, 4555 }, + { {OperationResultDetail_names + 8836, 56}, 4554 }, + { {OperationResultDetail_names + 8892, 43}, 4559 }, + { {OperationResultDetail_names + 8935, 43}, 4560 }, + { {OperationResultDetail_names + 8978, 37}, 4561 }, + { {OperationResultDetail_names + 9015, 41}, 4562 }, + { {OperationResultDetail_names + 9056, 46}, 4505 }, + { {OperationResultDetail_names + 9102, 26}, 4519 }, + { {OperationResultDetail_names + 9128, 40}, 4537 }, + { {OperationResultDetail_names + 9168, 29}, 4566 }, + { {OperationResultDetail_names + 9197, 44}, 4507 }, + { {OperationResultDetail_names + 9241, 36}, 4531 }, + { {OperationResultDetail_names + 9277, 24}, 4525 }, + { {OperationResultDetail_names + 9301, 38}, 4539 }, + { {OperationResultDetail_names + 9339, 42}, 4564 }, + { {OperationResultDetail_names + 9381, 44}, 4508 }, + { {OperationResultDetail_names + 9425, 24}, 4522 }, + { {OperationResultDetail_names + 9449, 44}, 4513 }, + { {OperationResultDetail_names + 9493, 24}, 4521 }, + { {OperationResultDetail_names + 9517, 35}, 4502 }, + { {OperationResultDetail_names + 9552, 48}, 4512 }, + { {OperationResultDetail_names + 9600, 28}, 4524 }, + { {OperationResultDetail_names + 9628, 42}, 4540 }, + { {OperationResultDetail_names + 9670, 51}, 4509 }, + { {OperationResultDetail_names + 9721, 31}, 4523 }, + { {OperationResultDetail_names + 9752, 45}, 4541 }, + { {OperationResultDetail_names + 9797, 52}, 4511 }, + { {OperationResultDetail_names + 9849, 39}, 4516 }, + { {OperationResultDetail_names + 9888, 41}, 4533 }, + { {OperationResultDetail_names + 9929, 32}, 4527 }, + { {OperationResultDetail_names + 9961, 32}, 4529 }, + { {OperationResultDetail_names + 9993, 28}, 4528 }, + { {OperationResultDetail_names + 10021, 46}, 4546 }, + { {OperationResultDetail_names + 10067, 48}, 4549 }, + { {OperationResultDetail_names + 10115, 48}, 4551 }, + { {OperationResultDetail_names + 10163, 54}, 4545 }, + { {OperationResultDetail_names + 10217, 54}, 4542 }, + { {OperationResultDetail_names + 10271, 53}, 4510 }, + { {OperationResultDetail_names + 10324, 40}, 4517 }, + { {OperationResultDetail_names + 10364, 52}, 4544 }, + { {OperationResultDetail_names + 10416, 44}, 4534 }, + { {OperationResultDetail_names + 10460, 33}, 4526 }, + { {OperationResultDetail_names + 10493, 49}, 4548 }, + { {OperationResultDetail_names + 10542, 49}, 4550 }, + { {OperationResultDetail_names + 10591, 55}, 4543 }, + { {OperationResultDetail_names + 10646, 32}, 4565 }, +}; + +static const int OperationResultDetail_entries_by_number[] = { + 98, // 0 -> DETAIL_UNKNOWN + 97, // 1 -> DETAIL_SUCCESS + 17, // 500 -> CLIENT_CANCELLATION_REMOTE_IN_CANCELED_STATE + 13, // 501 -> CLIENT_CANCELLATION_LOCAL_CANCEL_PAYLOAD + 15, // 502 -> CLIENT_CANCELLATION_REMOTE_CANCEL_PAYLOAD + 18, // 503 -> CLIENT_CANCELLATION_UPGRADE_CANCELED_BY_REMOTE + 1, // 504 -> CLIENT_CANCELLATION_CANCEL_BLE_OUTGOING_CONNECTION + 2, // 505 -> CLIENT_CANCELLATION_CANCEL_BT_OUTGOING_CONNECTION + 4, // 506 -> CLIENT_CANCELLATION_CANCEL_L2CAP_OUTGOING_CONNECTION + 5, // 507 -> CLIENT_CANCELLATION_CANCEL_LAN_OUTGOING_CONNECTION + 6, // 508 -> CLIENT_CANCELLATION_CANCEL_NFC_OUTGOING_CONNECTION + 8, // 509 -> CLIENT_CANCELLATION_CANCEL_USB_OUTGOING_CONNECTION + 10, // 510 -> CLIENT_CANCELLATION_CANCEL_WIFI_AWARE_OUTGOING_CONNECTION + 11, // 511 -> CLIENT_CANCELLATION_CANCEL_WIFI_DIRECT_OUTGOING_CONNECTION + 12, // 512 -> CLIENT_CANCELLATION_CANCEL_WIFI_HOTSPOT_OUTGOING_CONNECTION + 9, // 513 -> CLIENT_CANCELLATION_CANCEL_WEB_RTC_OUTGOING_CONNECTION + 7, // 514 -> CLIENT_CANCELLATION_CANCEL_OUTGOING_CONNECTION + 3, // 515 -> CLIENT_CANCELLATION_CANCEL_INCOMING_CONNECTION + 20, // 516 -> CLIENT_CANCELLATION_WIFI_AWARE_SERVER_SOCKET_CREATION + 21, // 517 -> CLIENT_CANCELLATION_WIFI_DIRECT_SERVER_SOCKET_CREATION + 22, // 518 -> CLIENT_CANCELLATION_WIFI_HOTSPOT_SERVER_SOCKET_CREATION + 0, // 519 -> CLIENT_CANCELLATION_BT_SERVER_SOCKET_CREATION + 19, // 520 -> CLIENT_CANCELLATION_WEB_RTC_SERVER_SOCKET_CREATION + 23, // 521 -> CLIENT_CANCELLATION_WIFI_LAN_SERVER_SOCKET_CREATION + 14, // 522 -> CLIENT_CANCELLATION_LOCAL_DISCONNECT + 16, // 523 -> CLIENT_CANCELLATION_REMOTE_DISCONNECT + 99, // 1000 -> DEVICE_STATE_ERROR_UNFINISHED_UPGRADE_ATTEMPTS + 100, // 1001 -> DEVICE_STATE_ERROR_USER_HOTSPOT_ENABLED + 101, // 1002 -> DEVICE_STATE_LOCATION_DISABLED + 102, // 1003 -> DEVICE_STATE_RADIO_DISABLING_FAILURE + 103, // 1004 -> DEVICE_STATE_RADIO_ENABLING_FAILURE + 151, // 1500 -> MEDIUM_UNAVAILABLE_WIFI_AWARE_RESOURCE_NOT_AVAILABLE + 125, // 1501 -> MEDIUM_UNAVAILABLE_DIRECT_HOTSPOT_NOT_SUPPORT + 136, // 1502 -> MEDIUM_UNAVAILABLE_SOFT_AP_NOT_SUPPORT + 130, // 1503 -> MEDIUM_UNAVAILABLE_LOCAL_ONLY_HOTSPOT_NOT_SUPPORT + 131, // 1504 -> MEDIUM_UNAVAILABLE_LOCAL_ONLY_HOTSPOT_NOT_SUPPORT_5G + 122, // 1505 -> MEDIUM_UNAVAILABLE_BLE_NOT_AVAILABLE + 126, // 1506 -> MEDIUM_UNAVAILABLE_L2CAP_NOT_AVAILABLE + 123, // 1507 -> MEDIUM_UNAVAILABLE_BLUETOOTH_NOT_AVAILABLE + 147, // 1508 -> MEDIUM_UNAVAILABLE_WEB_RTC_NOT_AVAILABLE + 150, // 1509 -> MEDIUM_UNAVAILABLE_WIFI_AWARE_NOT_AVAILABLE + 156, // 1510 -> MEDIUM_UNAVAILABLE_WIFI_HOTSPOT_NOT_AVAILABLE + 153, // 1511 -> MEDIUM_UNAVAILABLE_WIFI_DIRECT_NOT_AVAILABLE + 133, // 1512 -> MEDIUM_UNAVAILABLE_NFC_NOT_AVAILABLE + 128, // 1513 -> MEDIUM_UNAVAILABLE_LAN_NOT_AVAILABLE + 145, // 1514 -> MEDIUM_UNAVAILABLE_USB_NOT_AVAILABLE + 121, // 1515 -> MEDIUM_UNAVAILABLE_BLE_NC_LOGICAL_NOT_AVAILABLE + 124, // 1516 -> MEDIUM_UNAVAILABLE_BT_NC_LOGICAL_NOT_AVAILABLE + 127, // 1517 -> MEDIUM_UNAVAILABLE_LAN_NC_LOGICAL_NOT_AVAILABLE + 132, // 1518 -> MEDIUM_UNAVAILABLE_NFC_NC_LOGICAL_NOT_AVAILABLE + 144, // 1519 -> MEDIUM_UNAVAILABLE_USB_NC_LOGICAL_NOT_AVAILABLE + 146, // 1520 -> MEDIUM_UNAVAILABLE_WEB_RTC_NC_LOGICAL_NOT_AVAILABLE + 149, // 1521 -> MEDIUM_UNAVAILABLE_WIFI_AWARE_NC_LOGICAL_NOT_AVAILABLE + 155, // 1522 -> MEDIUM_UNAVAILABLE_WIFI_HOTSPOT_NC_LOGICAL_NOT_AVAILABLE + 152, // 1523 -> MEDIUM_UNAVAILABLE_WIFI_DIRECT_NC_LOGICAL_NOT_AVAILABLE + 157, // 1524 -> MEDIUM_UNAVAILABLE_WIFI_HOTSPOT_P2P_RESOURCE_NOT_AVAILABLE + 154, // 1525 -> MEDIUM_UNAVAILABLE_WIFI_DIRECT_P2P_RESOURCE_NOT_AVAILABLE + 138, // 1526 -> MEDIUM_UNAVAILABLE_UPGRADE_SKIP_BLE_LOW_QUALITY_MEDIUMS + 140, // 1527 -> MEDIUM_UNAVAILABLE_UPGRADE_SKIP_L2CAP_LOW_QUALITY_MEDIUMS + 143, // 1528 -> MEDIUM_UNAVAILABLE_UPGRADE_SKIP_WEB_RTC_LOW_QUALITY_MEDIUMS + 141, // 1529 -> MEDIUM_UNAVAILABLE_UPGRADE_SKIP_LAN_LOW_QUALITY_MEDIUMS + 139, // 1530 -> MEDIUM_UNAVAILABLE_UPGRADE_SKIP_BT_LOW_QUALITY_MEDIUMS + 142, // 1531 -> MEDIUM_UNAVAILABLE_UPGRADE_SKIP_USB_LOW_QUALITY_MEDIUMS + 129, // 1532 -> MEDIUM_UNAVAILABLE_LOCAL_ONLY_HOTSPOT_DISRUPTIVE_FALSE + 135, // 1533 -> MEDIUM_UNAVAILABLE_SOFT_AP_DISRUPTIVE_FALSE + 119, // 1534 -> MEDIUM_UNAVAILABLE_ALREADY_HAVE_A_WIFI_DIRECT_GROUP + 120, // 1535 -> MEDIUM_UNAVAILABLE_ALREADY_HOSTING_HOTSPOT_FOR_OTHER_CLIENTS + 134, // 1536 -> MEDIUM_UNAVAILABLE_REJECT_L2CAP_ON_GATT_MULTIPLEX_CONNECTION + 137, // 1537 -> MEDIUM_UNAVAILABLE_UPGRADE_ON_SAME_MEDIUM + 148, // 1538 -> MEDIUM_UNAVAILABLE_WEB_RTC_NO_INTERNET + 39, // 2000 -> CLIENT_WIFI_DIRECT_ALREADY_HOSTING_DIRECT_GROUP_FOR_THIS_CLIENT + 40, // 2001 -> CLIENT_WIFI_HOTSPOT_ALREADY_HOSTING_HOTSPOT_FOR_THIS_CLIENT + 24, // 2002 -> CLIENT_DUPLICATE_ACCEPTING_BLE_CONNECTION_REQUEST + 26, // 2003 -> CLIENT_DUPLICATE_ACCEPTING_L2CAP_CONNECTION_REQUEST + 25, // 2004 -> CLIENT_DUPLICATE_ACCEPTING_BT_CONNECTION_REQUEST + 27, // 2005 -> CLIENT_DUPLICATE_ACCEPTING_LAN_CONNECTION_REQUEST + 28, // 2006 -> CLIENT_DUPLICATE_ACCEPTING_NFC_CONNECTION_REQUEST + 30, // 2007 -> CLIENT_DUPLICATE_ACCEPTING_WEB_RTC_CONNECTION_REQUEST + 31, // 2008 -> CLIENT_DUPLICATE_ACCEPTING_WIFI_AWARE_CONNECTION_REQUEST + 33, // 2009 -> CLIENT_DUPLICATE_ACCEPTING_WIFI_HOTSPOT_CONNECTION_REQUEST + 32, // 2010 -> CLIENT_DUPLICATE_ACCEPTING_WIFI_DIRECT_CONNECTION_REQUEST + 29, // 2011 -> CLIENT_DUPLICATE_ACCEPTING_USB_CONNECTION_REQUEST + 34, // 2012 -> CLIENT_DUPLICATE_WIFI_AWARE_CONNECTION_REQUEST + 36, // 2013 -> CLIENT_DUPLICATE_WIFI_DIRECT_CONNECTION_REQUEST + 37, // 2014 -> CLIENT_DUPLICATE_WIFI_HOTSPOT_CONNECTION_REQUEST + 35, // 2015 -> CLIENT_DUPLICATE_WIFI_AWARE_SUBSCRIBING_REQUEST + 38, // 2016 -> CLIENT_UNSUPPORTED_USB_TO_BE_UPGRADE_MEDIUM + 159, // 2500 -> MISCELLEANEOUS_BLUETOOTH_MAC_ADDRESS_NULL + 163, // 2501 -> MISCELLEANEOUS_MOVE_TO_NEW_MEDIUM + 168, // 2502 -> MISCELLEANEOUS_WIFI_HOTSPOT_SOFT_AP_BLOCKED_BY_PROVISION + 158, // 2503 -> MISCELLEANEOUS_BLE_SYSTEM_SERVICE_NULL + 162, // 2504 -> MISCELLEANEOUS_L2CAP_SYSTEM_SERVICE_NULL + 161, // 2505 -> MISCELLEANEOUS_BT_SYSTEM_SERVICE_NULL + 166, // 2506 -> MISCELLEANEOUS_WIFI_AWARE_SYSTEM_SERVICE_NULL + 167, // 2507 -> MISCELLEANEOUS_WIFI_DIRECT_SYSTEM_SERVICE_NULL + 170, // 2508 -> MISCELLEANEOUS_WIFI_LAN_SYSTEM_SERVICE_NULL + 169, // 2509 -> MISCELLEANEOUS_WIFI_HOTSPOT_SYSTEM_SERVICE_NULL + 160, // 2510 -> MISCELLEANEOUS_BT_NOT_ACCEPTING_CONNECTION_FOR_WORK_PROFILE + 164, // 2511 -> MISCELLEANEOUS_WEB_RTC_GET_DROIDGUARD_RESULT_FAILURE + 165, // 2512 -> MISCELLEANEOUS_WEB_RTC_TACHYON_SIGNALING_MESSENGER_NULL + 114, // 3000 -> IO_FILE_OPENING_ERROR + 115, // 3001 -> IO_FILE_READING_ERROR + 116, // 3002 -> IO_FILE_WRITING_ERROR + 117, // 3003 -> IO_FOLDER_CREATION_ERROR + 118, // 3004 -> IO_STREAM_CREATE_PIPE_FAILURE + 104, // 3005 -> IO_ENDPOINT_IO_ERROR_ON_BLE + 106, // 3006 -> IO_ENDPOINT_IO_ERROR_ON_L2CAP + 105, // 3007 -> IO_ENDPOINT_IO_ERROR_ON_BT + 110, // 3008 -> IO_ENDPOINT_IO_ERROR_ON_WEB_RTC + 107, // 3009 -> IO_ENDPOINT_IO_ERROR_ON_LAN + 112, // 3010 -> IO_ENDPOINT_IO_ERROR_ON_WIFI_DIRECT + 113, // 3011 -> IO_ENDPOINT_IO_ERROR_ON_WIFI_HOTSPOT + 111, // 3012 -> IO_ENDPOINT_IO_ERROR_ON_WIFI_AWARE + 108, // 3013 -> IO_ENDPOINT_IO_ERROR_ON_NFC + 109, // 3014 -> IO_ENDPOINT_IO_ERROR_ON_USB + 69, // 3500 -> CONNECTIVITY_WIFI_AWARE_ATTACH_FAILURE + 44, // 3501 -> CONNECTIVITY_BLUETOOTH_DEVICE_OBTAIN_FAILURE + 41, // 3502 -> CONNECTIVITY_BLE_CLIENT_SOCKET_CREATION_FAILURE + 54, // 3503 -> CONNECTIVITY_L2CAP_CLIENT_SOCKET_CREATION_FAILURE + 46, // 3504 -> CONNECTIVITY_BT_CLIENT_SOCKET_CREATION_FAILURE + 58, // 3505 -> CONNECTIVITY_LAN_CLIENT_SOCKET_CREATION_FAILURE + 62, // 3506 -> CONNECTIVITY_NFC_CLIENT_SOCKET_CREATION_FAILURE + 65, // 3507 -> CONNECTIVITY_WEB_RTC_CLIENT_SOCKET_CREATION_FAILURE + 70, // 3508 -> CONNECTIVITY_WIFI_AWARE_CLIENT_SOCKET_CREATION_FAILURE + 86, // 3509 -> CONNECTIVITY_WIFI_HOTSPOT_CLIENT_SOCKET_CREATION_FAILURE + 79, // 3510 -> CONNECTIVITY_WIFI_DIRECT_CLIENT_SOCKET_CREATION_FAILURE + 64, // 3511 -> CONNECTIVITY_USB_CLIENT_SOCKET_CREATION_FAILURE + 66, // 3512 -> CONNECTIVITY_WEB_RTC_CONNECT_TO_TACHYON_FAILURE + 42, // 3513 -> CONNECTIVITY_BLE_CREATE_GATT_CONNECTION_FAILURE + 73, // 3514 -> CONNECTIVITY_WIFI_AWARE_GET_REMOTE_IP_FRAME_FAILURE + 72, // 3515 -> CONNECTIVITY_WIFI_AWARE_GET_REMOTE_IP_ADDRESS_FAILURE + 81, // 3516 -> CONNECTIVITY_WIFI_DIRECT_INCONSISTENT_HOSTED_WIFI_BAND + 88, // 3517 -> CONNECTIVITY_WIFI_HOTSPOT_INCONSISTENT_HOSTED_WIFI_BAND + 45, // 3518 -> CONNECTIVITY_BLUETOOTH_INVALID_CREDENTIAL + 95, // 3519 -> CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL + 82, // 3520 -> CONNECTIVITY_WIFI_DIRECT_INVALID_CREDENTIAL + 89, // 3521 -> CONNECTIVITY_WIFI_HOTSPOT_INVALID_CREDENTIAL + 74, // 3522 -> CONNECTIVITY_WIFI_AWARE_INVALID_CREDENTIAL + 67, // 3523 -> CONNECTIVITY_WEB_RTC_INVALID_CREDENTIAL + 96, // 3524 -> CONNECTIVITY_WIFI_LAN_IP_ADDRESS_ERROR + 53, // 3525 -> CONNECTIVITY_L2CAP_CLIENT_OBTAIN_FAIURE + 55, // 3526 -> CONNECTIVITY_L2CAP_DATA_CONNECTION_FAILURE + 75, // 3527 -> CONNECTIVITY_WIFI_AWARE_L2MESSAGE_NETWORK_AVAILABLE_FRAME_NULL + 76, // 3528 -> CONNECTIVITY_WIFI_AWARE_L2MESSAGE_SEND_HOST_NETWORK_FRAME_FAILURE + 61, // 3529 -> CONNECTIVITY_LAN_UNREACHABLE + 90, // 3530 -> CONNECTIVITY_WIFI_HOTSPOT_LOHS_CREATION_FAILURE + 59, // 3531 -> CONNECTIVITY_LAN_GET_NETWORK_INTERFACES_FAILURE + 80, // 3532 -> CONNECTIVITY_WIFI_DIRECT_GET_NETWORK_INTERFACES_FAILURE + 87, // 3533 -> CONNECTIVITY_WIFI_HOTSPOT_GET_NETWORK_INTERFACES_FAILURE + 91, // 3534 -> CONNECTIVITY_WIFI_HOTSPOT_P2P_CHANNEL_INITIALIZE_FAILURE + 83, // 3535 -> CONNECTIVITY_WIFI_DIRECT_P2P_CHANNEL_INITIALIZE_FAILURE + 92, // 3536 -> CONNECTIVITY_WIFI_HOTSPOT_P2P_GROUP_CREATION_FAILURE + 84, // 3537 -> CONNECTIVITY_WIFI_DIRECT_P2P_GROUP_CREATION_FAILURE + 49, // 3538 -> CONNECTIVITY_GATT_SERVER_OPEN_FAILURE + 43, // 3539 -> CONNECTIVITY_BLE_SERVER_SOCKET_CREATION_FAILURE + 56, // 3540 -> CONNECTIVITY_L2CAP_SERVER_SOCKET_CREATION_FAILURE + 47, // 3541 -> CONNECTIVITY_BT_SERVER_SOCKET_CREATION_FAILURE + 60, // 3542 -> CONNECTIVITY_LAN_SERVER_SOCKET_CREATION_FAILURE + 68, // 3543 -> CONNECTIVITY_WEB_RTC_SERVER_SOCKET_CREATION_FAILURE + 77, // 3544 -> CONNECTIVITY_WIFI_AWARE_SERVER_SOCKET_CREATION_FAILURE + 93, // 3545 -> CONNECTIVITY_WIFI_HOTSPOT_SERVER_SOCKET_CREATION_FAILURE + 85, // 3546 -> CONNECTIVITY_WIFI_DIRECT_SERVER_SOCKET_CREATION_FAILURE + 63, // 3547 -> CONNECTIVITY_NFC_SERVER_SOCKET_CREATION_FAILURE + 94, // 3548 -> CONNECTIVITY_WIFI_HOTSPOT_SOFT_AP_CREATION_FAILURE + 78, // 3549 -> CONNECTIVITY_WIFI_AWARE_UPDATE_PUBLISH_FAILURE + 52, // 3550 -> CONNECTIVITY_GENERIC_WRITING_CHANNEL_IO_ERROR + 51, // 3551 -> CONNECTIVITY_GENERIC_WRITE_CLIENT_INTRODUCTION_ACK_IO_ERROR + 71, // 3552 -> CONNECTIVITY_WIFI_AWARE_DISCOVERED_PEER_NULL + 50, // 3553 -> CONNECTIVITY_GENERIC_PAYLOAD_SENT_ERROR + 57, // 3554 -> CONNECTIVITY_L2CAP_SERVER_SOCKET_CREATION_SECURITY_EXCEPTION_FAILURE + 48, // 3555 -> CONNECTIVITY_BT_SERVER_SOCKET_CREATION_SECURITY_EXCEPTION_FAILURE + 171, // 4500 -> NEARBY_BLE_ADVERTISEMENT_MAPPING_TO_MAC_ERROR + 176, // 4501 -> NEARBY_BLUETOOTH_MAC_ADDRESS_INVALID_FOR_CONNECT + 211, // 4502 -> NEARBY_WEB_RTC_CONNECTION_FLOW_NULL + 182, // 4503 -> NEARBY_GENERIC_CONNECTION_CLOSED + 172, // 4504 -> NEARBY_BLE_ENDPOINT_CHANNEL_CREATION_FAILURE + 198, // 4505 -> NEARBY_L2CAP_ENDPOINT_CHANNEL_CREATION_FAILURE + 177, // 4506 -> NEARBY_BT_ENDPOINT_CHANNEL_CREATION_FAILURE + 202, // 4507 -> NEARBY_LAN_ENDPOINT_CHANNEL_CREATION_FAILURE + 207, // 4508 -> NEARBY_NFC_ENDPOINT_CHANNEL_CREATION_FAILURE + 215, // 4509 -> NEARBY_WIFI_AWARE_ENDPOINT_CHANNEL_CREATION_FAILURE + 229, // 4510 -> NEARBY_WIFI_HOTSPOT_ENDPOINT_CHANNEL_CREATION_FAILURE + 218, // 4511 -> NEARBY_WIFI_DIRECT_ENDPOINT_CHANNEL_CREATION_FAILURE + 212, // 4512 -> NEARBY_WEB_RTC_ENDPOINT_CHANNEL_CREATION_FAILURE + 209, // 4513 -> NEARBY_USB_ENDPOINT_CHANNEL_CREATION_FAILURE + 183, // 4514 -> NEARBY_GENERIC_ENDPOINT_UNENCRYPTED + 173, // 4515 -> NEARBY_BLE_GATT_ADVERTISEMENT_NULL_FOR_CONNECTION + 219, // 4516 -> NEARBY_WIFI_DIRECT_HOST_ON_SRD_CHANNELS + 230, // 4517 -> NEARBY_WIFI_HOTSPOT_HOST_ON_SRD_CHANNELS + 174, // 4518 -> NEARBY_BLE_GATT_NULL_CALLBACK + 199, // 4519 -> NEARBY_L2CAP_NULL_CALLBACK + 179, // 4520 -> NEARBY_BT_NULL_CALLBACK + 210, // 4521 -> NEARBY_USB_NULL_CALLBACK + 208, // 4522 -> NEARBY_NFC_NULL_CALLBACK + 216, // 4523 -> NEARBY_WIFI_AWARE_NULL_CALLBACK + 213, // 4524 -> NEARBY_WEB_RTC_NULL_CALLBACK + 204, // 4525 -> NEARBY_LAN_NULL_CALLBACK + 233, // 4526 -> NEARBY_WIFI_HOTSPOT_NULL_CALLBACK + 221, // 4527 -> NEARBY_WIFI_DIRECT_NULL_CALLBACK + 223, // 4528 -> NEARBY_WIFI_DIRECT_NULL_SSID + 222, // 4529 -> NEARBY_WIFI_DIRECT_NULL_PASSWORD + 178, // 4530 -> NEARBY_BT_MULTIPLEX_SOCKET_DISABLED + 203, // 4531 -> NEARBY_LAN_MULTIPLEX_SOCKET_DISABLED + 185, // 4532 -> NEARBY_GENERIC_NEW_ENDPOINT_CHANNEL_NULL + 220, // 4533 -> NEARBY_WIFI_DIRECT_NO_GROUP_FOR_LISTENING + 232, // 4534 -> NEARBY_WIFI_HOTSPOT_NO_HOTSPOT_FOR_LISTENING + 186, // 4535 -> NEARBY_GENERIC_OLD_ENDPOINT_CHANNEL_NULL + 175, // 4536 -> NEARBY_BLE_OPERATION_REGISTERED_FAILED + 200, // 4537 -> NEARBY_L2CAP_OPERATION_REGISTERED_FAILED + 180, // 4538 -> NEARBY_BT_OPERATION_REGISTERED_FAILED + 205, // 4539 -> NEARBY_LAN_OPERATION_REGISTERED_FAILED + 214, // 4540 -> NEARBY_WEB_RTC_OPERATION_REGISTERED_FAILED + 217, // 4541 -> NEARBY_WIFI_AWARE_OPERATION_REGISTERED_FAILED + 228, // 4542 -> NEARBY_WIFI_HOTSPOT_DIRECT_OPERATION_REGISTERED_FAILED + 236, // 4543 -> NEARBY_WIFI_HOTSPOT_SOFT_AP_OPERATION_REGISTERED_FAILED + 231, // 4544 -> NEARBY_WIFI_HOTSPOT_LOHS_OPERATION_REGISTERED_FAILED + 227, // 4545 -> NEARBY_WIFI_HOTSPOT_CLIENT_OPERATION_REGISTERED_FAILED + 224, // 4546 -> NEARBY_WIFI_DIRECT_OPERATION_REGISTERED_FAILED + 187, // 4547 -> NEARBY_GENERIC_OUTGOING_PAYLOAD_CREATION_FAILURE + 234, // 4548 -> NEARBY_WIFI_HOTSPOT_P2P_NON_DBS_WANT_2G_BUT_AP_5G + 225, // 4549 -> NEARBY_WIFI_DIRECT_P2P_NON_DBS_WANT_2G_BUT_AP_5G + 235, // 4550 -> NEARBY_WIFI_HOTSPOT_P2P_NON_DBS_WANT_5G_BUT_AP_2G + 226, // 4551 -> NEARBY_WIFI_DIRECT_P2P_NON_DBS_WANT_5G_BUT_AP_2G + 184, // 4552 -> NEARBY_GENERIC_INCOMING_PAYLOAD_NOT_DATA_TYPE + 191, // 4553 -> NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_EVENT_TYPE_ERROR + 193, // 4554 -> NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_FRAME_TYPE_ERROR + 192, // 4555 -> NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_FORMAT_ERROR + 188, // 4556 -> NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_ACK_EVENT_TYPE_ERROR + 190, // 4557 -> NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_ACK_FRAME_TYPE_ERROR + 189, // 4558 -> NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_ACK_FORMAT_ERROR + 194, // 4559 -> NEARBY_GENERIC_REMOTE_ENDPOINT_STATUS_ERROR + 195, // 4560 -> NEARBY_GENERIC_REMOTE_REPORT_PAYLOADS_ERROR + 196, // 4561 -> NEARBY_GENERIC_REMOTE_UPGRADE_FAILURE + 197, // 4562 -> NEARBY_GENERIC_SEND_PAYLOAD_EXECUTOR_NULL + 181, // 4563 -> NEARBY_BT_VIRTUAL_SOCKET_CREATION_FAILURE + 206, // 4564 -> NEARBY_LAN_VIRTUAL_SOCKET_CREATION_FAILURE + 237, // 4565 -> NEARBY_WIFI_LAN_IP_ADDRESS_ERROR + 201, // 4566 -> NEARBY_L2CAP_PSM_NOT_POSITIVE +}; + +const std::string& OperationResultDetail_Name( + OperationResultDetail value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + OperationResultDetail_entries, + OperationResultDetail_entries_by_number, + 238, OperationResultDetail_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + OperationResultDetail_entries, + OperationResultDetail_entries_by_number, + 238, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + OperationResultDetail_strings[idx].get(); +} +bool OperationResultDetail_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, OperationResultDetail* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + OperationResultDetail_entries, 238, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} // @@protoc_insertion_point(namespace_scope) } // namespace connections diff --git a/compiled_proto/proto/connections_enums.pb.h b/compiled_proto/proto/connections_enums.pb.h index 079b18b6..5f00902d 100644 --- a/compiled_proto/proto/connections_enums.pb.h +++ b/compiled_proto/proto/connections_enums.pb.h @@ -517,6 +517,288 @@ inline const std::string& PowerLevel_Name(T enum_t_value) { } bool PowerLevel_Parse( ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, PowerLevel* value); +enum OperationResultCategory : int { + CATEGORY_UNKNOWN = 0, + CATEGORY_SUCCESS = 1, + CATEGORY_CLIENT_CANCELLATION = 2, + CATEGORY_MEDIUM_UNAVAILABLE = 3, + CATEGORY_DEVICE_STATE_ERROR = 4, + CATEGORY_CLIENT_ERROR = 5, + CATEGORY_NEARBY_ERROR = 6, + CATEGORY_CONNECTIVITY_ERROR = 7, + CATEGORY_MISCELLANEOUS = 8, + CATEGORY_IO_ERROR = 9 +}; +bool OperationResultCategory_IsValid(int value); +constexpr OperationResultCategory OperationResultCategory_MIN = CATEGORY_UNKNOWN; +constexpr OperationResultCategory OperationResultCategory_MAX = CATEGORY_IO_ERROR; +constexpr int OperationResultCategory_ARRAYSIZE = OperationResultCategory_MAX + 1; + +const std::string& OperationResultCategory_Name(OperationResultCategory value); +template +inline const std::string& OperationResultCategory_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function OperationResultCategory_Name."); + return OperationResultCategory_Name(static_cast(enum_t_value)); +} +bool OperationResultCategory_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, OperationResultCategory* value); +enum OperationResultDetail : int { + DETAIL_UNKNOWN = 0, + DETAIL_SUCCESS = 1, + CLIENT_CANCELLATION_REMOTE_IN_CANCELED_STATE = 500, + CLIENT_CANCELLATION_LOCAL_CANCEL_PAYLOAD = 501, + CLIENT_CANCELLATION_REMOTE_CANCEL_PAYLOAD = 502, + CLIENT_CANCELLATION_UPGRADE_CANCELED_BY_REMOTE = 503, + CLIENT_CANCELLATION_CANCEL_BLE_OUTGOING_CONNECTION = 504, + CLIENT_CANCELLATION_CANCEL_BT_OUTGOING_CONNECTION = 505, + CLIENT_CANCELLATION_CANCEL_L2CAP_OUTGOING_CONNECTION = 506, + CLIENT_CANCELLATION_CANCEL_LAN_OUTGOING_CONNECTION = 507, + CLIENT_CANCELLATION_CANCEL_NFC_OUTGOING_CONNECTION = 508, + CLIENT_CANCELLATION_CANCEL_USB_OUTGOING_CONNECTION = 509, + CLIENT_CANCELLATION_CANCEL_WIFI_AWARE_OUTGOING_CONNECTION = 510, + CLIENT_CANCELLATION_CANCEL_WIFI_DIRECT_OUTGOING_CONNECTION = 511, + CLIENT_CANCELLATION_CANCEL_WIFI_HOTSPOT_OUTGOING_CONNECTION = 512, + CLIENT_CANCELLATION_CANCEL_WEB_RTC_OUTGOING_CONNECTION = 513, + CLIENT_CANCELLATION_CANCEL_OUTGOING_CONNECTION = 514, + CLIENT_CANCELLATION_CANCEL_INCOMING_CONNECTION = 515, + CLIENT_CANCELLATION_WIFI_AWARE_SERVER_SOCKET_CREATION = 516, + CLIENT_CANCELLATION_WIFI_DIRECT_SERVER_SOCKET_CREATION = 517, + CLIENT_CANCELLATION_WIFI_HOTSPOT_SERVER_SOCKET_CREATION = 518, + CLIENT_CANCELLATION_BT_SERVER_SOCKET_CREATION = 519, + CLIENT_CANCELLATION_WEB_RTC_SERVER_SOCKET_CREATION = 520, + CLIENT_CANCELLATION_WIFI_LAN_SERVER_SOCKET_CREATION = 521, + CLIENT_CANCELLATION_LOCAL_DISCONNECT = 522, + CLIENT_CANCELLATION_REMOTE_DISCONNECT = 523, + DEVICE_STATE_ERROR_UNFINISHED_UPGRADE_ATTEMPTS = 1000, + DEVICE_STATE_ERROR_USER_HOTSPOT_ENABLED = 1001, + DEVICE_STATE_LOCATION_DISABLED = 1002, + DEVICE_STATE_RADIO_DISABLING_FAILURE = 1003, + DEVICE_STATE_RADIO_ENABLING_FAILURE = 1004, + MEDIUM_UNAVAILABLE_WIFI_AWARE_RESOURCE_NOT_AVAILABLE = 1500, + MEDIUM_UNAVAILABLE_DIRECT_HOTSPOT_NOT_SUPPORT = 1501, + MEDIUM_UNAVAILABLE_SOFT_AP_NOT_SUPPORT = 1502, + MEDIUM_UNAVAILABLE_LOCAL_ONLY_HOTSPOT_NOT_SUPPORT = 1503, + MEDIUM_UNAVAILABLE_LOCAL_ONLY_HOTSPOT_NOT_SUPPORT_5G = 1504, + MEDIUM_UNAVAILABLE_BLE_NOT_AVAILABLE = 1505, + MEDIUM_UNAVAILABLE_L2CAP_NOT_AVAILABLE = 1506, + MEDIUM_UNAVAILABLE_BLUETOOTH_NOT_AVAILABLE = 1507, + MEDIUM_UNAVAILABLE_WEB_RTC_NOT_AVAILABLE = 1508, + MEDIUM_UNAVAILABLE_WIFI_AWARE_NOT_AVAILABLE = 1509, + MEDIUM_UNAVAILABLE_WIFI_HOTSPOT_NOT_AVAILABLE = 1510, + MEDIUM_UNAVAILABLE_WIFI_DIRECT_NOT_AVAILABLE = 1511, + MEDIUM_UNAVAILABLE_NFC_NOT_AVAILABLE = 1512, + MEDIUM_UNAVAILABLE_LAN_NOT_AVAILABLE = 1513, + MEDIUM_UNAVAILABLE_USB_NOT_AVAILABLE = 1514, + MEDIUM_UNAVAILABLE_BLE_NC_LOGICAL_NOT_AVAILABLE = 1515, + MEDIUM_UNAVAILABLE_BT_NC_LOGICAL_NOT_AVAILABLE = 1516, + MEDIUM_UNAVAILABLE_LAN_NC_LOGICAL_NOT_AVAILABLE = 1517, + MEDIUM_UNAVAILABLE_NFC_NC_LOGICAL_NOT_AVAILABLE = 1518, + MEDIUM_UNAVAILABLE_USB_NC_LOGICAL_NOT_AVAILABLE = 1519, + MEDIUM_UNAVAILABLE_WEB_RTC_NC_LOGICAL_NOT_AVAILABLE = 1520, + MEDIUM_UNAVAILABLE_WIFI_AWARE_NC_LOGICAL_NOT_AVAILABLE = 1521, + MEDIUM_UNAVAILABLE_WIFI_HOTSPOT_NC_LOGICAL_NOT_AVAILABLE = 1522, + MEDIUM_UNAVAILABLE_WIFI_DIRECT_NC_LOGICAL_NOT_AVAILABLE = 1523, + MEDIUM_UNAVAILABLE_WIFI_HOTSPOT_P2P_RESOURCE_NOT_AVAILABLE = 1524, + MEDIUM_UNAVAILABLE_WIFI_DIRECT_P2P_RESOURCE_NOT_AVAILABLE = 1525, + MEDIUM_UNAVAILABLE_UPGRADE_SKIP_BLE_LOW_QUALITY_MEDIUMS = 1526, + MEDIUM_UNAVAILABLE_UPGRADE_SKIP_L2CAP_LOW_QUALITY_MEDIUMS = 1527, + MEDIUM_UNAVAILABLE_UPGRADE_SKIP_WEB_RTC_LOW_QUALITY_MEDIUMS = 1528, + MEDIUM_UNAVAILABLE_UPGRADE_SKIP_LAN_LOW_QUALITY_MEDIUMS = 1529, + MEDIUM_UNAVAILABLE_UPGRADE_SKIP_BT_LOW_QUALITY_MEDIUMS = 1530, + MEDIUM_UNAVAILABLE_UPGRADE_SKIP_USB_LOW_QUALITY_MEDIUMS = 1531, + MEDIUM_UNAVAILABLE_LOCAL_ONLY_HOTSPOT_DISRUPTIVE_FALSE = 1532, + MEDIUM_UNAVAILABLE_SOFT_AP_DISRUPTIVE_FALSE = 1533, + MEDIUM_UNAVAILABLE_ALREADY_HAVE_A_WIFI_DIRECT_GROUP = 1534, + MEDIUM_UNAVAILABLE_ALREADY_HOSTING_HOTSPOT_FOR_OTHER_CLIENTS = 1535, + MEDIUM_UNAVAILABLE_REJECT_L2CAP_ON_GATT_MULTIPLEX_CONNECTION = 1536, + MEDIUM_UNAVAILABLE_UPGRADE_ON_SAME_MEDIUM = 1537, + MEDIUM_UNAVAILABLE_WEB_RTC_NO_INTERNET = 1538, + CLIENT_WIFI_DIRECT_ALREADY_HOSTING_DIRECT_GROUP_FOR_THIS_CLIENT = 2000, + CLIENT_WIFI_HOTSPOT_ALREADY_HOSTING_HOTSPOT_FOR_THIS_CLIENT = 2001, + CLIENT_DUPLICATE_ACCEPTING_BLE_CONNECTION_REQUEST = 2002, + CLIENT_DUPLICATE_ACCEPTING_L2CAP_CONNECTION_REQUEST = 2003, + CLIENT_DUPLICATE_ACCEPTING_BT_CONNECTION_REQUEST = 2004, + CLIENT_DUPLICATE_ACCEPTING_LAN_CONNECTION_REQUEST = 2005, + CLIENT_DUPLICATE_ACCEPTING_NFC_CONNECTION_REQUEST = 2006, + CLIENT_DUPLICATE_ACCEPTING_WEB_RTC_CONNECTION_REQUEST = 2007, + CLIENT_DUPLICATE_ACCEPTING_WIFI_AWARE_CONNECTION_REQUEST = 2008, + CLIENT_DUPLICATE_ACCEPTING_WIFI_HOTSPOT_CONNECTION_REQUEST = 2009, + CLIENT_DUPLICATE_ACCEPTING_WIFI_DIRECT_CONNECTION_REQUEST = 2010, + CLIENT_DUPLICATE_ACCEPTING_USB_CONNECTION_REQUEST = 2011, + CLIENT_DUPLICATE_WIFI_AWARE_CONNECTION_REQUEST = 2012, + CLIENT_DUPLICATE_WIFI_DIRECT_CONNECTION_REQUEST = 2013, + CLIENT_DUPLICATE_WIFI_HOTSPOT_CONNECTION_REQUEST = 2014, + CLIENT_DUPLICATE_WIFI_AWARE_SUBSCRIBING_REQUEST = 2015, + CLIENT_UNSUPPORTED_USB_TO_BE_UPGRADE_MEDIUM = 2016, + MISCELLEANEOUS_BLUETOOTH_MAC_ADDRESS_NULL = 2500, + MISCELLEANEOUS_MOVE_TO_NEW_MEDIUM = 2501, + MISCELLEANEOUS_WIFI_HOTSPOT_SOFT_AP_BLOCKED_BY_PROVISION = 2502, + MISCELLEANEOUS_BLE_SYSTEM_SERVICE_NULL = 2503, + MISCELLEANEOUS_L2CAP_SYSTEM_SERVICE_NULL = 2504, + MISCELLEANEOUS_BT_SYSTEM_SERVICE_NULL = 2505, + MISCELLEANEOUS_WIFI_AWARE_SYSTEM_SERVICE_NULL = 2506, + MISCELLEANEOUS_WIFI_DIRECT_SYSTEM_SERVICE_NULL = 2507, + MISCELLEANEOUS_WIFI_LAN_SYSTEM_SERVICE_NULL = 2508, + MISCELLEANEOUS_WIFI_HOTSPOT_SYSTEM_SERVICE_NULL = 2509, + MISCELLEANEOUS_BT_NOT_ACCEPTING_CONNECTION_FOR_WORK_PROFILE = 2510, + MISCELLEANEOUS_WEB_RTC_GET_DROIDGUARD_RESULT_FAILURE = 2511, + MISCELLEANEOUS_WEB_RTC_TACHYON_SIGNALING_MESSENGER_NULL = 2512, + IO_FILE_OPENING_ERROR = 3000, + IO_FILE_READING_ERROR = 3001, + IO_FILE_WRITING_ERROR = 3002, + IO_FOLDER_CREATION_ERROR = 3003, + IO_STREAM_CREATE_PIPE_FAILURE = 3004, + IO_ENDPOINT_IO_ERROR_ON_BLE = 3005, + IO_ENDPOINT_IO_ERROR_ON_L2CAP = 3006, + IO_ENDPOINT_IO_ERROR_ON_BT = 3007, + IO_ENDPOINT_IO_ERROR_ON_WEB_RTC = 3008, + IO_ENDPOINT_IO_ERROR_ON_LAN = 3009, + IO_ENDPOINT_IO_ERROR_ON_WIFI_DIRECT = 3010, + IO_ENDPOINT_IO_ERROR_ON_WIFI_HOTSPOT = 3011, + IO_ENDPOINT_IO_ERROR_ON_WIFI_AWARE = 3012, + IO_ENDPOINT_IO_ERROR_ON_NFC = 3013, + IO_ENDPOINT_IO_ERROR_ON_USB = 3014, + CONNECTIVITY_WIFI_AWARE_ATTACH_FAILURE = 3500, + CONNECTIVITY_BLUETOOTH_DEVICE_OBTAIN_FAILURE = 3501, + CONNECTIVITY_BLE_CLIENT_SOCKET_CREATION_FAILURE = 3502, + CONNECTIVITY_L2CAP_CLIENT_SOCKET_CREATION_FAILURE = 3503, + CONNECTIVITY_BT_CLIENT_SOCKET_CREATION_FAILURE = 3504, + CONNECTIVITY_LAN_CLIENT_SOCKET_CREATION_FAILURE = 3505, + CONNECTIVITY_NFC_CLIENT_SOCKET_CREATION_FAILURE = 3506, + CONNECTIVITY_WEB_RTC_CLIENT_SOCKET_CREATION_FAILURE = 3507, + CONNECTIVITY_WIFI_AWARE_CLIENT_SOCKET_CREATION_FAILURE = 3508, + CONNECTIVITY_WIFI_HOTSPOT_CLIENT_SOCKET_CREATION_FAILURE = 3509, + CONNECTIVITY_WIFI_DIRECT_CLIENT_SOCKET_CREATION_FAILURE = 3510, + CONNECTIVITY_USB_CLIENT_SOCKET_CREATION_FAILURE = 3511, + CONNECTIVITY_WEB_RTC_CONNECT_TO_TACHYON_FAILURE = 3512, + CONNECTIVITY_BLE_CREATE_GATT_CONNECTION_FAILURE = 3513, + CONNECTIVITY_WIFI_AWARE_GET_REMOTE_IP_FRAME_FAILURE = 3514, + CONNECTIVITY_WIFI_AWARE_GET_REMOTE_IP_ADDRESS_FAILURE = 3515, + CONNECTIVITY_WIFI_DIRECT_INCONSISTENT_HOSTED_WIFI_BAND = 3516, + CONNECTIVITY_WIFI_HOTSPOT_INCONSISTENT_HOSTED_WIFI_BAND = 3517, + CONNECTIVITY_BLUETOOTH_INVALID_CREDENTIAL = 3518, + CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL = 3519, + CONNECTIVITY_WIFI_DIRECT_INVALID_CREDENTIAL = 3520, + CONNECTIVITY_WIFI_HOTSPOT_INVALID_CREDENTIAL = 3521, + CONNECTIVITY_WIFI_AWARE_INVALID_CREDENTIAL = 3522, + CONNECTIVITY_WEB_RTC_INVALID_CREDENTIAL = 3523, + CONNECTIVITY_WIFI_LAN_IP_ADDRESS_ERROR = 3524, + CONNECTIVITY_L2CAP_CLIENT_OBTAIN_FAIURE = 3525, + CONNECTIVITY_L2CAP_DATA_CONNECTION_FAILURE = 3526, + CONNECTIVITY_WIFI_AWARE_L2MESSAGE_NETWORK_AVAILABLE_FRAME_NULL = 3527, + CONNECTIVITY_WIFI_AWARE_L2MESSAGE_SEND_HOST_NETWORK_FRAME_FAILURE = 3528, + CONNECTIVITY_LAN_UNREACHABLE = 3529, + CONNECTIVITY_WIFI_HOTSPOT_LOHS_CREATION_FAILURE = 3530, + CONNECTIVITY_LAN_GET_NETWORK_INTERFACES_FAILURE = 3531, + CONNECTIVITY_WIFI_DIRECT_GET_NETWORK_INTERFACES_FAILURE = 3532, + CONNECTIVITY_WIFI_HOTSPOT_GET_NETWORK_INTERFACES_FAILURE = 3533, + CONNECTIVITY_WIFI_HOTSPOT_P2P_CHANNEL_INITIALIZE_FAILURE = 3534, + CONNECTIVITY_WIFI_DIRECT_P2P_CHANNEL_INITIALIZE_FAILURE = 3535, + CONNECTIVITY_WIFI_HOTSPOT_P2P_GROUP_CREATION_FAILURE = 3536, + CONNECTIVITY_WIFI_DIRECT_P2P_GROUP_CREATION_FAILURE = 3537, + CONNECTIVITY_GATT_SERVER_OPEN_FAILURE = 3538, + CONNECTIVITY_BLE_SERVER_SOCKET_CREATION_FAILURE = 3539, + CONNECTIVITY_L2CAP_SERVER_SOCKET_CREATION_FAILURE = 3540, + CONNECTIVITY_BT_SERVER_SOCKET_CREATION_FAILURE = 3541, + CONNECTIVITY_LAN_SERVER_SOCKET_CREATION_FAILURE = 3542, + CONNECTIVITY_WEB_RTC_SERVER_SOCKET_CREATION_FAILURE = 3543, + CONNECTIVITY_WIFI_AWARE_SERVER_SOCKET_CREATION_FAILURE = 3544, + CONNECTIVITY_WIFI_HOTSPOT_SERVER_SOCKET_CREATION_FAILURE = 3545, + CONNECTIVITY_WIFI_DIRECT_SERVER_SOCKET_CREATION_FAILURE = 3546, + CONNECTIVITY_NFC_SERVER_SOCKET_CREATION_FAILURE = 3547, + CONNECTIVITY_WIFI_HOTSPOT_SOFT_AP_CREATION_FAILURE = 3548, + CONNECTIVITY_WIFI_AWARE_UPDATE_PUBLISH_FAILURE = 3549, + CONNECTIVITY_GENERIC_WRITING_CHANNEL_IO_ERROR = 3550, + CONNECTIVITY_GENERIC_WRITE_CLIENT_INTRODUCTION_ACK_IO_ERROR = 3551, + CONNECTIVITY_WIFI_AWARE_DISCOVERED_PEER_NULL = 3552, + CONNECTIVITY_GENERIC_PAYLOAD_SENT_ERROR = 3553, + CONNECTIVITY_L2CAP_SERVER_SOCKET_CREATION_SECURITY_EXCEPTION_FAILURE = 3554, + CONNECTIVITY_BT_SERVER_SOCKET_CREATION_SECURITY_EXCEPTION_FAILURE = 3555, + NEARBY_BLE_ADVERTISEMENT_MAPPING_TO_MAC_ERROR = 4500, + NEARBY_BLUETOOTH_MAC_ADDRESS_INVALID_FOR_CONNECT = 4501, + NEARBY_WEB_RTC_CONNECTION_FLOW_NULL = 4502, + NEARBY_GENERIC_CONNECTION_CLOSED = 4503, + NEARBY_BLE_ENDPOINT_CHANNEL_CREATION_FAILURE = 4504, + NEARBY_L2CAP_ENDPOINT_CHANNEL_CREATION_FAILURE = 4505, + NEARBY_BT_ENDPOINT_CHANNEL_CREATION_FAILURE = 4506, + NEARBY_LAN_ENDPOINT_CHANNEL_CREATION_FAILURE = 4507, + NEARBY_NFC_ENDPOINT_CHANNEL_CREATION_FAILURE = 4508, + NEARBY_WIFI_AWARE_ENDPOINT_CHANNEL_CREATION_FAILURE = 4509, + NEARBY_WIFI_HOTSPOT_ENDPOINT_CHANNEL_CREATION_FAILURE = 4510, + NEARBY_WIFI_DIRECT_ENDPOINT_CHANNEL_CREATION_FAILURE = 4511, + NEARBY_WEB_RTC_ENDPOINT_CHANNEL_CREATION_FAILURE = 4512, + NEARBY_USB_ENDPOINT_CHANNEL_CREATION_FAILURE = 4513, + NEARBY_GENERIC_ENDPOINT_UNENCRYPTED = 4514, + NEARBY_BLE_GATT_ADVERTISEMENT_NULL_FOR_CONNECTION = 4515, + NEARBY_WIFI_DIRECT_HOST_ON_SRD_CHANNELS = 4516, + NEARBY_WIFI_HOTSPOT_HOST_ON_SRD_CHANNELS = 4517, + NEARBY_BLE_GATT_NULL_CALLBACK = 4518, + NEARBY_L2CAP_NULL_CALLBACK = 4519, + NEARBY_BT_NULL_CALLBACK = 4520, + NEARBY_USB_NULL_CALLBACK = 4521, + NEARBY_NFC_NULL_CALLBACK = 4522, + NEARBY_WIFI_AWARE_NULL_CALLBACK = 4523, + NEARBY_WEB_RTC_NULL_CALLBACK = 4524, + NEARBY_LAN_NULL_CALLBACK = 4525, + NEARBY_WIFI_HOTSPOT_NULL_CALLBACK = 4526, + NEARBY_WIFI_DIRECT_NULL_CALLBACK = 4527, + NEARBY_WIFI_DIRECT_NULL_SSID = 4528, + NEARBY_WIFI_DIRECT_NULL_PASSWORD = 4529, + NEARBY_BT_MULTIPLEX_SOCKET_DISABLED = 4530, + NEARBY_LAN_MULTIPLEX_SOCKET_DISABLED = 4531, + NEARBY_GENERIC_NEW_ENDPOINT_CHANNEL_NULL = 4532, + NEARBY_WIFI_DIRECT_NO_GROUP_FOR_LISTENING = 4533, + NEARBY_WIFI_HOTSPOT_NO_HOTSPOT_FOR_LISTENING = 4534, + NEARBY_GENERIC_OLD_ENDPOINT_CHANNEL_NULL = 4535, + NEARBY_BLE_OPERATION_REGISTERED_FAILED = 4536, + NEARBY_L2CAP_OPERATION_REGISTERED_FAILED = 4537, + NEARBY_BT_OPERATION_REGISTERED_FAILED = 4538, + NEARBY_LAN_OPERATION_REGISTERED_FAILED = 4539, + NEARBY_WEB_RTC_OPERATION_REGISTERED_FAILED = 4540, + NEARBY_WIFI_AWARE_OPERATION_REGISTERED_FAILED = 4541, + NEARBY_WIFI_HOTSPOT_DIRECT_OPERATION_REGISTERED_FAILED = 4542, + NEARBY_WIFI_HOTSPOT_SOFT_AP_OPERATION_REGISTERED_FAILED = 4543, + NEARBY_WIFI_HOTSPOT_LOHS_OPERATION_REGISTERED_FAILED = 4544, + NEARBY_WIFI_HOTSPOT_CLIENT_OPERATION_REGISTERED_FAILED = 4545, + NEARBY_WIFI_DIRECT_OPERATION_REGISTERED_FAILED = 4546, + NEARBY_GENERIC_OUTGOING_PAYLOAD_CREATION_FAILURE = 4547, + NEARBY_WIFI_HOTSPOT_P2P_NON_DBS_WANT_2G_BUT_AP_5G = 4548, + NEARBY_WIFI_DIRECT_P2P_NON_DBS_WANT_2G_BUT_AP_5G = 4549, + NEARBY_WIFI_HOTSPOT_P2P_NON_DBS_WANT_5G_BUT_AP_2G = 4550, + NEARBY_WIFI_DIRECT_P2P_NON_DBS_WANT_5G_BUT_AP_2G = 4551, + NEARBY_GENERIC_INCOMING_PAYLOAD_NOT_DATA_TYPE = 4552, + NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_EVENT_TYPE_ERROR = 4553, + NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_FRAME_TYPE_ERROR = 4554, + NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_FORMAT_ERROR = 4555, + NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_ACK_EVENT_TYPE_ERROR = 4556, + NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_ACK_FRAME_TYPE_ERROR = 4557, + NEARBY_GENERIC_READ_CLIENT_INTRODUCTION_ACK_FORMAT_ERROR = 4558, + NEARBY_GENERIC_REMOTE_ENDPOINT_STATUS_ERROR = 4559, + NEARBY_GENERIC_REMOTE_REPORT_PAYLOADS_ERROR = 4560, + NEARBY_GENERIC_REMOTE_UPGRADE_FAILURE = 4561, + NEARBY_GENERIC_SEND_PAYLOAD_EXECUTOR_NULL = 4562, + NEARBY_BT_VIRTUAL_SOCKET_CREATION_FAILURE = 4563, + NEARBY_LAN_VIRTUAL_SOCKET_CREATION_FAILURE = 4564, + NEARBY_WIFI_LAN_IP_ADDRESS_ERROR = 4565, + NEARBY_L2CAP_PSM_NOT_POSITIVE = 4566 +}; +bool OperationResultDetail_IsValid(int value); +constexpr OperationResultDetail OperationResultDetail_MIN = DETAIL_UNKNOWN; +constexpr OperationResultDetail OperationResultDetail_MAX = NEARBY_L2CAP_PSM_NOT_POSITIVE; +constexpr int OperationResultDetail_ARRAYSIZE = OperationResultDetail_MAX + 1; + +const std::string& OperationResultDetail_Name(OperationResultDetail value); +template +inline const std::string& OperationResultDetail_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function OperationResultDetail_Name."); + return OperationResultDetail_Name(static_cast(enum_t_value)); +} +bool OperationResultDetail_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, OperationResultDetail* value); // =================================================================== @@ -560,6 +842,8 @@ template <> struct is_proto_enum< ::location::nearby::proto::connections::Bandwi template <> struct is_proto_enum< ::location::nearby::proto::connections::BandwidthUpgradeErrorStage> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::connections::LogSource> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::connections::PowerLevel> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::proto::connections::OperationResultCategory> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::proto::connections::OperationResultDetail> : ::std::true_type {}; PROTOBUF_NAMESPACE_CLOSE diff --git a/compiled_proto/proto/mediums/ble_frames.pb.cc b/compiled_proto/proto/mediums/ble_frames.pb.cc index 42f55f75..e52eb70c 100644 --- a/compiled_proto/proto/mediums/ble_frames.pb.cc +++ b/compiled_proto/proto/mediums/ble_frames.pb.cc @@ -35,6 +35,7 @@ PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT SocketControlFrameDefaultTypeIn constexpr IntroductionFrame::IntroductionFrame( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : service_id_hash_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , service_id_hash_salt_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) , socket_version_(0) {} struct IntroductionFrameDefaultTypeInternal { @@ -552,6 +553,9 @@ class IntroductionFrame::_Internal { (*has_bits)[0] |= 1u; } static void set_has_socket_version(HasBits* has_bits) { + (*has_bits)[0] |= 4u; + } + static void set_has_service_id_hash_salt(HasBits* has_bits) { (*has_bits)[0] |= 2u; } }; @@ -577,6 +581,14 @@ IntroductionFrame::IntroductionFrame(const IntroductionFrame& from) service_id_hash_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_service_id_hash(), GetArenaForAllocation()); } + service_id_hash_salt_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + service_id_hash_salt_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (from._internal_has_service_id_hash_salt()) { + service_id_hash_salt_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_service_id_hash_salt(), + GetArenaForAllocation()); + } socket_version_ = from.socket_version_; // @@protoc_insertion_point(copy_constructor:location.nearby.mediums.IntroductionFrame) } @@ -586,6 +598,10 @@ service_id_hash_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptySt #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING service_id_hash_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +service_id_hash_salt_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + service_id_hash_salt_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING socket_version_ = 0; } @@ -599,6 +615,7 @@ IntroductionFrame::~IntroductionFrame() { inline void IntroductionFrame::SharedDtor() { GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); service_id_hash_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + service_id_hash_salt_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); } void IntroductionFrame::ArenaDtor(void* object) { @@ -618,8 +635,13 @@ void IntroductionFrame::Clear() { (void) cached_has_bits; cached_has_bits = _has_bits_[0]; - if (cached_has_bits & 0x00000001u) { - service_id_hash_.ClearNonDefaultToEmpty(); + if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000001u) { + service_id_hash_.ClearNonDefaultToEmpty(); + } + if (cached_has_bits & 0x00000002u) { + service_id_hash_salt_.ClearNonDefaultToEmpty(); + } } socket_version_ = 0; _has_bits_.Clear(); @@ -655,6 +677,15 @@ const char* IntroductionFrame::_InternalParse(const char* ptr, ::PROTOBUF_NAMESP } else goto handle_unusual; continue; + // optional string service_id_hash_salt = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 26)) { + auto str = _internal_mutable_service_id_hash_salt(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(ptr); + } else + goto handle_unusual; + continue; default: goto handle_unusual; } // switch @@ -693,12 +724,18 @@ uint8_t* IntroductionFrame::_InternalSerialize( } // optional .location.nearby.mediums.SocketVersion socket_version = 2; - if (cached_has_bits & 0x00000002u) { + if (cached_has_bits & 0x00000004u) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray( 2, this->_internal_socket_version(), target); } + // optional string service_id_hash_salt = 3; + if (cached_has_bits & 0x00000002u) { + target = stream->WriteStringMaybeAliased( + 3, this->_internal_service_id_hash_salt(), target); + } + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = stream->WriteRaw(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).data(), static_cast(_internal_metadata_.unknown_fields(::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString).size()), target); @@ -716,7 +753,7 @@ size_t IntroductionFrame::ByteSizeLong() const { (void) cached_has_bits; cached_has_bits = _has_bits_[0]; - if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000007u) { // optional bytes service_id_hash = 1; if (cached_has_bits & 0x00000001u) { total_size += 1 + @@ -724,8 +761,15 @@ size_t IntroductionFrame::ByteSizeLong() const { this->_internal_service_id_hash()); } - // optional .location.nearby.mediums.SocketVersion socket_version = 2; + // optional string service_id_hash_salt = 3; if (cached_has_bits & 0x00000002u) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_service_id_hash_salt()); + } + + // optional .location.nearby.mediums.SocketVersion socket_version = 2; + if (cached_has_bits & 0x00000004u) { total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_socket_version()); } @@ -752,11 +796,14 @@ void IntroductionFrame::MergeFrom(const IntroductionFrame& from) { (void) cached_has_bits; cached_has_bits = from._has_bits_[0]; - if (cached_has_bits & 0x00000003u) { + if (cached_has_bits & 0x00000007u) { if (cached_has_bits & 0x00000001u) { _internal_set_service_id_hash(from._internal_service_id_hash()); } if (cached_has_bits & 0x00000002u) { + _internal_set_service_id_hash_salt(from._internal_service_id_hash_salt()); + } + if (cached_has_bits & 0x00000004u) { socket_version_ = from.socket_version_; } _has_bits_[0] |= cached_has_bits; @@ -786,6 +833,11 @@ void IntroductionFrame::InternalSwap(IntroductionFrame* other) { &service_id_hash_, lhs_arena, &other->service_id_hash_, rhs_arena ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &service_id_hash_salt_, lhs_arena, + &other->service_id_hash_salt_, rhs_arena + ); swap(socket_version_, other->socket_version_); } diff --git a/compiled_proto/proto/mediums/ble_frames.pb.h b/compiled_proto/proto/mediums/ble_frames.pb.h index fec28893..a57a4e39 100644 --- a/compiled_proto/proto/mediums/ble_frames.pb.h +++ b/compiled_proto/proto/mediums/ble_frames.pb.h @@ -468,6 +468,7 @@ class IntroductionFrame final : enum : int { kServiceIdHashFieldNumber = 1, + kServiceIdHashSaltFieldNumber = 3, kSocketVersionFieldNumber = 2, }; // optional bytes service_id_hash = 1; @@ -488,6 +489,24 @@ class IntroductionFrame final : std::string* _internal_mutable_service_id_hash(); public: + // optional string service_id_hash_salt = 3; + bool has_service_id_hash_salt() const; + private: + bool _internal_has_service_id_hash_salt() const; + public: + void clear_service_id_hash_salt(); + const std::string& service_id_hash_salt() const; + template + void set_service_id_hash_salt(ArgT0&& arg0, ArgT... args); + std::string* mutable_service_id_hash_salt(); + PROTOBUF_NODISCARD std::string* release_service_id_hash_salt(); + void set_allocated_service_id_hash_salt(std::string* service_id_hash_salt); + private: + const std::string& _internal_service_id_hash_salt() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_service_id_hash_salt(const std::string& value); + std::string* _internal_mutable_service_id_hash_salt(); + public: + // optional .location.nearby.mediums.SocketVersion socket_version = 2; bool has_socket_version() const; private: @@ -511,6 +530,7 @@ class IntroductionFrame final : ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr service_id_hash_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr service_id_hash_salt_; int socket_version_; friend struct ::TableStruct_proto_2fmediums_2fble_5fframes_2eproto; }; @@ -1208,7 +1228,7 @@ inline void IntroductionFrame::set_allocated_service_id_hash(std::string* servic // optional .location.nearby.mediums.SocketVersion socket_version = 2; inline bool IntroductionFrame::_internal_has_socket_version() const { - bool value = (_has_bits_[0] & 0x00000002u) != 0; + bool value = (_has_bits_[0] & 0x00000004u) != 0; return value; } inline bool IntroductionFrame::has_socket_version() const { @@ -1216,7 +1236,7 @@ inline bool IntroductionFrame::has_socket_version() const { } inline void IntroductionFrame::clear_socket_version() { socket_version_ = 0; - _has_bits_[0] &= ~0x00000002u; + _has_bits_[0] &= ~0x00000004u; } inline ::location::nearby::mediums::SocketVersion IntroductionFrame::_internal_socket_version() const { return static_cast< ::location::nearby::mediums::SocketVersion >(socket_version_); @@ -1227,7 +1247,7 @@ inline ::location::nearby::mediums::SocketVersion IntroductionFrame::socket_vers } inline void IntroductionFrame::_internal_set_socket_version(::location::nearby::mediums::SocketVersion value) { assert(::location::nearby::mediums::SocketVersion_IsValid(value)); - _has_bits_[0] |= 0x00000002u; + _has_bits_[0] |= 0x00000004u; socket_version_ = value; } inline void IntroductionFrame::set_socket_version(::location::nearby::mediums::SocketVersion value) { @@ -1235,6 +1255,75 @@ inline void IntroductionFrame::set_socket_version(::location::nearby::mediums::S // @@protoc_insertion_point(field_set:location.nearby.mediums.IntroductionFrame.socket_version) } +// optional string service_id_hash_salt = 3; +inline bool IntroductionFrame::_internal_has_service_id_hash_salt() const { + bool value = (_has_bits_[0] & 0x00000002u) != 0; + return value; +} +inline bool IntroductionFrame::has_service_id_hash_salt() const { + return _internal_has_service_id_hash_salt(); +} +inline void IntroductionFrame::clear_service_id_hash_salt() { + service_id_hash_salt_.ClearToEmpty(); + _has_bits_[0] &= ~0x00000002u; +} +inline const std::string& IntroductionFrame::service_id_hash_salt() const { + // @@protoc_insertion_point(field_get:location.nearby.mediums.IntroductionFrame.service_id_hash_salt) + return _internal_service_id_hash_salt(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void IntroductionFrame::set_service_id_hash_salt(ArgT0&& arg0, ArgT... args) { + _has_bits_[0] |= 0x00000002u; + service_id_hash_salt_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:location.nearby.mediums.IntroductionFrame.service_id_hash_salt) +} +inline std::string* IntroductionFrame::mutable_service_id_hash_salt() { + std::string* _s = _internal_mutable_service_id_hash_salt(); + // @@protoc_insertion_point(field_mutable:location.nearby.mediums.IntroductionFrame.service_id_hash_salt) + return _s; +} +inline const std::string& IntroductionFrame::_internal_service_id_hash_salt() const { + return service_id_hash_salt_.Get(); +} +inline void IntroductionFrame::_internal_set_service_id_hash_salt(const std::string& value) { + _has_bits_[0] |= 0x00000002u; + service_id_hash_salt_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* IntroductionFrame::_internal_mutable_service_id_hash_salt() { + _has_bits_[0] |= 0x00000002u; + return service_id_hash_salt_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* IntroductionFrame::release_service_id_hash_salt() { + // @@protoc_insertion_point(field_release:location.nearby.mediums.IntroductionFrame.service_id_hash_salt) + if (!_internal_has_service_id_hash_salt()) { + return nullptr; + } + _has_bits_[0] &= ~0x00000002u; + auto* p = service_id_hash_salt_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (service_id_hash_salt_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + service_id_hash_salt_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return p; +} +inline void IntroductionFrame::set_allocated_service_id_hash_salt(std::string* service_id_hash_salt) { + if (service_id_hash_salt != nullptr) { + _has_bits_[0] |= 0x00000002u; + } else { + _has_bits_[0] &= ~0x00000002u; + } + service_id_hash_salt_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), service_id_hash_salt, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (service_id_hash_salt_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + service_id_hash_salt_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:location.nearby.mediums.IntroductionFrame.service_id_hash_salt) +} + // ------------------------------------------------------------------- // DisconnectionFrame diff --git a/compiled_proto/proto/sharing_enums.pb.cc b/compiled_proto/proto/sharing_enums.pb.cc index 0c7a9b0b..9b200e94 100644 --- a/compiled_proto/proto/sharing_enums.pb.cc +++ b/compiled_proto/proto/sharing_enums.pb.cc @@ -86,13 +86,18 @@ bool EventType_IsValid(int value) { case 57: case 58: case 59: + case 60: + case 61: + case 62: + case 63: + case 64: return true; default: return false; } } -static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed EventType_strings[60] = {}; +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed EventType_strings[65] = {}; static const char EventType_names[] = "ACCEPT_AGREEMENTS" @@ -107,6 +112,7 @@ static const char EventType_names[] = "CANCEL_RECEIVING_ATTACHMENTS" "CANCEL_SENDING_ATTACHMENTS" "DECLINE_AGREEMENTS" + "DECRYPT_CERTIFICATE_FAILURE" "DEFAULT_OPT_IN" "DESCRIBE_ATTACHMENTS" "DEVICE_SETTINGS" @@ -117,6 +123,7 @@ static const char EventType_names[] = "DISPLAY_PRIVACY_NOTIFICATION" "ENABLE_NEARBY_SHARING" "ESTABLISH_CONNECTION" + "FAST_INIT_DISCOVER_DEVICE" "FAST_SHARE_SERVER_RESPONSE" "INSTALL_APK" "LAUNCH_ACTIVITY" @@ -124,6 +131,7 @@ static const char EventType_names[] = "LAUNCH_PHONE_CONSENT" "LAUNCH_SETUP_ACTIVITY" "OPEN_RECEIVED_ATTACHMENTS" + "PARSING_FAILED_ENDPOINT_ID" "PREFERENCES_USAGE" "PROCESS_RECEIVED_ATTACHMENTS_END" "QR_CODE_LINK_SHOWN" @@ -139,10 +147,12 @@ static const char EventType_names[] = "SCAN_FOR_SHARE_TARGETS_START" "SEND_ATTACHMENTS_END" "SEND_ATTACHMENTS_START" + "SEND_DESKTOP_NOTIFICATION" "SEND_FAST_INITIALIZATION" "SEND_INTRODUCTION" "SEND_START" "SETUP_WIZARD" + "SET_ACCOUNT" "SET_DATA_USAGE" "SET_DEVICE_NAME" "SET_VISIBILITY" @@ -169,117 +179,127 @@ static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry EventType_entries[] = { {EventType_names + 195, 28}, 20 }, { {EventType_names + 223, 26}, 19 }, { {EventType_names + 249, 18}, 46 }, - { {EventType_names + 267, 14}, 56 }, - { {EventType_names + 281, 20}, 4 }, - { {EventType_names + 301, 15}, 49 }, - { {EventType_names + 316, 21}, 11 }, - { {EventType_names + 337, 27}, 29 }, - { {EventType_names + 364, 28}, 32 }, - { {EventType_names + 392, 21}, 54 }, - { {EventType_names + 413, 28}, 53 }, - { {EventType_names + 441, 21}, 2 }, - { {EventType_names + 462, 20}, 48 }, - { {EventType_names + 482, 26}, 25 }, - { {EventType_names + 508, 11}, 40 }, - { {EventType_names + 519, 15}, 31 }, - { {EventType_names + 534, 14}, 42 }, - { {EventType_names + 548, 20}, 38 }, - { {EventType_names + 568, 21}, 22 }, - { {EventType_names + 589, 25}, 21 }, - { {EventType_names + 614, 17}, 55 }, - { {EventType_names + 631, 32}, 43 }, - { {EventType_names + 663, 18}, 59 }, - { {EventType_names + 681, 23}, 18 }, - { {EventType_names + 704, 25}, 17 }, - { {EventType_names + 729, 27}, 10 }, - { {EventType_names + 756, 20}, 13 }, - { {EventType_names + 776, 14}, 24 }, - { {EventType_names + 790, 26}, 37 }, - { {EventType_names + 816, 27}, 47 }, - { {EventType_names + 843, 23}, 14 }, - { {EventType_names + 866, 26}, 6 }, - { {EventType_names + 892, 28}, 5 }, - { {EventType_names + 920, 20}, 16 }, - { {EventType_names + 940, 22}, 15 }, - { {EventType_names + 962, 24}, 9 }, - { {EventType_names + 986, 17}, 12 }, - { {EventType_names + 1003, 10}, 26 }, - { {EventType_names + 1013, 12}, 57 }, - { {EventType_names + 1025, 14}, 28 }, - { {EventType_names + 1039, 15}, 45 }, - { {EventType_names + 1054, 14}, 3 }, - { {EventType_names + 1068, 12}, 35 }, - { {EventType_names + 1080, 8}, 34 }, - { {EventType_names + 1088, 24}, 33 }, - { {EventType_names + 1112, 11}, 58 }, - { {EventType_names + 1123, 29}, 52 }, - { {EventType_names + 1152, 23}, 39 }, - { {EventType_names + 1175, 24}, 44 }, - { {EventType_names + 1199, 18}, 0 }, - { {EventType_names + 1217, 10}, 41 }, + { {EventType_names + 267, 27}, 64 }, + { {EventType_names + 294, 14}, 56 }, + { {EventType_names + 308, 20}, 4 }, + { {EventType_names + 328, 15}, 49 }, + { {EventType_names + 343, 21}, 11 }, + { {EventType_names + 364, 27}, 29 }, + { {EventType_names + 391, 28}, 32 }, + { {EventType_names + 419, 21}, 54 }, + { {EventType_names + 440, 28}, 53 }, + { {EventType_names + 468, 21}, 2 }, + { {EventType_names + 489, 20}, 48 }, + { {EventType_names + 509, 25}, 61 }, + { {EventType_names + 534, 26}, 25 }, + { {EventType_names + 560, 11}, 40 }, + { {EventType_names + 571, 15}, 31 }, + { {EventType_names + 586, 14}, 42 }, + { {EventType_names + 600, 20}, 38 }, + { {EventType_names + 620, 21}, 22 }, + { {EventType_names + 641, 25}, 21 }, + { {EventType_names + 666, 26}, 60 }, + { {EventType_names + 692, 17}, 55 }, + { {EventType_names + 709, 32}, 43 }, + { {EventType_names + 741, 18}, 59 }, + { {EventType_names + 759, 23}, 18 }, + { {EventType_names + 782, 25}, 17 }, + { {EventType_names + 807, 27}, 10 }, + { {EventType_names + 834, 20}, 13 }, + { {EventType_names + 854, 14}, 24 }, + { {EventType_names + 868, 26}, 37 }, + { {EventType_names + 894, 27}, 47 }, + { {EventType_names + 921, 23}, 14 }, + { {EventType_names + 944, 26}, 6 }, + { {EventType_names + 970, 28}, 5 }, + { {EventType_names + 998, 20}, 16 }, + { {EventType_names + 1018, 22}, 15 }, + { {EventType_names + 1040, 25}, 62 }, + { {EventType_names + 1065, 24}, 9 }, + { {EventType_names + 1089, 17}, 12 }, + { {EventType_names + 1106, 10}, 26 }, + { {EventType_names + 1116, 12}, 57 }, + { {EventType_names + 1128, 11}, 63 }, + { {EventType_names + 1139, 14}, 28 }, + { {EventType_names + 1153, 15}, 45 }, + { {EventType_names + 1168, 14}, 3 }, + { {EventType_names + 1182, 12}, 35 }, + { {EventType_names + 1194, 8}, 34 }, + { {EventType_names + 1202, 24}, 33 }, + { {EventType_names + 1226, 11}, 58 }, + { {EventType_names + 1237, 29}, 52 }, + { {EventType_names + 1266, 23}, 39 }, + { {EventType_names + 1289, 24}, 44 }, + { {EventType_names + 1313, 18}, 0 }, + { {EventType_names + 1331, 10}, 41 }, }; static const int EventType_entries_by_number[] = { - 58, // 0 -> UNKNOWN_EVENT_TYPE + 63, // 0 -> UNKNOWN_EVENT_TYPE 0, // 1 -> ACCEPT_AGREEMENTS - 20, // 2 -> ENABLE_NEARBY_SHARING - 50, // 3 -> SET_VISIBILITY - 13, // 4 -> DESCRIBE_ATTACHMENTS - 41, // 5 -> SCAN_FOR_SHARE_TARGETS_START - 40, // 6 -> SCAN_FOR_SHARE_TARGETS_END + 21, // 2 -> ENABLE_NEARBY_SHARING + 55, // 3 -> SET_VISIBILITY + 14, // 4 -> DESCRIBE_ATTACHMENTS + 44, // 5 -> SCAN_FOR_SHARE_TARGETS_START + 43, // 6 -> SCAN_FOR_SHARE_TARGETS_END 5, // 7 -> ADVERTISE_DEVICE_PRESENCE_START 4, // 8 -> ADVERTISE_DEVICE_PRESENCE_END - 44, // 9 -> SEND_FAST_INITIALIZATION - 34, // 10 -> RECEIVE_FAST_INITIALIZATION - 15, // 11 -> DISCOVER_SHARE_TARGET - 45, // 12 -> SEND_INTRODUCTION - 35, // 13 -> RECEIVE_INTRODUCTION - 39, // 14 -> RESPOND_TO_INTRODUCTION - 43, // 15 -> SEND_ATTACHMENTS_START - 42, // 16 -> SEND_ATTACHMENTS_END - 33, // 17 -> RECEIVE_ATTACHMENTS_START - 32, // 18 -> RECEIVE_ATTACHMENTS_END + 48, // 9 -> SEND_FAST_INITIALIZATION + 37, // 10 -> RECEIVE_FAST_INITIALIZATION + 16, // 11 -> DISCOVER_SHARE_TARGET + 49, // 12 -> SEND_INTRODUCTION + 38, // 13 -> RECEIVE_INTRODUCTION + 42, // 14 -> RESPOND_TO_INTRODUCTION + 46, // 15 -> SEND_ATTACHMENTS_START + 45, // 16 -> SEND_ATTACHMENTS_END + 36, // 17 -> RECEIVE_ATTACHMENTS_START + 35, // 18 -> RECEIVE_ATTACHMENTS_END 10, // 19 -> CANCEL_SENDING_ATTACHMENTS 9, // 20 -> CANCEL_RECEIVING_ATTACHMENTS - 28, // 21 -> OPEN_RECEIVED_ATTACHMENTS - 27, // 22 -> LAUNCH_SETUP_ACTIVITY + 30, // 21 -> OPEN_RECEIVED_ATTACHMENTS + 29, // 22 -> LAUNCH_SETUP_ACTIVITY 2, // 23 -> ADD_CONTACT - 36, // 24 -> REMOVE_CONTACT - 22, // 25 -> FAST_SHARE_SERVER_RESPONSE - 46, // 26 -> SEND_START + 39, // 24 -> REMOVE_CONTACT + 24, // 25 -> FAST_SHARE_SERVER_RESPONSE + 50, // 26 -> SEND_START 1, // 27 -> ACCEPT_FAST_INITIALIZATION - 48, // 28 -> SET_DATA_USAGE - 16, // 29 -> DISMISS_FAST_INITIALIZATION + 53, // 28 -> SET_DATA_USAGE + 17, // 29 -> DISMISS_FAST_INITIALIZATION 8, // 30 -> CANCEL_CONNECTION - 24, // 31 -> LAUNCH_ACTIVITY - 17, // 32 -> DISMISS_PRIVACY_NOTIFICATION - 53, // 33 -> TAP_PRIVACY_NOTIFICATION - 52, // 34 -> TAP_HELP - 51, // 35 -> TAP_FEEDBACK + 26, // 31 -> LAUNCH_ACTIVITY + 18, // 32 -> DISMISS_PRIVACY_NOTIFICATION + 58, // 33 -> TAP_PRIVACY_NOTIFICATION + 57, // 34 -> TAP_HELP + 56, // 35 -> TAP_FEEDBACK 3, // 36 -> ADD_QUICK_SETTINGS_TILE - 37, // 37 -> REMOVE_QUICK_SETTINGS_TILE - 26, // 38 -> LAUNCH_PHONE_CONSENT - 56, // 39 -> TAP_QUICK_SETTINGS_TILE - 23, // 40 -> INSTALL_APK - 59, // 41 -> VERIFY_APK - 25, // 42 -> LAUNCH_CONSENT - 30, // 43 -> PROCESS_RECEIVED_ATTACHMENTS_END - 57, // 44 -> TOGGLE_SHOW_NOTIFICATION - 49, // 45 -> SET_DEVICE_NAME + 40, // 37 -> REMOVE_QUICK_SETTINGS_TILE + 28, // 38 -> LAUNCH_PHONE_CONSENT + 61, // 39 -> TAP_QUICK_SETTINGS_TILE + 25, // 40 -> INSTALL_APK + 64, // 41 -> VERIFY_APK + 27, // 42 -> LAUNCH_CONSENT + 33, // 43 -> PROCESS_RECEIVED_ATTACHMENTS_END + 62, // 44 -> TOGGLE_SHOW_NOTIFICATION + 54, // 45 -> SET_DEVICE_NAME 11, // 46 -> DECLINE_AGREEMENTS - 38, // 47 -> REQUEST_SETTING_PERMISSIONS - 21, // 48 -> ESTABLISH_CONNECTION - 14, // 49 -> DEVICE_SETTINGS + 41, // 47 -> REQUEST_SETTING_PERMISSIONS + 22, // 48 -> ESTABLISH_CONNECTION + 15, // 49 -> DEVICE_SETTINGS 7, // 50 -> AUTO_DISMISS_FAST_INITIALIZATION 6, // 51 -> APP_CRASH - 55, // 52 -> TAP_QUICK_SETTINGS_FILE_SHARE - 19, // 53 -> DISPLAY_PRIVACY_NOTIFICATION - 18, // 54 -> DISPLAY_PHONE_CONSENT - 29, // 55 -> PREFERENCES_USAGE - 12, // 56 -> DEFAULT_OPT_IN - 47, // 57 -> SETUP_WIZARD - 54, // 58 -> TAP_QR_CODE - 31, // 59 -> QR_CODE_LINK_SHOWN + 60, // 52 -> TAP_QUICK_SETTINGS_FILE_SHARE + 20, // 53 -> DISPLAY_PRIVACY_NOTIFICATION + 19, // 54 -> DISPLAY_PHONE_CONSENT + 32, // 55 -> PREFERENCES_USAGE + 13, // 56 -> DEFAULT_OPT_IN + 51, // 57 -> SETUP_WIZARD + 59, // 58 -> TAP_QR_CODE + 34, // 59 -> QR_CODE_LINK_SHOWN + 31, // 60 -> PARSING_FAILED_ENDPOINT_ID + 23, // 61 -> FAST_INIT_DISCOVER_DEVICE + 47, // 62 -> SEND_DESKTOP_NOTIFICATION + 52, // 63 -> SET_ACCOUNT + 12, // 64 -> DECRYPT_CERTIFICATE_FAILURE }; const std::string& EventType_Name( @@ -288,12 +308,12 @@ const std::string& EventType_Name( ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( EventType_entries, EventType_entries_by_number, - 60, EventType_strings); + 65, EventType_strings); (void) dummy; int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( EventType_entries, EventType_entries_by_number, - 60, value); + 65, value); return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : EventType_strings[idx].get(); } @@ -301,7 +321,7 @@ bool EventType_Parse( ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, EventType* value) { int int_value; bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( - EventType_entries, 60, name, &int_value); + EventType_entries, 65, name, &int_value); if (success) { *value = static_cast(int_value); } @@ -626,13 +646,17 @@ bool AttachmentTransmissionStatus_IsValid(int value) { case 15: case 16: case 17: + case 18: + case 19: + case 20: + case 21: return true; default: return false; } } -static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed AttachmentTransmissionStatus_strings[18] = {}; +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed AttachmentTransmissionStatus_strings[22] = {}; static const char AttachmentTransmissionStatus_names[] = "AWAITING_REMOTE_ACCEPTANCE_FAILED_ATTACHMENT" @@ -643,6 +667,10 @@ static const char AttachmentTransmissionStatus_names[] = "FAILED_NO_SHARE_TARGET_ENDPOINT" "FAILED_NO_TRANSFER_UPDATE_CALLBACK" "FAILED_NULL_CONNECTION" + "FAILED_NULL_CONNECTION_DISCONNECTED" + "FAILED_NULL_CONNECTION_FAILURE" + "FAILED_NULL_CONNECTION_INIT_OUTGOING" + "FAILED_NULL_CONNECTION_LOST_CONNECTIVITY" "FAILED_PAIRED_KEYHANDSHAKE" "FAILED_UNKNOWN_REMOTE_RESPONSE" "FAILED_WRITE_INTRODUCTION" @@ -663,37 +691,45 @@ static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry AttachmentTransmission { {AttachmentTransmissionStatus_names + 176, 31}, 12 }, { {AttachmentTransmissionStatus_names + 207, 34}, 8 }, { {AttachmentTransmissionStatus_names + 241, 22}, 14 }, - { {AttachmentTransmissionStatus_names + 263, 26}, 13 }, - { {AttachmentTransmissionStatus_names + 289, 30}, 17 }, - { {AttachmentTransmissionStatus_names + 319, 25}, 16 }, - { {AttachmentTransmissionStatus_names + 344, 28}, 9 }, - { {AttachmentTransmissionStatus_names + 372, 27}, 7 }, - { {AttachmentTransmissionStatus_names + 399, 19}, 11 }, - { {AttachmentTransmissionStatus_names + 418, 19}, 4 }, - { {AttachmentTransmissionStatus_names + 437, 20}, 5 }, - { {AttachmentTransmissionStatus_names + 457, 38}, 0 }, - { {AttachmentTransmissionStatus_names + 495, 38}, 10 }, + { {AttachmentTransmissionStatus_names + 263, 35}, 19 }, + { {AttachmentTransmissionStatus_names + 298, 30}, 21 }, + { {AttachmentTransmissionStatus_names + 328, 36}, 18 }, + { {AttachmentTransmissionStatus_names + 364, 40}, 20 }, + { {AttachmentTransmissionStatus_names + 404, 26}, 13 }, + { {AttachmentTransmissionStatus_names + 430, 30}, 17 }, + { {AttachmentTransmissionStatus_names + 460, 25}, 16 }, + { {AttachmentTransmissionStatus_names + 485, 28}, 9 }, + { {AttachmentTransmissionStatus_names + 513, 27}, 7 }, + { {AttachmentTransmissionStatus_names + 540, 19}, 11 }, + { {AttachmentTransmissionStatus_names + 559, 19}, 4 }, + { {AttachmentTransmissionStatus_names + 578, 20}, 5 }, + { {AttachmentTransmissionStatus_names + 598, 38}, 0 }, + { {AttachmentTransmissionStatus_names + 636, 38}, 10 }, }; static const int AttachmentTransmissionStatus_entries_by_number[] = { - 16, // 0 -> UNKNOWN_ATTACHMENT_TRANSMISSION_STATUS + 20, // 0 -> UNKNOWN_ATTACHMENT_TRANSMISSION_STATUS 2, // 1 -> COMPLETE_ATTACHMENT_TRANSMISSION_STATUS 1, // 2 -> CANCELED_ATTACHMENT_TRANSMISSION_STATUS 3, // 3 -> FAILED_ATTACHMENT_TRANSMISSION_STATUS - 14, // 4 -> REJECTED_ATTACHMENT - 15, // 5 -> TIMED_OUT_ATTACHMENT + 18, // 4 -> REJECTED_ATTACHMENT + 19, // 5 -> TIMED_OUT_ATTACHMENT 0, // 6 -> AWAITING_REMOTE_ACCEPTANCE_FAILED_ATTACHMENT - 12, // 7 -> NOT_ENOUGH_SPACE_ATTACHMENT + 16, // 7 -> NOT_ENOUGH_SPACE_ATTACHMENT 6, // 8 -> FAILED_NO_TRANSFER_UPDATE_CALLBACK - 11, // 9 -> MEDIA_UNAVAILABLE_ATTACHMENT - 17, // 10 -> UNSUPPORTED_ATTACHMENT_TYPE_ATTACHMENT - 13, // 11 -> NO_ATTACHMENT_FOUND + 15, // 9 -> MEDIA_UNAVAILABLE_ATTACHMENT + 21, // 10 -> UNSUPPORTED_ATTACHMENT_TYPE_ATTACHMENT + 17, // 11 -> NO_ATTACHMENT_FOUND 5, // 12 -> FAILED_NO_SHARE_TARGET_ENDPOINT - 8, // 13 -> FAILED_PAIRED_KEYHANDSHAKE + 12, // 13 -> FAILED_PAIRED_KEYHANDSHAKE 7, // 14 -> FAILED_NULL_CONNECTION 4, // 15 -> FAILED_NO_PAYLOAD - 10, // 16 -> FAILED_WRITE_INTRODUCTION - 9, // 17 -> FAILED_UNKNOWN_REMOTE_RESPONSE + 14, // 16 -> FAILED_WRITE_INTRODUCTION + 13, // 17 -> FAILED_UNKNOWN_REMOTE_RESPONSE + 10, // 18 -> FAILED_NULL_CONNECTION_INIT_OUTGOING + 8, // 19 -> FAILED_NULL_CONNECTION_DISCONNECTED + 11, // 20 -> FAILED_NULL_CONNECTION_LOST_CONNECTIVITY + 9, // 21 -> FAILED_NULL_CONNECTION_FAILURE }; const std::string& AttachmentTransmissionStatus_Name( @@ -702,12 +738,12 @@ const std::string& AttachmentTransmissionStatus_Name( ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( AttachmentTransmissionStatus_entries, AttachmentTransmissionStatus_entries_by_number, - 18, AttachmentTransmissionStatus_strings); + 22, AttachmentTransmissionStatus_strings); (void) dummy; int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( AttachmentTransmissionStatus_entries, AttachmentTransmissionStatus_entries_by_number, - 18, value); + 22, value); return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : AttachmentTransmissionStatus_strings[idx].get(); } @@ -715,12 +751,131 @@ bool AttachmentTransmissionStatus_Parse( ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, AttachmentTransmissionStatus* value) { int int_value; bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( - AttachmentTransmissionStatus_entries, 18, name, &int_value); + AttachmentTransmissionStatus_entries, 22, name, &int_value); if (success) { *value = static_cast(int_value); } return success; } +bool ConnectionLayerStatus_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed ConnectionLayerStatus_strings[19] = {}; + +static const char ConnectionLayerStatus_names[] = + "CONNECTION_LAYER_STATUS_ALREADY_ADVERTISING" + "CONNECTION_LAYER_STATUS_ALREADY_CONNECTED_TO_END_POINT" + "CONNECTION_LAYER_STATUS_ALREADY_DISCOVERING" + "CONNECTION_LAYER_STATUS_ALREADY_HAVE_ACTIVE_STRATEGY" + "CONNECTION_LAYER_STATUS_ALREADY_LISTENING" + "CONNECTION_LAYER_STATUS_BLE_ERROR" + "CONNECTION_LAYER_STATUS_BLUETOOTH_ERROR" + "CONNECTION_LAYER_STATUS_CONNECTION_REJECTED" + "CONNECTION_LAYER_STATUS_END_POINT_IO_ERROR" + "CONNECTION_LAYER_STATUS_END_POINT_UNKNOWN" + "CONNECTION_LAYER_STATUS_ERROR" + "CONNECTION_LAYER_STATUS_NOT_CONNECTED_TO_END_POINT" + "CONNECTION_LAYER_STATUS_OUT_OF_ORDER_API_CALL" + "CONNECTION_LAYER_STATUS_PAYLOAD_UNKNOWN" + "CONNECTION_LAYER_STATUS_RESET" + "CONNECTION_LAYER_STATUS_SUCCESS" + "CONNECTION_LAYER_STATUS_TIMEOUT" + "CONNECTION_LAYER_STATUS_UNKNOWN" + "CONNECTION_LAYER_STATUS_WIFI_LAN_ERROR"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry ConnectionLayerStatus_entries[] = { + { {ConnectionLayerStatus_names + 0, 43}, 5 }, + { {ConnectionLayerStatus_names + 43, 54}, 11 }, + { {ConnectionLayerStatus_names + 97, 43}, 6 }, + { {ConnectionLayerStatus_names + 140, 52}, 4 }, + { {ConnectionLayerStatus_names + 192, 41}, 7 }, + { {ConnectionLayerStatus_names + 233, 33}, 14 }, + { {ConnectionLayerStatus_names + 266, 39}, 13 }, + { {ConnectionLayerStatus_names + 305, 43}, 10 }, + { {ConnectionLayerStatus_names + 348, 42}, 8 }, + { {ConnectionLayerStatus_names + 390, 41}, 9 }, + { {ConnectionLayerStatus_names + 431, 29}, 2 }, + { {ConnectionLayerStatus_names + 460, 50}, 12 }, + { {ConnectionLayerStatus_names + 510, 45}, 3 }, + { {ConnectionLayerStatus_names + 555, 39}, 16 }, + { {ConnectionLayerStatus_names + 594, 29}, 17 }, + { {ConnectionLayerStatus_names + 623, 31}, 1 }, + { {ConnectionLayerStatus_names + 654, 31}, 18 }, + { {ConnectionLayerStatus_names + 685, 31}, 0 }, + { {ConnectionLayerStatus_names + 716, 38}, 15 }, +}; + +static const int ConnectionLayerStatus_entries_by_number[] = { + 17, // 0 -> CONNECTION_LAYER_STATUS_UNKNOWN + 15, // 1 -> CONNECTION_LAYER_STATUS_SUCCESS + 10, // 2 -> CONNECTION_LAYER_STATUS_ERROR + 12, // 3 -> CONNECTION_LAYER_STATUS_OUT_OF_ORDER_API_CALL + 3, // 4 -> CONNECTION_LAYER_STATUS_ALREADY_HAVE_ACTIVE_STRATEGY + 0, // 5 -> CONNECTION_LAYER_STATUS_ALREADY_ADVERTISING + 2, // 6 -> CONNECTION_LAYER_STATUS_ALREADY_DISCOVERING + 4, // 7 -> CONNECTION_LAYER_STATUS_ALREADY_LISTENING + 8, // 8 -> CONNECTION_LAYER_STATUS_END_POINT_IO_ERROR + 9, // 9 -> CONNECTION_LAYER_STATUS_END_POINT_UNKNOWN + 7, // 10 -> CONNECTION_LAYER_STATUS_CONNECTION_REJECTED + 1, // 11 -> CONNECTION_LAYER_STATUS_ALREADY_CONNECTED_TO_END_POINT + 11, // 12 -> CONNECTION_LAYER_STATUS_NOT_CONNECTED_TO_END_POINT + 6, // 13 -> CONNECTION_LAYER_STATUS_BLUETOOTH_ERROR + 5, // 14 -> CONNECTION_LAYER_STATUS_BLE_ERROR + 18, // 15 -> CONNECTION_LAYER_STATUS_WIFI_LAN_ERROR + 13, // 16 -> CONNECTION_LAYER_STATUS_PAYLOAD_UNKNOWN + 14, // 17 -> CONNECTION_LAYER_STATUS_RESET + 16, // 18 -> CONNECTION_LAYER_STATUS_TIMEOUT +}; + +const std::string& ConnectionLayerStatus_Name( + ConnectionLayerStatus value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + ConnectionLayerStatus_entries, + ConnectionLayerStatus_entries_by_number, + 19, ConnectionLayerStatus_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + ConnectionLayerStatus_entries, + ConnectionLayerStatus_entries_by_number, + 19, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + ConnectionLayerStatus_strings[idx].get(); +} +bool ConnectionLayerStatus_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, ConnectionLayerStatus* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + ConnectionLayerStatus_entries, 19, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} bool ProcessReceivedAttachmentsStatus_IsValid(int value) { switch (value) { case 0: @@ -1328,6 +1483,168 @@ bool ServerResponseState_Parse( } return success; } +bool SyncPurpose_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed SyncPurpose_strings[16] = {}; + +static const char SyncPurpose_names[] = + "SYNC_PURPOSE_ACCOUNT_CHANGE" + "SYNC_PURPOSE_CHECK_DEFAULT_OPT_IN" + "SYNC_PURPOSE_CHIME_NOTIFICATION" + "SYNC_PURPOSE_CONTACT_LIST_CHANGE" + "SYNC_PURPOSE_DAILY_SYNC" + "SYNC_PURPOSE_NEARBY_SHARE_ENABLED" + "SYNC_PURPOSE_ON_DEMAND_SYNC" + "SYNC_PURPOSE_OPT_IN_FIRST_SYNC" + "SYNC_PURPOSE_REGULAR_CHECK_CONTACT_REACHABILITY" + "SYNC_PURPOSE_SHOW_C11N_VIEW" + "SYNC_PURPOSE_SYNC_AT_ADVERTISEMENT" + "SYNC_PURPOSE_SYNC_AT_DISCOVERY" + "SYNC_PURPOSE_SYNC_AT_FAST_INIT" + "SYNC_PURPOSE_SYNC_AT_LOAD_PRIVATE_CERTIFICATE" + "SYNC_PURPOSE_UNKNOWN" + "SYNC_PURPOSE_VISIBILITY_SELECTED_CONTACT_CHANGE"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry SyncPurpose_entries[] = { + { {SyncPurpose_names + 0, 27}, 15 }, + { {SyncPurpose_names + 27, 33}, 5 }, + { {SyncPurpose_names + 60, 31}, 2 }, + { {SyncPurpose_names + 91, 32}, 11 }, + { {SyncPurpose_names + 123, 23}, 3 }, + { {SyncPurpose_names + 146, 33}, 6 }, + { {SyncPurpose_names + 179, 27}, 1 }, + { {SyncPurpose_names + 206, 30}, 4 }, + { {SyncPurpose_names + 236, 47}, 13 }, + { {SyncPurpose_names + 283, 27}, 12 }, + { {SyncPurpose_names + 310, 34}, 10 }, + { {SyncPurpose_names + 344, 30}, 8 }, + { {SyncPurpose_names + 374, 30}, 7 }, + { {SyncPurpose_names + 404, 45}, 9 }, + { {SyncPurpose_names + 449, 20}, 0 }, + { {SyncPurpose_names + 469, 47}, 14 }, +}; + +static const int SyncPurpose_entries_by_number[] = { + 14, // 0 -> SYNC_PURPOSE_UNKNOWN + 6, // 1 -> SYNC_PURPOSE_ON_DEMAND_SYNC + 2, // 2 -> SYNC_PURPOSE_CHIME_NOTIFICATION + 4, // 3 -> SYNC_PURPOSE_DAILY_SYNC + 7, // 4 -> SYNC_PURPOSE_OPT_IN_FIRST_SYNC + 1, // 5 -> SYNC_PURPOSE_CHECK_DEFAULT_OPT_IN + 5, // 6 -> SYNC_PURPOSE_NEARBY_SHARE_ENABLED + 12, // 7 -> SYNC_PURPOSE_SYNC_AT_FAST_INIT + 11, // 8 -> SYNC_PURPOSE_SYNC_AT_DISCOVERY + 13, // 9 -> SYNC_PURPOSE_SYNC_AT_LOAD_PRIVATE_CERTIFICATE + 10, // 10 -> SYNC_PURPOSE_SYNC_AT_ADVERTISEMENT + 3, // 11 -> SYNC_PURPOSE_CONTACT_LIST_CHANGE + 9, // 12 -> SYNC_PURPOSE_SHOW_C11N_VIEW + 8, // 13 -> SYNC_PURPOSE_REGULAR_CHECK_CONTACT_REACHABILITY + 15, // 14 -> SYNC_PURPOSE_VISIBILITY_SELECTED_CONTACT_CHANGE + 0, // 15 -> SYNC_PURPOSE_ACCOUNT_CHANGE +}; + +const std::string& SyncPurpose_Name( + SyncPurpose value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + SyncPurpose_entries, + SyncPurpose_entries_by_number, + 16, SyncPurpose_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + SyncPurpose_entries, + SyncPurpose_entries_by_number, + 16, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + SyncPurpose_strings[idx].get(); +} +bool SyncPurpose_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, SyncPurpose* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + SyncPurpose_entries, 16, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} +bool ClientRole_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed ClientRole_strings[3] = {}; + +static const char ClientRole_names[] = + "CLIENT_ROLE_RECEIVER" + "CLIENT_ROLE_SENDER" + "CLIENT_ROLE_UNKNOWN"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry ClientRole_entries[] = { + { {ClientRole_names + 0, 20}, 2 }, + { {ClientRole_names + 20, 18}, 1 }, + { {ClientRole_names + 38, 19}, 0 }, +}; + +static const int ClientRole_entries_by_number[] = { + 2, // 0 -> CLIENT_ROLE_UNKNOWN + 1, // 1 -> CLIENT_ROLE_SENDER + 0, // 2 -> CLIENT_ROLE_RECEIVER +}; + +const std::string& ClientRole_Name( + ClientRole value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + ClientRole_entries, + ClientRole_entries_by_number, + 3, ClientRole_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + ClientRole_entries, + ClientRole_entries_by_number, + 3, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + ClientRole_strings[idx].get(); +} +bool ClientRole_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, ClientRole* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + ClientRole_entries, 3, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} bool ScanType_IsValid(int value) { switch (value) { case 0: @@ -1391,6 +1708,61 @@ bool ScanType_Parse( } return success; } +bool ParsingFailedType_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed ParsingFailedType_strings[3] = {}; + +static const char ParsingFailedType_names[] = + "FAILED_CONVERT_SHARE_TARGET" + "FAILED_PARSE_ADVERTISEMENT" + "FAILED_UNKNOWN_TYPE"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry ParsingFailedType_entries[] = { + { {ParsingFailedType_names + 0, 27}, 2 }, + { {ParsingFailedType_names + 27, 26}, 1 }, + { {ParsingFailedType_names + 53, 19}, 0 }, +}; + +static const int ParsingFailedType_entries_by_number[] = { + 2, // 0 -> FAILED_UNKNOWN_TYPE + 1, // 1 -> FAILED_PARSE_ADVERTISEMENT + 0, // 2 -> FAILED_CONVERT_SHARE_TARGET +}; + +const std::string& ParsingFailedType_Name( + ParsingFailedType value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + ParsingFailedType_entries, + ParsingFailedType_entries_by_number, + 3, ParsingFailedType_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + ParsingFailedType_entries, + ParsingFailedType_entries_by_number, + 3, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + ParsingFailedType_strings[idx].get(); +} +bool ParsingFailedType_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, ParsingFailedType* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + ParsingFailedType_entries, 3, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} bool AdvertisingMode_IsValid(int value) { switch (value) { case 0: @@ -2348,6 +2720,341 @@ bool PreferencesActionStatus_Parse( } return success; } +bool FastInitState_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + case 3: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed FastInitState_strings[4] = {}; + +static const char FastInitState_names[] = + "FAST_INIT_CLOSE_STATE" + "FAST_INIT_FAR_STATE" + "FAST_INIT_LOST_STATE" + "FAST_INIT_UNKNOWN_STATE"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry FastInitState_entries[] = { + { {FastInitState_names + 0, 21}, 1 }, + { {FastInitState_names + 21, 19}, 2 }, + { {FastInitState_names + 40, 20}, 3 }, + { {FastInitState_names + 60, 23}, 0 }, +}; + +static const int FastInitState_entries_by_number[] = { + 3, // 0 -> FAST_INIT_UNKNOWN_STATE + 0, // 1 -> FAST_INIT_CLOSE_STATE + 1, // 2 -> FAST_INIT_FAR_STATE + 2, // 3 -> FAST_INIT_LOST_STATE +}; + +const std::string& FastInitState_Name( + FastInitState value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + FastInitState_entries, + FastInitState_entries_by_number, + 4, FastInitState_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + FastInitState_entries, + FastInitState_entries_by_number, + 4, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + FastInitState_strings[idx].get(); +} +bool FastInitState_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FastInitState* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + FastInitState_entries, 4, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} +bool FastInitType_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed FastInitType_strings[3] = {}; + +static const char FastInitType_names[] = + "FAST_INIT_NOTIFY_TYPE" + "FAST_INIT_SILENT_TYPE" + "FAST_INIT_UNKNOWN_TYPE"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry FastInitType_entries[] = { + { {FastInitType_names + 0, 21}, 1 }, + { {FastInitType_names + 21, 21}, 2 }, + { {FastInitType_names + 42, 22}, 0 }, +}; + +static const int FastInitType_entries_by_number[] = { + 2, // 0 -> FAST_INIT_UNKNOWN_TYPE + 0, // 1 -> FAST_INIT_NOTIFY_TYPE + 1, // 2 -> FAST_INIT_SILENT_TYPE +}; + +const std::string& FastInitType_Name( + FastInitType value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + FastInitType_entries, + FastInitType_entries_by_number, + 3, FastInitType_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + FastInitType_entries, + FastInitType_entries_by_number, + 3, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + FastInitType_strings[idx].get(); +} +bool FastInitType_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FastInitType* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + FastInitType_entries, 3, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} +bool DesktopNotification_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed DesktopNotification_strings[6] = {}; + +static const char DesktopNotification_names[] = + "DESKTOP_NOTIFICATION_ACCEPT" + "DESKTOP_NOTIFICATION_CONNECTING" + "DESKTOP_NOTIFICATION_ERROR" + "DESKTOP_NOTIFICATION_PROGRESS" + "DESKTOP_NOTIFICATION_RECEIVED" + "DESKTOP_NOTIFICATION_UNKNOWN"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry DesktopNotification_entries[] = { + { {DesktopNotification_names + 0, 27}, 3 }, + { {DesktopNotification_names + 27, 31}, 1 }, + { {DesktopNotification_names + 58, 26}, 5 }, + { {DesktopNotification_names + 84, 29}, 2 }, + { {DesktopNotification_names + 113, 29}, 4 }, + { {DesktopNotification_names + 142, 28}, 0 }, +}; + +static const int DesktopNotification_entries_by_number[] = { + 5, // 0 -> DESKTOP_NOTIFICATION_UNKNOWN + 1, // 1 -> DESKTOP_NOTIFICATION_CONNECTING + 3, // 2 -> DESKTOP_NOTIFICATION_PROGRESS + 0, // 3 -> DESKTOP_NOTIFICATION_ACCEPT + 4, // 4 -> DESKTOP_NOTIFICATION_RECEIVED + 2, // 5 -> DESKTOP_NOTIFICATION_ERROR +}; + +const std::string& DesktopNotification_Name( + DesktopNotification value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + DesktopNotification_entries, + DesktopNotification_entries_by_number, + 6, DesktopNotification_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + DesktopNotification_entries, + DesktopNotification_entries_by_number, + 6, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + DesktopNotification_strings[idx].get(); +} +bool DesktopNotification_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, DesktopNotification* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + DesktopNotification_entries, 6, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} +bool DesktopTransferEventType_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed DesktopTransferEventType_strings[10] = {}; + +static const char DesktopTransferEventType_names[] = + "DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_ACCEPT" + "DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_ERROR" + "DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_PROGRESS" + "DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_RECEIVED" + "DESKTOP_TRANSFER_EVENT_SEND_TYPE_ERROR" + "DESKTOP_TRANSFER_EVENT_SEND_TYPE_PROGRESS" + "DESKTOP_TRANSFER_EVENT_SEND_TYPE_SELECT_A_DEVICE" + "DESKTOP_TRANSFER_EVENT_SEND_TYPE_SENT" + "DESKTOP_TRANSFER_EVENT_SEND_TYPE_START" + "DESKTOP_TRANSFER_EVENT_TYPE_UNKNOWN"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry DesktopTransferEventType_entries[] = { + { {DesktopTransferEventType_names + 0, 42}, 1 }, + { {DesktopTransferEventType_names + 42, 41}, 4 }, + { {DesktopTransferEventType_names + 83, 44}, 2 }, + { {DesktopTransferEventType_names + 127, 44}, 3 }, + { {DesktopTransferEventType_names + 171, 38}, 9 }, + { {DesktopTransferEventType_names + 209, 41}, 7 }, + { {DesktopTransferEventType_names + 250, 48}, 6 }, + { {DesktopTransferEventType_names + 298, 37}, 8 }, + { {DesktopTransferEventType_names + 335, 38}, 5 }, + { {DesktopTransferEventType_names + 373, 35}, 0 }, +}; + +static const int DesktopTransferEventType_entries_by_number[] = { + 9, // 0 -> DESKTOP_TRANSFER_EVENT_TYPE_UNKNOWN + 0, // 1 -> DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_ACCEPT + 2, // 2 -> DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_PROGRESS + 3, // 3 -> DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_RECEIVED + 1, // 4 -> DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_ERROR + 8, // 5 -> DESKTOP_TRANSFER_EVENT_SEND_TYPE_START + 6, // 6 -> DESKTOP_TRANSFER_EVENT_SEND_TYPE_SELECT_A_DEVICE + 5, // 7 -> DESKTOP_TRANSFER_EVENT_SEND_TYPE_PROGRESS + 7, // 8 -> DESKTOP_TRANSFER_EVENT_SEND_TYPE_SENT + 4, // 9 -> DESKTOP_TRANSFER_EVENT_SEND_TYPE_ERROR +}; + +const std::string& DesktopTransferEventType_Name( + DesktopTransferEventType value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + DesktopTransferEventType_entries, + DesktopTransferEventType_entries_by_number, + 10, DesktopTransferEventType_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + DesktopTransferEventType_entries, + DesktopTransferEventType_entries_by_number, + 10, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + DesktopTransferEventType_strings[idx].get(); +} +bool DesktopTransferEventType_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, DesktopTransferEventType* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + DesktopTransferEventType_entries, 10, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} +bool DecryptCertificateFailureStatus_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + return true; + default: + return false; + } +} + +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed DecryptCertificateFailureStatus_strings[7] = {}; + +static const char DecryptCertificateFailureStatus_names[] = + "DECRYPT_CERT_BAD_PADDING_FAILURE" + "DECRYPT_CERT_ILLEGAL_BLOCK_SIZE_FAILURE" + "DECRYPT_CERT_INVALID_ALGORITHM_PARAMETER_FAILURE" + "DECRYPT_CERT_INVALID_KEY_FAILURE" + "DECRYPT_CERT_NO_SUCH_ALGORITHM_FAILURE" + "DECRYPT_CERT_NO_SUCH_PADDING_FAILURE" + "DECRYPT_CERT_UNKNOWN_FAILURE"; + +static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry DecryptCertificateFailureStatus_entries[] = { + { {DecryptCertificateFailureStatus_names + 0, 32}, 6 }, + { {DecryptCertificateFailureStatus_names + 32, 39}, 5 }, + { {DecryptCertificateFailureStatus_names + 71, 48}, 4 }, + { {DecryptCertificateFailureStatus_names + 119, 32}, 3 }, + { {DecryptCertificateFailureStatus_names + 151, 38}, 1 }, + { {DecryptCertificateFailureStatus_names + 189, 36}, 2 }, + { {DecryptCertificateFailureStatus_names + 225, 28}, 0 }, +}; + +static const int DecryptCertificateFailureStatus_entries_by_number[] = { + 6, // 0 -> DECRYPT_CERT_UNKNOWN_FAILURE + 4, // 1 -> DECRYPT_CERT_NO_SUCH_ALGORITHM_FAILURE + 5, // 2 -> DECRYPT_CERT_NO_SUCH_PADDING_FAILURE + 3, // 3 -> DECRYPT_CERT_INVALID_KEY_FAILURE + 2, // 4 -> DECRYPT_CERT_INVALID_ALGORITHM_PARAMETER_FAILURE + 1, // 5 -> DECRYPT_CERT_ILLEGAL_BLOCK_SIZE_FAILURE + 0, // 6 -> DECRYPT_CERT_BAD_PADDING_FAILURE +}; + +const std::string& DecryptCertificateFailureStatus_Name( + DecryptCertificateFailureStatus value) { + static const bool dummy = + ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( + DecryptCertificateFailureStatus_entries, + DecryptCertificateFailureStatus_entries_by_number, + 7, DecryptCertificateFailureStatus_strings); + (void) dummy; + int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( + DecryptCertificateFailureStatus_entries, + DecryptCertificateFailureStatus_entries_by_number, + 7, value); + return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : + DecryptCertificateFailureStatus_strings[idx].get(); +} +bool DecryptCertificateFailureStatus_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, DecryptCertificateFailureStatus* value) { + int int_value; + bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( + DecryptCertificateFailureStatus_entries, 7, name, &int_value); + if (success) { + *value = static_cast(int_value); + } + return success; +} // @@protoc_insertion_point(namespace_scope) } // namespace sharing diff --git a/compiled_proto/proto/sharing_enums.pb.h b/compiled_proto/proto/sharing_enums.pb.h index 21e0a4b7..6bf8b7c6 100644 --- a/compiled_proto/proto/sharing_enums.pb.h +++ b/compiled_proto/proto/sharing_enums.pb.h @@ -117,11 +117,16 @@ enum EventType : int { DEFAULT_OPT_IN = 56, SETUP_WIZARD = 57, TAP_QR_CODE = 58, - QR_CODE_LINK_SHOWN = 59 + QR_CODE_LINK_SHOWN = 59, + PARSING_FAILED_ENDPOINT_ID = 60, + FAST_INIT_DISCOVER_DEVICE = 61, + SEND_DESKTOP_NOTIFICATION = 62, + SET_ACCOUNT = 63, + DECRYPT_CERTIFICATE_FAILURE = 64 }; bool EventType_IsValid(int value); constexpr EventType EventType_MIN = UNKNOWN_EVENT_TYPE; -constexpr EventType EventType_MAX = QR_CODE_LINK_SHOWN; +constexpr EventType EventType_MAX = DECRYPT_CERTIFICATE_FAILURE; constexpr int EventType_ARRAYSIZE = EventType_MAX + 1; const std::string& EventType_Name(EventType value); @@ -258,11 +263,15 @@ enum AttachmentTransmissionStatus : int { FAILED_NULL_CONNECTION = 14, FAILED_NO_PAYLOAD = 15, FAILED_WRITE_INTRODUCTION = 16, - FAILED_UNKNOWN_REMOTE_RESPONSE = 17 + FAILED_UNKNOWN_REMOTE_RESPONSE = 17, + FAILED_NULL_CONNECTION_INIT_OUTGOING = 18, + FAILED_NULL_CONNECTION_DISCONNECTED = 19, + FAILED_NULL_CONNECTION_LOST_CONNECTIVITY = 20, + FAILED_NULL_CONNECTION_FAILURE = 21 }; bool AttachmentTransmissionStatus_IsValid(int value); constexpr AttachmentTransmissionStatus AttachmentTransmissionStatus_MIN = UNKNOWN_ATTACHMENT_TRANSMISSION_STATUS; -constexpr AttachmentTransmissionStatus AttachmentTransmissionStatus_MAX = FAILED_UNKNOWN_REMOTE_RESPONSE; +constexpr AttachmentTransmissionStatus AttachmentTransmissionStatus_MAX = FAILED_NULL_CONNECTION_FAILURE; constexpr int AttachmentTransmissionStatus_ARRAYSIZE = AttachmentTransmissionStatus_MAX + 1; const std::string& AttachmentTransmissionStatus_Name(AttachmentTransmissionStatus value); @@ -275,6 +284,42 @@ inline const std::string& AttachmentTransmissionStatus_Name(T enum_t_value) { } bool AttachmentTransmissionStatus_Parse( ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, AttachmentTransmissionStatus* value); +enum ConnectionLayerStatus : int { + CONNECTION_LAYER_STATUS_UNKNOWN = 0, + CONNECTION_LAYER_STATUS_SUCCESS = 1, + CONNECTION_LAYER_STATUS_ERROR = 2, + CONNECTION_LAYER_STATUS_OUT_OF_ORDER_API_CALL = 3, + CONNECTION_LAYER_STATUS_ALREADY_HAVE_ACTIVE_STRATEGY = 4, + CONNECTION_LAYER_STATUS_ALREADY_ADVERTISING = 5, + CONNECTION_LAYER_STATUS_ALREADY_DISCOVERING = 6, + CONNECTION_LAYER_STATUS_ALREADY_LISTENING = 7, + CONNECTION_LAYER_STATUS_END_POINT_IO_ERROR = 8, + CONNECTION_LAYER_STATUS_END_POINT_UNKNOWN = 9, + CONNECTION_LAYER_STATUS_CONNECTION_REJECTED = 10, + CONNECTION_LAYER_STATUS_ALREADY_CONNECTED_TO_END_POINT = 11, + CONNECTION_LAYER_STATUS_NOT_CONNECTED_TO_END_POINT = 12, + CONNECTION_LAYER_STATUS_BLUETOOTH_ERROR = 13, + CONNECTION_LAYER_STATUS_BLE_ERROR = 14, + CONNECTION_LAYER_STATUS_WIFI_LAN_ERROR = 15, + CONNECTION_LAYER_STATUS_PAYLOAD_UNKNOWN = 16, + CONNECTION_LAYER_STATUS_RESET = 17, + CONNECTION_LAYER_STATUS_TIMEOUT = 18 +}; +bool ConnectionLayerStatus_IsValid(int value); +constexpr ConnectionLayerStatus ConnectionLayerStatus_MIN = CONNECTION_LAYER_STATUS_UNKNOWN; +constexpr ConnectionLayerStatus ConnectionLayerStatus_MAX = CONNECTION_LAYER_STATUS_TIMEOUT; +constexpr int ConnectionLayerStatus_ARRAYSIZE = ConnectionLayerStatus_MAX + 1; + +const std::string& ConnectionLayerStatus_Name(ConnectionLayerStatus value); +template +inline const std::string& ConnectionLayerStatus_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function ConnectionLayerStatus_Name."); + return ConnectionLayerStatus_Name(static_cast(enum_t_value)); +} +bool ConnectionLayerStatus_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, ConnectionLayerStatus* value); enum ProcessReceivedAttachmentsStatus : int { PROCESSING_STATUS_UNKNOWN = 0, PROCESSING_STATUS_COMPLETE_PROCESSING_ATTACHMENTS = 1, @@ -483,6 +528,59 @@ inline const std::string& ServerResponseState_Name(T enum_t_value) { } bool ServerResponseState_Parse( ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, ServerResponseState* value); +enum SyncPurpose : int { + SYNC_PURPOSE_UNKNOWN = 0, + SYNC_PURPOSE_ON_DEMAND_SYNC = 1, + SYNC_PURPOSE_CHIME_NOTIFICATION = 2, + SYNC_PURPOSE_DAILY_SYNC = 3, + SYNC_PURPOSE_OPT_IN_FIRST_SYNC = 4, + SYNC_PURPOSE_CHECK_DEFAULT_OPT_IN = 5, + SYNC_PURPOSE_NEARBY_SHARE_ENABLED = 6, + SYNC_PURPOSE_SYNC_AT_FAST_INIT = 7, + SYNC_PURPOSE_SYNC_AT_DISCOVERY = 8, + SYNC_PURPOSE_SYNC_AT_LOAD_PRIVATE_CERTIFICATE = 9, + SYNC_PURPOSE_SYNC_AT_ADVERTISEMENT = 10, + SYNC_PURPOSE_CONTACT_LIST_CHANGE = 11, + SYNC_PURPOSE_SHOW_C11N_VIEW = 12, + SYNC_PURPOSE_REGULAR_CHECK_CONTACT_REACHABILITY = 13, + SYNC_PURPOSE_VISIBILITY_SELECTED_CONTACT_CHANGE = 14, + SYNC_PURPOSE_ACCOUNT_CHANGE = 15 +}; +bool SyncPurpose_IsValid(int value); +constexpr SyncPurpose SyncPurpose_MIN = SYNC_PURPOSE_UNKNOWN; +constexpr SyncPurpose SyncPurpose_MAX = SYNC_PURPOSE_ACCOUNT_CHANGE; +constexpr int SyncPurpose_ARRAYSIZE = SyncPurpose_MAX + 1; + +const std::string& SyncPurpose_Name(SyncPurpose value); +template +inline const std::string& SyncPurpose_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function SyncPurpose_Name."); + return SyncPurpose_Name(static_cast(enum_t_value)); +} +bool SyncPurpose_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, SyncPurpose* value); +enum ClientRole : int { + CLIENT_ROLE_UNKNOWN = 0, + CLIENT_ROLE_SENDER = 1, + CLIENT_ROLE_RECEIVER = 2 +}; +bool ClientRole_IsValid(int value); +constexpr ClientRole ClientRole_MIN = CLIENT_ROLE_UNKNOWN; +constexpr ClientRole ClientRole_MAX = CLIENT_ROLE_RECEIVER; +constexpr int ClientRole_ARRAYSIZE = ClientRole_MAX + 1; + +const std::string& ClientRole_Name(ClientRole value); +template +inline const std::string& ClientRole_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function ClientRole_Name."); + return ClientRole_Name(static_cast(enum_t_value)); +} +bool ClientRole_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, ClientRole* value); enum ScanType : int { UNKNOWN_SCAN_TYPE = 0, FOREGROUND_SCAN = 1, @@ -505,6 +603,26 @@ inline const std::string& ScanType_Name(T enum_t_value) { } bool ScanType_Parse( ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, ScanType* value); +enum ParsingFailedType : int { + FAILED_UNKNOWN_TYPE = 0, + FAILED_PARSE_ADVERTISEMENT = 1, + FAILED_CONVERT_SHARE_TARGET = 2 +}; +bool ParsingFailedType_IsValid(int value); +constexpr ParsingFailedType ParsingFailedType_MIN = FAILED_UNKNOWN_TYPE; +constexpr ParsingFailedType ParsingFailedType_MAX = FAILED_CONVERT_SHARE_TARGET; +constexpr int ParsingFailedType_ARRAYSIZE = ParsingFailedType_MAX + 1; + +const std::string& ParsingFailedType_Name(ParsingFailedType value); +template +inline const std::string& ParsingFailedType_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function ParsingFailedType_Name."); + return ParsingFailedType_Name(static_cast(enum_t_value)); +} +bool ParsingFailedType_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, ParsingFailedType* value); enum AdvertisingMode : int { UNKNOWN_ADVERTISING_MODE = 0, SCREEN_OFF_ADVERTISING_MODE = 1, @@ -838,6 +956,121 @@ inline const std::string& PreferencesActionStatus_Name(T enum_t_value) { } bool PreferencesActionStatus_Parse( ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, PreferencesActionStatus* value); +enum FastInitState : int { + FAST_INIT_UNKNOWN_STATE = 0, + FAST_INIT_CLOSE_STATE = 1, + FAST_INIT_FAR_STATE = 2, + FAST_INIT_LOST_STATE = 3 +}; +bool FastInitState_IsValid(int value); +constexpr FastInitState FastInitState_MIN = FAST_INIT_UNKNOWN_STATE; +constexpr FastInitState FastInitState_MAX = FAST_INIT_LOST_STATE; +constexpr int FastInitState_ARRAYSIZE = FastInitState_MAX + 1; + +const std::string& FastInitState_Name(FastInitState value); +template +inline const std::string& FastInitState_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function FastInitState_Name."); + return FastInitState_Name(static_cast(enum_t_value)); +} +bool FastInitState_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FastInitState* value); +enum FastInitType : int { + FAST_INIT_UNKNOWN_TYPE = 0, + FAST_INIT_NOTIFY_TYPE = 1, + FAST_INIT_SILENT_TYPE = 2 +}; +bool FastInitType_IsValid(int value); +constexpr FastInitType FastInitType_MIN = FAST_INIT_UNKNOWN_TYPE; +constexpr FastInitType FastInitType_MAX = FAST_INIT_SILENT_TYPE; +constexpr int FastInitType_ARRAYSIZE = FastInitType_MAX + 1; + +const std::string& FastInitType_Name(FastInitType value); +template +inline const std::string& FastInitType_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function FastInitType_Name."); + return FastInitType_Name(static_cast(enum_t_value)); +} +bool FastInitType_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FastInitType* value); +enum DesktopNotification : int { + DESKTOP_NOTIFICATION_UNKNOWN = 0, + DESKTOP_NOTIFICATION_CONNECTING = 1, + DESKTOP_NOTIFICATION_PROGRESS = 2, + DESKTOP_NOTIFICATION_ACCEPT = 3, + DESKTOP_NOTIFICATION_RECEIVED = 4, + DESKTOP_NOTIFICATION_ERROR = 5 +}; +bool DesktopNotification_IsValid(int value); +constexpr DesktopNotification DesktopNotification_MIN = DESKTOP_NOTIFICATION_UNKNOWN; +constexpr DesktopNotification DesktopNotification_MAX = DESKTOP_NOTIFICATION_ERROR; +constexpr int DesktopNotification_ARRAYSIZE = DesktopNotification_MAX + 1; + +const std::string& DesktopNotification_Name(DesktopNotification value); +template +inline const std::string& DesktopNotification_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function DesktopNotification_Name."); + return DesktopNotification_Name(static_cast(enum_t_value)); +} +bool DesktopNotification_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, DesktopNotification* value); +enum DesktopTransferEventType : int { + DESKTOP_TRANSFER_EVENT_TYPE_UNKNOWN = 0, + DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_ACCEPT = 1, + DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_PROGRESS = 2, + DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_RECEIVED = 3, + DESKTOP_TRANSFER_EVENT_RECEIVE_TYPE_ERROR = 4, + DESKTOP_TRANSFER_EVENT_SEND_TYPE_START = 5, + DESKTOP_TRANSFER_EVENT_SEND_TYPE_SELECT_A_DEVICE = 6, + DESKTOP_TRANSFER_EVENT_SEND_TYPE_PROGRESS = 7, + DESKTOP_TRANSFER_EVENT_SEND_TYPE_SENT = 8, + DESKTOP_TRANSFER_EVENT_SEND_TYPE_ERROR = 9 +}; +bool DesktopTransferEventType_IsValid(int value); +constexpr DesktopTransferEventType DesktopTransferEventType_MIN = DESKTOP_TRANSFER_EVENT_TYPE_UNKNOWN; +constexpr DesktopTransferEventType DesktopTransferEventType_MAX = DESKTOP_TRANSFER_EVENT_SEND_TYPE_ERROR; +constexpr int DesktopTransferEventType_ARRAYSIZE = DesktopTransferEventType_MAX + 1; + +const std::string& DesktopTransferEventType_Name(DesktopTransferEventType value); +template +inline const std::string& DesktopTransferEventType_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function DesktopTransferEventType_Name."); + return DesktopTransferEventType_Name(static_cast(enum_t_value)); +} +bool DesktopTransferEventType_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, DesktopTransferEventType* value); +enum DecryptCertificateFailureStatus : int { + DECRYPT_CERT_UNKNOWN_FAILURE = 0, + DECRYPT_CERT_NO_SUCH_ALGORITHM_FAILURE = 1, + DECRYPT_CERT_NO_SUCH_PADDING_FAILURE = 2, + DECRYPT_CERT_INVALID_KEY_FAILURE = 3, + DECRYPT_CERT_INVALID_ALGORITHM_PARAMETER_FAILURE = 4, + DECRYPT_CERT_ILLEGAL_BLOCK_SIZE_FAILURE = 5, + DECRYPT_CERT_BAD_PADDING_FAILURE = 6 +}; +bool DecryptCertificateFailureStatus_IsValid(int value); +constexpr DecryptCertificateFailureStatus DecryptCertificateFailureStatus_MIN = DECRYPT_CERT_UNKNOWN_FAILURE; +constexpr DecryptCertificateFailureStatus DecryptCertificateFailureStatus_MAX = DECRYPT_CERT_BAD_PADDING_FAILURE; +constexpr int DecryptCertificateFailureStatus_ARRAYSIZE = DecryptCertificateFailureStatus_MAX + 1; + +const std::string& DecryptCertificateFailureStatus_Name(DecryptCertificateFailureStatus value); +template +inline const std::string& DecryptCertificateFailureStatus_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function DecryptCertificateFailureStatus_Name."); + return DecryptCertificateFailureStatus_Name(static_cast(enum_t_value)); +} +bool DecryptCertificateFailureStatus_Parse( + ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, DecryptCertificateFailureStatus* value); // =================================================================== @@ -870,6 +1103,7 @@ template <> struct is_proto_enum< ::location::nearby::proto::sharing::Visibility template <> struct is_proto_enum< ::location::nearby::proto::sharing::DataUsage> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::EstablishConnectionStatus> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::AttachmentTransmissionStatus> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::proto::sharing::ConnectionLayerStatus> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::ProcessReceivedAttachmentsStatus> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::SessionStatus> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::ResponseToIntroduction> : ::std::true_type {}; @@ -879,7 +1113,10 @@ template <> struct is_proto_enum< ::location::nearby::proto::sharing::DeviceRela template <> struct is_proto_enum< ::location::nearby::proto::sharing::LogSource> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::ServerActionName> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::ServerResponseState> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::proto::sharing::SyncPurpose> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::proto::sharing::ClientRole> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::ScanType> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::proto::sharing::ParsingFailedType> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::AdvertisingMode> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::ActivityName> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::ConsentType> : ::std::true_type {}; @@ -895,6 +1132,11 @@ template <> struct is_proto_enum< ::location::nearby::proto::sharing::AppCrashRe template <> struct is_proto_enum< ::location::nearby::proto::sharing::AttachmentSourceType> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::PreferencesAction> : ::std::true_type {}; template <> struct is_proto_enum< ::location::nearby::proto::sharing::PreferencesActionStatus> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::proto::sharing::FastInitState> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::proto::sharing::FastInitType> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::proto::sharing::DesktopNotification> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::proto::sharing::DesktopTransferEventType> : ::std::true_type {}; +template <> struct is_proto_enum< ::location::nearby::proto::sharing::DecryptCertificateFailureStatus> : ::std::true_type {}; PROTOBUF_NAMESPACE_CLOSE diff --git a/connections/BUILD b/connections/BUILD index 04cc0ff9..a8f9d09d 100644 --- a/connections/BUILD +++ b/connections/BUILD @@ -35,7 +35,6 @@ cc_library( "//internal/analytics:event_logger", "//internal/interop:device", "//internal/platform:base", - "//internal/platform:logging", "//internal/platform:types", "@com_google_absl//absl/strings", "@com_google_absl//absl/time", @@ -102,7 +101,6 @@ cc_test( "//connections/implementation:internal_test", "//connections/v3:v3_types", "//internal/platform:base", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep "@com_github_protobuf_matchers//protobuf-matchers", diff --git a/connections/advertising_options.cc b/connections/advertising_options.cc index 1874badb..2355175f 100644 --- a/connections/advertising_options.cc +++ b/connections/advertising_options.cc @@ -1,4 +1,4 @@ -// Copyright 2021 Google LLC +// 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. diff --git a/connections/advertising_options.h b/connections/advertising_options.h index d0fbf7f3..1f87960f 100644 --- a/connections/advertising_options.h +++ b/connections/advertising_options.h @@ -1,4 +1,4 @@ -// Copyright 2021 Google LLC +// 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. diff --git a/connections/c/BUILD b/connections/c/BUILD index c248c76e..17db7c4f 100644 --- a/connections/c/BUILD +++ b/connections/c/BUILD @@ -119,7 +119,7 @@ cc_test( ], deps = [ "//connections:core", - "//internal/platform:logging", + "//internal/platform:types", "//internal/platform/implementation/windows", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_googletest//:gtest_main", diff --git a/connections/c/bluetooth_classic_server_socket_test.cc b/connections/c/bluetooth_classic_server_socket_test.cc index 10cb1051..2b0e1394 100644 --- a/connections/c/bluetooth_classic_server_socket_test.cc +++ b/connections/c/bluetooth_classic_server_socket_test.cc @@ -117,10 +117,10 @@ TEST(BluetoothClassicServerSocketTest, PerformanceTimer::start(); core.StartAdvertising(SERVICE_ID, AdvertiseOptions, request_info, - {.result_cb = [&](Status status) { + [&](Status status) { request_result = status; notification.Notify(); - }}); + }); if (notification.WaitForNotificationWithTimeout( absl::Seconds(TimeoutSeconds))) { @@ -163,10 +163,10 @@ TEST(BluetoothClassicServerSocketTest, PerformanceTimer::start(); core.StartAdvertising(SERVICE_ID, AdvertiseOptions, request_info, - {.result_cb = [&](Status status) { + [&](Status status) { request_result = status; notification2.Notify(); - }}); + }); if (notification2.WaitForNotificationWithTimeout( absl::Seconds(TimeoutSeconds))) { @@ -209,10 +209,10 @@ TEST(BluetoothClassicServerSocketTest, PerformanceTimer::start(); - core.StopAdvertising({.result_cb = [&](Status status) { + core.StopAdvertising([&](Status status) { request_result = status; notification3.Notify(); - }}); + }); if (notification3.WaitForNotificationWithTimeout( absl::Seconds(TimeoutSeconds))) { @@ -273,10 +273,10 @@ TEST(BluetoothClassicServerSocketTest, DISABLED_MultiRunWithTimeoutReproStuck) { PerformanceTimer::start(); core.StartAdvertising(SERVICE_ID, AdvertiseOptions, request_info, - {.result_cb = [&](Status status) { + [&](Status status) { request_result = status; notification.Notify(); - }}); + }); if (notification.WaitForNotificationWithTimeout( absl::Seconds(TimeoutSeconds))) { @@ -319,10 +319,10 @@ TEST(BluetoothClassicServerSocketTest, DISABLED_MultiRunWithTimeoutReproStuck) { PerformanceTimer::start(); core.StartAdvertising(SERVICE_ID, AdvertiseOptions, request_info, - {.result_cb = [&](Status status) { + [&](Status status) { request_result = status; notification2.Notify(); - }}); + }); if (notification2.WaitForNotificationWithTimeout( absl::Seconds(TimeoutSeconds))) { @@ -361,10 +361,10 @@ TEST(BluetoothClassicServerSocketTest, DISABLED_MultiRunWithTimeoutReproStuck) { PerformanceTimer::start(); - core.StopAdvertising({.result_cb = [&](Status status) { + core.StopAdvertising([&](Status status) { request_result = status; notification3.Notify(); - }}); + }); if (notification3.WaitForNotificationWithTimeout( absl::Seconds(TimeoutSeconds))) { @@ -424,10 +424,10 @@ TEST(BluetoothClassicServerSocketTest, DISABLED_SingleRunNoTimeoutReproStuck) { PerformanceTimer::start(); core.StartAdvertising(SERVICE_ID, AdvertiseOptions, request_info, - {.result_cb = [&](Status status) { + [&](Status status) { request_result = status; notification.Notify(); - }}); + }); notification.WaitForNotification(); PerformanceTimer::stop(); @@ -451,10 +451,10 @@ TEST(BluetoothClassicServerSocketTest, DISABLED_SingleRunNoTimeoutReproStuck) { PerformanceTimer::start(); core.StartAdvertising(SERVICE_ID, AdvertiseOptions, request_info, - {.result_cb = [&](Status status) { + [&](Status status) { request_result = status; notification2.Notify(); - }}); + }); notification2.WaitForNotification(); PerformanceTimer::stop(); @@ -477,10 +477,10 @@ TEST(BluetoothClassicServerSocketTest, DISABLED_SingleRunNoTimeoutReproStuck) { PerformanceTimer::start(); - core.StopAdvertising({.result_cb = [&](Status status) { + core.StopAdvertising([&](Status status) { request_result = status; notification3.Notify(); - }}); + }); notification3.WaitForNotification(); PerformanceTimer::stop(); @@ -521,10 +521,10 @@ TEST(BluetoothClassicServerSocketTest, DISABLED_MultiRunNoTimeoutReproStuck) { PerformanceTimer::start(); core.StartAdvertising(SERVICE_ID, AdvertiseOptions, request_info, - {.result_cb = [&](Status status) { + [&](Status status) { request_result = status; notification.Notify(); - }}); + }); notification.WaitForNotification(); @@ -551,10 +551,10 @@ TEST(BluetoothClassicServerSocketTest, DISABLED_MultiRunNoTimeoutReproStuck) { PerformanceTimer::start(); core.StartAdvertising(SERVICE_ID, AdvertiseOptions, request_info, - {.result_cb = [&](Status status) { + [&](Status status) { request_result = status; notification2.Notify(); - }}); + }); notification2.WaitForNotification(); PerformanceTimer::stop(); @@ -580,10 +580,10 @@ TEST(BluetoothClassicServerSocketTest, DISABLED_MultiRunNoTimeoutReproStuck) { PerformanceTimer::start(); - core.StopAdvertising({.result_cb = [&](Status status) { + core.StopAdvertising([&](Status status) { request_result = status; notification3.Notify(); - }}); + }); notification3.WaitForNotification(); PerformanceTimer::stop(); diff --git a/connections/c/core_adapter.cc b/connections/c/core_adapter.cc index fa038f3a..f8521f6d 100644 --- a/connections/c/core_adapter.cc +++ b/connections/c/core_adapter.cc @@ -32,8 +32,7 @@ void CloseCore(Core *pCore) { if (pCore == nullptr) { return; } - pCore->StopAllEndpoints( - {.result_cb = std::function{[](Status) {}}}); + pCore->StopAllEndpoints([](Status) {}); delete pCore; } @@ -80,14 +79,14 @@ void StartAdvertising(Core *pCore, const char *service_id, advertising_options.strategy = connections::Strategy::kP2pStar; pCore->StartAdvertising(service_id, advertising_options, crInfo, - *callback.GetImpl()); + std::move(*callback.GetImpl())); } void StopAdvertising(connections::Core *pCore, ResultCallbackW callback) { if (pCore == nullptr) { return; } - pCore->StopAdvertising(*callback.GetImpl()); + pCore->StopAdvertising(std::move(*callback.GetImpl())); } void StartDiscovery(connections::Core *pCore, const char *service_id, @@ -134,7 +133,7 @@ void StopDiscovery(connections::Core *pCore, ResultCallbackW callback) { if (pCore == nullptr) { return; } - pCore->StopDiscovery(*callback.GetImpl()); + pCore->StopDiscovery(std::move(*callback.GetImpl())); } void InjectEndpoint(connections::Core *pCore, char *service_id, @@ -153,7 +152,7 @@ void InjectEndpoint(connections::Core *pCore, char *service_id, metadata.remote_bluetooth_mac_address_size}; pCore->InjectEndpoint(service_id, outOfBandConnectionMetadata, - *callback.GetImpl()); + std::move(*callback.GetImpl())); } void RequestConnection(connections::Core *pCore, const char *endpoint_id, @@ -203,7 +202,7 @@ void RequestConnection(connections::Core *pCore, const char *endpoint_id, connection_options.strategy = connections::Strategy::kP2pStar; pCore->RequestConnection(endpoint_id, connectionRequestInfo, - connection_options, *callback.GetImpl()); + connection_options, std::move(*callback.GetImpl())); } void AcceptConnection(connections::Core *pCore, const char *endpoint_id, @@ -214,7 +213,7 @@ void AcceptConnection(connections::Core *pCore, const char *endpoint_id, connections::PayloadListener payload_listener = std::move(*listener.GetImpl()); pCore->AcceptConnection(endpoint_id, std::move(payload_listener), - *callback.GetImpl()); + std::move(*callback.GetImpl())); } void RejectConnection(connections::Core *pCore, const char *endpoint_id, @@ -222,7 +221,7 @@ void RejectConnection(connections::Core *pCore, const char *endpoint_id, if (pCore == nullptr) { return; } - pCore->RejectConnection(endpoint_id, *callback.GetImpl()); + pCore->RejectConnection(endpoint_id, std::move(*callback.GetImpl())); } void SendPayload(connections::Core *pCore, @@ -235,7 +234,8 @@ void SendPayload(connections::Core *pCore, } std::string payloadData = std::string(*endpoint_ids); absl::Span span{&payloadData, 1}; - pCore->SendPayload(span, std::move(*payloadw.GetImpl()), *callback.GetImpl()); + pCore->SendPayload(span, std::move(*payloadw.GetImpl()), + std::move(*callback.GetImpl())); } void CancelPayload(connections::Core *pCore, std::int64_t payload_id, @@ -243,7 +243,7 @@ void CancelPayload(connections::Core *pCore, std::int64_t payload_id, if (pCore == nullptr) { return; } - pCore->CancelPayload(payload_id, *callback.GetImpl()); + pCore->CancelPayload(payload_id, std::move(*callback.GetImpl())); } void DisconnectFromEndpoint(connections::Core *pCore, const char *endpoint_id, @@ -251,14 +251,14 @@ void DisconnectFromEndpoint(connections::Core *pCore, const char *endpoint_id, if (pCore == nullptr) { return; } - pCore->DisconnectFromEndpoint(endpoint_id, *callback.GetImpl()); + pCore->DisconnectFromEndpoint(endpoint_id, std::move(*callback.GetImpl())); } void StopAllEndpoints(connections::Core *pCore, ResultCallbackW callback) { if (pCore == nullptr) { return; } - pCore->StopAllEndpoints(*callback.GetImpl()); + pCore->StopAllEndpoints(std::move(*callback.GetImpl())); } void InitiateBandwidthUpgrade(connections::Core *pCore, char *endpoint_id, @@ -266,7 +266,7 @@ void InitiateBandwidthUpgrade(connections::Core *pCore, char *endpoint_id, if (pCore == nullptr) { return; } - pCore->InitiateBandwidthUpgrade(endpoint_id, *callback.GetImpl()); + pCore->InitiateBandwidthUpgrade(endpoint_id, std::move(*callback.GetImpl())); } const char *GetLocalEndpointId(connections::Core *pCore) { diff --git a/connections/c/listeners_w.cc b/connections/c/listeners_w.cc index e99e22fe..cfed3fac 100644 --- a/connections/c/listeners_w.cc +++ b/connections/c/listeners_w.cc @@ -12,6 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include + #include "connections/c/listeners_w.h" #include "connections/listeners.h" @@ -20,9 +23,6 @@ namespace nearby { // Must implement Deleters, since the connections classes weren't // fully defined in the header namespace connections { -void ResultCallbackDeleter::operator()(connections::ResultCallback *p) { - delete p; -} void ConnectionListenerDeleter::operator()(connections::ConnectionListener *p) { delete p; } @@ -41,21 +41,18 @@ static ResultCallbackW *ResultCallbackImpl; void ResultCB(Status status) { ResultCallbackImpl->result_cb(status); } ResultCallbackW::ResultCallbackW() - : impl_(std::unique_ptr( - new connections::ResultCallback())) { + : impl(std::make_unique(ResultCB)) { ResultCallbackImpl = this; - impl_->result_cb = ResultCB; } ResultCallbackW::~ResultCallbackW() {} ResultCallbackW::ResultCallbackW(ResultCallbackW &other) { - impl_ = std::move(other.impl_); + impl = std::move(other.impl); } ResultCallbackW::ResultCallbackW(ResultCallbackW &&other) noexcept { - impl_ = std::move(other.impl_); + impl = std::move(other.impl); } ConnectionListenerW::ConnectionListenerW(InitiatedCB initiatedCB, diff --git a/connections/c/listeners_w.h b/connections/c/listeners_w.h index a0b49b28..5d69acfd 100644 --- a/connections/c/listeners_w.h +++ b/connections/c/listeners_w.h @@ -15,10 +15,8 @@ #ifndef THIRD_PARTY_NEARBY_CONNECTIONS_C_LISTENERS_W_H_ #define THIRD_PARTY_NEARBY_CONNECTIONS_C_LISTENERS_W_H_ -#include -#include #include -#include +#include // This file defines all the protocol listeners and their parameter structures. // Listeners are defined as collections of std::function instances, which is @@ -50,10 +48,7 @@ struct DLL_API PayloadListenerDeleter { void operator()(connections::PayloadListener* p); }; -struct ResultCallback; -struct ResultCallbackDeleter { - void operator()(connections::ResultCallback* p); -}; +using ResultCallback = absl::AnyInvocable; struct ConnectionResponseInfo; struct PayloadProgressInfo; @@ -92,16 +87,12 @@ struct DLL_API ResultCallbackW { void (*result_cb)(Status status) = DefaultConstructor; - std::unique_ptr - GetImpl() { - return std::move(impl_); + std::unique_ptr GetImpl() { + return std::move(impl); } private: - std::unique_ptr - impl_; + std::unique_ptr impl; }; struct DLL_API ConnectionResponseInfoW { diff --git a/connections/c/payload_w.cc b/connections/c/payload_w.cc index 6205ffda..5faf69c0 100644 --- a/connections/c/payload_w.cc +++ b/connections/c/payload_w.cc @@ -13,9 +13,16 @@ // limitations under the License. #include "connections/c/payload_w.h" +#include +#include +#include +#include + #include "connections/c/file_w.h" #include "connections/payload.h" +#include "connections/payload_type.h" #include "internal/platform/byte_array.h" +#include "internal/platform/input_stream.h" #include "internal/platform/payload_id.h" namespace nearby { @@ -32,7 +39,7 @@ PayloadW::PayloadW() : impl_(std::unique_ptr( new connections::Payload())) {} -PayloadW::~PayloadW() {} +PayloadW::~PayloadW() = default; PayloadW::PayloadW(PayloadW &&other) noexcept : impl_(std::move(other.impl_)) {} PayloadW &PayloadW::operator=(PayloadW &&other) noexcept { @@ -49,10 +56,9 @@ PayloadW::PayloadW(InputFileW &file) : impl_(std::unique_ptr( new connections::Payload(InputFile(std::move(*file.GetImpl()))))) {} -// TODO(jfcarroll): Convert std::function to function pointer -PayloadW::PayloadW(std::function stream) +PayloadW::PayloadW(std::unique_ptr stream) : impl_(std::unique_ptr( - new connections::Payload(stream))) {} + new connections::Payload(std::move(stream)))) {} // Constructors for incoming payloads. PayloadW::PayloadW(PayloadId id, const char *bytes, const size_t bytes_size) @@ -69,9 +75,9 @@ PayloadW::PayloadW(const char *parent_folder, const char *file_name, new connections::Payload(parent_folder, file_name, std::move(*file.GetImpl())))) {} -PayloadW::PayloadW(PayloadId id, std::function stream) +PayloadW::PayloadW(PayloadId id, std::unique_ptr stream) : impl_(std::unique_ptr( - new connections::Payload(id, stream))) {} + new connections::Payload(id, std::move(stream)))) {} // Returns ByteArray payload, if it has been defined, or empty ByteArray. bool PayloadW::AsBytes(const char *&bytes, size_t &bytes_size) const & { diff --git a/connections/c/payload_w.h b/connections/c/payload_w.h index d4baeaf1..17972e6e 100644 --- a/connections/c/payload_w.h +++ b/connections/c/payload_w.h @@ -60,19 +60,18 @@ class DLL_API PayloadW { ~PayloadW(); // Constructors for outgoing payloads. - explicit PayloadW(const char* bytes, const size_t size); + explicit PayloadW(const char* bytes, size_t size); explicit PayloadW(InputFileW& file); - explicit PayloadW(std::function stream); + explicit PayloadW(std::unique_ptr stream); // Constructors for incoming payloads. - PayloadW(PayloadId id, const char* bytes, const size_t size); + PayloadW(PayloadId id, const char* bytes, size_t size); PayloadW(PayloadId id, InputFileW file); explicit PayloadW(const char* parent_folder, const char* file_name, InputFileW file); - // TODO(jfcarroll): Convert std::function to function pointer - PayloadW(PayloadId id, std::function stream); + PayloadW(PayloadId id, std::unique_ptr stream); // Returns ByteArray payload, if it has // been defined, or empty ByteArray. bool AsBytes(const char*& bytes, size_t& bytes_size) const&; diff --git a/connections/core.cc b/connections/core.cc index 27729a85..2dbb44a2 100644 --- a/connections/core.cc +++ b/connections/core.cc @@ -19,15 +19,32 @@ #include #include "absl/strings/string_view.h" -#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "absl/types/span.h" +#include "connections/advertising_options.h" +#include "connections/connection_options.h" +#include "connections/discovery_options.h" +#include "connections/implementation/service_controller_router.h" #include "connections/implementation/service_id_constants.h" #include "connections/listeners.h" +#include "connections/medium_selector.h" +#include "connections/out_of_band_connection_metadata.h" +#include "connections/params.h" +#include "connections/payload.h" +#include "connections/payload_type.h" +#include "connections/power_level.h" +#include "connections/status.h" +#include "connections/v3/advertising_options.h" #include "connections/v3/bandwidth_info.h" +#include "connections/v3/connection_listening_options.h" #include "connections/v3/connection_result.h" #include "connections/v3/connections_device.h" +#include "connections/v3/discovery_options.h" #include "connections/v3/listeners.h" +#include "connections/v3/listening_result.h" #include "connections/v3/params.h" #include "internal/interop/device.h" +#include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/feature_flags.h" #include "internal/platform/logging.h" @@ -54,10 +71,7 @@ Core::Core(ServiceControllerRouter* router) : router_(router) {} Core::~Core() { CountDownLatch latch(1); - router_->StopAllEndpoints( - &client_, { - .result_cb = [&latch](Status) { latch.CountDown(); }, - }); + router_->StopAllEndpoints(&client_, [&latch](Status) { latch.CountDown(); }); if (!latch.Await(kWaitForDisconnect).result()) { NEARBY_LOG(FATAL, "Unable to shutdown"); } @@ -75,11 +89,11 @@ void Core::StartAdvertising(absl::string_view service_id, CHECK(advertising_options.strategy.IsValid()); router_->StartAdvertising(&client_, service_id, advertising_options, info, - callback); + std::move(callback)); } -void Core::StopAdvertising(const ResultCallback callback) { - router_->StopAdvertising(&client_, callback); +void Core::StopAdvertising(ResultCallback callback) { + router_->StopAdvertising(&client_, std::move(callback)); } void Core::StartDiscovery(absl::string_view service_id, @@ -89,18 +103,18 @@ void Core::StartDiscovery(absl::string_view service_id, CHECK(discovery_options.strategy.IsValid()); router_->StartDiscovery(&client_, service_id, discovery_options, listener, - callback); + std::move(callback)); } void Core::InjectEndpoint(absl::string_view service_id, OutOfBandConnectionMetadata metadata, ResultCallback callback) { CheckServiceId(service_id); - router_->InjectEndpoint(&client_, service_id, metadata, callback); + router_->InjectEndpoint(&client_, service_id, metadata, std::move(callback)); } void Core::StopDiscovery(ResultCallback callback) { - router_->StopDiscovery(&client_, callback); + router_->StopDiscovery(&client_, std::move(callback)); } void Core::RequestConnection(absl::string_view endpoint_id, @@ -128,7 +142,7 @@ void Core::RequestConnection(absl::string_view endpoint_id, } router_->RequestConnection(&client_, endpoint_id, info, connection_options, - callback); + std::move(callback)); } void Core::AcceptConnection(absl::string_view endpoint_id, @@ -136,19 +150,19 @@ void Core::AcceptConnection(absl::string_view endpoint_id, CHECK(!endpoint_id.empty()); router_->AcceptConnection(&client_, endpoint_id, std::move(listener), - callback); + std::move(callback)); } void Core::RejectConnection(absl::string_view endpoint_id, ResultCallback callback) { CHECK(!endpoint_id.empty()); - router_->RejectConnection(&client_, endpoint_id, callback); + router_->RejectConnection(&client_, endpoint_id, std::move(callback)); } void Core::InitiateBandwidthUpgrade(absl::string_view endpoint_id, ResultCallback callback) { - router_->InitiateBandwidthUpgrade(&client_, endpoint_id, callback); + router_->InitiateBandwidthUpgrade(&client_, endpoint_id, std::move(callback)); } void Core::SendPayload(absl::Span endpoint_ids, @@ -156,35 +170,36 @@ void Core::SendPayload(absl::Span endpoint_ids, CHECK(payload.GetType() != PayloadType::kUnknown); CHECK(!endpoint_ids.empty()); - router_->SendPayload(&client_, endpoint_ids, std::move(payload), callback); + router_->SendPayload(&client_, endpoint_ids, std::move(payload), + std::move(callback)); } void Core::CancelPayload(std::int64_t payload_id, ResultCallback callback) { CHECK_NE(payload_id, 0); - router_->CancelPayload(&client_, payload_id, callback); + router_->CancelPayload(&client_, payload_id, std::move(callback)); } void Core::DisconnectFromEndpoint(absl::string_view endpoint_id, ResultCallback callback) { CHECK(!endpoint_id.empty()); - router_->DisconnectFromEndpoint(&client_, endpoint_id, callback); + router_->DisconnectFromEndpoint(&client_, endpoint_id, std::move(callback)); } void Core::StopAllEndpoints(ResultCallback callback) { - router_->StopAllEndpoints(&client_, callback); + router_->StopAllEndpoints(&client_, std::move(callback)); } void Core::SetCustomSavePath(absl::string_view path, ResultCallback callback) { - router_->SetCustomSavePath(&client_, path, callback); + router_->SetCustomSavePath(&client_, path, std::move(callback)); } std::string Core::Dump() { return client_.Dump(); } // V3 void Core::StartAdvertisingV3(absl::string_view service_id, - const AdvertisingOptions& advertising_options, + const v3::AdvertisingOptions& advertising_options, const NearbyDevice& local_device, v3::ConnectionListener listener, ResultCallback callback) { @@ -240,55 +255,32 @@ void Core::StartAdvertisingV3(absl::string_view service_id, .endpoint_info = local_endpoint_info, .listener = old_listener, }; - StartAdvertising(service_id, advertising_options, old_info, callback); + + CheckServiceId(service_id); + CHECK(advertising_options.strategy.IsValid()); + AdvertisingOptions old_advertising_options = { + { + advertising_options.strategy, + advertising_options.advertising_mediums, + }, + advertising_options.auto_upgrade_bandwidth, + advertising_options.enforce_topology_constraints, + advertising_options.power_level == PowerLevel::kLowPower, // low_power + advertising_options.enable_bluetooth_listening, + advertising_options.advertising_mediums.web_rtc, + false, // is_out_of_band_connection + advertising_options.fast_advertisement_service_uuid, + "" // device_info + }; + // TODO(b/291295755): Refactor deeper to use v3 options throughout. + router_->StartAdvertising(&client_, service_id, old_advertising_options, + old_info, std::move(callback)); } void Core::StartAdvertisingV3(absl::string_view service_id, - const AdvertisingOptions& advertising_options, + const v3::AdvertisingOptions& advertising_options, v3::ConnectionListener listener, ResultCallback callback) { - ConnectionListener old_listener = { - .initiated_cb = - [&listener](const std::string& endpoint_id, - const ConnectionResponseInfo& info) { - auto remote_device = v3::ConnectionsDevice( - endpoint_id, info.remote_endpoint_info.AsStringView(), {}); - listener.initiated_cb( - remote_device, - v3::InitialConnectionInfo{ - .authentication_digits = info.authentication_token, - .raw_authentication_token = - info.raw_authentication_token.string_data(), - .is_incoming_connection = info.is_incoming_connection, - }); - }, - .accepted_cb = - [v3_cb = listener.result_cb](const std::string& endpoint_id) { - auto remote_device = v3::ConnectionsDevice(endpoint_id, "", {}); - v3_cb(remote_device, - v3::ConnectionResult{.status = Status{ - .value = Status::kSuccess, - }}); - }, - .rejected_cb = - [v3_cb = listener.result_cb](const std::string& endpoint_id, - Status status) { - auto remote_device = v3::ConnectionsDevice(endpoint_id, "", {}); - v3_cb(remote_device, v3::ConnectionResult{ - .status = status, - }); - }, - .disconnected_cb = - [&listener](const std::string& endpoint_id) { - auto remote_device = v3::ConnectionsDevice(endpoint_id, "", {}); - listener.disconnected_cb(remote_device); - }, - .bandwidth_changed_cb = - [&listener](const std::string& endpoint_id, Medium medium) { - auto remote_device = v3::ConnectionsDevice(endpoint_id, "", {}); - listener.bandwidth_changed_cb(remote_device, - v3::BandwidthInfo{.medium = medium}); - }}; ByteArray local_endpoint_info; const NearbyDevice* local_device = client_.GetLocalDevice(); if (local_device->GetType() == NearbyDevice::kConnectionsDevice) { @@ -296,19 +288,16 @@ void Core::StartAdvertisingV3(absl::string_view service_id, ByteArray(reinterpret_cast(local_device) ->GetEndpointInfo()); } - ConnectionRequestInfo old_info = { - .endpoint_info = local_endpoint_info, - .listener = old_listener, - }; - StartAdvertising(service_id, advertising_options, old_info, callback); + StartAdvertisingV3(service_id, advertising_options, *local_device, + std::move(listener), std::move(callback)); } void Core::StopAdvertisingV3(ResultCallback result_cb) { - StopAdvertising(result_cb); + StopAdvertising(std::move(result_cb)); } void Core::StartDiscoveryV3(absl::string_view service_id, - const DiscoveryOptions& discovery_options, + const v3::DiscoveryOptions& discovery_options, v3::DiscoveryListener listener, ResultCallback callback) { DiscoveryListener old_listener = { @@ -332,11 +321,24 @@ void Core::StartDiscoveryV3(absl::string_view service_id, listener.endpoint_distance_changed_cb(remote, distance_info); }, }; - StartDiscovery(service_id, discovery_options, old_listener, callback); + DiscoveryOptions old_discovery_options = { + { + discovery_options.strategy, + discovery_options.discovery_mediums, + }, + true, // auto_upgrade_bandwidth + true, // enforce_topology_constraints + false, // is_out_of_band_connection + discovery_options.fast_advertisement_service_uuid, + discovery_options.power_level == PowerLevel::kLowPower, + }; + // TODO(b/291295755): Deeper refactor to use v3 options throughout. + StartDiscovery(service_id, old_discovery_options, old_listener, + std::move(callback)); } void Core::StopDiscoveryV3(ResultCallback result_cb) { - router_->StopDiscovery(&client_, result_cb); + router_->StopDiscovery(&client_, std::move(result_cb)); } void Core::StartListeningForIncomingConnectionsV3( @@ -383,7 +385,7 @@ void Core::RequestConnectionV3(const NearbyDevice& local_device, FeatureFlags::GetInstance().GetFlags().keep_alive_timeout_millis; } router_->RequestConnectionV3(&client_, remote_device, std::move(info), - connection_options, result_cb); + connection_options, std::move(result_cb)); } void Core::RequestConnectionV3(const NearbyDevice& remote_device, @@ -414,7 +416,7 @@ void Core::RequestConnectionV3(const NearbyDevice& remote_device, FeatureFlags::GetInstance().GetFlags().keep_alive_timeout_millis; } router_->RequestConnectionV3(&client_, remote_device, std::move(info), - connection_options, result_cb); + connection_options, std::move(result_cb)); } void Core::AcceptConnectionV3(const NearbyDevice& remote_device, @@ -423,14 +425,14 @@ void Core::AcceptConnectionV3(const NearbyDevice& remote_device, CHECK(!remote_device.GetEndpointId().empty()); router_->AcceptConnectionV3(&client_, remote_device, std::move(listener_cb), - result_cb); + std::move(result_cb)); } void Core::RejectConnectionV3(const NearbyDevice& remote_device, ResultCallback result_cb) { CHECK(!remote_device.GetEndpointId().empty()); - router_->RejectConnectionV3(&client_, remote_device, result_cb); + router_->RejectConnectionV3(&client_, remote_device, std::move(result_cb)); } void Core::SendPayloadV3(const NearbyDevice& remote_device, Payload payload, @@ -439,44 +441,74 @@ void Core::SendPayloadV3(const NearbyDevice& remote_device, Payload payload, CHECK(!remote_device.GetEndpointId().empty()); router_->SendPayloadV3(&client_, remote_device, std::move(payload), - result_cb); + std::move(result_cb)); } void Core::CancelPayloadV3(const NearbyDevice& remote_device, int64_t payload_id, ResultCallback result_cb) { CHECK_NE(payload_id, 0); - router_->CancelPayloadV3(&client_, remote_device, payload_id, result_cb); + router_->CancelPayloadV3(&client_, remote_device, payload_id, + std::move(result_cb)); } void Core::DisconnectFromDeviceV3(const NearbyDevice& remote_device, ResultCallback result_cb) { CHECK(!remote_device.GetEndpointId().empty()); - router_->DisconnectFromDeviceV3(&client_, remote_device, result_cb); + router_->DisconnectFromDeviceV3(&client_, remote_device, + std::move(result_cb)); } void Core::StopAllDevicesV3(ResultCallback result_cb) { - router_->StopAllEndpoints(&client_, result_cb); + router_->StopAllEndpoints(&client_, std::move(result_cb)); } void Core::InitiateBandwidthUpgradeV3(const NearbyDevice& remote_device, ResultCallback result_cb) { - router_->InitiateBandwidthUpgradeV3(&client_, remote_device, result_cb); + router_->InitiateBandwidthUpgradeV3(&client_, remote_device, + std::move(result_cb)); } -void Core::UpdateAdvertisingOptionsV3(absl::string_view service_id, - AdvertisingOptions advertising_options, - ResultCallback result_cb) { - router_->UpdateAdvertisingOptionsV3(&client_, service_id, advertising_options, - result_cb); +void Core::UpdateAdvertisingOptionsV3( + absl::string_view service_id, v3::AdvertisingOptions advertising_options, + ResultCallback result_cb) { + // TODO(b/291295755): Deeper refactor to use new advertising options. + AdvertisingOptions old_advertising_options = { + { + advertising_options.strategy, + advertising_options.advertising_mediums, + }, + advertising_options.auto_upgrade_bandwidth, + advertising_options.enforce_topology_constraints, + advertising_options.power_level == PowerLevel::kLowPower, // low_power + advertising_options.enable_bluetooth_listening, + advertising_options.advertising_mediums.web_rtc, + false, // is_out_of_band_connection + advertising_options.fast_advertisement_service_uuid, + "" // device_info + }; + router_->UpdateAdvertisingOptionsV3( + &client_, service_id, old_advertising_options, std::move(result_cb)); } void Core::UpdateDiscoveryOptionsV3(absl::string_view service_id, - DiscoveryOptions discovery_options, + v3::DiscoveryOptions discovery_options, ResultCallback result_cb) { - router_->UpdateDiscoveryOptionsV3(&client_, service_id, discovery_options, - result_cb); + // TODO(b/291295755): Deeper refactor to use new discovery options. + DiscoveryOptions old_discovery_options = { + { + discovery_options.strategy, + discovery_options.discovery_mediums, + }, + true, // auto_upgrade_bandwidth + true, // enforce_topology_constraints + false, // is_out_of_band_connection + discovery_options.fast_advertisement_service_uuid, + discovery_options.power_level == PowerLevel::kLowPower, + }; + router_->UpdateDiscoveryOptionsV3(&client_, service_id, old_discovery_options, + std::move(result_cb)); } } // namespace connections diff --git a/connections/core.h b/connections/core.h index f58c3962..7cf6fcc8 100644 --- a/connections/core.h +++ b/connections/core.h @@ -28,7 +28,9 @@ #include "connections/listeners.h" #include "connections/params.h" #include "connections/payload.h" +#include "connections/v3/advertising_options.h" #include "connections/v3/connection_listening_options.h" +#include "connections/v3/discovery_options.h" #include "connections/v3/listeners.h" #include "connections/v3/listening_result.h" #include "internal/analytics/event_logger.h" @@ -273,7 +275,7 @@ class Core { // Status::STATUS_OUT_OF_ORDER_API_CALL if the app is currently // connected to remote endpoints; call StopAllEndpoints first. void StartAdvertisingV3(absl::string_view service_id, - const AdvertisingOptions& advertising_options, + const v3::AdvertisingOptions& advertising_options, const NearbyDevice& local_device, v3::ConnectionListener listener, ResultCallback callback); @@ -296,7 +298,7 @@ class Core { // Status::STATUS_OUT_OF_ORDER_API_CALL if the app is currently // connected to remote endpoints; call StopAllEndpoints first. void StartAdvertisingV3(absl::string_view service_id, - const AdvertisingOptions& advertising_options, + const v3::AdvertisingOptions& advertising_options, v3::ConnectionListener listener, ResultCallback callback); @@ -322,7 +324,7 @@ class Core { // Status::STATUS_OUT_OF_ORDER_API_CALL if the app is currently // connected to remote endpoints; call StopAllEndpoints first. void StartDiscoveryV3(absl::string_view service_id, - const DiscoveryOptions& discovery_options, + const v3::DiscoveryOptions& discovery_options, v3::DiscoveryListener listener_cb, ResultCallback callback); @@ -504,7 +506,7 @@ class Core { // advertising_options - The new advertising options a client wishes to use. // result_cb - to access the status of the operation when available. void UpdateAdvertisingOptionsV3(absl::string_view service_id, - AdvertisingOptions advertising_options, + v3::AdvertisingOptions advertising_options, ResultCallback result_cb); // Updates DiscoveryOptions. It compares the old DiscoveryOptions and the new @@ -513,7 +515,7 @@ class Core { // discovery_options - The new discovery options a client wishes to use. // result_cb - to access the status of the operation when available. void UpdateDiscoveryOptionsV3(absl::string_view service_id, - DiscoveryOptions discovery_options, + v3::DiscoveryOptions discovery_options, ResultCallback result_cb); // Registers a DeviceProvider to provide functionality for Nearby Connections diff --git a/connections/core_test.cc b/connections/core_test.cc index 22ec1afa..5456963c 100644 --- a/connections/core_test.cc +++ b/connections/core_test.cc @@ -14,16 +14,29 @@ #include "connections/core.h" -#include +#include +#include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" -#include "absl/time/clock.h" +#include "connections/advertising_options.h" +#include "connections/discovery_options.h" #include "connections/implementation/mock_service_controller_router.h" +#include "connections/listeners.h" +#include "connections/medium_selector.h" +#include "connections/params.h" +#include "connections/payload.h" +#include "connections/power_level.h" +#include "connections/status.h" +#include "connections/strategy.h" +#include "connections/v3/advertising_options.h" #include "connections/v3/bandwidth_info.h" +#include "connections/v3/connection_result.h" #include "connections/v3/connections_device.h" +#include "connections/v3/discovery_options.h" +#include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/logging.h" @@ -54,8 +67,8 @@ TEST(CoreTest, ConstructorDestructorWorks) { MockServiceControllerRouter mock; // Called when Core is destroyed. EXPECT_CALL(mock, StopAllEndpoints) - .WillOnce([&](ClientProxy* client, const ResultCallback& callback) { - callback.result_cb({Status::kSuccess}); + .WillOnce([&](ClientProxy* client, ResultCallback callback) { + callback({Status::kSuccess}); }); Core core{&mock}; } @@ -71,6 +84,97 @@ TEST(CoreTest, DestructorReportsFatalFailure) { "Unable to shutdown"); } +TEST(CoreTest, RequestConnectionCallsScRouter) { + MockServiceControllerRouter mock; + // Called when Core is destroyed. + EXPECT_CALL(mock, StopAllEndpoints) + .WillOnce([&](ClientProxy* client, ResultCallback callback) { + callback({Status::kSuccess}); + }); + EXPECT_CALL(mock, RequestConnection); + Core core{&mock}; + core.RequestConnection("TEST", {}, {}, {}); +} + +TEST(CoreTest, AcceptConnectionCallsScRouter) { + MockServiceControllerRouter mock; + // Called when Core is destroyed. + EXPECT_CALL(mock, StopAllEndpoints) + .WillOnce([&](ClientProxy* client, ResultCallback callback) { + callback({Status::kSuccess}); + }); + EXPECT_CALL(mock, AcceptConnection); + Core core{&mock}; + core.AcceptConnection("TEST", {}, {}); +} + +TEST(CoreTest, SendPayloadCallsScRouter) { + MockServiceControllerRouter mock; + // Called when Core is destroyed. + EXPECT_CALL(mock, StopAllEndpoints) + .WillOnce([&](ClientProxy* client, ResultCallback callback) { + callback({Status::kSuccess}); + }); + EXPECT_CALL(mock, SendPayload); + Core core{&mock}; + core.SendPayload({"TEST"}, Payload(ByteArray("Hello world")), {}); +} + +TEST(CoreV3Test, TestAdvertisingOptionsConversionWorks) { + MockServiceControllerRouter mock; + // Called when Core is destroyed. + EXPECT_CALL(mock, StopAllEndpoints) + .WillOnce([&](ClientProxy* client, ResultCallback callback) { + callback({Status::kSuccess}); + }); + EXPECT_CALL(mock, StartAdvertising) + .WillOnce([](ClientProxy*, absl::string_view, + const AdvertisingOptions& options, + const ConnectionRequestInfo& info, ResultCallback) { + EXPECT_EQ(options.strategy, Strategy::kP2pCluster); + EXPECT_FALSE(options.low_power); + EXPECT_TRUE(options.enable_bluetooth_listening); + EXPECT_FALSE(options.auto_upgrade_bandwidth); + EXPECT_EQ(options.fast_advertisement_service_uuid, "NearbyConnections"); + }); + Core core{&mock}; + v3::AdvertisingOptions advertising_options = { + .strategy = Strategy::kP2pCluster, + .power_level = PowerLevel::kHighPower, + .enable_bluetooth_listening = true, + .auto_upgrade_bandwidth = false, + .fast_advertisement_service_uuid = "NearbyConnections", + }; + core.StartAdvertisingV3("service", advertising_options, {}, {}); + core.StopDiscoveryV3({}); +} + +TEST(CoreV3Test, TestDiscoveryOptionsConversionWorks) { + MockServiceControllerRouter mock; + // Called when Core is destroyed. + EXPECT_CALL(mock, StopAllEndpoints) + .WillOnce([&](ClientProxy* client, ResultCallback callback) { + callback({Status::kSuccess}); + }); + EXPECT_CALL(mock, StartDiscovery) + .WillOnce([](ClientProxy*, absl::string_view, + const DiscoveryOptions& options, + const DiscoveryListener& info, ResultCallback) { + EXPECT_EQ(options.strategy, Strategy::kP2pCluster); + EXPECT_FALSE(options.low_power); + EXPECT_TRUE(options.auto_upgrade_bandwidth); + EXPECT_EQ(options.fast_advertisement_service_uuid, "NearbyConnections"); + }); + Core core{&mock}; + v3::DiscoveryOptions discovery_options = { + .strategy = Strategy::kP2pCluster, + .power_level = PowerLevel::kHighPower, + .fast_advertisement_service_uuid = "NearbyConnections", + }; + core.StartDiscoveryV3("service", discovery_options, {}, {}); + core.StopDiscoveryV3({}); +} + TEST(CoreV3Test, TestCallbackWrapWorksStartAdvertisingV3FourArgs) { MockServiceControllerRouter mock; EXPECT_CALL(mock, StartAdvertising) @@ -86,16 +190,16 @@ TEST(CoreV3Test, TestCallbackWrapWorksStartAdvertisingV3FourArgs) { info.listener.disconnected_cb("FAKE"); }); EXPECT_CALL(mock, StopAllEndpoints) - .WillOnce([&](ClientProxy* client, const ResultCallback& callback) { + .WillOnce([&](ClientProxy* client, ResultCallback callback) { NEARBY_LOGS(INFO) << "StopAllEndpoints called"; - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); Core core{&mock}; CountDownLatch result_latch(2); CountDownLatch bandwidth_changed_latch(1); CountDownLatch disconnected_latch(1); CountDownLatch initiated_latch(1); - AdvertisingOptions advertising_options; + v3::AdvertisingOptions advertising_options; advertising_options.strategy = Strategy::kP2pCluster; core.StartAdvertisingV3( "service", advertising_options, @@ -132,7 +236,7 @@ TEST(CoreV3Test, TestStartAdvertisingV3NonConnectionsDeviceProvider) { MockServiceControllerRouter mock; EXPECT_CALL(mock, StartAdvertising) .WillOnce([&](ClientProxy*, absl::string_view, const AdvertisingOptions&, - const ConnectionRequestInfo& info, const ResultCallback&) { + const ConnectionRequestInfo& info, ResultCallback) { NEARBY_LOGS(INFO) << "StartAdvertising called"; ASSERT_TRUE(info.endpoint_info.Empty()); // call all callbacks to make sure it all gets called correctly. @@ -143,16 +247,16 @@ TEST(CoreV3Test, TestStartAdvertisingV3NonConnectionsDeviceProvider) { info.listener.disconnected_cb("FAKE"); }); EXPECT_CALL(mock, StopAllEndpoints) - .WillOnce([&](ClientProxy* client, const ResultCallback& callback) { + .WillOnce([&](ClientProxy* client, ResultCallback callback) { NEARBY_LOGS(INFO) << "StopAllEndpoints called"; - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); Core core{&mock}; CountDownLatch result_latch(2); CountDownLatch bandwidth_changed_latch(1); CountDownLatch disconnected_latch(1); CountDownLatch initiated_latch(1); - AdvertisingOptions advertising_options; + v3::AdvertisingOptions advertising_options; advertising_options.strategy = Strategy::kP2pCluster; FakeNearbyDeviceProvider device_provider; core.RegisterDeviceProvider(&device_provider); @@ -202,16 +306,16 @@ TEST(CoreV3Test, TestStartAdvertisingV3NonConnectionsDevice) { info.listener.disconnected_cb("FAKE"); }); EXPECT_CALL(mock, StopAllEndpoints) - .WillOnce([&](ClientProxy* client, const ResultCallback& callback) { + .WillOnce([&](ClientProxy* client, ResultCallback callback) { NEARBY_LOGS(INFO) << "StopAllEndpoints called"; - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); Core core{&mock}; CountDownLatch result_latch(2); CountDownLatch bandwidth_changed_latch(1); CountDownLatch disconnected_latch(1); CountDownLatch initiated_latch(1); - AdvertisingOptions advertising_options; + v3::AdvertisingOptions advertising_options; advertising_options.strategy = Strategy::kP2pCluster; auto local_device = FakeNearbyDevice(); core.StartAdvertisingV3( @@ -260,16 +364,16 @@ TEST(CoreV3Test, TestCallbackWrapWorksStartAdvertisingV3FiveArgs) { info.listener.disconnected_cb("FAKE"); }); EXPECT_CALL(mock, StopAllEndpoints) - .WillOnce([&](ClientProxy* client, const ResultCallback& callback) { + .WillOnce([&](ClientProxy* client, ResultCallback callback) { NEARBY_LOGS(INFO) << "StopAllEndpoints called"; - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); Core core{&mock}; CountDownLatch result_latch(2); CountDownLatch bandwidth_changed_latch(1); CountDownLatch disconnected_latch(1); CountDownLatch initiated_latch(1); - AdvertisingOptions advertising_options; + v3::AdvertisingOptions advertising_options; advertising_options.strategy = Strategy::kP2pCluster; auto local_device = v3::ConnectionsDevice("FAKE", "endpoint_info", {}); core.StartAdvertisingV3( @@ -315,11 +419,11 @@ TEST(CoreV3Test, TestCallbackWrapWorksStartDiscoveryV3) { info.endpoint_lost_cb("FAKE"); }); EXPECT_CALL(mock, StopAllEndpoints) - .WillOnce([&](ClientProxy* client, const ResultCallback& callback) { + .WillOnce([&](ClientProxy* client, ResultCallback callback) { NEARBY_LOGS(INFO) << "StopAllEndpoints called"; - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); - DiscoveryOptions options; + v3::DiscoveryOptions options; options.strategy = Strategy::kP2pCluster; Core core{&mock}; CountDownLatch endpoint_distance_latch(1); diff --git a/connections/implementation/BUILD b/connections/implementation/BUILD index 187965ba..649b57f2 100644 --- a/connections/implementation/BUILD +++ b/connections/implementation/BUILD @@ -126,18 +126,20 @@ cc_library( "//internal/platform:comm", "//internal/platform:connection_info", "//internal/platform:error_code_recorder", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform:util", "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", "//internal/platform/implementation/shared:file", + "//internal/proto/analytics:connections_log_cc_proto", "//proto:connections_enums_cc_proto", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:btree", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/functional:bind_front", + "@com_google_absl//absl/log:check", "@com_google_absl//absl/memory", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", @@ -181,10 +183,13 @@ cc_library( deps = [ ":internal", "//connections:core_types", + "//connections/implementation/flags:connections_flags", "//connections/v3:v3_types", + "//internal/flags:nearby_flags", "//internal/platform:base", "//internal/platform:test_util", "//internal/platform:types", + "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/functional:bind_front", "@com_google_absl//absl/strings", "@com_google_googletest//:gtest_for_library_testonly", @@ -225,6 +230,7 @@ cc_test( ":internal", ":internal_test", "//connections:core_types", + "//connections/implementation/analytics", "//connections/implementation/flags:connections_flags", "//connections/implementation/mediums", "//connections/implementation/proto:offline_wire_formats_cc_proto", @@ -234,13 +240,14 @@ cc_test( "//internal/interop:device", "//internal/platform:base", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep + "//internal/proto/analytics:connections_log_cc_proto", "//internal/test", "//proto:connections_enums_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", diff --git a/connections/implementation/analytics/BUILD b/connections/implementation/analytics/BUILD index 63989a25..022bb0cd 100644 --- a/connections/implementation/analytics/BUILD +++ b/connections/implementation/analytics/BUILD @@ -31,7 +31,6 @@ cc_library( "//connections:core_types", "//internal/analytics:event_logger", "//internal/platform:error_code_recorder", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform/implementation:types", "//internal/proto/analytics:connections_log_cc_proto", @@ -61,7 +60,6 @@ cc_test( "//internal/platform:base", "//internal/platform:comm", "//internal/platform:error_code_recorder", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep "//internal/proto/analytics:connections_log_cc_proto", diff --git a/connections/implementation/analytics/analytics_recorder.cc b/connections/implementation/analytics/analytics_recorder.cc index 60b90a90..cb50febf 100644 --- a/connections/implementation/analytics/analytics_recorder.cc +++ b/connections/implementation/analytics/analytics_recorder.cc @@ -220,7 +220,7 @@ void AnalyticsRecorder::OnStartedIncomingConnectionListening( return; } UpdateStrategySessionLocked(strategy, ADVERTISER); - if (started_advertising_phase_time_ == absl::Now()) { + if (started_advertising_phase_time_ == absl::InfinitePast()) { started_advertising_phase_time_ = SystemClock::ElapsedRealtime(); } } @@ -250,6 +250,19 @@ void AnalyticsRecorder::OnEndpointFound(Medium medium) { SystemClock::ElapsedRealtime() - started_discovery_phase_time_)); } +void AnalyticsRecorder::OnRequestConnection( + const connections::Strategy &strategy, const std::string &endpoint_id) { + MutexLock lock(&mutex_); + if (!CanRecordAnalyticsLocked("onRequestConnection")) { + return; + } + + UpdateStrategySessionLocked(strategy, DISCOVERER); + if (started_discovery_phase_time_ == absl::InfinitePast()) { + started_discovery_phase_time_ = SystemClock::ElapsedRealtime(); + } +} + void AnalyticsRecorder::OnConnectionRequestReceived( const std::string &remote_endpoint_id) { MutexLock lock(&mutex_); @@ -1034,10 +1047,15 @@ void AnalyticsRecorder::FinishStrategySessionLocked() { bandwidth_upgrade_attempts_.clear(); // Add the StrategySession in ClientSession - current_strategy_session_->set_duration_millis(absl::ToInt64Milliseconds( - started_strategy_session_time_ - SystemClock::ElapsedRealtime())); - *client_session_->add_strategy_session() = - *std::move(current_strategy_session_); + if (current_strategy_session_ != nullptr) { + current_strategy_session_->set_duration_millis(absl::ToInt64Milliseconds( + SystemClock::ElapsedRealtime() - started_strategy_session_time_)); + *client_session_->add_strategy_session() = + *std::move(current_strategy_session_); + } + + current_strategy_session_ = nullptr; + current_strategy_ = connections::Strategy::kNone; LogEvent(STOP_STRATEGY_SESSION); } } diff --git a/connections/implementation/analytics/analytics_recorder.h b/connections/implementation/analytics/analytics_recorder.h index d082e3e8..141022af 100644 --- a/connections/implementation/analytics/analytics_recorder.h +++ b/connections/implementation/analytics/analytics_recorder.h @@ -74,6 +74,10 @@ class AnalyticsRecorder { ABSL_LOCKS_EXCLUDED(mutex_); // Connection request + void OnRequestConnection(const connections::Strategy &strategy, + const std::string &endpoint_id) + ABSL_LOCKS_EXCLUDED(mutex_); + void OnConnectionRequestReceived(const std::string &remote_endpoint_id) ABSL_LOCKS_EXCLUDED(mutex_); void OnConnectionRequestSent(const std::string &remote_endpoint_id) @@ -374,13 +378,13 @@ class AnalyticsRecorder { std::unique_ptr< location::nearby::analytics::proto::ConnectionsLog::AdvertisingPhase> current_advertising_phase_; - absl::Time started_advertising_phase_time_; + absl::Time started_advertising_phase_time_ = absl::InfinitePast(); // Current DiscoveryPhase std::unique_ptr< location::nearby::analytics::proto::ConnectionsLog::DiscoveryPhase> current_discovery_phase_; - absl::Time started_discovery_phase_time_; + absl::Time started_discovery_phase_time_ = absl::InfinitePast(); absl::btree_map 0) { diff --git a/connections/implementation/analytics/throughput_recorder.h b/connections/implementation/analytics/throughput_recorder.h index d2bacd9c..e6dcdc05 100644 --- a/connections/implementation/analytics/throughput_recorder.h +++ b/connections/implementation/analytics/throughput_recorder.h @@ -87,7 +87,7 @@ class ThroughputRecorder { int64_t GetDurationMillis(); void OnFrameSent(Medium medium, PacketMetaData& packetMetaData); void OnFrameReceived(Medium medium, PacketMetaData& packetMetaData); - void MarkAsSuccess() { success_ = true; } + void MarkAsSuccess(); private: void CalculateDurationTimes(PacketMetaData packetMetaData); diff --git a/connections/implementation/base_bwu_handler.cc b/connections/implementation/base_bwu_handler.cc index c652dfbf..272e100d 100644 --- a/connections/implementation/base_bwu_handler.cc +++ b/connections/implementation/base_bwu_handler.cc @@ -23,8 +23,9 @@ namespace nearby { namespace connections { -BaseBwuHandler::BaseBwuHandler(BwuNotifications bwu_notifications) - : bwu_notifications_(std::move(bwu_notifications)) {} +BaseBwuHandler::BaseBwuHandler( + IncomingConnectionCallback incoming_connection_callback) + : incoming_connection_callback_(std::move(incoming_connection_callback)) {} ByteArray BaseBwuHandler::InitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& service_id, @@ -78,5 +79,14 @@ void BaseBwuHandler::RevertResponderState(const std::string& service_id) { HandleRevertInitiatorStateForService(service_id); } +void BaseBwuHandler::NotifyOnIncomingConnection( + ClientProxy* client, std::unique_ptr connection) { + if (!incoming_connection_callback_) { + NEARBY_LOGS(WARNING) + << "Ignoring incoming connection, no callback registered"; + return; + } + incoming_connection_callback_(client, std::move(connection)); +} } // namespace connections } // namespace nearby diff --git a/connections/implementation/base_bwu_handler.h b/connections/implementation/base_bwu_handler.h index a6d93625..783d90e4 100644 --- a/connections/implementation/base_bwu_handler.h +++ b/connections/implementation/base_bwu_handler.h @@ -30,7 +30,8 @@ namespace connections { // of the service IDs and endpoint IDs that initiated a bandwidth upgrade. class BaseBwuHandler : public BwuHandler { public: - explicit BaseBwuHandler(BwuNotifications bwu_notifications); + explicit BaseBwuHandler( + IncomingConnectionCallback incoming_connection_callback); // BwuHandler implementation: ByteArray InitializeUpgradedMediumForEndpoint( @@ -55,9 +56,13 @@ class BaseBwuHandler : public BwuHandler { virtual void HandleRevertInitiatorStateForService( const std::string& upgrade_service_id) = 0; - BwuNotifications bwu_notifications_; + // Notifies the caller about incoming connection. + void NotifyOnIncomingConnection( + ClientProxy* client, + std::unique_ptr connection); private: + IncomingConnectionCallback incoming_connection_callback_; // Map from the (wrapped) service ID to endpoint IDs that are initiating a // bandwidth upgrade. Not used for endpoints that respond to bandwidth upgrade // requests from another device. diff --git a/connections/implementation/base_bwu_handler_test.cc b/connections/implementation/base_bwu_handler_test.cc index d04cff92..13fe331b 100644 --- a/connections/implementation/base_bwu_handler_test.cc +++ b/connections/implementation/base_bwu_handler_test.cc @@ -38,7 +38,7 @@ class BwuHandlerImpl : public BaseBwuHandler { absl::optional endpoint_id; }; - BwuHandlerImpl() : BaseBwuHandler(BwuNotifications{}) {} + BwuHandlerImpl() : BaseBwuHandler(nullptr) {} const std::vector& handle_initialize_calls() const { return handle_initialize_calls_; diff --git a/connections/implementation/base_endpoint_channel.h b/connections/implementation/base_endpoint_channel.h index 5259748c..889cf4fa 100644 --- a/connections/implementation/base_endpoint_channel.h +++ b/connections/implementation/base_endpoint_channel.h @@ -21,9 +21,10 @@ #include "absl/base/thread_annotations.h" #include "connections/implementation/analytics/analytics_recorder.h" +#include "connections/implementation/analytics/packet_meta_data.h" #include "connections/implementation/endpoint_channel.h" #include "internal/platform/byte_array.h" -#include "internal/platform/condition_variable.h" +#include "internal/platform/exception.h" #include "internal/platform/input_stream.h" #include "internal/platform/mutex.h" #include "internal/platform/output_stream.h" diff --git a/connections/implementation/base_endpoint_channel_test.cc b/connections/implementation/base_endpoint_channel_test.cc index 03ca6898..00646455 100644 --- a/connections/implementation/base_endpoint_channel_test.cc +++ b/connections/implementation/base_endpoint_channel_test.cc @@ -14,7 +14,9 @@ #include "connections/implementation/base_endpoint_channel.h" +#include #include +#include #include #include @@ -22,9 +24,13 @@ #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" +#include "absl/time/clock.h" #include "absl/time/time.h" +#include "connections/implementation/client_proxy.h" #include "connections/implementation/encryption_runner.h" +#include "connections/implementation/endpoint_channel.h" #include "connections/implementation/offline_frames.h" #include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" @@ -34,7 +40,6 @@ #include "internal/platform/multi_thread_executor.h" #include "internal/platform/output_stream.h" #include "internal/platform/pipe.h" -#include "internal/platform/single_thread_executor.h" #include "proto/connections_enums.pb.h" namespace nearby { @@ -44,6 +49,7 @@ namespace { using ::location::nearby::proto::connections::DisconnectionReason; using ::location::nearby::proto::connections::Medium; using EncryptionContext = BaseEndpointChannel::EncryptionContext; +constexpr size_t kChunkSize = 64 * 1024; class TestEndpointChannel : public BaseEndpointChannel { public: @@ -62,7 +68,7 @@ std::function MakeDataPump( return [label, input, output, monitor]() { NEARBY_LOGS(INFO) << "streaming data through '" << label << "'"; while (true) { - auto read_response = input->Read(Pipe::kChunkSize); + auto read_response = input->Read(kChunkSize); if (!read_response.ok()) { NEARBY_LOGS(INFO) << "Peer reader closed on '" << label << "'"; output->Close(); @@ -158,21 +164,17 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a, } TEST(BaseEndpointChannelTest, ConstructorDestructorWorks) { - Pipe pipe; - InputStream& input_stream = pipe.GetInputStream(); - OutputStream& output_stream = pipe.GetOutputStream(); + auto [input, output] = CreatePipe(); - TestEndpointChannel test_channel(&input_stream, &output_stream); + TestEndpointChannel test_channel(input.get(), output.get()); } TEST(BaseEndpointChannelTest, ReadWrite) { // Direct not-encrypted IO. - Pipe pipe_a; // channel_a writes to pipe_a, reads from pipe_b. - Pipe pipe_b; // channel_b writes to pipe_b, reads from pipe_a. - TestEndpointChannel channel_a(&pipe_b.GetInputStream(), - &pipe_a.GetOutputStream()); - TestEndpointChannel channel_b(&pipe_a.GetInputStream(), - &pipe_b.GetOutputStream()); + auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b. + auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a. + TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get()); + TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get()); ByteArray tx_message{"data message"}; channel_a.Write(tx_message); ByteArray rx_message = std::move(channel_b.Read().result()); @@ -180,8 +182,8 @@ TEST(BaseEndpointChannelTest, ReadWrite) { } TEST(BaseEndpointChannelTest, ChannelUnencryptedByDefault) { - Pipe pipe; - TestEndpointChannel channel(&pipe.GetInputStream(), &pipe.GetOutputStream()); + auto pipe = CreatePipe(); + TestEndpointChannel channel(pipe.first.get(), pipe.second.get()); ExceptionOr result = channel.TryDecrypt(ByteArray("message")); @@ -192,12 +194,10 @@ TEST(BaseEndpointChannelTest, ChannelUnencryptedByDefault) { TEST(BaseEndpointChannelTest, TryDecrypt) { absl::string_view kMessage = "message"; - Pipe pipe_a; // channel_a writes to pipe_a, reads from pipe_b. - Pipe pipe_b; // channel_b writes to pipe_b, reads from pipe_a. - TestEndpointChannel channel_a(&pipe_b.GetInputStream(), - &pipe_a.GetOutputStream()); - TestEndpointChannel channel_b(&pipe_a.GetInputStream(), - &pipe_b.GetOutputStream()); + auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b. + auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a. + TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get()); + TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get()); auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b); ASSERT_NE(context_a, nullptr); ASSERT_NE(context_b, nullptr); @@ -215,12 +215,10 @@ TEST(BaseEndpointChannelTest, TryDecrypt) { } TEST(BaseEndpointChannelTest, TryDecryptFailsWhenDecryptionFails) { - Pipe pipe_a; // channel_a writes to pipe_a, reads from pipe_b. - Pipe pipe_b; // channel_b writes to pipe_b, reads from pipe_a. - TestEndpointChannel channel_a(&pipe_b.GetInputStream(), - &pipe_a.GetOutputStream()); - TestEndpointChannel channel_b(&pipe_a.GetInputStream(), - &pipe_b.GetOutputStream()); + auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b. + auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a. + TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get()); + TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get()); auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b); ASSERT_NE(context_a, nullptr); channel_a.EnableEncryption(context_a); @@ -240,25 +238,27 @@ TEST(BaseEndpointChannelTest, NotEncryptedReadWriteCanBeIntercepted) { absl::Mutex mutex; std::string capture_a; std::string capture_b; - Pipe client_a; // Channel "a" writes to client "a", reads from server "a". - Pipe client_b; // Channel "b" writes to client "b", reads from server "b". - Pipe server_a; // Data pump "a" reads from client "a", writes to server "b". - Pipe server_b; // Data pump "b" reads from client "b", writes to server "a". - TestEndpointChannel channel_a(&server_a.GetInputStream(), - &client_a.GetOutputStream()); - TestEndpointChannel channel_b(&server_b.GetInputStream(), - &client_b.GetOutputStream()); + auto client_a = + CreatePipe(); // Channel "a" writes to client "a", reads from server "a". + auto client_b = + CreatePipe(); // Channel "b" writes to client "b", reads from server "b". + auto server_a = CreatePipe(); // Data pump "a" reads from client "a", writes + // to server "b". + auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes + // to server "a". + TestEndpointChannel channel_a(server_a.first.get(), client_a.second.get()); + TestEndpointChannel channel_b(server_b.first.get(), client_b.second.get()); ON_CALL(channel_a, GetMedium).WillByDefault([]() { return Medium::BLE; }); ON_CALL(channel_b, GetMedium).WillByDefault([]() { return Medium::BLE; }); MultiThreadExecutor executor(2); - executor.Execute(MakeDataPump( - "pump_a", &client_a.GetInputStream(), &server_b.GetOutputStream(), - MakeDataMonitor("monitor_a", &capture_a, &mutex))); - executor.Execute(MakeDataPump( - "pump_b", &client_b.GetInputStream(), &server_a.GetOutputStream(), - MakeDataMonitor("monitor_b", &capture_b, &mutex))); + executor.Execute( + MakeDataPump("pump_a", client_a.first.get(), server_b.second.get(), + MakeDataMonitor("monitor_a", &capture_a, &mutex))); + executor.Execute( + MakeDataPump("pump_b", client_b.first.get(), server_a.second.get(), + MakeDataMonitor("monitor_b", &capture_b, &mutex))); EXPECT_EQ(channel_a.GetType(), "BLE"); EXPECT_EQ(channel_b.GetType(), "BLE"); @@ -289,14 +289,16 @@ TEST(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) { absl::Mutex mutex; std::string capture_a; std::string capture_b; - Pipe client_a; // Channel "a" writes to client "a", reads from server "a". - Pipe client_b; // Channel "b" writes to client "b", reads from server "b". - Pipe server_a; // Data pump "a" reads from client "a", writes to server "b". - Pipe server_b; // Data pump "b" reads from client "b", writes to server "a". - TestEndpointChannel channel_a(&server_a.GetInputStream(), - &client_a.GetOutputStream()); - TestEndpointChannel channel_b(&server_b.GetInputStream(), - &client_b.GetOutputStream()); + auto client_a = + CreatePipe(); // Channel "a" writes to client "a", reads from server "a". + auto client_b = + CreatePipe(); // Channel "b" writes to client "b", reads from server "b". + auto server_a = CreatePipe(); // Data pump "a" reads from client "a", writes + // to server "b". + auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes + // to server "a". + TestEndpointChannel channel_a(server_a.first.get(), client_a.second.get()); + TestEndpointChannel channel_b(server_b.first.get(), client_b.second.get()); ON_CALL(channel_a, GetMedium).WillByDefault([]() { return Medium::BLUETOOTH; @@ -306,12 +308,12 @@ TEST(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) { }); MultiThreadExecutor executor(2); - executor.Execute(MakeDataPump( - "pump_a", &client_a.GetInputStream(), &server_b.GetOutputStream(), - MakeDataMonitor("monitor_a", &capture_a, &mutex))); - executor.Execute(MakeDataPump( - "pump_b", &client_b.GetInputStream(), &server_a.GetOutputStream(), - MakeDataMonitor("monitor_b", &capture_b, &mutex))); + executor.Execute( + MakeDataPump("pump_a", client_a.first.get(), server_b.second.get(), + MakeDataMonitor("monitor_a", &capture_a, &mutex))); + executor.Execute( + MakeDataPump("pump_b", client_b.first.get(), server_a.second.get(), + MakeDataMonitor("monitor_b", &capture_b, &mutex))); // Run DH key exchange; setup encryption contexts for channels. auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b); @@ -346,12 +348,10 @@ TEST(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) { TEST(BaseEndpointChannelTest, CanBesuspendedAndResumed) { // Setup test communication environment. - Pipe pipe_a; // channel_a writes to pipe_a, reads from pipe_b. - Pipe pipe_b; // channel_b writes to pipe_b, reads from pipe_a. - TestEndpointChannel channel_a(&pipe_b.GetInputStream(), - &pipe_a.GetOutputStream()); - TestEndpointChannel channel_b(&pipe_a.GetInputStream(), - &pipe_b.GetOutputStream()); + auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b. + auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a. + TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get()); + TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get()); ON_CALL(channel_a, GetMedium).WillByDefault([]() { return Medium::WIFI_LAN; @@ -399,14 +399,12 @@ TEST(BaseEndpointChannelTest, CanBesuspendedAndResumed) { } TEST(BaseEndpointChannelTest, ReadAfterInputStreamClosed) { - Pipe pipe; - InputStream& input_stream = pipe.GetInputStream(); - OutputStream& output_stream = pipe.GetOutputStream(); + auto [input, output] = CreatePipe(); - TestEndpointChannel test_channel(&input_stream, &output_stream); + TestEndpointChannel test_channel(input.get(), output.get()); // Close the output stream before trying to read from the input. - output_stream.Close(); + output->Close(); // Trying to read should fail gracefully with an IO error. ExceptionOr read_data = test_channel.Read(); @@ -417,12 +415,10 @@ TEST(BaseEndpointChannelTest, ReadAfterInputStreamClosed) { TEST(BaseEndpointChannelTest, ReadUnencryptedFrameOnEncryptedChannel) { // Setup test communication environment. - Pipe pipe_a; // channel_a writes to pipe_a, reads from pipe_b. - Pipe pipe_b; // channel_b writes to pipe_b, reads from pipe_a. - TestEndpointChannel channel_a(&pipe_b.GetInputStream(), - &pipe_a.GetOutputStream()); - TestEndpointChannel channel_b(&pipe_a.GetInputStream(), - &pipe_b.GetOutputStream()); + auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b. + auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a. + TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get()); + TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get()); ON_CALL(channel_a, GetMedium).WillByDefault([]() { return Medium::BLUETOOTH; diff --git a/connections/implementation/base_pcp_handler.cc b/connections/implementation/base_pcp_handler.cc index 38729c65..085121d8 100644 --- a/connections/implementation/base_pcp_handler.cc +++ b/connections/implementation/base_pcp_handler.cc @@ -28,6 +28,8 @@ #include "absl/types/span.h" #include "connections/advertising_options.h" #include "connections/connection_options.h" +#include "connections/implementation/endpoint_channel_manager.h" +#include "connections/implementation/client_proxy.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/mediums/utils.h" #include "connections/implementation/offline_frames.h" @@ -84,7 +86,7 @@ BasePcpHandler::~BasePcpHandler() { } void BasePcpHandler::Shutdown() { - if (stop_) return; + if (closed_.Set(true)) return; NEARBY_LOGS(INFO) << "Initiating shutdown of BasePcpHandler(" << strategy_.GetName() << ")"; DisconnectFromEndpointManager(); @@ -694,6 +696,9 @@ Status BasePcpHandler::RequestConnection( "to endpoint_id=" << endpoint_id; + client->OnRequestConnection(GetStrategy(), endpoint_id, + connection_options); + ConnectionInfo connection_info = FillConnectionInfo(client, info, connection_options); @@ -1009,9 +1014,12 @@ void BasePcpHandler::ProcessPreConnectionInitiationFailure( } void BasePcpHandler::ProcessPreConnectionResultFailure( - ClientProxy* client, const std::string& endpoint_id) { + ClientProxy* client, const std::string& endpoint_id, + bool should_call_disconnect_endpoint, const DisconnectionReason& reason) { auto item = pending_connections_.extract(endpoint_id); - endpoint_manager_->DiscardEndpoint(client, endpoint_id); + if (should_call_disconnect_endpoint) { + endpoint_manager_->DiscardEndpoint(client, endpoint_id, reason); + } client->OnConnectionRejected(endpoint_id, {Status::kError}); } @@ -1045,7 +1053,9 @@ Status BasePcpHandler::AcceptConnection(ClientProxy* client, NEARBY_LOGS(ERROR) << "Channel destroyed before Accept; bring down " "connection: endpoint_id=" << endpoint_id; - ProcessPreConnectionResultFailure(client, endpoint_id); + ProcessPreConnectionResultFailure( + client, endpoint_id, /* should_call_disconnect_endpoint= */ true, + DisconnectionReason::IO_ERROR); response.Set({Status::kEndpointUnknown}); return; } @@ -1057,7 +1067,9 @@ Status BasePcpHandler::AcceptConnection(ClientProxy* client, NEARBY_LOGS(INFO) << "AcceptConnection: failed to send response: endpoint_id=" << endpoint_id; - ProcessPreConnectionResultFailure(client, endpoint_id); + ProcessPreConnectionResultFailure( + client, endpoint_id, /* should_call_disconnect_endpoint= */ true, + DisconnectionReason::IO_ERROR); response.Set({Status::kEndpointIoError}); return; } @@ -1103,7 +1115,9 @@ Status BasePcpHandler::RejectConnection(ClientProxy* client, << "Channel destroyed before Reject; bring down connection: " "endpoint_id=" << endpoint_id; - ProcessPreConnectionResultFailure(client, endpoint_id); + ProcessPreConnectionResultFailure( + client, endpoint_id, /* should_call_disconnect_endpoint= */ true, + DisconnectionReason::IO_ERROR); response.Set({Status::kEndpointUnknown}); return; } @@ -1115,7 +1129,9 @@ Status BasePcpHandler::RejectConnection(ClientProxy* client, NEARBY_LOGS(INFO) << "RejectConnection: failed to send response: endpoint_id=" << endpoint_id; - ProcessPreConnectionResultFailure(client, endpoint_id); + ProcessPreConnectionResultFailure( + client, endpoint_id, /* should_call_disconnect_endpoint= */ true, + DisconnectionReason::IO_ERROR); response.Set({Status::kEndpointIoError}); return; } @@ -1179,6 +1195,16 @@ void BasePcpHandler::OnIncomingFrame( client->SetRemoteOsInfo(endpoint_id, connection_response.os_info()); } + if (connection_response.has_safe_to_disconnect_version()) { + NEARBY_LOGS(INFO) + << "[safe-to-disconnect]: endpoint_id=" << endpoint_id + << "; Version = " + << connection_response.safe_to_disconnect_version(); + client->SetRemoteSafeToDisconnectVersion( + endpoint_id, connection_response.safe_to_disconnect_version()); + } + channel_manager_->UpdateSafeToDisconnectForEndpoint(endpoint_id, + client->IsSafeToDisconnectEnabled(endpoint_id)); EvaluateConnectionResult(client, endpoint_id, /* can_close_immediately= */ true); @@ -1190,13 +1216,14 @@ void BasePcpHandler::OnIncomingFrame( void BasePcpHandler::OnEndpointDisconnect(ClientProxy* client, const std::string& service_id, const std::string& endpoint_id, - CountDownLatch barrier) { + CountDownLatch barrier, + DisconnectionReason reason) { if (stop_.Get()) { barrier.CountDown(); return; } RunOnPcpHandlerThread("on-endpoint-disconnect", - [this, client, endpoint_id, barrier]() + [this, client, endpoint_id, barrier, reason]() RUN_ON_PCP_HANDLER_THREAD() mutable { auto item = pending_alarms_.find(endpoint_id); if (item != pending_alarms_.end()) { @@ -1204,8 +1231,10 @@ void BasePcpHandler::OnEndpointDisconnect(ClientProxy* client, alarm->Cancel(); pending_alarms_.erase(item); } - ProcessPreConnectionResultFailure(client, - endpoint_id); + ProcessPreConnectionResultFailure( + client, endpoint_id, + /* should_call_disconnect_endpoint= */ false, + reason); barrier.CountDown(); }); } @@ -1648,7 +1677,9 @@ void BasePcpHandler::ProcessTieBreakLoss( client, info->channel->GetMedium(), endpoint_id, info->channel.get(), info->is_incoming, info->start_time, {Status::kEndpointIoError}, info->result.lock().get()); - ProcessPreConnectionResultFailure(client, endpoint_id); + ProcessPreConnectionResultFailure(client, endpoint_id, + /* should_call_disconnect_endpoint= */ true, + DisconnectionReason::IO_ERROR); } bool BasePcpHandler::AppendRemoteBluetoothMacAddressEndpoint( @@ -1795,14 +1826,16 @@ void BasePcpHandler::EvaluateConnectionResult(ClientProxy* client, // Clean up the channel in EndpointManager if it's no longer required. if (can_close_immediately) { - endpoint_manager_->DiscardEndpoint(client, endpoint_id); + endpoint_manager_->DiscardEndpoint(client, endpoint_id, + DisconnectionReason::UNFINISHED); } else { pending_alarms_.emplace( endpoint_id, std::make_unique( "BasePcpHandler.evaluateConnectionResult() delayed close", [this, client, endpoint_id]() { - endpoint_manager_->DiscardEndpoint(client, endpoint_id); + endpoint_manager_->DiscardEndpoint( + client, endpoint_id, DisconnectionReason::UNFINISHED); }, kRejectedConnectionCloseDelay, &alarm_executor_)); } diff --git a/connections/implementation/base_pcp_handler.h b/connections/implementation/base_pcp_handler.h index c149e360..07496504 100644 --- a/connections/implementation/base_pcp_handler.h +++ b/connections/implementation/base_pcp_handler.h @@ -22,6 +22,7 @@ #include #include "securegcm/ukey2_handshake.h" +#include "absl/base/thread_annotations.h" #include "absl/container/btree_map.h" #include "absl/container/flat_hash_map.h" #include "absl/time/time.h" @@ -148,7 +149,8 @@ class BasePcpHandler : public PcpHandler, // @EndpointManagerThread void OnEndpointDisconnect(ClientProxy* client, const std::string& service_id, const std::string& endpoint_id, - CountDownLatch barrier) override; + CountDownLatch barrier, + DisconnectionReason reason) override; Status UpdateAdvertisingOptions( ClientProxy* client, absl::string_view service_id, @@ -359,11 +361,13 @@ class BasePcpHandler : public PcpHandler, // Start alarms for endpoints lost by their mediums. Used when updating // discovery options. void StartEndpointLostByMediumAlarms( - ClientProxy* client, location::nearby::proto::connections::Medium medium); + ClientProxy* client, location::nearby::proto::connections::Medium medium) + RUN_ON_PCP_HANDLER_THREAD(); void StopEndpointLostByMediumAlarm( absl::string_view endpoint_id, - location::nearby::proto::connections::Medium medium); + location::nearby::proto::connections::Medium medium) + RUN_ON_PCP_HANDLER_THREAD(); // Returns a vector of ConnectionInfos generated from a StartOperationResult. std::vector GetConnectionInfoFromResult( @@ -379,9 +383,8 @@ class BasePcpHandler : public PcpHandler, } // Test only. - absl::flat_hash_map>& - GetEndpointLostByMediumAlarms() { - return endpoint_lost_by_medium_alarms_; + int GetEndpointLostByMediumAlarmsCount() RUN_ON_PCP_HANDLER_THREAD() { + return endpoint_lost_by_medium_alarms_.size(); } Mediums* mediums_; @@ -505,7 +508,9 @@ class BasePcpHandler : public PcpHandler, EndpointChannel* channel, bool is_incoming, absl::Time start_time, Status status, Future* result); void ProcessPreConnectionResultFailure(ClientProxy* client, - const std::string& endpoint_id); + const std::string& endpoint_id, + bool should_call_disconnect_endpoint, + const DisconnectionReason& reason); // Called when either side accepts/rejects the connection, but only takes // effect after both have accepted or one side has rejected. @@ -603,12 +608,13 @@ class BasePcpHandler : public PcpHandler, // Mapping from endpoint_id -> CancelableAlarm for triggering endpoint loss // while discovery options are updated. absl::flat_hash_map> - endpoint_lost_by_medium_alarms_; + endpoint_lost_by_medium_alarms_ ABSL_GUARDED_BY(GetPcpHandlerThread()); Pcp pcp_; Strategy strategy_{PcpToStrategy(pcp_)}; EncryptionRunner encryption_runner_; BwuManager* bwu_manager_; + AtomicBoolean closed_{false}; }; } // namespace connections diff --git a/connections/implementation/base_pcp_handler_test.cc b/connections/implementation/base_pcp_handler_test.cc index 28343a0d..59cdded1 100644 --- a/connections/implementation/base_pcp_handler_test.cc +++ b/connections/implementation/base_pcp_handler_test.cc @@ -18,33 +18,48 @@ #include #include #include +#include +#include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/base/thread_annotations.h" #include "absl/strings/string_view.h" +#include "absl/time/clock.h" #include "absl/time/time.h" +#include "connections/advertising_options.h" +#include "connections/connection_options.h" #include "connections/discovery_options.h" +#include "connections/implementation/analytics/packet_meta_data.h" #include "connections/implementation/base_endpoint_channel.h" #include "connections/implementation/bwu_manager.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/encryption_runner.h" +#include "connections/implementation/endpoint_manager.h" +#include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "connections/implementation/mediums/mediums.h" #include "connections/implementation/offline_frames.h" +#include "connections/implementation/pcp.h" #include "connections/implementation/proto/offline_wire_formats.pb.h" #include "connections/listeners.h" #include "connections/medium_selector.h" +#include "connections/out_of_band_connection_metadata.h" #include "connections/params.h" #include "connections/status.h" #include "connections/strategy.h" #include "connections/v3/connection_listening_options.h" +#include "internal/flags/nearby_flags.h" #include "internal/interop/device.h" #include "internal/interop/device_provider.h" #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" +#include "internal/platform/feature_flags.h" +#include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" +#include "internal/platform/output_stream.h" #include "internal/platform/pipe.h" #include "proto/connections_enums.pb.h" -#include "proto/connections_enums.proto.h" namespace nearby { namespace connections { @@ -108,9 +123,12 @@ class FakePresenceDeviceProvider : public NearbyDeviceProvider { class MockEndpointChannel : public BaseEndpointChannel { public: - explicit MockEndpointChannel(Pipe* reader, Pipe* writer) - : BaseEndpointChannel("service_id", "channel", &reader->GetInputStream(), - &writer->GetOutputStream()) {} + explicit MockEndpointChannel(std::unique_ptr reader, + std::unique_ptr writer) + : BaseEndpointChannel("service_id", "channel", reader.get(), + writer.get()), + input_stream_(std::move(reader)), + output_stream_(std::move(writer)) {} ExceptionOr DoRead() { return BaseEndpointChannel::Read(); } Exception DoWrite(const ByteArray& data) { @@ -136,6 +154,10 @@ class MockEndpointChannel : public BaseEndpointChannel { MOCK_METHOD(absl::Time, GetLastReadTimestamp, (), (const override)); bool broken_write_{false}; + + private: + std::unique_ptr input_stream_; + std::unique_ptr output_stream_; }; class MockPcpHandler : public BasePcpHandler { @@ -233,19 +255,36 @@ class MockPcpHandler : public BasePcpHandler { return BasePcpHandler::GetDiscoveredEndpoints(medium); } - absl::flat_hash_map>& - GetEndpointLostByMediumAlarms() { - return BasePcpHandler::GetEndpointLostByMediumAlarms(); + int GetEndpointLostByMediumAlarmsCount() { + Future alarms_count; + RunOnPcpHandlerThread( + "GetEndpointLostByMediumAlarmsCount", + [this, alarms_count]() RUN_ON_PCP_HANDLER_THREAD() mutable { + alarms_count.Set( + BasePcpHandler::GetEndpointLostByMediumAlarmsCount()); + }); + return alarms_count.Get().result(); } void StartEndpointLostByMediumAlarms( - ClientProxy* client, location::nearby::proto::connections::Medium medium) { - BasePcpHandler::StartEndpointLostByMediumAlarms(client, medium); + ClientProxy* client, + location::nearby::proto::connections::Medium medium) { + RunOnPcpHandlerThread("StartEndpointLostByMediumAlarms", + [this, client, medium]() RUN_ON_PCP_HANDLER_THREAD() { + BasePcpHandler::StartEndpointLostByMediumAlarms( + client, medium); + }); } - void StopEndpointLostByMediumAlarm(absl::string_view endpoint_id, - location::nearby::proto::connections::Medium medium) { - BasePcpHandler::StopEndpointLostByMediumAlarm(endpoint_id, medium); + void StopEndpointLostByMediumAlarm( + absl::string_view endpoint_id, + location::nearby::proto::connections::Medium medium) { + RunOnPcpHandlerThread("StopEndpointLostByMediumAlarm", + [this, endpoint_id = std::string(endpoint_id), + medium]() RUN_ON_PCP_HANDLER_THREAD() { + BasePcpHandler::StopEndpointLostByMediumAlarm( + endpoint_id, medium); + }); } std::vector GetDiscoveryMediums( @@ -318,6 +357,16 @@ struct MockDiscoveredEndpoint : public MockPcpHandler::DiscoveredEndpoint { MockContext context; }; +class SetSafeToDisconnect { + public: + explicit SetSafeToDisconnect(bool safe_to_disconnect) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature:: + kEnableSafeToDisconnect, + safe_to_disconnect); + } +}; + class BasePcpHandlerTest : public ::testing::TestWithParam { protected: @@ -442,10 +491,13 @@ class BasePcpHandlerTest std::pair, std::unique_ptr> SetupConnection( - Pipe& pipe_a, Pipe& pipe_b, location::nearby::proto::connections::Medium medium) { // NOLINT - auto channel_a = std::make_unique(&pipe_b, &pipe_a); - auto channel_b = std::make_unique(&pipe_a, &pipe_b); + auto [input_a, output_a] = CreatePipe(); + auto [input_b, output_b] = CreatePipe(); + auto channel_a = std::make_unique(std::move(input_a), + std::move(output_b)); + auto channel_b = std::make_unique(std::move(input_b), + std::move(output_a)); // On initiator (A) side, we drop the first write, since this is a // connection establishment packet, and we don't have the peer entity, just // the peer channel. The rest of the exchange must happen for the benefit of @@ -553,8 +605,7 @@ class BasePcpHandlerTest const std::string& endpoint_id, std::unique_ptr channel_a, MockEndpointChannel* channel_b, ClientProxy* client, - MockPcpHandler* pcp_handler, - std::atomic_int* flag = nullptr, + MockPcpHandler* pcp_handler, std::atomic_int* flag = nullptr, Status expected_result = {Status::kSuccess}) { ConnectionRequestInfo info{ .endpoint_info = ByteArray{"ABCD"}, @@ -581,29 +632,29 @@ class BasePcpHandlerTest auto allowed_mediums = pcp_handler->GetDiscoveryMediums(client); EXPECT_CALL(*pcp_handler, ConnectImpl) - .WillRepeatedly(Invoke([&channel_a]( - ClientProxy* client, - MockPcpHandler::DiscoveredEndpoint* endpoint) { - if (endpoint->medium == - location::nearby::proto::connections::WIFI_LAN) { - NEARBY_LOGS(INFO) << "Connect with Medium WIFI_LAN failed."; - return MockPcpHandler::ConnectImplResult{ - .medium = endpoint->medium, - .status = {Status::kError}, - .endpoint_channel = nullptr, - }; - } else { - NEARBY_LOGS(INFO) - << "Connect with Medium: " - << location::nearby::proto::connections::Medium_Name( - endpoint->medium); - return MockPcpHandler::ConnectImplResult{ - .medium = endpoint->medium, - .status = {Status::kSuccess}, - .endpoint_channel = std::move(channel_a), - }; - } - })); + .WillRepeatedly( + Invoke([&channel_a](ClientProxy* client, + MockPcpHandler::DiscoveredEndpoint* endpoint) { + if (endpoint->medium == + location::nearby::proto::connections::WIFI_LAN) { + NEARBY_LOGS(INFO) << "Connect with Medium WIFI_LAN failed."; + return MockPcpHandler::ConnectImplResult{ + .medium = endpoint->medium, + .status = {Status::kError}, + .endpoint_channel = nullptr, + }; + } else { + NEARBY_LOGS(INFO) + << "Connect with Medium: " + << location::nearby::proto::connections::Medium_Name( + endpoint->medium); + return MockPcpHandler::ConnectImplResult{ + .medium = endpoint->medium, + .status = {Status::kSuccess}, + .endpoint_channel = std::move(channel_a), + }; + } + })); for (const auto& discovered_medium : allowed_mediums) { pcp_handler->OnEndpointFound( @@ -632,9 +683,6 @@ class BasePcpHandlerTest expected_result); NEARBY_LOG(INFO, "Stopping Encryption Runner"); } - - Pipe pipe_a_; - Pipe pipe_b_; MockConnectionListener mock_connection_listener_; MockDiscoveryListener mock_discovery_listener_; ConnectionListener connection_listener_{ @@ -654,6 +702,7 @@ class BasePcpHandlerTest .endpoint_distance_changed_cb = mock_discovery_listener_.endpoint_distance_changed_cb.AsStdFunction(), }; + SetSafeToDisconnect set_safe_to_disconnect_{true}; MediumEnvironment& env_ = MediumEnvironment::Instance(); }; @@ -823,7 +872,7 @@ TEST_F(BasePcpHandlerTest, WifiMediumFailFallBackToBT) { auto mediums = pcp_handler.GetDiscoveryMediums(&client); auto connect_medium = mediums[mediums.size() - 1]; - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium); + auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; auto& channel_b = channel_pair.second; EXPECT_CALL(*channel_a, CloseImpl).Times(1); @@ -849,7 +898,7 @@ TEST_P(BasePcpHandlerTest, RequestConnectionChangesState) { StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(&client); auto connect_medium = mediums[mediums.size() - 1]; - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium); + auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; auto& channel_b = channel_pair.second; EXPECT_CALL(*channel_a, CloseImpl).Times(1); @@ -894,7 +943,7 @@ TEST_P(BasePcpHandlerTest, CanRequestConnectionPresence) { StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(&client); auto connect_medium = mediums[mediums.size() - 1]; - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium); + auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; auto& channel_b = channel_pair.second; EXPECT_CALL(*channel_a, CloseImpl).Times(1); @@ -925,7 +974,7 @@ TEST_P(BasePcpHandlerTest, CanRequestConnectionLegacy) { StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(&client); auto connect_medium = mediums[mediums.size() - 1]; - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium); + auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; auto& channel_b = channel_pair.second; EXPECT_CALL(*channel_a, CloseImpl).Times(1); @@ -952,7 +1001,7 @@ TEST_P(BasePcpHandlerTest, IoError_RequestConnectionFails) { StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(&client); auto connect_medium = mediums[mediums.size() - 1]; - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium); + auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; auto& channel_b = channel_pair.second; EXPECT_CALL(*channel_a, CloseImpl).Times(AtLeast(1)); @@ -981,7 +1030,7 @@ TEST_P(BasePcpHandlerTest, AcceptConnectionChangesState) { StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(&client); auto connect_medium = mediums[mediums.size() - 1]; - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium); + auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; auto& channel_b = channel_pair.second; EXPECT_CALL(*channel_a, CloseImpl).Times(1); @@ -1012,7 +1061,7 @@ TEST_P(BasePcpHandlerTest, RejectConnectionChangesState) { StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(&client); auto connect_medium = mediums[mediums.size() - 1]; - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium); + auto channel_pair = SetupConnection(connect_medium); auto& channel_b = channel_pair.second; EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(1); RequestConnection(endpoint_id, std::move(channel_pair.first), channel_b.get(), @@ -1040,7 +1089,7 @@ TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) { StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(&client); auto connect_medium = mediums[mediums.size() - 1]; - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium); + auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; auto& channel_b = channel_pair.second; EXPECT_CALL(*channel_a, CloseImpl).Times(1); @@ -1082,7 +1131,7 @@ TEST_P(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) { StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(&client); auto connect_medium = mediums[mediums.size() - 1]; - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium); + auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; auto& channel_b = channel_pair.second; EXPECT_CALL(*channel_a, CloseImpl).Times(1); @@ -1125,7 +1174,7 @@ TEST_P(BasePcpHandlerTest, MultipleMediumsProduceSingleEndpointLostEvent) { StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(&client); auto connect_medium = mediums[mediums.size() - 1]; - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium); + auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; auto& channel_b = channel_pair.second; EXPECT_CALL(*channel_a, CloseImpl).Times(1); @@ -1247,9 +1296,9 @@ TEST_F(BasePcpHandlerTest, TestStartStopEndpointLostAlarm) { .status = {Status::kSuccess}, .mediums = allowed.GetMediums(true), })); - EXPECT_EQ(pcp_handler.StartDiscovery(&client, service_id, discovery_options, - {}), - Status{Status::kSuccess}); + EXPECT_EQ( + pcp_handler.StartDiscovery(&client, service_id, discovery_options, {}), + Status{Status::kSuccess}); EXPECT_TRUE(client.IsDiscovering()); EXPECT_CALL(pcp_handler, InjectEndpointImpl) @@ -1277,11 +1326,11 @@ TEST_F(BasePcpHandlerTest, TestStartStopEndpointLostAlarm) { .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), }); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 1); - EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0); + EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); pcp_handler.StartEndpointLostByMediumAlarms(&client, Medium::BLUETOOTH); - EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 1); + EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 1); pcp_handler.StopEndpointLostByMediumAlarm(endpoint_id, Medium::BLUETOOTH); - EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0); + EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); env_.Stop(); } @@ -1311,9 +1360,9 @@ TEST_F(BasePcpHandlerTest, TestStartEndpointLostByMediumAlarms) { .status = {Status::kSuccess}, .mediums = allowed.GetMediums(true), })); - EXPECT_EQ(pcp_handler.StartDiscovery(&client, service_id, discovery_options, - {}), - Status{Status::kSuccess}); + EXPECT_EQ( + pcp_handler.StartDiscovery(&client, service_id, discovery_options, {}), + Status{Status::kSuccess}); EXPECT_TRUE(client.IsDiscovering()); EXPECT_CALL(pcp_handler, InjectEndpointImpl) @@ -1341,12 +1390,12 @@ TEST_F(BasePcpHandlerTest, TestStartEndpointLostByMediumAlarms) { .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), }); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 1); - EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0); + EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); pcp_handler.StartEndpointLostByMediumAlarms(&client, Medium::BLUETOOTH); - EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 1); + EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 1); absl::SleepFor(absl::Seconds(11)); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 0); - EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0); + EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); env_.Stop(); } @@ -1376,37 +1425,39 @@ TEST_F(BasePcpHandlerTest, TestEndpointFoundStopsAlarm) { .status = {Status::kSuccess}, .mediums = allowed.GetMediums(true), })); - EXPECT_EQ(pcp_handler.StartDiscovery(&client, service_id, discovery_options, - {}), - Status{Status::kSuccess}); + EXPECT_EQ( + pcp_handler.StartDiscovery(&client, service_id, discovery_options, {}), + Status{Status::kSuccess}); EXPECT_TRUE(client.IsDiscovering()); bool first_call = true; - EXPECT_CALL(pcp_handler, InjectEndpointImpl).Times(2) - .WillRepeatedly(Invoke([&pcp_handler, &endpoint_id, &first_call]( - ClientProxy* client, const std::string& service_id, - const OutOfBandConnectionMetadata& metadata) { - ByteArray endpoint_info; - if (first_call) { - endpoint_info = ByteArray("ABCD"); - } else { - endpoint_info = ByteArray("ABCDE"); - } - first_call = false; - pcp_handler.OnEndpointFound( - client, - std::make_shared(MockDiscoveredEndpoint{ - { - endpoint_id, - endpoint_info, - service_id, - Medium::BLUETOOTH, - WebRtcState::kUndefined, - }, - MockContext{nullptr}, - })); - return Status{Status::kSuccess}; - })); + EXPECT_CALL(pcp_handler, InjectEndpointImpl) + .Times(2) + .WillRepeatedly( + Invoke([&pcp_handler, &endpoint_id, &first_call]( + ClientProxy* client, const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) { + ByteArray endpoint_info; + if (first_call) { + endpoint_info = ByteArray("ABCD"); + } else { + endpoint_info = ByteArray("ABCDE"); + } + first_call = false; + pcp_handler.OnEndpointFound( + client, + std::make_shared(MockDiscoveredEndpoint{ + { + endpoint_id, + endpoint_info, + service_id, + Medium::BLUETOOTH, + WebRtcState::kUndefined, + }, + MockContext{nullptr}, + })); + return Status{Status::kSuccess}; + })); pcp_handler.InjectEndpoint( &client, service_id, OutOfBandConnectionMetadata{ @@ -1414,16 +1465,16 @@ TEST_F(BasePcpHandlerTest, TestEndpointFoundStopsAlarm) { .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), }); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 1); - EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0); + EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); pcp_handler.StartEndpointLostByMediumAlarms(&client, Medium::BLUETOOTH); - EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 1); + EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 1); pcp_handler.InjectEndpoint( &client, service_id, OutOfBandConnectionMetadata{ .medium = Medium::BLUETOOTH, .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), }); - EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0); + EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); env_.Stop(); } @@ -1564,7 +1615,7 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithUnknown) { .first.Ok()); ASSERT_TRUE(client.IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(&client)); - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, Medium::BLUETOOTH); + auto channel_pair = SetupConnection(Medium::BLUETOOTH); ByteArray serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", @@ -1613,7 +1664,7 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithUnknown) { .first.Ok()); ASSERT_TRUE(client.IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(&client)); - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, Medium::BLUETOOTH); + auto channel_pair = SetupConnection(Medium::BLUETOOTH); ByteArray serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", @@ -1663,7 +1714,7 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithConnections) { .first.Ok()); ASSERT_TRUE(client.IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(&client)); - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, Medium::BLUETOOTH); + auto channel_pair = SetupConnection(Medium::BLUETOOTH); ByteArray serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", @@ -1714,7 +1765,7 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithPresence) { .first.Ok()); ASSERT_TRUE(client.IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(&client)); - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, Medium::BLUETOOTH); + auto channel_pair = SetupConnection(Medium::BLUETOOTH); ByteArray serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", @@ -1764,7 +1815,7 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithConnections) { .first.Ok()); ASSERT_TRUE(client.IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(&client)); - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, Medium::BLUETOOTH); + auto channel_pair = SetupConnection(Medium::BLUETOOTH); ByteArray serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", @@ -1814,7 +1865,7 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithPresence) { .first.Ok()); ASSERT_TRUE(client.IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(&client)); - auto channel_pair = SetupConnection(pipe_a_, pipe_b_, Medium::BLUETOOTH); + auto channel_pair = SetupConnection(Medium::BLUETOOTH); ByteArray serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", diff --git a/connections/implementation/bluetooth_bwu_handler.cc b/connections/implementation/bluetooth_bwu_handler.cc index 894740d0..21328239 100644 --- a/connections/implementation/bluetooth_bwu_handler.cc +++ b/connections/implementation/bluetooth_bwu_handler.cc @@ -28,9 +28,10 @@ namespace nearby { namespace connections { -BluetoothBwuHandler::BluetoothBwuHandler(Mediums& mediums, - BwuNotifications notifications) - : BaseBwuHandler(std::move(notifications)), mediums_(mediums) {} +BluetoothBwuHandler::BluetoothBwuHandler( + Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) + : BaseBwuHandler(std::move(incoming_connection_callback)), + mediums_(mediums) {} // Called by BWU target. Retrieves a new medium info from incoming message, // and establishes connection over BT using this info. @@ -110,11 +111,9 @@ ByteArray BluetoothBwuHandler::HandleInitializeUpgradedMediumForEndpoint( if (!bluetooth_medium_.IsAcceptingConnections(upgrade_service_id)) { if (!bluetooth_medium_.StartAcceptingConnections( upgrade_service_id, - { - .accepted_cb = absl::bind_front( - &BluetoothBwuHandler::OnIncomingBluetoothConnection, this, - client), - })) { + absl::bind_front( + &BluetoothBwuHandler::OnIncomingBluetoothConnection, this, + client))) { NEARBY_LOGS(ERROR) << "BluetoothBwuHandler couldn't initiate the " "BLUETOOTH upgrade for endpoint " << endpoint_id @@ -153,7 +152,7 @@ void BluetoothBwuHandler::OnIncomingBluetoothConnection( upgrade_service_id, socket), .channel = std::move(channel), }}; - bwu_notifications_.incoming_connection_cb(client, std::move(connection)); + NotifyOnIncomingConnection(client, std::move(connection)); } } // namespace connections diff --git a/connections/implementation/bluetooth_bwu_handler.h b/connections/implementation/bluetooth_bwu_handler.h index 2fa4d09b..6563eebf 100644 --- a/connections/implementation/bluetooth_bwu_handler.h +++ b/connections/implementation/bluetooth_bwu_handler.h @@ -31,8 +31,9 @@ namespace connections { // per-Medium-specific operations needed to upgrade an EndpointChannel. class BluetoothBwuHandler : public BaseBwuHandler { public: - explicit BluetoothBwuHandler(Mediums& mediums, - BwuNotifications notifications); + explicit BluetoothBwuHandler( + Mediums& mediums, + IncomingConnectionCallback incoming_connection_callback); private: class BluetoothIncomingSocket : public IncomingSocket { diff --git a/connections/implementation/bwu_handler.h b/connections/implementation/bwu_handler.h index d8ab4750..de1ee7e0 100644 --- a/connections/implementation/bwu_handler.h +++ b/connections/implementation/bwu_handler.h @@ -18,6 +18,7 @@ #include #include +#include "absl/functional/any_invocable.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/offline_frames.h" @@ -47,12 +48,9 @@ class BwuHandler { std::unique_ptr socket; std::unique_ptr channel; }; - - struct BwuNotifications { - std::function connection)> - incoming_connection_cb; - }; + using IncomingConnectionCallback = absl::AnyInvocable connection)>; virtual ~BwuHandler() = default; diff --git a/connections/implementation/bwu_manager.cc b/connections/implementation/bwu_manager.cc index 0729c118..78ab4992 100644 --- a/connections/implementation/bwu_manager.cc +++ b/connections/implementation/bwu_manager.cc @@ -24,6 +24,8 @@ #include "absl/time/time.h" #include "connections/implementation/bluetooth_bwu_handler.h" #include "connections/implementation/bwu_handler.h" +#include "connections/implementation/client_proxy.h" +#include "connections/implementation/endpoint_channel_manager.h" #include "connections/implementation/offline_frames.h" #include "connections/implementation/service_id_constants.h" #ifdef NO_WEBRTC @@ -103,31 +105,40 @@ BwuManager::~BwuManager() { void BwuManager::InitBwuHandlers() { // Register the supported concrete BwuMedium implementations. - BwuHandler::BwuNotifications notifications{ - .incoming_connection_cb = - absl::bind_front(&BwuManager::OnIncomingConnection, this), - }; if (config_.allow_upgrade_to.wifi_hotspot) { handlers_.emplace( Medium::WIFI_HOTSPOT, - std::make_unique(*mediums_, notifications)); + std::make_unique( + *mediums_, + absl::bind_front(&BwuManager::OnIncomingConnection, this))); } if (config_.allow_upgrade_to.wifi_direct) { handlers_.emplace( Medium::WIFI_DIRECT, - std::make_unique(*mediums_, notifications)); + std::make_unique( + *mediums_, + absl::bind_front(&BwuManager::OnIncomingConnection, this))); } if (config_.allow_upgrade_to.wifi_lan) { - handlers_.emplace(Medium::WIFI_LAN, std::make_unique( - *mediums_, notifications)); + handlers_.emplace( + Medium::WIFI_LAN, + std::make_unique( + *mediums_, + absl::bind_front(&BwuManager::OnIncomingConnection, this))); } if (config_.allow_upgrade_to.web_rtc) { - handlers_.emplace(Medium::WEB_RTC, std::make_unique( - *mediums_, notifications)); + handlers_.emplace( + Medium::WEB_RTC, + std::make_unique( + *mediums_, + absl::bind_front(&BwuManager::OnIncomingConnection, this))); } if (config_.allow_upgrade_to.bluetooth) { - handlers_.emplace(Medium::BLUETOOTH, std::make_unique( - *mediums_, notifications)); + handlers_.emplace( + Medium::BLUETOOTH, + std::make_unique( + *mediums_, + absl::bind_front(&BwuManager::OnIncomingConnection, this))); } } @@ -334,7 +345,8 @@ void BwuManager::OnIncomingFrame(OfflineFrame& frame, void BwuManager::OnEndpointDisconnect(ClientProxy* client, const std::string& service_id, const std::string& endpoint_id, - CountDownLatch barrier) { + CountDownLatch barrier, + DisconnectionReason reason) { NEARBY_LOGS(INFO) << "BwuManager has processed endpoint disconnection for endpoint " << endpoint_id; @@ -700,8 +712,8 @@ void BwuManager::ProcessBwuPathAvailableEvent( return; } - Medium current_medium = GetBwuMediumForEndpoint(endpoint_id); - if (current_medium == Medium::UNKNOWN_MEDIUM) { + Medium current_bwu_medium = GetBwuMediumForEndpoint(endpoint_id); + if (current_bwu_medium == Medium::UNKNOWN_MEDIUM) { SetBwuMediumForEndpoint(endpoint_id, upgrade_medium); } // Check for the correct medium so we don't process an incorrect OfflineFrame. @@ -711,6 +723,9 @@ void BwuManager::ProcessBwuPathAvailableEvent( return; } + auto current_channel = channel_manager_->GetChannelForEndpoint(endpoint_id); + Medium current_medium = + current_channel ? current_channel->GetMedium() : Medium::UNKNOWN_MEDIUM; client->GetAnalyticsRecorder().OnBandwidthUpgradeStarted( endpoint_id, current_medium, upgrade_medium, location::nearby::proto::connections::OUTGOING, @@ -1100,7 +1115,11 @@ void BwuManager::ProcessSafeToClosePriorChannelEvent( // circumstances so it is necessary to send it unencrypted. This way the // serial crypto context does not increment here. previous_endpoint_channel->DisableEncryption(); - previous_endpoint_channel->Write(parser::ForDisconnection()); + NEARBY_LOGS(INFO) << "[safe-to-disconnect] Sending " + "DISCONNECTION frame with request 0, ack 0"; + previous_endpoint_channel->Write( + parser::ForDisconnection(/* request_safe_to_disconnect */ false, + /* ack_safe_to_disconnect */ false)); // Attempt to read the disconnect message from the previous channel. We don't // care whether we successfully read it or whether we get an exception here. diff --git a/connections/implementation/bwu_manager.h b/connections/implementation/bwu_manager.h index 354564e6..c13d3208 100644 --- a/connections/implementation/bwu_manager.h +++ b/connections/implementation/bwu_manager.h @@ -94,7 +94,8 @@ class BwuManager : public EndpointManager::FrameProcessor { void OnEndpointDisconnect(ClientProxy* client_proxy, const std::string& service_id, const std::string& endpoint_id, - CountDownLatch barrier) override; + CountDownLatch barrier, + DisconnectionReason reason) override; void Shutdown(); diff --git a/connections/implementation/bwu_manager_test.cc b/connections/implementation/bwu_manager_test.cc index 037dccdd..5a5e2659 100644 --- a/connections/implementation/bwu_manager_test.cc +++ b/connections/implementation/bwu_manager_test.cc @@ -30,15 +30,19 @@ #include "connections/implementation/offline_frames.h" #include "connections/implementation/service_id_constants.h" #include "internal/platform/exception.h" +#include "internal/proto/analytics/connections_log.pb.h" +#include "proto/connections_enums.pb.h" namespace nearby { namespace connections { namespace { +using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; using ::location::nearby::connections:: BandwidthUpgradeNegotiationFrame_UpgradePathInfo; using ::location::nearby::connections::OfflineFrame; using ::location::nearby::connections::V1Frame; +using ::location::nearby::proto::connections::DisconnectionReason; constexpr absl::string_view kServiceIdA = "ServiceA"; constexpr absl::string_view kServiceIdB = "ServiceB"; @@ -95,6 +99,11 @@ class BwuManagerTest : public ::testing::Test { std::move(channel)); return channel_raw; } + void UnRegisterChannelForEndpoint(absl::string_view endpoint_id) { + ecm_.UnregisterChannelForEndpoint( + std::string(endpoint_id), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + } // Upgrade from |initial_medium| to |upgrade_medium|, close down the BLUETOOTH // channel, return the upgraded endpoint channel. This logic is tested in @@ -175,6 +184,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1), Medium::WIFI_LAN); EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); + ecm.UnregisterChannelForEndpoint( + std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); auto channel2 = std::make_unique( Medium::BLUETOOTH, std::string(kServiceIdA)); @@ -183,6 +195,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId2), Medium::WIFI_HOTSPOT); EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId2))); + ecm.UnregisterChannelForEndpoint( + std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); auto channel3 = std::make_unique( Medium::BLUETOOTH, std::string(kServiceIdA)); @@ -191,6 +206,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId3), Medium::WIFI_DIRECT); EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId3))); + ecm.UnregisterChannelForEndpoint( + std::string(kEndpointId3), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); auto channel4 = std::make_unique( Medium::WEB_RTC, std::string(kServiceIdA)); @@ -199,6 +217,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId4), Medium::BLUETOOTH); EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId4))); + ecm.UnregisterChannelForEndpoint( + std::string(kEndpointId4), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); bwu_manager->Shutdown(); } @@ -272,6 +293,7 @@ TEST_P(BwuManagerTestParam, InitiateBwu_Success) { EXPECT_TRUE(old_channel->is_closed()); EXPECT_EQ(location::nearby::proto::connections::DisconnectionReason::UPGRADED, old_channel->disconnection_reason()); + UnRegisterChannelForEndpoint(kEndpointId1); } TEST_P(BwuManagerTestParam, @@ -285,6 +307,7 @@ TEST_P(BwuManagerTestParam, bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), Medium::WEB_RTC); EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); + UnRegisterChannelForEndpoint(kEndpointId1); } TEST_P(BwuManagerTestParam, @@ -296,6 +319,7 @@ TEST_P(BwuManagerTestParam, Medium::WIFI_HOTSPOT); EXPECT_TRUE( fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty()); + UnRegisterChannelForEndpoint(kEndpointId1); } TEST_P(BwuManagerTestParam, InitiateBwu_Error_NoInitialMedium) { @@ -327,6 +351,7 @@ TEST_P(BwuManagerTestParam, InitiateBwu_Error_UpgradeAlreadyInProgress) { EXPECT_TRUE( fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty()); EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty()); + UnRegisterChannelForEndpoint(kEndpointId1); } TEST_P(BwuManagerTestParam, @@ -358,6 +383,7 @@ TEST_P(BwuManagerTestParam, ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get()); EXPECT_EQ(initial_channel, ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get()); + UnRegisterChannelForEndpoint(kEndpointId1); } TEST_F(BwuManagerTest, @@ -380,9 +406,12 @@ TEST_F(BwuManagerTest, // Disconnect the first WebRTC endpoint. We don't expect a revert until the // last WebRTC endpoint for the service is disconnected. CountDownLatch latch(1); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId1)); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id, - std::string(kEndpointId1), latch); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id, std::string(kEndpointId1), latch, + DisconnectionReason::LOCAL_DISCONNECTION); ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->disconnect_calls().size()); EXPECT_EQ(kEndpointId1, fake_web_rtc_bwu_handler_->disconnect_calls()[0].endpoint_id); @@ -391,9 +420,12 @@ TEST_F(BwuManagerTest, { // Disconnect the second WebRTC endpoint. We expect a revert. CountDownLatch latch(1); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId2)); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id, - std::string(kEndpointId2), latch); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id, std::string(kEndpointId2), latch, + DisconnectionReason::LOCAL_DISCONNECTION); ASSERT_EQ(2u, fake_web_rtc_bwu_handler_->disconnect_calls().size()); EXPECT_EQ(kEndpointId2, fake_web_rtc_bwu_handler_->disconnect_calls()[1].endpoint_id); @@ -423,9 +455,12 @@ TEST_F(BwuManagerTest, { // Disconnect the first WebRTC endpoint. CountDownLatch latch(1); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId1)); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id, - std::string(kEndpointId1), latch); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id, std::string(kEndpointId1), latch, + DisconnectionReason::LOCAL_DISCONNECTION); ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->disconnect_calls().size()); EXPECT_EQ(kEndpointId1, fake_web_rtc_bwu_handler_->disconnect_calls()[0].endpoint_id); @@ -440,9 +475,12 @@ TEST_F(BwuManagerTest, { // Disconnect the second WebRTC endpoint. CountDownLatch latch(1); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId2)); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id, - std::string(kEndpointId2), latch); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id, std::string(kEndpointId2), latch, + DisconnectionReason::LOCAL_DISCONNECTION); // Note(nohle): There appears to be an off-by-one error in the // existing/flag-disabled code. Revert is called when there are "<= 1" @@ -474,10 +512,13 @@ TEST_F(BwuManagerTest, { CountDownLatch latch(1); EXPECT_EQ(2u, ecm_.GetConnectedEndpointsCount()); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId1)); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); EXPECT_EQ(1u, ecm_.GetConnectedEndpointsCount()); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id_A, - std::string(kEndpointId1), latch); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id_A, std::string(kEndpointId1), latch, + DisconnectionReason::LOCAL_DISCONNECTION); ASSERT_EQ(1u, fake_wifi_lan_bwu_handler_->disconnect_calls().size()); EXPECT_EQ(kEndpointId1, fake_wifi_lan_bwu_handler_->disconnect_calls()[0].endpoint_id); @@ -491,10 +532,13 @@ TEST_F(BwuManagerTest, } { CountDownLatch latch(1); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId2)); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); EXPECT_EQ(0u, ecm_.GetConnectedEndpointsCount()); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id_B, - std::string(kEndpointId2), latch); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id_B, std::string(kEndpointId2), latch, + DisconnectionReason::LOCAL_DISCONNECTION); ASSERT_EQ(2u, fake_wifi_lan_bwu_handler_->disconnect_calls().size()); EXPECT_EQ(kEndpointId2, fake_wifi_lan_bwu_handler_->disconnect_calls()[1].endpoint_id); @@ -523,10 +567,13 @@ TEST_F(BwuManagerTest, { CountDownLatch latch(1); EXPECT_EQ(2u, ecm_.GetConnectedEndpointsCount()); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId1)); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); EXPECT_EQ(1u, ecm_.GetConnectedEndpointsCount()); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id_A, - std::string(kEndpointId1), latch); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id_A, std::string(kEndpointId1), latch, + DisconnectionReason::LOCAL_DISCONNECTION); ASSERT_EQ(1u, fake_wifi_lan_bwu_handler_->disconnect_calls().size()); EXPECT_EQ(kEndpointId1, fake_wifi_lan_bwu_handler_->disconnect_calls()[0].endpoint_id); @@ -540,10 +587,13 @@ TEST_F(BwuManagerTest, } { CountDownLatch latch(1); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId2)); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); EXPECT_EQ(0u, ecm_.GetConnectedEndpointsCount()); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id_B, - std::string(kEndpointId2), latch); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id_B, std::string(kEndpointId2), latch, + DisconnectionReason::LOCAL_DISCONNECTION); // Note(nohle): There appears to be an off-by-one error in the // existing/flag-disabled code. Revert is called when there are "<= 1" // (instead of "== 0") connected endpoints. @@ -593,9 +643,12 @@ TEST_F( EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_revert_calls().empty()); { CountDownLatch latch(1); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId1)); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id_A, - std::string(kEndpointId1), latch); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id_A, std::string(kEndpointId1), latch, + DisconnectionReason::LOCAL_DISCONNECTION); // No more WebRTC channels for service A; expect revert call. ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->disconnect_calls().size()); @@ -615,9 +668,12 @@ TEST_F( } { CountDownLatch latch(1); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId2)); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id_A, - std::string(kEndpointId2), latch); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id_A, std::string(kEndpointId2), latch, + DisconnectionReason::LOCAL_DISCONNECTION); // We reverted a WLAN channel; no additional WebRTC calls expected. EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->disconnect_calls().size()); @@ -633,9 +689,12 @@ TEST_F( } { CountDownLatch latch(1); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId3)); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id_B, - std::string(kEndpointId3), latch); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId3), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id_B, std::string(kEndpointId3), latch, + DisconnectionReason::LOCAL_DISCONNECTION); // We reverted a WLAN channel; no additional WebRTC calls expected. EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->disconnect_calls().size()); @@ -651,9 +710,12 @@ TEST_F( } { CountDownLatch latch(1); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId4)); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id_B, - std::string(kEndpointId4), latch); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId4), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id_B, std::string(kEndpointId4), latch, + DisconnectionReason::LOCAL_DISCONNECTION); // We reverted a Hotspot channel; no additional WebRTC calls expected. EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->disconnect_calls().size()); @@ -671,9 +733,12 @@ TEST_F( } { CountDownLatch latch(1); - ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId5)); - bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id_B, - std::string(kEndpointId5), latch); + ecm_.UnregisterChannelForEndpoint( + std::string(kEndpointId5), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + bwu_manager_->OnEndpointDisconnect( + &client_, upgrade_service_id_B, std::string(kEndpointId5), latch, + DisconnectionReason::LOCAL_DISCONNECTION); // We reverted a WifiDirect channel; no additional WebRTC calls expected. EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->disconnect_calls().size()); @@ -722,6 +787,9 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnUpgradeFailure_FlagEnabled) { ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->handle_revert_calls().size()); EXPECT_EQ(WrapInitiatorUpgradeServiceId(kServiceIdB), fake_web_rtc_bwu_handler_->handle_revert_calls()[0].service_id); + UnRegisterChannelForEndpoint(kEndpointId1); + UnRegisterChannelForEndpoint(kEndpointId2); + UnRegisterChannelForEndpoint(kEndpointId3); } TEST_F(BwuManagerTest, InitiateBwu_Revert_OnUpgradeFailure_FlagDisabled) { @@ -756,6 +824,9 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnUpgradeFailure_FlagDisabled) { // endpoints for _any_ service. We don't have service-level bookkeeping; we // only know that there is some active WebRTC endpoint. EXPECT_TRUE(fake_web_rtc_bwu_handler_->handle_revert_calls().empty()); + UnRegisterChannelForEndpoint(kEndpointId1); + UnRegisterChannelForEndpoint(kEndpointId2); + UnRegisterChannelForEndpoint(kEndpointId3); } TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_WifiDirect) { @@ -779,7 +850,8 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_WifiDirect) { Medium::BLUETOOTH, packet_meta_data_); CountDownLatch latch(1); bwu_manager_->OnEndpointDisconnect(&client_, (std::string)kServiceIdA, - std::string(kEndpointId1), latch); + std::string(kEndpointId1), latch, + DisconnectionReason::LOCAL_DISCONNECTION); ASSERT_EQ(fake_wifi_direct_bwu_handler_->disconnect_calls().size(), 1u); EXPECT_EQ(kEndpointId1, @@ -787,6 +859,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_WifiDirect) { // This is called by the RESPONDER--call RevertInitiatorState only when // BWU Medium is Hotspot or WifiDirect. ASSERT_EQ(fake_wifi_direct_bwu_handler_->handle_revert_calls().size(), 1u); + UnRegisterChannelForEndpoint(kEndpointId1); } TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_Hotspot) { @@ -811,9 +884,11 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_Hotspot) { Medium::BLUETOOTH, packet_meta_data_); CountDownLatch latch(1); bwu_manager_->OnEndpointDisconnect(&client_, (std::string)kServiceIdA, - std::string(kEndpointId1), latch); + std::string(kEndpointId1), latch, + DisconnectionReason::LOCAL_DISCONNECTION); ASSERT_EQ(fake_wifi_hotspot_bwu_handler_->handle_revert_calls().size(), 1u); + UnRegisterChannelForEndpoint(kEndpointId1); } TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_Wlan) { @@ -837,9 +912,11 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_Wlan) { Medium::BLUETOOTH, packet_meta_data_); CountDownLatch latch(1); bwu_manager_->OnEndpointDisconnect(&client_, (std::string)kServiceIdA, - std::string(kEndpointId1), latch); + std::string(kEndpointId1), latch, + DisconnectionReason::LOCAL_DISCONNECTION); ASSERT_EQ(fake_wifi_lan_bwu_handler_->handle_revert_calls().size(), 0u); + UnRegisterChannelForEndpoint(kEndpointId1); } TEST_F(BwuManagerTest, OnReceiveBwuEvent) { diff --git a/connections/implementation/client_proxy.cc b/connections/implementation/client_proxy.cc index abef015c..06768e72 100644 --- a/connections/implementation/client_proxy.cc +++ b/connections/implementation/client_proxy.cc @@ -14,6 +14,7 @@ #include "connections/implementation/client_proxy.h" +#include #include #include #include @@ -26,12 +27,15 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" +#include "absl/functional/any_invocable.h" #include "absl/strings/escaping.h" -#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/v3/bandwidth_info.h" #include "connections/v3/connection_listening_options.h" #include "connections/v3/connections_device_provider.h" #include "internal/analytics/event_logger.h" +#include "internal/flags/nearby_flags.h" #include "internal/platform/error_code_recorder.h" #include "internal/platform/feature_flags.h" #include "internal/platform/implementation/platform.h" @@ -66,6 +70,12 @@ ClientProxy::ClientProxy(::nearby::analytics::EventLogger* event_logger) }); local_os_info_.set_type( OSNameToOsInfoType(api::ImplementationPlatform::GetCurrentOS())); + supports_safe_to_disconnect_ = NearbyFlags::GetInstance().GetBoolFlag( + config_package_nearby::nearby_connections_feature:: + kEnableSafeToDisconnect); + local_safe_to_disconnect_version_ = NearbyFlags::GetInstance().GetInt64Flag( + config_package_nearby::nearby_connections_feature:: + kSafeToDisconnectVersion); } ClientProxy::~ClientProxy() { Reset(); } @@ -318,8 +328,11 @@ void ClientProxy::OnEndpointFound( MutexLock lock(&mutex_); NEARBY_LOGS(INFO) << "ClientProxy [Endpoint Found]: [enter] id=" - << endpoint_id << "; service=" << service_id << "; info=" - << absl::BytesToHexString(endpoint_info.data()); + << endpoint_id << "; service=" << service_id + << "; info=" << absl::BytesToHexString(endpoint_info.data()) + << "; medium=" + << location::nearby::proto::connections::Medium_Name( + medium); if (!IsDiscoveringServiceId(service_id)) { NEARBY_LOGS(INFO) << "ClientProxy [Endpoint Found]: Ignoring event for id=" << endpoint_id @@ -366,6 +379,12 @@ void ClientProxy::OnEndpointLost(const std::string& service_id, discovery_info_.listener.endpoint_lost_cb(endpoint_id); } +void ClientProxy::OnRequestConnection( + const Strategy& strategy, const std::string& endpoint_id, + const ConnectionOptions& connection_options) { + analytics_recorder_->OnRequestConnection(strategy, endpoint_id); +} + void ClientProxy::OnConnectionInitiated( const std::string& endpoint_id, const ConnectionResponseInfo& info, const ConnectionOptions& connection_options, @@ -545,7 +564,7 @@ bool ClientProxy::IsConnectedToEndpoint(const std::string& endpoint_id) const { } std::vector ClientProxy::GetMatchingEndpoints( - std::function pred) const { + absl::AnyInvocable pred) const { MutexLock lock(&mutex_); std::vector connected_endpoints; @@ -779,9 +798,7 @@ void ClientProxy::CancelEndpoint(const std::string& endpoint_id) { } } -const OsInfo& ClientProxy::GetLocalOsInfo() const { - return local_os_info_; -} +const OsInfo& ClientProxy::GetLocalOsInfo() const { return local_os_info_; } std::optional ClientProxy::GetRemoteOsInfo( absl::string_view endpoint_id) const { @@ -799,6 +816,44 @@ void ClientProxy::SetRemoteOsInfo(absl::string_view endpoint_id, item->first.os_info.emplace(remote_os_info); } } + +std::optional ClientProxy::GetRemoteSafeToDisconnectVersion( + absl::string_view endpoint_id) const { + const ConnectionPair* item = LookupConnection(endpoint_id); + if (item != nullptr) { + return item->first.safe_to_disconnect_version; + } + return std::nullopt; +} + +void ClientProxy::SetRemoteSafeToDisconnectVersion( + absl::string_view endpoint_id, + const std::int32_t& safe_to_disconnect_version) { + ConnectionPair* item = LookupConnection(endpoint_id); + if (item != nullptr) { + item->first.safe_to_disconnect_version = safe_to_disconnect_version; + } +} + +bool ClientProxy::IsSafeToDisconnectEnabled(absl::string_view endpoint_id) { + return IsSupportSafeToDisconnect() && + GetRemoteSafeToDisconnectVersion(endpoint_id).has_value() && + (GetRemoteSafeToDisconnectVersion(endpoint_id) >= + FeatureFlags::GetInstance() + .GetFlags() + .min_nc_version_supports_safe_to_disconnect); +} + +bool ClientProxy::IsPayloadReceivedAckEnabled(absl::string_view endpoint_id) { + return IsSupportSafeToDisconnect() && + GetRemoteSafeToDisconnectVersion(endpoint_id).has_value() && + (GetRemoteSafeToDisconnectVersion(endpoint_id) >= + FeatureFlags::GetInstance() + .GetFlags() + .min_nc_version_supports_payload_received_ack); +} + + void ClientProxy::CancelAllEndpoints() { for (const auto& item : cancellation_flags_) { CancellationFlag* cancellation_flag = item.second.get(); diff --git a/connections/implementation/client_proxy.h b/connections/implementation/client_proxy.h index 90032f24..e39ae058 100644 --- a/connections/implementation/client_proxy.h +++ b/connections/implementation/client_proxy.h @@ -16,13 +16,13 @@ #define CORE_INTERNAL_CLIENT_PROXY_H_ #include -#include #include #include #include #include #include +#include "absl/functional/any_invocable.h" #include "connections/advertising_options.h" #include "connections/discovery_options.h" #include "connections/implementation/analytics/analytics_recorder.h" @@ -143,11 +143,17 @@ class ClientProxy final { void OnEndpointLost(const std::string& service_id, const std::string& endpoint_id); + // Triggered when client request connection to remote device. + void OnRequestConnection(const Strategy& strategy, + const std::string& endpoint_id, + const ConnectionOptions& connection_options); + // Proxies to the client's ConnectionListener::OnInitiated() callback. - void OnConnectionInitiated( - const std::string& endpoint_id, const ConnectionResponseInfo& info, - const ConnectionOptions& connection_options, - const ConnectionListener& listener, const std::string& connection_token); + void OnConnectionInitiated(const std::string& endpoint_id, + const ConnectionResponseInfo& info, + const ConnectionOptions& connection_options, + const ConnectionListener& listener, + const std::string& connection_token); // Proxies to the client's ConnectionListener::OnAccepted() callback. void OnConnectionAccepted(const std::string& endpoint_id); @@ -261,6 +267,20 @@ class ClientProxy final { connections_device_provider_ = std::move(provider); } + const bool& IsSupportSafeToDisconnect() const { + return supports_safe_to_disconnect_; + } + const std::int32_t& GetLocalSafeToDisconnectVersion() const { + return local_safe_to_disconnect_version_; + } + std::optional GetRemoteSafeToDisconnectVersion( + absl::string_view endpoint_id) const; + void SetRemoteSafeToDisconnectVersion( + absl::string_view endpoint_id, + const std::int32_t& safe_to_disconnect_version); + bool IsSafeToDisconnectEnabled(absl::string_view endpoint_id); + bool IsPayloadReceivedAckEnabled(absl::string_view endpoint_id); + private: struct Connection { // Status: may be either: @@ -290,6 +310,7 @@ class ClientProxy final { AdvertisingOptions advertising_options; std::string connection_token; std::optional os_info; + std::int32_t safe_to_disconnect_version; }; using ConnectionPair = std::pair; @@ -332,7 +353,7 @@ class ClientProxy final { bool ConnectionStatusMatches(const std::string& endpoint_id, Connection::Status status) const; std::vector GetMatchingEndpoints( - std::function pred) const; + absl::AnyInvocable pred) const; std::string GenerateLocalEndpointId(); void ScheduleClearLocalHighVisModeCacheEndpointIdAlarm(); @@ -421,6 +442,8 @@ class ClientProxy final { NearbyDeviceProvider* external_device_provider_ = nullptr; // For Nearby Connections' own device provider. std::unique_ptr connections_device_provider_; + bool supports_safe_to_disconnect_; + std::int32_t local_safe_to_disconnect_version_; }; } // namespace connections diff --git a/connections/implementation/client_proxy_test.cc b/connections/implementation/client_proxy_test.cc index 011cb8ec..3d53bc87 100644 --- a/connections/implementation/client_proxy_test.cc +++ b/connections/implementation/client_proxy_test.cc @@ -14,6 +14,7 @@ #include "connections/implementation/client_proxy.h" +#include #include #include #include @@ -40,7 +41,7 @@ #include "internal/platform/count_down_latch.h" #include "internal/platform/feature_flags.h" #include "internal/platform/medium_environment.h" -#include "proto/connections_enums.proto.h" +#include "proto/connections_enums.pb.h" namespace nearby { namespace connections { @@ -1023,6 +1024,9 @@ TEST_F(ClientProxyTest, GetRemoteInfoNullWithoutConnections) { StartAdvertising(&client1_, advertising_connection_listener_); EXPECT_FALSE(client1_.GetRemoteOsInfo(advertising_endpoint.id).has_value()); + EXPECT_FALSE( + client1_.GetRemoteSafeToDisconnectVersion(advertising_endpoint.id) + .has_value()); } TEST_F(ClientProxyTest, SetRemoteInfoCorrect) { @@ -1032,11 +1036,16 @@ TEST_F(ClientProxyTest, SetRemoteInfoCorrect) { OsInfo os_info; os_info.set_type(OsInfo::ANDROID); + std::int32_t nearby_connections_version = 2; client1_.SetRemoteOsInfo(advertising_endpoint.id, os_info); + client1_.SetRemoteSafeToDisconnectVersion(advertising_endpoint.id, + nearby_connections_version); ASSERT_TRUE(client1_.GetRemoteOsInfo(advertising_endpoint.id).has_value()); EXPECT_EQ(client1_.GetRemoteOsInfo(advertising_endpoint.id).value().type(), OsInfo::ANDROID); + EXPECT_EQ(client1_.GetRemoteSafeToDisconnectVersion(advertising_endpoint.id), + nearby_connections_version); } // Test ClientProxy::AddCancellationFlag, where if a flag is already in the map, diff --git a/connections/implementation/encryption_runner.cc b/connections/implementation/encryption_runner.cc index b424b5ab..43146980 100644 --- a/connections/implementation/encryption_runner.cc +++ b/connections/implementation/encryption_runner.cc @@ -17,15 +17,19 @@ #include #include #include +#include +#include #include "securegcm/ukey2_handshake.h" #include "absl/strings/ascii.h" #include "absl/time/clock.h" #include "absl/time/time.h" +#include "connections/implementation/client_proxy.h" +#include "connections/implementation/endpoint_channel.h" #include "internal/platform/base64_utils.h" #include "internal/platform/byte_array.h" -#include "internal/platform/exception.h" #include "internal/platform/cancelable_alarm.h" +#include "internal/platform/exception.h" #include "internal/platform/logging.h" namespace nearby { @@ -49,7 +53,7 @@ std::string ToHumanReadableString(const ByteArray& token) { bool HandleEncryptionSuccess(const std::string& endpoint_id, std::unique_ptr ukey2, - const EncryptionRunner::ResultListener& listener) { + EncryptionRunner::ResultListener& listener) { std::unique_ptr verification_string = ukey2->GetVerificationString(kMaxUkey2VerificationStringLength); if (verification_string == nullptr) { @@ -58,9 +62,9 @@ bool HandleEncryptionSuccess(const std::string& endpoint_id, ByteArray raw_authentication_token(*verification_string); - listener.on_success_cb(endpoint_id, std::move(ukey2), - ToHumanReadableString(raw_authentication_token), - raw_authentication_token); + listener.CallSuccessCallback(endpoint_id, std::move(ukey2), + ToHumanReadableString(raw_authentication_token), + raw_authentication_token); return true; } @@ -79,14 +83,14 @@ class ServerRunnable final { public: ServerRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor, const std::string& endpoint_id, EndpointChannel* channel, - EncryptionRunner::ResultListener&& listener) + EncryptionRunner::ResultListener listener) : client_(client), alarm_executor_(alarm_executor), endpoint_id_(endpoint_id), channel_(channel), listener_(std::move(listener)) {} - void operator()() const { + void operator()() { CancelableAlarm timeout_alarm( "EncryptionRunner.StartServer() timeout", [this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); }, @@ -189,9 +193,9 @@ class ServerRunnable final { << endpoint_id_ << ")."; } - void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) const { + void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) { timeout_alarm->Cancel(); - listener_.on_failure_cb(endpoint_id_, channel_); + listener_.CallFailureCallback(endpoint_id_, channel_); } void HandleAlertException( @@ -217,14 +221,14 @@ class ClientRunnable final { public: ClientRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor, const std::string& endpoint_id, EndpointChannel* channel, - EncryptionRunner::ResultListener&& listener) + EncryptionRunner::ResultListener listener) : client_(client), alarm_executor_(alarm_executor), endpoint_id_(endpoint_id), channel_(channel), listener_(std::move(listener)) {} - void operator()() const { + void operator()() { CancelableAlarm timeout_alarm( "EncryptionRunner.StartClient() timeout", [this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); }, @@ -326,9 +330,9 @@ class ClientRunnable final { << endpoint_id_ << ")."; } - void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) const { + void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) { timeout_alarm->Cancel(); - listener_.on_failure_cb(endpoint_id_, channel_); + listener_.CallFailureCallback(endpoint_id_, channel_); } void HandleAlertException( @@ -359,28 +363,46 @@ EncryptionRunner::~EncryptionRunner() { alarm_executor_.Shutdown(); } -void EncryptionRunner::StartServer( - ClientProxy* client, const std::string& endpoint_id, - EndpointChannel* endpoint_channel, - EncryptionRunner::ResultListener&& listener) { - server_executor_.Execute( - "encryption-server", - [runnable{ServerRunnable(client, &alarm_executor_, endpoint_id, - endpoint_channel, std::move(listener))}]() { - runnable(); - }); +void EncryptionRunner::StartServer(ClientProxy* client, + const std::string& endpoint_id, + EndpointChannel* endpoint_channel, + EncryptionRunner::ResultListener listener) { + ServerRunnable runnable(client, &alarm_executor_, endpoint_id, + endpoint_channel, std::move(listener)); + server_executor_.Execute("encryption-server", std::move(runnable)); } -void EncryptionRunner::StartClient( - ClientProxy* client, const std::string& endpoint_id, - EndpointChannel* endpoint_channel, - EncryptionRunner::ResultListener&& listener) { - client_executor_.Execute( - "encryption-client", - [runnable{ClientRunnable(client, &alarm_executor_, endpoint_id, - endpoint_channel, std::move(listener))}]() { - runnable(); - }); +void EncryptionRunner::StartClient(ClientProxy* client, + const std::string& endpoint_id, + EndpointChannel* endpoint_channel, + EncryptionRunner::ResultListener listener) { + ClientRunnable runnable(client, &alarm_executor_, endpoint_id, + endpoint_channel, std::move(listener)); + client_executor_.Execute("encryption-client", std::move(runnable)); +} + +void EncryptionRunner::ResultListener::CallSuccessCallback( + const std::string& endpoint_id, + std::unique_ptr ukey2, + const std::string& auth_token, const ByteArray& raw_auth_token) { + if (on_success_cb) { + std::move(on_success_cb)(endpoint_id, std::move(ukey2), auth_token, + raw_auth_token); + } + Reset(); +} + +void EncryptionRunner::ResultListener::CallFailureCallback( + const std::string& endpoint_id, EndpointChannel* channel) { + if (on_failure_cb) { + std::move(on_failure_cb)(endpoint_id, channel); + } + Reset(); +} + +void EncryptionRunner::ResultListener::Reset() { + on_success_cb = nullptr; + on_failure_cb = nullptr; } } // namespace connections diff --git a/connections/implementation/encryption_runner.h b/connections/implementation/encryption_runner.h index a8bb367d..7c2b401f 100644 --- a/connections/implementation/encryption_runner.h +++ b/connections/implementation/encryption_runner.h @@ -18,6 +18,7 @@ #include #include "securegcm/ukey2_handshake.h" +#include "absl/functional/any_invocable.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "connections/listeners.h" @@ -39,14 +40,20 @@ class EncryptionRunner { ~EncryptionRunner(); struct ResultListener { + void CallSuccessCallback(const std::string& endpoint_id, + std::unique_ptr ukey2, + const std::string& auth_token, + const ByteArray& raw_auth_token); + void CallFailureCallback(const std::string& endpoint_id, + EndpointChannel* channel); + void Reset(); + // @EncryptionRunnerThread - std::function ukey2, - const std::string& auth_token, - const ByteArray& raw_auth_token)> - on_success_cb = [](const std::string&, - std::unique_ptr, - const std::string&, const ByteArray&) {}; + absl::AnyInvocable ukey2, + const std::string& auth_token, + const ByteArray& raw_auth_token) &&> + on_success_cb; // Encryption has failed. The remote_endpoint_id and channel are given so // that any pending state can be cleaned up. @@ -57,19 +64,19 @@ class EncryptionRunner { // channel to the same endpoint. // // @EncryptionRunnerThread - std::function - on_failure_cb = [](const std::string&, EndpointChannel*) {}; + absl::AnyInvocable + on_failure_cb; }; // @AnyThread void StartServer(ClientProxy* client, const std::string& endpoint_id, EndpointChannel* endpoint_channel, - ResultListener&& result_listener); + ResultListener result_listener); // @AnyThread void StartClient(ClientProxy* client, const std::string& endpoint_id, EndpointChannel* endpoint_channel, - ResultListener&& result_listener); + ResultListener result_listener); private: ScheduledExecutor alarm_executor_; diff --git a/connections/implementation/encryption_runner_test.cc b/connections/implementation/encryption_runner_test.cc index 0bc91960..4dbd624e 100644 --- a/connections/implementation/encryption_runner_test.cc +++ b/connections/implementation/encryption_runner_test.cc @@ -14,23 +14,30 @@ #include "connections/implementation/encryption_runner.h" -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" +#include +#include + #include "gtest/gtest.h" -#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" +#include "internal/platform/exception.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/output_stream.h" #include "internal/platform/pipe.h" #include "internal/platform/system_clock.h" #include "proto/connections_enums.pb.h" +#include "third_party/ukey2/src/main/cpp/include/securegcm/ukey2_handshake.h" namespace nearby { namespace connections { namespace { using ::location::nearby::proto::connections::Medium; +constexpr size_t kChunkSize = 64 * 1024; class FakeEndpointChannel : public EndpointChannel { public: @@ -38,13 +45,11 @@ class FakeEndpointChannel : public EndpointChannel { : in_(in), out_(out) {} ExceptionOr Read() override { read_timestamp_ = SystemClock::ElapsedRealtime(); - return in_ ? in_->Read(Pipe::kChunkSize) - : ExceptionOr{Exception::kIo}; + return in_ ? in_->Read(kChunkSize) : ExceptionOr{Exception::kIo}; } ExceptionOr Read(PacketMetaData& packet_meta_data) override { read_timestamp_ = SystemClock::ElapsedRealtime(); - return in_ ? in_->Read(Pipe::kChunkSize) - : ExceptionOr{Exception::kIo}; + return in_ ? in_->Read(kChunkSize) : ExceptionOr{Exception::kIo}; } Exception Write(const ByteArray& data) override { write_timestamp_ = SystemClock::ElapsedRealtime(); @@ -103,8 +108,7 @@ class FakeEndpointChannel : public EndpointChannel { }; struct User { - User(Pipe* reader, Pipe* writer) - : channel(&reader->GetInputStream(), &writer->GetOutputStream()) {} + User(InputStream* reader, OutputStream* writer) : channel(reader, writer) {} FakeEndpointChannel channel; EncryptionRunner crypto; @@ -126,10 +130,12 @@ struct Response { TEST(EncryptionRunnerTest, ConstructorDestructorWorks) { EncryptionRunner enc; } TEST(EncryptionRunnerTest, ReadWrite) { - Pipe from_a_to_b; - Pipe from_b_to_a; - User user_a(/*reader=*/&from_b_to_a, /*writer=*/&from_a_to_b); - User user_b(/*reader=*/&from_a_to_b, /*writer=*/&from_b_to_a); + auto from_a_to_b = CreatePipe(); + auto from_b_to_a = CreatePipe(); + User user_a(/*reader=*/from_b_to_a.first.get(), + /*writer=*/from_a_to_b.second.get()); + User user_b(/*reader=*/from_a_to_b.first.get(), + /*writer=*/from_b_to_a.second.get()); Response response; user_a.crypto.StartServer( diff --git a/connections/implementation/endpoint_channel_manager.cc b/connections/implementation/endpoint_channel_manager.cc index f8c66e21..cc3b5282 100644 --- a/connections/implementation/endpoint_channel_manager.cc +++ b/connections/implementation/endpoint_channel_manager.cc @@ -20,12 +20,16 @@ #include "absl/time/time.h" #include "connections/implementation/offline_frames.h" +#include "internal/platform/condition_variable.h" +#include "internal/platform/feature_flags.h" #include "internal/platform/logging.h" #include "internal/platform/mutex.h" #include "internal/platform/mutex_lock.h" +#include "proto/connections_enums.pb.h" namespace nearby { namespace connections { +using ::location::nearby::analytics::proto::ConnectionsLog; namespace { const absl::Duration kDataTransferDelay = absl::Milliseconds(500); @@ -97,7 +101,8 @@ void EndpointChannelManager::SetActiveEndpointChannel( // crypto context is present. channel->SetAnalyticsRecorder(&client->GetAnalyticsRecorder(), endpoint_id); channel_state_.UpdateChannelForEndpoint(endpoint_id, std::move(channel)); - + channel_state_.UpdateSafeToDisconnectForEndpoint( + endpoint_id, client->IsSafeToDisconnectEnabled(endpoint_id)); auto* endpoint = channel_state_.LookupEndpointData(endpoint_id); if (endpoint->IsEncrypted() && enable_encryption) channel_state_.EncryptChannel(endpoint); @@ -113,6 +118,37 @@ bool EndpointChannelManager::isWifiLanConnected() const { return channel_state_.isWifiLanConnected(); } +void EndpointChannelManager::UpdateSafeToDisconnectForEndpoint( + const std::string& endpoint_id, + bool safe_to_disconnect_enabled) { + MutexLock lock(&mutex_); + channel_state_.UpdateSafeToDisconnectForEndpoint(endpoint_id, + safe_to_disconnect_enabled); +} + +void EndpointChannelManager::MarkEndpointStopWaitToDisconnect( + const std::string& endpoint_id, bool is_safe_to_disconnect, + bool notify_stop_waiting) { + MutexLock lock(&mutex_); + channel_state_.MarkEndpointStopWaitToDisconnect( + endpoint_id, is_safe_to_disconnect, notify_stop_waiting); +} + +bool EndpointChannelManager::CreateNewTimeoutDisconnectedState( + const std::string& endpoint_id) { + return channel_state_.CreateNewTimeoutDisconnectedState(endpoint_id); +} + +bool EndpointChannelManager::IsSafeToDisconnect( + const std::string& endpoint_id) { + return channel_state_.IsSafeToDisconnect(endpoint_id); +} +void EndpointChannelManager::RemoveTimeoutDisconnectedState( + const std::string& endpoint_id) { + MutexLock lock(&mutex_); + channel_state_.RemoveTimeoutDisconnectedState(endpoint_id); +} + ///////////////////////////////// ChannelState ///////////////////////////////// // endpoint - channel endpoint to encrypt @@ -133,6 +169,15 @@ EndpointChannelManager::ChannelState::LookupEndpointData( return item != endpoints_.end() ? &item->second : nullptr; } +void EndpointChannelManager::ChannelState::DestroyAll() { + for (auto& item : endpoints_) { + RemoveEndpoint(item.first, DisconnectionReason::SHUTDOWN, + /* safe_to_disconnect_enabled */ false, + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + } + endpoints_.clear(); +} + void EndpointChannelManager::ChannelState::UpdateChannelForEndpoint( const std::string& endpoint_id, std::unique_ptr channel) { // Create EndpointData instance, if necessary, and populate channel. @@ -146,24 +191,54 @@ void EndpointChannelManager::ChannelState::UpdateEncryptionContextForEndpoint( endpoints_[endpoint_id].context = std::move(context); } -bool EndpointChannelManager::ChannelState::RemoveEndpoint( +void EndpointChannelManager::ChannelState::UpdateSafeToDisconnectForEndpoint( const std::string& endpoint_id, - location::nearby::proto::connections::DisconnectionReason reason) { + bool safe_to_disconnect_enabled) { + NEARBY_LOGS(INFO) << "[safe-to-disconnect] " + "UpdateSafeToDisconnectForEndpoint for: " + << endpoint_id << " " << safe_to_disconnect_enabled; + + endpoints_[endpoint_id].safe_to_disconnect_enabled = + safe_to_disconnect_enabled; +} + +bool EndpointChannelManager::ChannelState::GetSafeToDisconnectForEndpoint( + const std::string& endpoint_id) { auto item = endpoints_.find(endpoint_id); if (item == endpoints_.end()) return false; + NEARBY_LOGS(INFO) << "[safe-to-disconnect] GetSafeToDisconnectForEndpoint: " + << item->second.safe_to_disconnect_enabled; + return item->second.safe_to_disconnect_enabled; +} + +bool EndpointChannelManager::ChannelState::RemoveEndpoint( + const std::string& endpoint_id, DisconnectionReason reason, + bool safe_to_disconnect_enabled, SafeDisconnectionResult result) { + auto item = endpoints_.find(endpoint_id); + if (item == endpoints_.end()) return false; + + MarkEndpointStopWaitToDisconnect(endpoint_id, + /* is_safe_to_disconnect */ true, + /* notify_stop_waiting */ true); item->second.disconnect_reason = reason; auto channel = item->second.channel; - if (channel) { + + if (channel && !safe_to_disconnect_enabled) { // If the channel was paused (i.e. during a bandwidth upgrade negotiation) // we resume to ensure the thread won't hang when trying to write to it. channel->Resume(); - channel->Write(parser::ForDisconnection()); + NEARBY_LOGS(INFO) << "[safe-to-disconnect] Sending DISCONNECTION frame" + " with request 0, ack 0"; + channel->Write( + parser::ForDisconnection(/* request_safe_to_disconnect */ false, + /* ack_safe_to_disconnect */ false)); NEARBY_LOGS(INFO) << "EndpointChannelManager reported the disconnection to endpoint " << endpoint_id; SystemClock::Sleep(kDataTransferDelay); } + NEARBY_LOGS(INFO) << "Remove Endpoint: " << endpoint_id; endpoints_.erase(item); return true; } @@ -183,20 +258,93 @@ bool EndpointChannelManager::ChannelState::isWifiLanConnected() const { return false; } -bool EndpointChannelManager::UnregisterChannelForEndpoint( +void EndpointChannelManager::ChannelState::MarkEndpointStopWaitToDisconnect( + const std::string& endpoint_id, bool is_safe_to_disconnect, + bool notify_stop_waiting) { + auto item = endpoints_.find(endpoint_id); + if (item == endpoints_.end()) return; + NEARBY_LOGS(INFO) << "[safe-to-disconnect] is_safe_to_disconnect= " + << is_safe_to_disconnect + << ", notify_stop_waiting= " << notify_stop_waiting + << " for endpoint: " << endpoint_id; + { + MutexLock lock(&item->second.timeout_to_disconnected_mutex); + item->second.is_safe_to_disconnect = is_safe_to_disconnect; + if (!item->second.timeout_to_disconnected_enabled) return; + if (notify_stop_waiting) { + NEARBY_LOGS(INFO) << "[safe-to-disconnect] Notify stop " + "waiting before timeout."; + item->second.timeout_to_disconnected.Notify(); + item->second.timeout_to_disconnected_notified = true; + } + } +} + +bool EndpointChannelManager::ChannelState::CreateNewTimeoutDisconnectedState( const std::string& endpoint_id) { + auto item = endpoints_.find(endpoint_id); + if (item == endpoints_.end()) return false; + NEARBY_LOGS(INFO) << "[safe-to-disconnect] " + "Create TimeoutDisconnectedState for endpoint: " + << endpoint_id; + { + MutexLock lock(&item->second.timeout_to_disconnected_mutex); + item->second.timeout_to_disconnected_enabled = true; + item->second.timeout_to_disconnected_notified = false; + item->second.timeout_to_disconnected.Wait(FeatureFlags::GetInstance() + .GetFlags() + .safe_to_disconnect_ack_delay_millis); + NEARBY_LOGS(INFO) << "[safe-to-disconnect] Wait is done with " + << (item->second.timeout_to_disconnected_notified + ? "notification" + : "timeout"); + if (!item->second.timeout_to_disconnected_notified) + item->second.is_safe_to_disconnect = true; + item->second.timeout_to_disconnected_notified = false; + item->second.timeout_to_disconnected_enabled = false; + } + return true; +} + +bool EndpointChannelManager::ChannelState::IsSafeToDisconnect( + const std::string& endpoint_id) { + + auto item = endpoints_.find(endpoint_id); + if (item == endpoints_.end()) return true; + { + MutexLock lock(&item->second.timeout_to_disconnected_mutex); + NEARBY_LOGS(INFO) + << "[safe-to-disconnect] Get SafeToDisconnect status for endpoint: " + << endpoint_id << ": " << item->second.is_safe_to_disconnect; + return (item->second.is_safe_to_disconnect); + } +} + +void EndpointChannelManager::ChannelState::RemoveTimeoutDisconnectedState( + const std::string& endpoint_id) { + auto item = endpoints_.find(endpoint_id); + if (item == endpoints_.end()) return; + { + MutexLock lock(&item->second.timeout_to_disconnected_mutex); + item->second.timeout_to_disconnected_notified = false; + item->second.timeout_to_disconnected_enabled = false; + } +} + +bool EndpointChannelManager::UnregisterChannelForEndpoint( + const std::string& endpoint_id, DisconnectionReason reason, + SafeDisconnectionResult result) { MutexLock lock(&mutex_); - if (!channel_state_.RemoveEndpoint( - endpoint_id, location::nearby::proto::connections:: - DisconnectionReason::LOCAL_DISCONNECTION)) { + auto safe_to_disconnect_enabled = + channel_state_.GetSafeToDisconnectForEndpoint(endpoint_id); + if (!channel_state_.RemoveEndpoint(endpoint_id, reason, + safe_to_disconnect_enabled, result)) { return false; } - NEARBY_LOGS(INFO) << "EndpointChannelManager unregistered channel for endpoint " << endpoint_id; - return true; } diff --git a/connections/implementation/endpoint_channel_manager.h b/connections/implementation/endpoint_channel_manager.h index 980c53a7..16980164 100644 --- a/connections/implementation/endpoint_channel_manager.h +++ b/connections/implementation/endpoint_channel_manager.h @@ -17,15 +17,23 @@ #include #include +#include #include "securegcm/d2d_connection_context_v1.h" +#include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" +#include "internal/platform/feature_flags.h" #include "internal/platform/mutex.h" +#include "internal/proto/analytics/connections_log.pb.h" namespace nearby { namespace connections { +using DisconnectionReason = + ::location::nearby::proto::connections::DisconnectionReason; +using SafeDisconnectionResult = ::location::nearby::analytics::proto:: + ConnectionsLog::EstablishedConnection::SafeDisconnectionResult; // NOTE(std::string): // All the strings in internal class public interfaces should be exchanged as @@ -90,13 +98,28 @@ class EndpointChannelManager final { // Returns true if 'endpoint_id' actually had a registered EndpointChannel. // IOW, a return of false signifies a no-op. - bool UnregisterChannelForEndpoint(const std::string& endpoint_id) + bool UnregisterChannelForEndpoint(const std::string& endpoint_id, + DisconnectionReason reason, + SafeDisconnectionResult result) ABSL_LOCKS_EXCLUDED(mutex_); int GetConnectedEndpointsCount() const ABSL_LOCKS_EXCLUDED(mutex_); // Check if any endpoint uses WLAN Medium bool isWifiLanConnected() const ABSL_LOCKS_EXCLUDED(mutex_); + void UpdateSafeToDisconnectForEndpoint(const std::string& endpoint_id, + bool safe_to_disconnect_enabled) + ABSL_LOCKS_EXCLUDED(mutex_); + void MarkEndpointStopWaitToDisconnect(const std::string& endpoint_id, + bool is_safe_to_disconnect, + bool notify_stop_waiting) + ABSL_LOCKS_EXCLUDED(mutex_); + bool CreateNewTimeoutDisconnectedState(const std::string& endpoint_id) + ABSL_LOCKS_EXCLUDED(mutex_); + bool IsSafeToDisconnect(const std::string& endpoint_id) + ABSL_LOCKS_EXCLUDED(mutex_); + void RemoveTimeoutDisconnectedState(const std::string& endpoint_id) + ABSL_LOCKS_EXCLUDED(mutex_); private: // Tracks channel state for all endpoints. This includes what EndpointChannel @@ -119,9 +142,17 @@ class EndpointChannelManager final { std::shared_ptr channel; std::shared_ptr context; - location::nearby::proto::connections::DisconnectionReason - disconnect_reason = location::nearby::proto::connections:: - DisconnectionReason::UNKNOWN_DISCONNECTION_REASON; + DisconnectionReason disconnect_reason = + DisconnectionReason::UNKNOWN_DISCONNECTION_REASON; + bool safe_to_disconnect_enabled = false; + mutable Mutex timeout_to_disconnected_mutex; + ConditionVariable timeout_to_disconnected{&timeout_to_disconnected_mutex}; + bool timeout_to_disconnected_enabled + ABSL_GUARDED_BY(timeout_to_disconnected_mutex) = false; + bool timeout_to_disconnected_notified + ABSL_GUARDED_BY(timeout_to_disconnected_mutex) = false; + bool is_safe_to_disconnect + ABSL_GUARDED_BY(timeout_to_disconnected_mutex) = false; }; ChannelState() = default; @@ -130,7 +161,7 @@ class EndpointChannelManager final { ChannelState& operator=(ChannelState&&) = default; // Provides a way to destroy contents of a container, while holding a lock. - void DestroyAll() { endpoints_.clear(); } + void DestroyAll(); // Return pointer to endpoint data, or nullptr, it not found. EndpointData* LookupEndpointData(const std::string& endpoint_id); @@ -145,15 +176,26 @@ class EndpointChannelManager final { const std::string& endpoint_id, std::unique_ptr context); + void UpdateSafeToDisconnectForEndpoint(const std::string& endpoint_id, + bool safe_to_disconnect_enabled); + bool GetSafeToDisconnectForEndpoint(const std::string& endpoint_id); + // Removes all knowledge of this endpoint, cleaning up as necessary. // Returns false if the endpoint was not found. - bool RemoveEndpoint( - const std::string& endpoint_id, - location::nearby::proto::connections::DisconnectionReason reason); + bool RemoveEndpoint(const std::string& endpoint_id, + DisconnectionReason reason, + bool safe_to_disconnect_enabled, + SafeDisconnectionResult result); bool EncryptChannel(EndpointData* endpoint); int GetConnectedEndpointsCount() const { return endpoints_.size(); } bool isWifiLanConnected() const; + void MarkEndpointStopWaitToDisconnect(const std::string& endpoint_id, + bool is_safe_to_disconnect, + bool notify_stop_waiting); + bool CreateNewTimeoutDisconnectedState(const std::string& endpoint_id); + bool IsSafeToDisconnect(const std::string& endpoint_id); + void RemoveTimeoutDisconnectedState(const std::string& endpoint_id); private: // Endpoint ID -> EndpointData. Contains everything we know about the @@ -168,7 +210,7 @@ class EndpointChannelManager final { ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); mutable Mutex mutex_; - ChannelState channel_state_ ABSL_GUARDED_BY(mutex_); + ChannelState channel_state_; }; } // namespace connections diff --git a/connections/implementation/endpoint_channel_manager_test.cc b/connections/implementation/endpoint_channel_manager_test.cc index fe34336b..eb0da0c2 100644 --- a/connections/implementation/endpoint_channel_manager_test.cc +++ b/connections/implementation/endpoint_channel_manager_test.cc @@ -14,20 +14,24 @@ #include "connections/implementation/endpoint_channel_manager.h" +#include #include #include #include #include -#include "securegcm/d2d_connection_context_v1.h" #include "securegcm/ukey2_handshake.h" #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "absl/time/time.h" #include "connections/implementation/base_endpoint_channel.h" +#include "connections/implementation/client_proxy.h" #include "connections/implementation/encryption_runner.h" +#include "connections/implementation/endpoint_channel.h" +#include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/exception.h" #include "internal/platform/input_stream.h" @@ -35,16 +39,19 @@ #include "internal/platform/multi_thread_executor.h" #include "internal/platform/output_stream.h" #include "internal/platform/pipe.h" +#include "internal/proto/analytics/connections_log.pb.h" #include "proto/connections_enums.pb.h" namespace nearby { namespace connections { namespace { +using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::proto::connections::DisconnectionReason; using ::location::nearby::proto::connections::Medium; using EncryptionContext = BaseEndpointChannel::EncryptionContext; +constexpr size_t kChunkSize = 64 * 1024; constexpr absl::string_view kEndpointId = "EndpointId"; constexpr absl::string_view kMonitorA = "MonitorA"; constexpr absl::string_view kMonitorB = "MonitorB"; @@ -66,7 +73,7 @@ std::function MakeDataPump( return [label, input, output, monitor]() { NEARBY_LOGS(INFO) << "streaming data through '" << label << "'"; while (true) { - auto read_response = input->Read(Pipe::kChunkSize); + auto read_response = input->Read(kChunkSize); if (!read_response.ok()) { NEARBY_LOGS(INFO) << "Peer reader closed on '" << label << "'"; output->Close(); @@ -169,14 +176,18 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) { std::string capture_b; ClientProxy proxy_a; ClientProxy proxy_b; - Pipe client_a; // Channel "a" writes to client "a", reads from server "a". - Pipe client_b; // Channel "b" writes to client "b", reads from server "b". - Pipe server_a; // Data pump "a" reads from client "a", writes to server "b". - Pipe server_b; // Data pump "b" reads from client "b", writes to server "a". - auto channel_a = std::make_unique( - &server_a.GetInputStream(), &client_a.GetOutputStream()); - auto channel_b = std::make_unique( - &server_b.GetInputStream(), &client_b.GetOutputStream()); + auto client_a = + CreatePipe(); // Channel "a" writes to client "a", reads from server "a". + auto client_b = + CreatePipe(); // Channel "b" writes to client "b", reads from server "b". + auto server_a = CreatePipe(); // Data pump "a" reads from client "a", writes + // to server "b". + auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes + // to server "a". + auto channel_a = std::make_unique(server_a.first.get(), + client_a.second.get()); + auto channel_b = std::make_unique(server_b.first.get(), + client_b.second.get()); auto channel_a_raw = channel_a.get(); auto channel_b_raw = channel_b.get(); @@ -188,12 +199,12 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) { }); MultiThreadExecutor executor(2); - executor.Execute(MakeDataPump( - kPumpA, &client_a.GetInputStream(), &server_b.GetOutputStream(), - MakeDataMonitor(kMonitorA, &capture_a, &mutex))); - executor.Execute(MakeDataPump( - kPumpB, &client_b.GetInputStream(), &server_a.GetOutputStream(), - MakeDataMonitor(kMonitorB, &capture_b, &mutex))); + executor.Execute( + MakeDataPump(kPumpA, client_a.first.get(), server_b.second.get(), + MakeDataMonitor(kMonitorA, &capture_a, &mutex))); + executor.Execute( + MakeDataPump(kPumpB, client_b.first.get(), server_a.second.get(), + MakeDataMonitor(kMonitorB, &capture_b, &mutex))); // Run DH key exchange; setup encryption contexts for channels. auto context = DoDhKeyExchange(channel_a.get(), channel_b.get()); @@ -231,6 +242,12 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) { // Shutdown test environment. channel_a_raw->Close(DisconnectionReason::LOCAL_DISCONNECTION); channel_b_raw->Close(DisconnectionReason::REMOTE_DISCONNECTION); + ecm_a.UnregisterChannelForEndpoint( + std::string(kEndpointId), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + ecm_b.UnregisterChannelForEndpoint( + std::string(kEndpointId), DisconnectionReason::REMOTE_DISCONNECTION, + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); } TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) { @@ -240,14 +257,18 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) { std::string capture_b; ClientProxy proxy_a; ClientProxy proxy_b; - Pipe client_a; // Channel "a" writes to client "a", reads from server "a". - Pipe client_b; // Channel "b" writes to client "b", reads from server "b". - Pipe server_a; // Data pump "a" reads from client "a", writes to server "b". - Pipe server_b; // Data pump "b" reads from client "b", writes to server "a". - auto channel_a = std::make_unique( - &server_a.GetInputStream(), &client_a.GetOutputStream()); - auto channel_b = std::make_unique( - &server_b.GetInputStream(), &client_b.GetOutputStream()); + auto client_a = + CreatePipe(); // Channel "a" writes to client "a", reads from server "a". + auto client_b = + CreatePipe(); // Channel "b" writes to client "b", reads from server "b". + auto server_a = CreatePipe(); // Data pump "a" reads from client "a", writes + // to server "b". + auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes + // to server "a". + auto channel_a = std::make_unique(server_a.first.get(), + client_a.second.get()); + auto channel_b = std::make_unique(server_b.first.get(), + client_b.second.get()); auto channel_a_raw = channel_a.get(); auto channel_b_raw = channel_b.get(); @@ -259,12 +280,12 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) { }); MultiThreadExecutor executor(2); - executor.Execute(MakeDataPump( - kPumpA, &client_a.GetInputStream(), &server_b.GetOutputStream(), - MakeDataMonitor(kMonitorA, &capture_a, &mutex))); - executor.Execute(MakeDataPump( - kPumpB, &client_b.GetInputStream(), &server_a.GetOutputStream(), - MakeDataMonitor(kMonitorB, &capture_b, &mutex))); + executor.Execute( + MakeDataPump(kPumpA, client_a.first.get(), server_b.second.get(), + MakeDataMonitor(kMonitorA, &capture_a, &mutex))); + executor.Execute( + MakeDataPump(kPumpB, client_b.first.get(), server_a.second.get(), + MakeDataMonitor(kMonitorB, &capture_b, &mutex))); // Run DH key exchange; setup encryption contexts for channels. auto context = DoDhKeyExchange(channel_a.get(), channel_b.get()); @@ -289,7 +310,12 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) { // Shutdown test environment. channel_a_raw->Close(DisconnectionReason::LOCAL_DISCONNECTION); channel_b_raw->Close(DisconnectionReason::REMOTE_DISCONNECTION); -} + ecm_a.UnregisterChannelForEndpoint( + std::string(kEndpointId), DisconnectionReason::LOCAL_DISCONNECTION, + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + ecm_b.UnregisterChannelForEndpoint( + std::string(kEndpointId), DisconnectionReason::REMOTE_DISCONNECTION, + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);} } // namespace } // namespace connections diff --git a/connections/implementation/endpoint_manager.cc b/connections/implementation/endpoint_manager.cc index 57f75942..1cccfc41 100644 --- a/connections/implementation/endpoint_manager.cc +++ b/connections/implementation/endpoint_manager.cc @@ -21,8 +21,11 @@ #include #include +#include "absl/time/time.h" #include "connections/implementation/analytics/throughput_recorder.h" +#include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" +#include "connections/implementation/endpoint_channel_manager.h" #include "connections/implementation/offline_frames.h" #include "connections/implementation/payload_manager.h" #include "connections/implementation/proto/offline_wire_formats.pb.h" @@ -30,12 +33,16 @@ #include "internal/platform/count_down_latch.h" #include "internal/platform/exception.h" #include "internal/platform/logging.h" +#include "internal/platform/mutex.h" #include "internal/platform/mutex_lock.h" +#include "internal/proto/analytics/connections_log.pb.h" +#include "proto/connections_enums.pb.h" namespace nearby { namespace connections { namespace { +using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::connections::OfflineFrame; using ::location::nearby::connections::V1Frame; using ::nearby::analytics::PacketMetaData; @@ -97,7 +104,7 @@ class EndpointManager::LockedFrameProcessor { void EndpointManager::EndpointChannelLoopRunnable( const std::string& runnable_name, ClientProxy* client, const std::string& endpoint_id, - std::function(EndpointChannel*)> handler) { + absl::AnyInvocable(EndpointChannel*)> handler) { // EndpointChannelManager will not let multiple channels exist simultaneously // for the same endpoint_id; it will be closing "old" channels as new ones // come. @@ -162,6 +169,11 @@ void EndpointManager::EndpointChannelLoopRunnable( NEARBY_LOGS(INFO) << "Dropping current channel: last medium=" << location::nearby::proto::connections::Medium_Name( last_failed_medium); + if (client->IsSafeToDisconnectEnabled(endpoint_id)) { + channel_manager_->MarkEndpointStopWaitToDisconnect( + endpoint_id, /* is_safe_to_disconnect */ false, + /* notify_stop_waiting */ true); + } break; } } @@ -171,7 +183,7 @@ void EndpointManager::EndpointChannelLoopRunnable( << "; endpoint_id=" << endpoint_id; // Always clear out all state related to this endpoint before terminating // this thread. - DiscardEndpoint(client, endpoint_id); + DiscardEndpoint(client, endpoint_id, DisconnectionReason::IO_ERROR); NEARBY_LOGS(INFO) << "Worker done; worker name=" << runnable_name << "; endpoint_id=" << endpoint_id; } @@ -260,7 +272,7 @@ ExceptionOr EndpointManager::HandleData( } else if (frame_type == V1Frame::DISCONNECTION) { NEARBY_LOG(INFO, "Disconnect message for endpoint %s", endpoint_id.c_str()); - endpoint_channel->Close(); + ProcessDisconnectionFrame(client, endpoint_id, endpoint_channel, frame); } else { NEARBY_LOGS(ERROR) << "Unhandled message: endpoint_id=" << endpoint_id << ", frame type=" @@ -275,6 +287,62 @@ ExceptionOr EndpointManager::HandleData( } } +void EndpointManager::ProcessDisconnectionFrame( + ClientProxy* client, const std::string& endpoint_id, + EndpointChannel* endpoint_channel, OfflineFrame& frame) { + if (!client->IsSafeToDisconnectEnabled(endpoint_id)) { + NEARBY_LOGS(INFO) + << "EndpointManager received a DISCONNECTION frame from endpoint " + << endpoint_id << " on channel " << endpoint_channel->GetType() + << ", disconnecting..."; + endpoint_channel->Close(DisconnectionReason::REMOTE_DISCONNECTION); + return; + } + + if (!frame.v1().has_disconnection() || + !frame.v1().disconnection().has_request_safe_to_disconnect() || + !frame.v1().disconnection().request_safe_to_disconnect()) { + NEARBY_LOGS(INFO) << "[safe-to-disconnect] no need to apply " + "safe-to-disconnect protocol for endpoint " + << endpoint_id << " on channel " + << endpoint_channel->GetType() << ", disconnecting..."; + endpoint_channel->Close(DisconnectionReason::REMOTE_DISCONNECTION); + return; + } + NEARBY_LOGS(INFO) + << "[safe-to-disconnect] received a " + "DISCONNECTION frame with request safe to disconnect = true and ack = " + << frame.v1().disconnection().ack_safe_to_disconnect() + << " from endpoint " << endpoint_id << " on channel " + << endpoint_channel->GetType() + << ", disconnecting with safe-to-disconnect protocol ..."; + if (frame.v1().disconnection().ack_safe_to_disconnect()) { + channel_manager_->MarkEndpointStopWaitToDisconnect( + endpoint_id, /* is_safe_to_disconnect */ true, + /* notify_stop_waiting */ true); + } else { + channel_manager_->MarkEndpointStopWaitToDisconnect( + endpoint_id, /* is_safe_to_disconnect */ true, + /* notify_stop_waiting */ false); + RunOnEndpointManagerThread( + "safe-to-disconnect", [this, client, &endpoint_id]() { + RemoveEndpoint(client, endpoint_id, /*notify=*/true, + DisconnectionReason::REMOTE_DISCONNECTION); + }); + endpoint_channel->Resume(); + NEARBY_LOGS(INFO) << "[safe-to-disconnect] Sending " + "DISCONNECTION frame with request 1, ack 1"; + Exception write_exception = endpoint_channel->Write( + parser::ForDisconnection(/* request_safe_to_disconnect= */ true, + /* ack_safe_to_disconnect= */ true)); + if (!write_exception.Ok()) { + NEARBY_LOGS(INFO) << "[safe-to-disconnect] Failed to send " + "DISCONNECTION frame with ack to endpoint" + << endpoint_id; + } + } +} + ExceptionOr EndpointManager::HandleKeepAlive( EndpointChannel* endpoint_channel, absl::Duration keep_alive_interval, absl::Duration keep_alive_timeout, Mutex* keep_alive_waiter_mutex, @@ -290,10 +358,10 @@ ExceptionOr EndpointManager::HandleKeepAlive( return ExceptionOr(false); } - // If we haven't written anything to the endpoint for a while, attempt to send - // the KeepAlive frame over the endpoint channel. If the write fails, our - // super class will loop back around and try our luck again in case there's - // been a replacement for this endpoint. + // If we haven't written anything to the endpoint for a while, attempt to + // send the KeepAlive frame over the endpoint channel. If the write fails, + // our super class will loop back around and try our luck again in case + // there's been a replacement for this endpoint. absl::Time last_write_time = endpoint_channel->GetLastWriteTimestamp(); absl::Duration duration_until_write_keep_alive = last_write_time == kInvalidTimestamp @@ -323,15 +391,15 @@ ExceptionOr EndpointManager::HandleKeepAlive( bool operator==(const EndpointManager::FrameProcessor& lhs, const EndpointManager::FrameProcessor& rhs) { - // We're comparing addresses because these objects are callbacks which need to - // be matched by exact instances. + // We're comparing addresses because these objects are callbacks which need + // to be matched by exact instances. return &lhs == &rhs; } bool operator<(const EndpointManager::FrameProcessor& lhs, const EndpointManager::FrameProcessor& rhs) { - // We're comparing addresses because these objects are callbacks which need to - // be matched by exact instances. + // We're comparing addresses because these objects are callbacks which need + // to be matched by exact instances. return &lhs < &rhs; } @@ -444,10 +512,11 @@ void EndpointManager::RegisterEndpoint( // NOTE (unique_ptr<> capture): // std::unique_ptr<> is not copyable, so we can not pass it to - // lambda capture, because lambda eventually is converted to std::function<>. - // Instead, we release() a pointer, and pass a raw pointer, which is copyalbe. - // We ignore the risk of job not scheduled (and an associated risk of memory - // leak), because this may only happen during service shutdown. + // lambda capture, because lambda eventually is converted to + // std::function<>. Instead, we release() a pointer, and pass a raw pointer, + // which is copyalbe. We ignore the risk of job not scheduled (and an + // associated risk of memory leak), because this may only happen during + // service shutdown. RunOnEndpointManagerThread("register-endpoint", [this, client, channel = channel.release(), &endpoint_id, &info, @@ -456,8 +525,8 @@ void EndpointManager::RegisterEndpoint( &latch]() { if (endpoints_.contains(endpoint_id)) { NEARBY_LOGS(WARNING) << "Registering duplicate endpoint " << endpoint_id; - // We must remove old endpoint state before registering a new one for the - // same endpoint_id. + // We must remove old endpoint state before registering a new one + // for the same endpoint_id. RemoveEndpointState(endpoint_id); } @@ -487,8 +556,8 @@ void EndpointManager::RegisterEndpoint( // For every endpoint, there's normally only one Read handler instance // running on a dedicated thread. This instance reads data from the // endpoint and delegates incoming frames to various FrameProcessors. - // Once the frame has been properly handled, it starts reading again for - // the next frame. If the handler fails its read and no other + // Once the frame has been properly handled, it starts reading again + // for the next frame. If the handler fails its read and no other // EndpointChannels are available for this endpoint, a disconnection // will be initiated. endpoint_state.StartEndpointReader([this, client, endpoint_id]() { @@ -499,17 +568,18 @@ void EndpointManager::RegisterEndpoint( }); }); - // For every endpoint, there's only one KeepAliveManager instance running on - // a dedicated thread. This instance will periodically send out a ping* to - // the endpoint while listening for an incoming pong**. If it fails to send - // the ping, or if no pong is heard within keep_alive_timeout, it initiates - // a disconnection. + // For every endpoint, there's only one KeepAliveManager instance + // running on a dedicated thread. This instance will periodically send + // out a ping* to the endpoint while listening for an incoming pong**. + // If it fails to send the ping, or if no pong is heard within + // keep_alive_timeout, it initiates a disconnection. // // (*) Bluetooth requires a constant outgoing stream of messages. If - // there's silence, Android will break the socket. This is why we ping. - // (**) Wifi Hotspots can fail to notice a connection has been lost, and - // they will happily keep writing to /dev/null. This is why we listen - // for the pong. + // there's silence, Android will break the socket. This is why we + // ping. + // (**) Wifi Hotspots can fail to notice a connection has been lost, + // and they will happily keep writing to /dev/null. This is why we + // listen for the pong. NEARBY_LOGS(VERBOSE) << "EndpointManager enabling KeepAlive for endpoint " << endpoint_id; endpoint_state.StartEndpointKeepAliveManager( @@ -545,7 +615,8 @@ void EndpointManager::UnregisterEndpoint(ClientProxy* client, RunOnEndpointManagerThread( "unregister-endpoint", [this, client, endpoint_id, &latch]() { RemoveEndpoint(client, endpoint_id, - /*notify=*/client->IsConnectedToEndpoint(endpoint_id)); + /*notify=*/client->IsConnectedToEndpoint(endpoint_id), + DisconnectionReason::LOCAL_DISCONNECTION); latch.CountDown(); }); latch.Await(); @@ -578,12 +649,19 @@ std::vector EndpointManager::SendPayloadChunk( } // Designed to run asynchronously. It is called from IO thread pools, and -// jobs in these pools may be waited for from the EndpointManager thread. If we -// allow synchronous behavior here it will cause a live lock. +// jobs in these pools may be waited for from the EndpointManager thread. If +// we allow synchronous behavior here it will cause a live lock. void EndpointManager::DiscardEndpoint(ClientProxy* client, - const std::string& endpoint_id) { - NEARBY_LOGS(VERBOSE) << "DiscardEndpoint for endpoint " << endpoint_id; - RunOnEndpointManagerThread("discard-endpoint", [this, client, endpoint_id]() { + const std::string& endpoint_id, + DisconnectionReason reason) { + NEARBY_LOGS(INFO) << "DiscardEndpoint for endpoint " << endpoint_id; + if (reason == DisconnectionReason::IO_ERROR) { + channel_manager_->MarkEndpointStopWaitToDisconnect( + endpoint_id, /* is_safe_to_disconnect */ false, + /* notify_stop_waiting */ true); + } + RunOnEndpointManagerThread("discard-endpoint", [this, client, endpoint_id, + reason]() { // `ClientProxy` is destroyed before `EndpointManager` in // `~NearbyConnections`, which means "discard-endpoint" needs to check // if this task is being executing during `~EndpointManager` to @@ -625,7 +703,8 @@ void EndpointManager::DiscardEndpoint(ClientProxy* client, } RemoveEndpoint(client, endpoint_id, - /*notify=*/client->IsConnectedToEndpoint(endpoint_id)); + /* notify */client->IsConnectedToEndpoint(endpoint_id), + reason); }); } @@ -647,8 +726,12 @@ std::vector EndpointManager::SendControlMessage( // @EndpointManagerThread void EndpointManager::RemoveEndpoint(ClientProxy* client, const std::string& endpoint_id, - bool notify) { - NEARBY_LOGS(INFO) << "RemoveEndpoint for endpoint " << endpoint_id; + bool notify, DisconnectionReason reason) { + NEARBY_LOGS(INFO) << "RemoveEndpoint for endpoint: " << endpoint_id + << ", reason: " << reason; + + SafeDisconnectionResult safe_disconnect_result = + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION; // Grab the service ID before we destroy the channel. EndpointChannel* channel = @@ -656,16 +739,35 @@ void EndpointManager::RemoveEndpoint(ClientProxy* client, std::string service_id = channel ? channel->GetServiceId() : std::string(kUnknownServiceId); + if (client->IsSafeToDisconnectEnabled(endpoint_id)) { + if (channel != nullptr) { + bool is_safe_disconnection = + ApplySafeToDisconnect(endpoint_id, channel, reason); + safe_disconnect_result = + is_safe_disconnection + ? ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION + : ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION; + NEARBY_LOGS(INFO) << "[safe-to-disconnect] safe_disconnect_result:" + << (safe_disconnect_result? "true" : "false"); + } + } + if (safe_disconnect_result == + ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION) { + // TODO(b/297259496): Autoreconnect + } + // Unregistering from channel_manager_ will also serve to terminate // the dedicated handler and KeepAlive threads we started when we registered // this endpoint. - if (channel_manager_->UnregisterChannelForEndpoint(endpoint_id)) { + if (channel_manager_->UnregisterChannelForEndpoint(endpoint_id, reason, + safe_disconnect_result)) { // Notify all frame processors of the disconnection immediately and wait // for them to clean up state. Only once all processors are done cleaning // up, we can remove the endpoint from ClientProxy after which there // should be no further interactions with the endpoint. // (See b/37352254 for history) - WaitForEndpointDisconnectionProcessing(client, service_id, endpoint_id); + WaitForEndpointDisconnectionProcessing(client, service_id, endpoint_id, + reason); client->OnDisconnected(endpoint_id, notify); NEARBY_LOGS(INFO) << "Removed endpoint for endpoint " << endpoint_id; @@ -673,15 +775,68 @@ void EndpointManager::RemoveEndpoint(ClientProxy* client, RemoveEndpointState(endpoint_id); } +bool EndpointManager::ApplySafeToDisconnect(const std::string& endpoint_id, + EndpointChannel* endpoint_channel, + DisconnectionReason reason) { + NEARBY_LOGS(INFO) << "[safe-to-disconnect] ApplySafeToDisconnect reason: " + << reason; + bool is_safe_disconnection = false; + bool send_disconnection_frame = true; + switch (reason) { + case DisconnectionReason::UPGRADED: + case DisconnectionReason::SHUTDOWN: + case DisconnectionReason::UNFINISHED: + return true; // safe disconnection + case DisconnectionReason::IO_ERROR: + return false; // unsafe disconnection + case DisconnectionReason::LOCAL_DISCONNECTION: + is_safe_disconnection = true; + send_disconnection_frame = true; + break; + case DisconnectionReason::REMOTE_DISCONNECTION: + is_safe_disconnection = true; + send_disconnection_frame = false; + break; + default: + is_safe_disconnection = false; + send_disconnection_frame = true; + } + + if (send_disconnection_frame) { + // If the channel was paused (i.e. during a bandwidth upgrade negotiation) + // we resume to ensure the thread won't hang when trying to write to it. + endpoint_channel->Resume(); + NEARBY_LOGS(INFO) << "[safe-to-disconnect] Sending " + "DISCONNECTION frame with request 1, ack 0"; + Exception write_exception = endpoint_channel->Write( + parser::ForDisconnection(/* request_safe_to_disconnect= */ true, + /* ack_safe_to_disconnect= */ false)); + + if (!write_exception.Ok()) { + NEARBY_LOGS(WARNING) << "[safe-to-disconnect] Failed to send " + "DISCONNECTION frame to endpoint" + << endpoint_id << " for reason: " << reason; + return is_safe_disconnection; + } + } + + bool state = + channel_manager_->CreateNewTimeoutDisconnectedState(endpoint_id); + if (!state) return is_safe_disconnection; + + return is_safe_disconnection || + channel_manager_->IsSafeToDisconnect(endpoint_id); +} + // @EndpointManagerThread void EndpointManager::WaitForEndpointDisconnectionProcessing( ClientProxy* client, const std::string& service_id, - const std::string& endpoint_id) { + const std::string& endpoint_id, DisconnectionReason reason) { NEARBY_LOGS(INFO) << "Wait: client=" << client << "; service_id=" << service_id << "; endpoint_id=" << endpoint_id; CountDownLatch barrier = NotifyFrameProcessorsOnEndpointDisconnect( - client, service_id, endpoint_id); + client, service_id, endpoint_id, reason); NEARBY_LOGS(INFO) << "Waiting for frame processors to disconnect from endpoint " @@ -690,15 +845,15 @@ void EndpointManager::WaitForEndpointDisconnectionProcessing( NEARBY_LOGS(INFO) << "Failed to disconnect frame processors from endpoint " << endpoint_id; } else { - NEARBY_LOGS(INFO) - << "Finished waiting for frame processors to disconnect from endpoint " - << endpoint_id; + NEARBY_LOGS(INFO) << "Finished waiting for frame processors to " + "disconnect from endpoint " + << endpoint_id; } } CountDownLatch EndpointManager::NotifyFrameProcessorsOnEndpointDisconnect( ClientProxy* client, const std::string& service_id, - const std::string& endpoint_id) { + const std::string& endpoint_id, DisconnectionReason reason) { NEARBY_LOGS(INFO) << "NotifyFrameProcessorsOnEndpointDisconnect: client=" << client << "; service_id=" << service_id << "; endpoint_id=" << endpoint_id; @@ -714,7 +869,8 @@ CountDownLatch EndpointManager::NotifyFrameProcessorsOnEndpointDisconnect( << "; frame type=" << V1Frame::FrameType_Name(item.first); if (processor) { valid++; - processor->OnEndpointDisconnect(client, service_id, endpoint_id, barrier); + processor->OnEndpointDisconnect(client, service_id, endpoint_id, barrier, + reason); } else { barrier.CountDown(); } @@ -739,7 +895,8 @@ std::vector EndpointManager::SendTransferFrameBytes( if (channel == nullptr) { // We no longer know about this endpoint (it was either explicitly - // unregistered, or a read/write error made us unregister it internally). + // unregistered, or a read/write error made us unregister it + // internally). NEARBY_LOGS(ERROR) << "EndpointManager failed to find EndpointChannel " "over which to write " << packet_type << " at offset " << offset @@ -766,12 +923,15 @@ std::vector EndpointManager::SendTransferFrameBytes( EndpointManager::EndpointState::~EndpointState() { // We must unregister the endpoint first to signal the runnables that they - // should exit their loops. SingleThreadExecutor destructors will wait for the - // workers to finish. |channel_manager_| is null after moved from this object - // (in move constructor) which prevents unregistering the channel prematurely. + // should exit their loops. SingleThreadExecutor destructors will wait for + // the workers to finish. |channel_manager_| is null after moved from this + // object (in move constructor) which prevents unregistering the channel + // prematurely. if (channel_manager_) { NEARBY_LOG(VERBOSE, "EndpointState destructor %s", endpoint_id_.c_str()); - channel_manager_->UnregisterChannelForEndpoint(endpoint_id_); + channel_manager_->UnregisterChannelForEndpoint( + endpoint_id_, DisconnectionReason::SHUTDOWN, + ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); } // Make sure the KeepAlive thread isn't blocking shutdown. @@ -786,11 +946,11 @@ void EndpointManager::EndpointState::StartEndpointReader(Runnable&& runnable) { } void EndpointManager::EndpointState::StartEndpointKeepAliveManager( - std::function runnable) { + absl::AnyInvocable runnable) { keep_alive_thread_.Execute( - "keep-alive", - [runnable, keep_alive_waiter_mutex = keep_alive_waiter_mutex_.get(), - keep_alive_waiter = keep_alive_waiter_.get()]() { + "keep-alive", [runnable = std::move(runnable), + keep_alive_waiter_mutex = keep_alive_waiter_mutex_.get(), + keep_alive_waiter = keep_alive_waiter_.get()]() mutable { runnable(keep_alive_waiter_mutex, keep_alive_waiter); }); } diff --git a/connections/implementation/endpoint_manager.h b/connections/implementation/endpoint_manager.h index c60e1484..02306ca2 100644 --- a/connections/implementation/endpoint_manager.h +++ b/connections/implementation/endpoint_manager.h @@ -25,6 +25,7 @@ #include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" +#include "absl/functional/any_invocable.h" #include "absl/time/time.h" #include "connections/implementation/analytics/packet_meta_data.h" #include "connections/implementation/client_proxy.h" @@ -89,7 +90,8 @@ class EndpointManager { virtual void OnEndpointDisconnect(ClientProxy* client, const std::string& service_id, const std::string& endpoint_id, - CountDownLatch barrier) = 0; + CountDownLatch barrier, + DisconnectionReason reason) = 0; }; explicit EndpointManager(EndpointChannelManager* manager); @@ -153,7 +155,8 @@ class EndpointManager { // ask everyone who's registered an FrameProcessor to // processEndpointDisconnection() while the caller of DiscardEndpoint() is // blocked here. - void DiscardEndpoint(ClientProxy* client, const std::string& endpoint_id); + void DiscardEndpoint(ClientProxy* client, const std::string& endpoint_id, + DisconnectionReason reason); protected: // For unit tests only to control executing tasks on the executor. @@ -189,7 +192,7 @@ class EndpointManager { void StartEndpointReader(Runnable&& runnable); void StartEndpointKeepAliveManager( - std::function runnable); + absl::AnyInvocable runnable); private: const std::string endpoint_id_; @@ -245,7 +248,7 @@ class EndpointManager { void EndpointChannelLoopRunnable( const std::string& runnable_name, ClientProxy* client_proxy, const std::string& endpoint_id, - std::function(EndpointChannel*)> handler); + absl::AnyInvocable(EndpointChannel*)> handler); static void WaitForLatch(const std::string& method_name, CountDownLatch* latch); @@ -259,15 +262,21 @@ class EndpointManager { // this method is idempotent. // @EndpointManagerThread void RemoveEndpoint(ClientProxy* client, const std::string& endpoint_id, - bool notify); - + bool notify, DisconnectionReason reason); + bool ApplySafeToDisconnect(const std::string& endpoint_id, + EndpointChannel* endpoint_channel, + DisconnectionReason reason); void WaitForEndpointDisconnectionProcessing(ClientProxy* client, const std::string& service_id, - const std::string& endpoint_id); - + const std::string& endpoint_id, + DisconnectionReason reason); + void ProcessDisconnectionFrame( + ClientProxy* client, const std::string& endpoint_id, + EndpointChannel* endpoint_channel, + location::nearby::connections::OfflineFrame& frame); CountDownLatch NotifyFrameProcessorsOnEndpointDisconnect( ClientProxy* client, const std::string& service_id, - const std::string& endpoint_id); + const std::string& endpoint_id, DisconnectionReason reason); std::vector SendTransferFrameBytes( const std::vector& endpoint_ids, diff --git a/connections/implementation/endpoint_manager_test.cc b/connections/implementation/endpoint_manager_test.cc index 49d87f6a..d2047130 100644 --- a/connections/implementation/endpoint_manager_test.cc +++ b/connections/implementation/endpoint_manager_test.cc @@ -29,10 +29,13 @@ #include "connections/connection_options.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel_manager.h" +#include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/offline_frames.h" +#include "internal/flags/nearby_flags.h" #include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/exception.h" +// #include "internal/platform/feature_flags.h" #include "internal/platform/logging.h" #include "internal/test/fake_single_thread_executor.h" #include "proto/connections_enums.pb.h" @@ -112,10 +115,21 @@ class MockFrameProcessor : public EndpointManager::FrameProcessor { MOCK_METHOD(void, OnEndpointDisconnect, (ClientProxy * client, const std::string& service_id, - const std::string& endpoint_id, CountDownLatch barrier), + const std::string& endpoint_id, CountDownLatch barrier, + DisconnectionReason reason), (override)); }; +class SetSafeToDisconnect { + public: + explicit SetSafeToDisconnect(bool safe_to_disconnect) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature:: + kEnableSafeToDisconnect, + safe_to_disconnect); + } +}; + class TestEndpointManager : public EndpointManager { public: TestEndpointManager(EndpointChannelManager* manager, @@ -146,7 +160,7 @@ class EndpointManagerTest : public ::testing::Test { EXPECT_TRUE(done.Await(absl::Milliseconds(1000)).result()); } } - + SetSafeToDisconnect set_safe_to_disconnect_{true}; std::unique_ptr client_ = std::make_unique(); ConnectionOptions connection_options_{ .keep_alive_interval_millis = 5000, @@ -199,9 +213,9 @@ TEST_F(EndpointManagerTest, RegisterEndpointCallsOnConnectionInitiated) { } TEST_F(EndpointManagerTest, UnregisterEndpointCallsOnDisconnected) { - auto endpoint_channel = std::make_unique(); - EXPECT_CALL(*endpoint_channel, Read()) - .WillRepeatedly(Return(ExceptionOr(Exception::kIo))); +// auto endpoint_channel = std::make_unique(); +// EXPECT_CALL(*endpoint_channel, Read()) +// .WillRepeatedly(Return(ExceptionOr(Exception::kIo))); RegisterEndpoint(std::make_unique()); // NOTE: disconnect_cb is not called, because we did not reach fully connected // state. On top of that, UnregisterEndpoint is suppressing this notification. @@ -211,6 +225,19 @@ TEST_F(EndpointManagerTest, UnregisterEndpointCallsOnDisconnected) { em_.UnregisterEndpoint(client_.get(), endpoint_id_); } +TEST_F(EndpointManagerTest, + UnregisterEndpointCallsOnDisconnectedSafeToDisconnect) { + RegisterEndpoint(std::make_unique()); + // NOTE: disconnect_cb is not called, because we did not reach fully connected + // state. On top of that, UnregisterEndpoint is suppressing this notification. + // (IMO, it should be called as long as any connection callback was called + // before. (in this case initiated_cb is called)). + // Test captures current protocol behavior. + client_->SetRemoteSafeToDisconnectVersion(endpoint_id_, 2); + ecm_.UpdateSafeToDisconnectForEndpoint(endpoint_id_, true); + em_.UnregisterEndpoint(client_.get(), endpoint_id_); +} + TEST_F(EndpointManagerTest, RegisterFrameProcessorWorks) { auto endpoint_channel = std::make_unique(); auto connect_request = std::make_unique(); @@ -434,7 +461,8 @@ TEST_F(EndpointManagerTest, DisconnectEndpointDuringDestruction) { // immediately. fake_serial_executor->SetRunExecutablesImmediately( /*run_executables_immediately=*/false); - endpoint_manager->DiscardEndpoint(client_.get(), endpoint_id_); + endpoint_manager->DiscardEndpoint(client_.get(), endpoint_id_, + DisconnectionReason::IO_ERROR); // Simulate Core destruction of ClientProxy by destroying `client_`. client_.reset(); diff --git a/connections/implementation/fake_bwu_handler.h b/connections/implementation/fake_bwu_handler.h index b735dc9e..78c13719 100644 --- a/connections/implementation/fake_bwu_handler.h +++ b/connections/implementation/fake_bwu_handler.h @@ -47,7 +47,7 @@ class FakeBwuHandler : public BaseBwuHandler { }; explicit FakeBwuHandler(Medium medium) - : BaseBwuHandler(BwuNotifications{}), medium_(medium) {} + : BaseBwuHandler(nullptr), medium_(medium) {} ~FakeBwuHandler() override = default; const std::vector& create_calls() const { return create_calls_; } diff --git a/connections/implementation/flags/nearby_connections_feature_flags.h b/connections/implementation/flags/nearby_connections_feature_flags.h index 430be69a..d7f6a398 100644 --- a/connections/implementation/flags/nearby_connections_feature_flags.h +++ b/connections/implementation/flags/nearby_connections_feature_flags.h @@ -15,6 +15,7 @@ #ifndef THIRD_PARTY_NEARBY_CONNECTIONS_IMPLEMENTATION_FLAGS_NEARBY_CONNECTIONS_FEATURE_FLAGS_H_ #define THIRD_PARTY_NEARBY_CONNECTIONS_IMPLEMENTATION_FLAGS_NEARBY_CONNECTIONS_FEATURE_FLAGS_H_ +#include #include "absl/strings/string_view.h" #include "internal/flags/flag.h" @@ -27,7 +28,6 @@ constexpr absl::string_view kConfigPackage = "nearby"; // The Nearby Connections features. namespace nearby_connections_feature { -// LINT.IfChanged // Disable/Enable BLE v2 in Nearby Connections SDK. constexpr auto kEnableBleV2 = flags::Flag(kConfigPackage, "45401515", false); @@ -44,11 +44,18 @@ constexpr auto kEnableGattQueryInThread = constexpr auto kEnablePayloadManagerToSkipChunkUpdate = flags::Flag(kConfigPackage, "45415729", false); -// LINT.ThenChange( -// //depot/google3/location/nearby/cpp/sharing/clients/cpp/nearby_sharing_service_adapter_dart.h, -// //depot/google3/location/nearby/cpp/sharing/clients/cpp/nearby_sharing_service_adapter_dart.cc, -// //depot/google3/location/nearby/cpp/sharing/clients/dart/platform/lib/types/models.dart -// ) +// Enable/Disable safe-to-disconnect feature. +constexpr auto kEnableSafeToDisconnect = + flags::Flag(kConfigPackage, "45425789", false); + +// When true, allows to enable payload-received-ack protocol. +constexpr auto kEnablePayloadReceivedAck = + flags::Flag(kConfigPackage, "45425840", false); + +// Support 1. safe-to-disconnect 2. reserved 3. auto-reconnect +// 4. auto-resume for dev device 5. payload_ack +constexpr auto kSafeToDisconnectVersion = + flags::Flag(kConfigPackage, "45425841", 2); } // namespace nearby_connections_feature } // namespace config_package_nearby diff --git a/connections/implementation/fuzzers/BUILD b/connections/implementation/fuzzers/BUILD index 64223d93..54b9df9b 100644 --- a/connections/implementation/fuzzers/BUILD +++ b/connections/implementation/fuzzers/BUILD @@ -23,6 +23,7 @@ cc_fuzz_target( deps = [ "//connections/implementation:internal", "//internal/platform:base", + "//internal/platform/implementation/g3", "//security/fuzzing/blaze:default_init_google_for_cc_fuzz_target", ], ) diff --git a/connections/implementation/internal_payload_factory.cc b/connections/implementation/internal_payload_factory.cc index 59d7de9d..38268fc9 100644 --- a/connections/implementation/internal_payload_factory.cc +++ b/connections/implementation/internal_payload_factory.cc @@ -14,24 +14,25 @@ #include "connections/implementation/internal_payload_factory.h" +#include #include #include #include #include -#include "absl/memory/memory.h" -#include "connections/implementation/offline_frames_validator.h" +#include "absl/strings/str_cat.h" +#include "connections/implementation/internal_payload.h" +#include "connections/implementation/proto/offline_wire_formats.pb.h" #include "connections/payload.h" +#include "connections/payload_type.h" #include "internal/platform/byte_array.h" -#include "internal/platform/condition_variable.h" #include "internal/platform/exception.h" -#include "internal/platform/feature_flags.h" #include "internal/platform/file.h" #include "internal/platform/implementation/platform.h" -#include "internal/platform/implementation/shared/file.h" +#include "internal/platform/input_stream.h" #include "internal/platform/logging.h" -#include "internal/platform/mutex.h" #include "internal/platform/os_name.h" +#include "internal/platform/output_stream.h" #include "internal/platform/pipe.h" namespace nearby { @@ -155,8 +156,9 @@ class OutgoingStreamInternalPayload : public InternalPayload { class IncomingStreamInternalPayload : public InternalPayload { public: - IncomingStreamInternalPayload(Payload payload, std::shared_ptr pipe) - : InternalPayload(std::move(payload)), pipe_(pipe) {} + IncomingStreamInternalPayload(Payload payload, + std::unique_ptr output) + : InternalPayload(std::move(payload)), output_(std::move(output)) {} PayloadTransferFrame::PayloadHeader::PayloadType GetType() const override { return PayloadTransferFrame::PayloadHeader::STREAM; @@ -174,7 +176,7 @@ class IncomingStreamInternalPayload : public InternalPayload { return {Exception::kSuccess}; } - return pipe_->GetOutputStream().Write(chunk); + return output_->Write(chunk); } ExceptionOr SkipToOffset(size_t offset) override { @@ -183,10 +185,10 @@ class IncomingStreamInternalPayload : public InternalPayload { return {Exception::kIo}; } - void Close() override { pipe_->GetOutputStream().Close(); } + void Close() override { output_->Close(); } private: - std::shared_ptr pipe_; + std::unique_ptr output_; }; class OutgoingFileInternalPayload : public InternalPayload { @@ -311,14 +313,14 @@ std::unique_ptr CreateOutgoingInternalPayload( Payload payload) { switch (payload.GetType()) { case PayloadType::kBytes: - return absl::make_unique(std::move(payload)); + return std::make_unique(std::move(payload)); case PayloadType::kFile: { - return absl::make_unique(std::move(payload)); + return std::make_unique(std::move(payload)); } case PayloadType::kStream: - return absl::make_unique( + return std::make_unique( std::move(payload)); default: @@ -359,19 +361,15 @@ std::unique_ptr CreateIncomingInternalPayload( const Payload::Id payload_id = frame.payload_header().id(); switch (frame.payload_header().type()) { case PayloadTransferFrame::PayloadHeader::BYTES: { - return absl::make_unique( + return std::make_unique( Payload(payload_id, ByteArray(frame.payload_chunk().body()))); } case PayloadTransferFrame::PayloadHeader::STREAM: { - auto pipe = std::make_shared(); + auto [input, output] = CreatePipe(); - return absl::make_unique( - Payload(payload_id, - [pipe]() -> InputStream& { - return pipe->GetInputStream(); // NOLINT - }), - pipe); + return std::make_unique( + Payload(payload_id, std::move(input)), std::move(output)); } case PayloadTransferFrame::PayloadHeader::FILE: { @@ -411,11 +409,11 @@ std::unique_ptr CreateIncomingInternalPayload( // there will be no input file to open. // On Chrome the file path should be empty, so use the payload id. if (ImplementationPlatform::GetCurrentOS() == OSName::kChromeOS) { - return absl::make_unique( + return std::make_unique( Payload(payload_id, InputFile(payload_id, total_size)), OutputFile(payload_id), total_size); } else { - return absl::make_unique( + return std::make_unique( Payload(payload_id, parent_folder, file_name, InputFile(file_path, total_size)), OutputFile(file_path), total_size); diff --git a/connections/implementation/internal_payload_factory_test.cc b/connections/implementation/internal_payload_factory_test.cc index d17556e1..9f6979ae 100644 --- a/connections/implementation/internal_payload_factory_test.cc +++ b/connections/implementation/internal_payload_factory_test.cc @@ -14,15 +14,19 @@ #include "connections/implementation/internal_payload_factory.h" +#include +#include #include #include -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" -#include "connections/implementation/offline_frames.h" +#include "connections/implementation/internal_payload.h" #include "connections/implementation/proto/offline_wire_formats.pb.h" +#include "connections/payload.h" +#include "connections/payload_type.h" #include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" +#include "internal/platform/file.h" #include "internal/platform/pipe.h" namespace nearby { @@ -44,11 +48,9 @@ TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromBytePayload) { } TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromStreamPayload) { - auto pipe = std::make_shared(); + auto [input, output] = CreatePipe(); std::unique_ptr internal_payload = - CreateOutgoingInternalPayload(Payload{[pipe]() -> InputStream& { - return pipe->GetInputStream(); // NOLINT - }}); + CreateOutgoingInternalPayload(Payload(std::move(input))); EXPECT_NE(internal_payload, nullptr); Payload payload = internal_payload->ReleasePayload(); EXPECT_EQ(payload.AsFile(), nullptr); @@ -212,13 +214,11 @@ TEST(InternalPayloadFactoryTest, SkipToOffset_StreamPayloadValidOffset_SkipsOffset) { ByteArray contents("0123456789"); constexpr size_t kOffset = 6; - auto pipe = std::make_shared(); + auto [input, output] = CreatePipe(); std::unique_ptr internal_payload = - CreateOutgoingInternalPayload(Payload{[pipe]() -> InputStream& { - return pipe->GetInputStream(); // NOLINT - }}); + CreateOutgoingInternalPayload(Payload(std::move(input))); EXPECT_NE(internal_payload, nullptr); - pipe->GetOutputStream().Write(contents); + output->Write(contents); ExceptionOr result = internal_payload->SkipToOffset(kOffset); diff --git a/connections/implementation/mediums/BUILD b/connections/implementation/mediums/BUILD index 61f968b4..554b8288 100644 --- a/connections/implementation/mediums/BUILD +++ b/connections/implementation/mediums/BUILD @@ -55,7 +55,6 @@ cc_library( "//internal/platform:base", "//internal/platform:cancellation_flag", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform:uuid", "//proto/mediums:web_rtc_signaling_frames_cc_proto", @@ -63,6 +62,7 @@ cc_library( "@com_google_absl//absl/container:btree", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/functional:bind_front", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", diff --git a/connections/implementation/mediums/ble_test.cc b/connections/implementation/mediums/ble_test.cc index 9ec605b1..51673a77 100644 --- a/connections/implementation/mediums/ble_test.cc +++ b/connections/implementation/mediums/ble_test.cc @@ -72,11 +72,7 @@ TEST_P(BleTest, CanStartAcceptingConnectionsAndConnect) { fast_advertisement_service_uuid); ble_a.StartAcceptingConnections( service_id, - { - .accepted_cb = [&accept_latch]( - BleSocket socket, - const std::string&) { accept_latch.CountDown(); }, - }); + [&](BleSocket socket, const std::string&) { accept_latch.CountDown(); }); BlePeripheral discovered_peripheral; ble_b.StartScanning( service_id, fast_advertisement_service_uuid, @@ -126,11 +122,7 @@ TEST_P(BleTest, CanCancelConnect) { fast_advertisement_service_uuid); ble_a.StartAcceptingConnections( service_id, - { - .accepted_cb = [&accept_latch]( - BleSocket socket, - const std::string&) { accept_latch.CountDown(); }, - }); + [&](BleSocket socket, const std::string&) { accept_latch.CountDown(); }); BlePeripheral discovered_peripheral; ble_b.StartScanning( service_id, fast_advertisement_service_uuid, diff --git a/connections/implementation/mediums/ble_v2.cc b/connections/implementation/mediums/ble_v2.cc index cbdc5fc8..88131d85 100644 --- a/connections/implementation/mediums/ble_v2.cc +++ b/connections/implementation/mediums/ble_v2.cc @@ -417,7 +417,9 @@ bool BleV2::StartAcceptingConnections(const std::string& service_id, }); incoming_sockets_.insert({service_id, client_socket}); } - callback.accepted_cb(std::move(client_socket), service_id); + if (callback) { + callback(std::move(client_socket), service_id); + } } }); diff --git a/connections/implementation/mediums/ble_v2.h b/connections/implementation/mediums/ble_v2.h index 23ff3cf8..0040dbd0 100644 --- a/connections/implementation/mediums/ble_v2.h +++ b/connections/implementation/mediums/ble_v2.h @@ -48,10 +48,8 @@ class BleV2 final { using DiscoveredPeripheralCallback = mediums::DiscoveredPeripheralCallback; // Callback that is invoked when a new connection is accepted. - struct AcceptedConnectionCallback { - absl::AnyInvocable - accepted_cb = DefaultCallback(); - }; + using AcceptedConnectionCallback = absl::AnyInvocable; explicit BleV2(BluetoothRadio& bluetooth_radio); ~BleV2(); diff --git a/connections/implementation/mediums/ble_v2/BUILD b/connections/implementation/mediums/ble_v2/BUILD index 69d727eb..17241f9e 100644 --- a/connections/implementation/mediums/ble_v2/BUILD +++ b/connections/implementation/mediums/ble_v2/BUILD @@ -45,12 +45,12 @@ cc_library( "//internal/flags:nearby_flags", "//internal/platform:base", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform:util", "//internal/platform:uuid", "//proto/mediums:ble_frames_cc_proto", "@aappleby_smhasher//:libmurmur3", + "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/numeric:int128", diff --git a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc index 3153ca1f..806cf3dc 100644 --- a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc +++ b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc @@ -30,6 +30,7 @@ #include "connections/implementation/mediums/ble_v2/bloom_filter.h" #include "internal/flags/nearby_flags.h" #include "internal/platform/ble_v2.h" +#include "internal/platform/byte_array.h" #include "internal/platform/logging.h" #include "internal/platform/multi_thread_executor.h" #include "internal/platform/mutex_lock.h" @@ -521,13 +522,35 @@ void DiscoveredPeripheralTracker::HandleAdvertisementHeader( << absl::BytesToHexString( ByteArray(advertisement_header).data()) << " in thread"; + ByteArray advertisement_data{advertisement_header}; + if (fetching_advertisements_.contains(advertisement_data)) { + NEARBY_LOGS(VERBOSE) << ": Ignore the advertisement header due to it " + "is already in fetcing."; + return; + } + + fetching_advertisements_.insert(advertisement_data); + if (executor_ == nullptr) { // The situation happens when flag value changed executor_ = std::make_unique(kGattThreadCount); } executor_->Execute([this, peripheral, advertisement_header, advertisement_fetcher = - std::move(advertisement_fetcher)]() { + std::move(advertisement_fetcher), + advertisement_data = + std::move(advertisement_data)]() { + { + MutexLock lock(&mutex_); + if (!IsInterestingAdvertisementHeader(advertisement_header)) { + NEARBY_LOGS(INFO) + << ": Ignore to read raw advertisement from server due to it " + "is not interesting header now."; + fetching_advertisements_.erase(advertisement_data); + return; + } + } + std::vector gatt_advertisement_bytes_list = FetchRawAdvertisementsInThread(peripheral, advertisement_header, std::move(advertisement_fetcher)); @@ -537,6 +560,7 @@ void DiscoveredPeripheralTracker::HandleAdvertisementHeader( gatt_advertisement_bytes_list, /*service_uuid=*/{}); UpdateCommonStateForFoundBleAdvertisement(advertisement_header); + fetching_advertisements_.erase(advertisement_data); NEARBY_LOGS(VERBOSE) << ": Completed to handle GATT advertisement " << absl::BytesToHexString(ByteArray(advertisement_header).data()) diff --git a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h index 423514cb..fcd59951 100644 --- a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h +++ b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h @@ -20,6 +20,9 @@ #include #include +#include "absl/base/thread_annotations.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" #include "connections/implementation/mediums//lost_entity_tracker.h" #include "connections/implementation/mediums/ble_v2/advertisement_read_result.h" #include "connections/implementation/mediums/ble_v2/ble_advertisement.h" @@ -289,6 +292,10 @@ class DiscoveredPeripheralTracker { absl::flat_hash_map gatt_advertisement_infos_ ABSL_GUARDED_BY(mutex_); + // Tracks the advertisements in GATT fetching. + absl::flat_hash_set fetching_advertisements_ + ABSL_GUARDED_BY(mutex_); + std::unique_ptr executor_ ABSL_GUARDED_BY(mutex_) = nullptr; }; diff --git a/connections/implementation/mediums/ble_v2_test.cc b/connections/implementation/mediums/ble_v2_test.cc index 484d1471..d1d1ca5e 100644 --- a/connections/implementation/mediums/ble_v2_test.cc +++ b/connections/implementation/mediums/ble_v2_test.cc @@ -77,14 +77,10 @@ TEST_P(BleV2Test, CanConnect) { BleV2Socket socket_for_server; EXPECT_TRUE(ble_server.StartAcceptingConnections( - service_id, { - .accepted_cb = - [&socket_for_server, &accept_latch]( - BleV2Socket socket, const std::string&) { - socket_for_server = std::move(socket); - accept_latch.CountDown(); - }, - })); + service_id, [&](BleV2Socket socket, const std::string&) { + socket_for_server = std::move(socket); + accept_latch.CountDown(); + })); ble_server.StartAdvertising(service_id, advertisement_bytes, PowerLevel::kHighPower, @@ -139,14 +135,10 @@ TEST_P(BleV2Test, CanCancelConnect) { BleV2Socket socket_for_server; EXPECT_TRUE(ble_server.StartAcceptingConnections( - service_id, { - .accepted_cb = - [&socket_for_server, &accept_latch]( - BleV2Socket socket, const std::string&) { - socket_for_server = std::move(socket); - accept_latch.CountDown(); - }, - })); + service_id, [&](BleV2Socket socket, const std::string&) { + socket_for_server = std::move(socket); + accept_latch.CountDown(); + })); ble_server.StartAdvertising(service_id, advertisement_bytes, PowerLevel::kHighPower, diff --git a/connections/implementation/mediums/bluetooth_classic.cc b/connections/implementation/mediums/bluetooth_classic.cc index ccf42d62..34803fd8 100644 --- a/connections/implementation/mediums/bluetooth_classic.cc +++ b/connections/implementation/mediums/bluetooth_classic.cc @@ -298,8 +298,9 @@ bool BluetoothClassic::StartAcceptingConnections( server_socket.Close(); break; } - - callback.accepted_cb(service_id, std::move(client_socket)); + if (callback) { + callback(service_id, std::move(client_socket)); + } } }); diff --git a/connections/implementation/mediums/bluetooth_classic.h b/connections/implementation/mediums/bluetooth_classic.h index 415129ec..8c84215f 100644 --- a/connections/implementation/mediums/bluetooth_classic.h +++ b/connections/implementation/mediums/bluetooth_classic.h @@ -17,9 +17,9 @@ #include #include -#include -#include #include +#include +#include #include "absl/container/flat_hash_map.h" #include "connections/implementation/mediums/bluetooth_radio.h" @@ -40,10 +40,8 @@ class BluetoothClassic { using ScanMode = BluetoothAdapter::ScanMode; // Callback that is invoked when a new connection is accepted. - struct AcceptedConnectionCallback { - std::function - accepted_cb = [](const std::string&, BluetoothSocket) {}; - }; + using AcceptedConnectionCallback = absl::AnyInvocable; explicit BluetoothClassic(BluetoothRadio& radio); ~BluetoothClassic(); diff --git a/connections/implementation/mediums/bluetooth_classic_test.cc b/connections/implementation/mediums/bluetooth_classic_test.cc index 8a1e771e..0c618524 100644 --- a/connections/implementation/mediums/bluetooth_classic_test.cc +++ b/connections/implementation/mediums/bluetooth_classic_test.cc @@ -162,13 +162,9 @@ TEST_P(BluetoothClassicTest, CanConnect) { CountDownLatch accept_latch(1); EXPECT_TRUE(bt_server.StartAcceptingConnections( std::string(kServiceName1), - { - .accepted_cb = - [&socket_for_server, &accept_latch](const std::string& service_id, - BluetoothSocket socket) { - socket_for_server = std::move(socket); - accept_latch.CountDown(); - }, + [&](const std::string& service_id, BluetoothSocket socket) { + socket_for_server = std::move(socket); + accept_latch.CountDown(); })); CancellationFlag flag; BluetoothSocket socket_for_client = @@ -217,13 +213,9 @@ TEST_P(BluetoothClassicTest, CanCancelBeforeConnect) { CountDownLatch accept_latch(1); EXPECT_TRUE(bt_server.StartAcceptingConnections( std::string(kServiceName1), - { - .accepted_cb = - [&socket_for_server, &accept_latch](const std::string& service_id, - BluetoothSocket socket) { - socket_for_server = std::move(socket); - accept_latch.CountDown(); - }, + [&](const std::string& service_id, BluetoothSocket socket) { + socket_for_server = std::move(socket); + accept_latch.CountDown(); })); CancellationFlag flag(true); BluetoothSocket socket_for_client = @@ -288,13 +280,9 @@ TEST_P(BluetoothClassicTest, CanCancelDuringConnect) { CountDownLatch accept_latch(1); EXPECT_TRUE(bt_server.StartAcceptingConnections( std::string(kServiceName1), - { - .accepted_cb = - [&socket_for_server, &accept_latch](const std::string& service_id, - BluetoothSocket socket) { - socket_for_server = std::move(socket); - accept_latch.CountDown(); - }, + [&](const std::string& service_id, BluetoothSocket socket) { + socket_for_server = std::move(socket); + accept_latch.CountDown(); })); CancellationFlag flag; BluetoothSocket socket_for_client = @@ -361,13 +349,9 @@ TEST_P(BluetoothClassicTest, CanCancelDuringConnect_MultipleEndpoints) { EXPECT_TRUE(bt_server.StartAcceptingConnections( std::string(kServiceName1), - { - .accepted_cb = - [&socket_for_server1, &accept_latch]( - const std::string& service_id, BluetoothSocket socket) { - socket_for_server1 = std::move(socket); - accept_latch.CountDown(); - }, + [&](const std::string& service_id, BluetoothSocket socket) { + socket_for_server1 = std::move(socket); + accept_latch.CountDown(); })); CancellationFlag flag; BluetoothSocket socket_for_client1 = @@ -378,13 +362,9 @@ TEST_P(BluetoothClassicTest, CanCancelDuringConnect_MultipleEndpoints) { medium_a_->CancelDuringConnectToService(); EXPECT_TRUE(bt_server.StartAcceptingConnections( std::string(kServiceName2), - { - .accepted_cb = - [&socket_for_server2, &accept_latch]( - const std::string& service_id, BluetoothSocket socket) { - socket_for_server2 = std::move(socket); - accept_latch.CountDown(); - }, + [&](const std::string& service_id, BluetoothSocket socket) { + socket_for_server2 = std::move(socket); + accept_latch.CountDown(); })); BluetoothSocket socket_for_client2 = diff --git a/connections/implementation/mediums/webrtc.cc b/connections/implementation/mediums/webrtc.cc index e02a81c2..21ad6e8c 100644 --- a/connections/implementation/mediums/webrtc.cc +++ b/connections/implementation/mediums/webrtc.cc @@ -107,7 +107,7 @@ bool WebRtc::StartAcceptingConnections(const std::string& service_id, // who may be also using WebRTC. AcceptingConnectionsInfo info = AcceptingConnectionsInfo(); info.self_peer_id = self_peer_id; - info.accepted_connection_callback = callback; + info.accepted_connection_callback = std::move(callback); // Create a new SignalingMessenger so that we can communicate w/ Tachyon. info.signaling_messenger = @@ -688,8 +688,9 @@ void WebRtc::ProcessDataChannelOpen(const std::string& service_id, const auto& accepting_connection_entry = accepting_connections_info_.find(service_id); - if (accepting_connection_entry != accepting_connections_info_.end()) { - accepting_connection_entry->second.accepted_connection_callback.accepted_cb( + if (accepting_connection_entry != accepting_connections_info_.end() && + accepting_connection_entry->second.accepted_connection_callback) { + accepting_connection_entry->second.accepted_connection_callback( service_id, socket_wrapper); return; } diff --git a/connections/implementation/mediums/webrtc.h b/connections/implementation/mediums/webrtc.h index 091cafb1..8e8eef39 100644 --- a/connections/implementation/mediums/webrtc.h +++ b/connections/implementation/mediums/webrtc.h @@ -17,13 +17,12 @@ #ifndef NO_WEBRTC -#include -#include #include #include #include #include "absl/container/flat_hash_map.h" +#include "absl/functional/any_invocable.h" #include "connections/implementation/mediums/webrtc/connection_flow.h" #include "connections/implementation/mediums/webrtc_peer_id.h" #include "connections/implementation/mediums/webrtc_socket.h" @@ -42,15 +41,13 @@ namespace nearby { namespace connections { namespace mediums { -// Callback that is invoked when a new connection is accepted. -struct AcceptedConnectionCallback { - std::function - accepted_cb = [](const std::string&, WebRtcSocketWrapper) {}; -}; - // Entry point for connecting a data channel between two devices via WebRtc. class WebRtc { public: + // Callback that is invoked when a new connection is accepted. + using AcceptedConnectionCallback = absl::AnyInvocable; + WebRtc(); ~WebRtc(); diff --git a/connections/implementation/mediums/webrtc/BUILD b/connections/implementation/mediums/webrtc/BUILD index 71e5abd2..2d15ee8d 100644 --- a/connections/implementation/mediums/webrtc/BUILD +++ b/connections/implementation/mediums/webrtc/BUILD @@ -39,7 +39,6 @@ cc_library( "//connections/implementation/mediums:utils", "//internal/platform:base", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:types", "//proto/mediums:web_rtc_signaling_frames_cc_proto", # TODO: Support WebRTC diff --git a/connections/implementation/mediums/webrtc/webrtc_socket_impl.cc b/connections/implementation/mediums/webrtc/webrtc_socket_impl.cc index 63e66752..96d1b9bb 100644 --- a/connections/implementation/mediums/webrtc/webrtc_socket_impl.cc +++ b/connections/implementation/mediums/webrtc/webrtc_socket_impl.cc @@ -12,10 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include +#include +#include + +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/pipe.h" #ifndef NO_WEBRTC #include "connections/implementation/mediums/webrtc/webrtc_socket_impl.h" - #include "internal/platform/logging.h" #include "internal/platform/mutex_lock.h" @@ -61,6 +69,7 @@ WebRtcSocket::WebRtcSocket( : name_(name), data_channel_(std::move(data_channel)) { NEARBY_LOGS(INFO) << "WebRtcSocket::WebRtcSocket(" << name_ << ") this: " << this; + std::tie(pipe_input_, pipe_output_) = CreatePipe(); data_channel_->RegisterObserver(this); } @@ -77,7 +86,7 @@ WebRtcSocket::~WebRtcSocket() { << ") this: " << this << " done"; } -InputStream& WebRtcSocket::GetInputStream() { return pipe_.GetInputStream(); } +InputStream& WebRtcSocket::GetInputStream() { return *pipe_input_; } OutputStream& WebRtcSocket::GetOutputStream() { return output_stream_; } @@ -129,12 +138,12 @@ void WebRtcSocket::OnMessage(const webrtc::DataBuffer& buffer) { // we don't block signaling. OffloadFromSignalingThread( [this, buffer = ByteArray(buffer.data.data(), buffer.size())] { - if (!pipe_.GetOutputStream().Write(buffer).Ok()) { + if (!pipe_output_->Write(buffer).Ok()) { Close(); return; } - if (!pipe_.GetOutputStream().Flush().Ok()) { + if (!pipe_output_->Flush().Ok()) { Close(); } }); @@ -159,8 +168,8 @@ void WebRtcSocket::ClosePipe() { // This is thread-safe to close these sockets even if a read or write is in // process on another thread, Close will wait for the exclusive mutex before // setting state. - pipe_.GetInputStream().Close(); - pipe_.GetOutputStream().Close(); + pipe_input_->Close(); + pipe_output_->Close(); WakeUpWriter(); NEARBY_LOGS(INFO) << "WebRtcSocket::ClosePipe(" << name_ << ") this: " << this << " done"; diff --git a/connections/implementation/mediums/webrtc/webrtc_socket_impl.h b/connections/implementation/mediums/webrtc/webrtc_socket_impl.h index beb1000d..723280b8 100644 --- a/connections/implementation/mediums/webrtc/webrtc_socket_impl.h +++ b/connections/implementation/mediums/webrtc/webrtc_socket_impl.h @@ -100,8 +100,8 @@ class WebRtcSocket : public Socket, public webrtc::DataChannelObserver { std::string name_; rtc::scoped_refptr data_channel_; - Pipe pipe_; - + std::unique_ptr pipe_input_; + std::unique_ptr pipe_output_; OutputStreamImpl output_stream_{this}; AtomicBoolean closed_{false}; diff --git a/connections/implementation/mediums/webrtc_stub.h b/connections/implementation/mediums/webrtc_stub.h index a0609d95..3bc01fe7 100644 --- a/connections/implementation/mediums/webrtc_stub.h +++ b/connections/implementation/mediums/webrtc_stub.h @@ -31,14 +31,13 @@ namespace nearby { namespace connections { namespace mediums { -// Callback that is invoked when a new connection is accepted. -struct AcceptedConnectionCallback { - std::function accepted_cb = - [](WebRtcSocketWrapper) {}; -}; + // Entry point for connecting a data channel between two devices via WebRtc. class WebRtc { public: + // Callback that is invoked when a new connection is accepted. + using AcceptedConnectionCallback = + absl::AnyInvocable; WebRtc(); ~WebRtc(); diff --git a/connections/implementation/mediums/webrtc_test.cc b/connections/implementation/mediums/webrtc_test.cc index 3b6bb0ca..3ab47b00 100644 --- a/connections/implementation/mediums/webrtc_test.cc +++ b/connections/implementation/mediums/webrtc_test.cc @@ -80,11 +80,11 @@ TEST_P(WebRtcTest, ConnectBothDevices_ShutdownSignaling_SendData) { receiver.StartAcceptingConnections( service_id, self_id, location_hint, - {[&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { + [&receiver_socket, connected](const std::string& service_id, + WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); - }}); + }); CancellationFlag flag; sender_socket = sender.Connect(service_id, self_id, location_hint, &flag); @@ -119,11 +119,11 @@ TEST_P(WebRtcTest, CanCancelConnect) { receiver.StartAcceptingConnections( service_id, self_id, location_hint, - {[&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { + [&receiver_socket, connected](const std::string& service_id, + WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); - }}); + }); CancellationFlag flag(true); sender_socket = sender.Connect(service_id, self_id, location_hint, &flag); @@ -173,10 +173,10 @@ TEST_F(WebRtcTest, StartAcceptingConnectionTwice) { ASSERT_TRUE(webrtc.IsAvailable()); ASSERT_TRUE(webrtc.StartAcceptingConnections( service_id, self_id, location_hint, - {mock_accepted_callback_.AsStdFunction()})); + mock_accepted_callback_.AsStdFunction())); EXPECT_FALSE(webrtc.StartAcceptingConnections( service_id, self_id, location_hint, - {mock_accepted_callback_.AsStdFunction()})); + mock_accepted_callback_.AsStdFunction())); EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id)); EXPECT_FALSE(webrtc.IsAcceptingConnections(std::string{})); env_.Stop(); @@ -197,8 +197,8 @@ TEST_F(WebRtcTest, Connect_NoPeer) { webrtc.Connect(service_id, peer_id, location_hint, &flag); EXPECT_FALSE(wrapper_1.IsValid()); - EXPECT_TRUE(webrtc.StartAcceptingConnections( - service_id, peer_id, location_hint, AcceptedConnectionCallback())); + EXPECT_TRUE(webrtc.StartAcceptingConnections(service_id, peer_id, + location_hint, nullptr)); env_.Stop(); } @@ -215,7 +215,7 @@ TEST_F(WebRtcTest, StartAcceptingConnection_ThenConnect) { ASSERT_TRUE(webrtc.IsAvailable()); ASSERT_TRUE(webrtc.StartAcceptingConnections( service_id, self_id, location_hint, - {mock_accepted_callback_.AsStdFunction()})); + mock_accepted_callback_.AsStdFunction())); CancellationFlag flag; WebRtcSocketWrapper wrapper = webrtc.Connect( service_id, WebrtcPeerId("random_peer_id"), location_hint, &flag); @@ -223,7 +223,7 @@ TEST_F(WebRtcTest, StartAcceptingConnection_ThenConnect) { EXPECT_FALSE(wrapper.IsValid()); EXPECT_FALSE(webrtc.StartAcceptingConnections( service_id, self_id, location_hint, - {mock_accepted_callback_.AsStdFunction()})); + mock_accepted_callback_.AsStdFunction())); env_.Stop(); } @@ -240,7 +240,7 @@ TEST_F(WebRtcTest, StartAndStopAcceptingConnections) { ASSERT_TRUE(webrtc.IsAvailable()); ASSERT_TRUE(webrtc.StartAcceptingConnections( service_id, self_id, location_hint, - {mock_accepted_callback_.AsStdFunction()})); + mock_accepted_callback_.AsStdFunction())); EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id)); webrtc.StopAcceptingConnections(service_id); EXPECT_FALSE(webrtc.IsAcceptingConnections(service_id)); @@ -261,15 +261,15 @@ TEST_F(WebRtcTest, ConnectTwice) { receiver.StartAcceptingConnections( service_id, self_id, location_hint, - {[&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { + [&receiver_socket, connected](const std::string& service_id, + WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); - }}); + }); device_c.StartAcceptingConnections( service_id, other_id, location_hint, - {[](const std::string& service_id, WebRtcSocketWrapper wrapper) {}}); + [](const std::string& service_id, WebRtcSocketWrapper wrapper) {}); CancellationFlag flag; sender_socket = sender.Connect(service_id, self_id, location_hint, &flag); @@ -311,11 +311,11 @@ TEST_F(WebRtcTest, ConnectBothDevicesAndAbort) { receiver.StartAcceptingConnections( service_id, self_id, location_hint, - {[&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { + [&receiver_socket, connected](const std::string& service_id, + WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); - }}); + }); CancellationFlag flag; sender_socket = sender.Connect(service_id, self_id, location_hint, &flag); @@ -343,11 +343,11 @@ TEST_F(WebRtcTest, ConnectBothDevicesAndSendData) { receiver.StartAcceptingConnections( service_id, self_id, location_hint, - {[&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { + [&receiver_socket, connected](const std::string& service_id, + WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); - }}); + }); CancellationFlag flag; sender_socket = sender.Connect(service_id, self_id, location_hint, &flag); @@ -399,7 +399,7 @@ TEST_F(WebRtcTest, ContinueAcceptingConnectionsOnComplete) { ASSERT_TRUE(webrtc.IsAvailable()); ASSERT_TRUE(webrtc.StartAcceptingConnections( service_id, self_id, location_hint, - {mock_accepted_callback_.AsStdFunction()})); + mock_accepted_callback_.AsStdFunction())); EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id)); // Simulate a failure in receiving messages stream, WebRtc should restart @@ -450,11 +450,11 @@ TEST_F(WebRtcTest, CancelDuringConnect) { receiver->StartAcceptingConnections( service_id, self_id, location_hint, - {[&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { + [&receiver_socket, connected](const std::string& service_id, + WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); - }}); + }); sender_socket = sender->Connect(service_id, self_id, location_hint, &sender_flag); @@ -496,11 +496,11 @@ TEST_F(WebRtcTest, CancelBeforeConnect) { receiver->StartAcceptingConnections( service_id, self_id, location_hint, - {[&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { + [&receiver_socket, connected](const std::string& service_id, + WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); - }}); + }); sender_socket = sender->Connect(service_id, self_id, location_hint, &sender_flag); @@ -541,11 +541,11 @@ TEST_F(WebRtcTest, CancelDuringConnect_MultipleConnect) { receiver->StartAcceptingConnections( ns_service_id, self_id, location_hint, - {[&receiver_socket, connected](const std::string& ns_service_id, - WebRtcSocketWrapper wrapper) mutable { + [&receiver_socket, connected](const std::string& ns_service_id, + WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); - }}); + }); // Simulate a successful connect for the endpoint of NearbySharing. sender_socket = sender->Connect(ns_service_id, self_id, location_hint, &flag); diff --git a/connections/implementation/mediums/wifi_direct.cc b/connections/implementation/mediums/wifi_direct.cc index aa03650d..81020856 100644 --- a/connections/implementation/mediums/wifi_direct.cc +++ b/connections/implementation/mediums/wifi_direct.cc @@ -185,7 +185,9 @@ bool WifiDirect::StartAcceptingConnections( server_socket.Close(); break; } - callback.accepted_cb(service_id, std::move(client_socket)); + if (callback) { + callback(service_id, std::move(client_socket)); + } } }); diff --git a/connections/implementation/mediums/wifi_direct.h b/connections/implementation/mediums/wifi_direct.h index f4ef22af..899b7d71 100644 --- a/connections/implementation/mediums/wifi_direct.h +++ b/connections/implementation/mediums/wifi_direct.h @@ -29,10 +29,8 @@ namespace connections { class WifiDirect { public: // Callback that is invoked when a new connection is accepted. - struct AcceptedConnectionCallback { - std::function - accepted_cb = [](const std::string&, WifiDirectSocket) {}; - }; + using AcceptedConnectionCallback = absl::AnyInvocable; WifiDirect() : is_go_started_(false), is_connected_to_go_(false) {} ~WifiDirect(); diff --git a/connections/implementation/mediums/wifi_hotspot.cc b/connections/implementation/mediums/wifi_hotspot.cc index 27b8256e..8605ad1d 100644 --- a/connections/implementation/mediums/wifi_hotspot.cc +++ b/connections/implementation/mediums/wifi_hotspot.cc @@ -14,8 +14,8 @@ #include "connections/implementation/mediums/wifi_hotspot.h" -#include #include +#include #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" @@ -188,7 +188,9 @@ bool WifiHotspot::StartAcceptingConnections( server_socket.Close(); break; } - callback.accepted_cb(service_id, std::move(client_socket)); + if (callback) { + callback(service_id, std::move(client_socket)); + } } }); diff --git a/connections/implementation/mediums/wifi_hotspot.h b/connections/implementation/mediums/wifi_hotspot.h index 7ca8e210..6b63eac7 100644 --- a/connections/implementation/mediums/wifi_hotspot.h +++ b/connections/implementation/mediums/wifi_hotspot.h @@ -29,10 +29,8 @@ namespace connections { class WifiHotspot { public: // Callback that is invoked when a new connection is accepted. - struct AcceptedConnectionCallback { - std::function - accepted_cb = [](const std::string&, WifiHotspotSocket) {}; - }; + using AcceptedConnectionCallback = absl::AnyInvocable; WifiHotspot() : is_hotspot_started_(false), is_connected_to_hotspot_(false) {} ~WifiHotspot(); diff --git a/connections/implementation/mediums/wifi_lan.cc b/connections/implementation/mediums/wifi_lan.cc index 44b18caa..2c3e262e 100644 --- a/connections/implementation/mediums/wifi_lan.cc +++ b/connections/implementation/mediums/wifi_lan.cc @@ -264,7 +264,9 @@ bool WifiLan::StartAcceptingConnections(const std::string& service_id, server_socket.Close(); break; } - callback.accepted_cb(service_id, std::move(client_socket)); + if (callback) { + callback(service_id, std::move(client_socket)); + } } }); diff --git a/connections/implementation/mediums/wifi_lan.h b/connections/implementation/mediums/wifi_lan.h index 9c0dd271..b9d53f22 100644 --- a/connections/implementation/mediums/wifi_lan.h +++ b/connections/implementation/mediums/wifi_lan.h @@ -36,10 +36,8 @@ class WifiLan { using DiscoveredServiceCallback = WifiLanMedium::DiscoveredServiceCallback; // Callback that is invoked when a new connection is accepted. - struct AcceptedConnectionCallback { - std::function - accepted_cb = [](const std::string&, WifiLanSocket) {}; - }; + using AcceptedConnectionCallback = absl::AnyInvocable; WifiLan() = default; ~WifiLan(); diff --git a/connections/implementation/mediums/wifi_lan_test.cc b/connections/implementation/mediums/wifi_lan_test.cc index fd23f51a..acd1df81 100644 --- a/connections/implementation/mediums/wifi_lan_test.cc +++ b/connections/implementation/mediums/wifi_lan_test.cc @@ -68,14 +68,9 @@ TEST_P(WifiLanTest, CanConnect) { WifiLanSocket socket_for_server; EXPECT_TRUE(wifi_lan_server.StartAcceptingConnections( - service_id, - { - .accepted_cb = - [&socket_for_server, &accept_latch](const std::string& service_id, - WifiLanSocket socket) { - socket_for_server = std::move(socket); - accept_latch.CountDown(); - }, + service_id, [&](const std::string& service_id, WifiLanSocket socket) { + socket_for_server = std::move(socket); + accept_latch.CountDown(); })); NsdServiceInfo nsd_service_info; @@ -125,14 +120,9 @@ TEST_P(WifiLanTest, CanCancelConnect) { WifiLanSocket socket_for_server; EXPECT_TRUE(wifi_lan_server.StartAcceptingConnections( - service_id, - { - .accepted_cb = - [&socket_for_server, &accept_latch](const std::string& service_id, - WifiLanSocket socket) { - socket_for_server = std::move(socket); - accept_latch.CountDown(); - }, + service_id, [&](const std::string& service_id, WifiLanSocket socket) { + socket_for_server = std::move(socket); + accept_latch.CountDown(); })); NsdServiceInfo nsd_service_info; diff --git a/connections/implementation/mock_service_controller_router.h b/connections/implementation/mock_service_controller_router.h index 9133fd1a..4d8ea108 100644 --- a/connections/implementation/mock_service_controller_router.h +++ b/connections/implementation/mock_service_controller_router.h @@ -26,118 +26,113 @@ class MockServiceControllerRouter : public ServiceControllerRouter { MOCK_METHOD(void, StartAdvertising, (ClientProxy * client, absl::string_view service_id, const AdvertisingOptions& advertising_options, - const ConnectionRequestInfo& info, - const ResultCallback& callback), + const ConnectionRequestInfo& info, ResultCallback callback), (override)); MOCK_METHOD(void, StopAdvertising, - (ClientProxy * client, const ResultCallback& callback), - (override)); + (ClientProxy * client, ResultCallback callback), (override)); MOCK_METHOD(void, StartDiscovery, (ClientProxy * client, absl::string_view service_id, const DiscoveryOptions& discovery_options, - const DiscoveryListener& listener, - const ResultCallback& callback), + const DiscoveryListener& listener, ResultCallback callback), (override)); MOCK_METHOD(void, StopDiscovery, - (ClientProxy * client, const ResultCallback& callback), - (override)); + (ClientProxy * client, ResultCallback callback), (override)); MOCK_METHOD(void, InjectEndpoint, (ClientProxy * client, absl::string_view service_id, const OutOfBandConnectionMetadata& metadata, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, RequestConnection, (ClientProxy * client, absl::string_view endpoint_id, const ConnectionRequestInfo& info, const ConnectionOptions& connection_options, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, AcceptConnection, (ClientProxy * client, absl::string_view endpoint_id, - PayloadListener listener, const ResultCallback& callback), + PayloadListener listener, ResultCallback callback), (override)); MOCK_METHOD(void, RejectConnection, (ClientProxy * client, absl::string_view endpoint_id, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, InitiateBandwidthUpgrade, (ClientProxy * client, absl::string_view endpoint_id, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, SendPayload, (ClientProxy * client, absl::Span endpoint_ids, - Payload payload, const ResultCallback& callback), + Payload payload, ResultCallback callback), (override)); MOCK_METHOD(void, CancelPayload, (ClientProxy * client, std::uint64_t payload_id, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, DisconnectFromEndpoint, (ClientProxy * client, absl::string_view endpoint_id, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, StopAllEndpoints, - (ClientProxy * client, const ResultCallback& callback), - (override)); + (ClientProxy * client, ResultCallback callback), (override)); MOCK_METHOD(void, SetCustomSavePath, (ClientProxy * client, absl::string_view path, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, RequestConnectionV3, (ClientProxy * client, const NearbyDevice&, v3::ConnectionRequestInfo, const ConnectionOptions&, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, AcceptConnectionV3, (ClientProxy * client, const NearbyDevice&, v3::PayloadListener, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, RejectConnectionV3, (ClientProxy * client, const NearbyDevice&, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, InitiateBandwidthUpgradeV3, (ClientProxy * client, const NearbyDevice&, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, SendPayloadV3, (ClientProxy * client, const NearbyDevice&, Payload, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, DisconnectFromDeviceV3, (ClientProxy * client, const NearbyDevice&, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, UpdateAdvertisingOptionsV3, (ClientProxy * client, absl::string_view service_id, const AdvertisingOptions& advertising_options, - const ResultCallback& callback), + ResultCallback callback), (override)); MOCK_METHOD(void, UpdateDiscoveryOptionsV3, (ClientProxy * client, absl::string_view service_id, const DiscoveryOptions& discovery_options, - const ResultCallback& callback), + ResultCallback callback), (override)); }; diff --git a/connections/implementation/offline_frames.cc b/connections/implementation/offline_frames.cc index fcebbddc..395d2a99 100644 --- a/connections/implementation/offline_frames.cc +++ b/connections/implementation/offline_frames.cc @@ -14,14 +14,17 @@ #include "connections/implementation/offline_frames.h" +#include #include #include #include #include +#include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/offline_frames_validator.h" #include "connections/implementation/proto/offline_wire_formats.pb.h" #include "connections/status.h" +#include "internal/flags/nearby_flags.h" #include "internal/platform/byte_array.h" namespace nearby { @@ -165,7 +168,8 @@ ByteArray ForConnectionRequestPresence( return ToBytes(std::move(frame)); } -ByteArray ForConnectionResponse(std::int32_t status, const OsInfo& os_info) { +ByteArray ForConnectionResponse( + std::int32_t status, const OsInfo& os_info) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); @@ -181,6 +185,10 @@ ByteArray ForConnectionResponse(std::int32_t status, const OsInfo& os_info) { ? ConnectionResponseFrame::ACCEPT : ConnectionResponseFrame::REJECT); *sub_frame->mutable_os_info() = os_info; + sub_frame->set_safe_to_disconnect_version( + NearbyFlags::GetInstance().GetInt64Flag( + config_package_nearby::nearby_connections_feature:: + kSafeToDisconnectVersion)); return ToBytes(std::move(frame)); } @@ -445,13 +453,16 @@ ByteArray ForKeepAlive() { return ToBytes(std::move(frame)); } -ByteArray ForDisconnection() { +ByteArray ForDisconnection(bool request_safe_to_disconnect, + bool ack_safe_to_disconnect) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::DISCONNECTION); - v1_frame->mutable_disconnection(); + auto* disconnection = v1_frame->mutable_disconnection(); + disconnection->set_request_safe_to_disconnect(request_safe_to_disconnect); + disconnection->set_ack_safe_to_disconnect(ack_safe_to_disconnect); return ToBytes(std::move(frame)); } diff --git a/connections/implementation/offline_frames.h b/connections/implementation/offline_frames.h index 6a66d9f7..fb6214ab 100644 --- a/connections/implementation/offline_frames.h +++ b/connections/implementation/offline_frames.h @@ -98,8 +98,8 @@ ByteArray ForBwuLastWrite(); ByteArray ForBwuSafeToClose(); ByteArray ForKeepAlive(); -ByteArray ForDisconnection(); - +ByteArray ForDisconnection(bool request_safe_to_disconnect, + bool ack_safe_to_disconnect); UpgradePathInfo::Medium MediumToUpgradePathInfoMedium(Medium medium); Medium UpgradePathInfoMediumToMedium(UpgradePathInfo::Medium medium); diff --git a/connections/implementation/offline_frames_test.cc b/connections/implementation/offline_frames_test.cc index a1b14320..55d1e8a1 100644 --- a/connections/implementation/offline_frames_test.cc +++ b/connections/implementation/offline_frames_test.cc @@ -269,6 +269,7 @@ TEST(OfflineFramesTest, CanGenerateConnectionResponse) { status: 1 response: REJECT os_info { type: LINUX } + safe_to_disconnect_version: 2 > >)pb"; @@ -538,6 +539,25 @@ TEST(OfflineFramesTest, CanGenerateKeepAlive) { EXPECT_THAT(message, EqualsProto(kExpected)); } +TEST(OfflineFramesTest, CanGenerateDisconnection) { + constexpr absl::string_view kExpected = + R"pb( + version: V1 + v1: < + type: DISCONNECTION + disconnection: < + request_safe_to_disconnect: true + ack_safe_to_disconnect: true + > + >)pb"; + ByteArray bytes = ForDisconnection(/* request_safe_to_disconnect */ true, + /* ack_safe_to_disconnect */ true); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = response.result(); + EXPECT_THAT(message, EqualsProto(kExpected)); +} + } // namespace } // namespace parser } // namespace connections diff --git a/connections/implementation/offline_service_controller_test.cc b/connections/implementation/offline_service_controller_test.cc index 3cedc81c..5173dc1f 100644 --- a/connections/implementation/offline_service_controller_test.cc +++ b/connections/implementation/offline_service_controller_test.cc @@ -12,31 +12,42 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/offline_service_controller.h" - #include +#include +#include +#include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/strings/string_view.h" #include "absl/time/time.h" +#include "connections/advertising_options.h" +#include "connections/discovery_options.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/offline_simulation_user.h" +#include "connections/listeners.h" +#include "connections/medium_selector.h" +#include "connections/out_of_band_connection_metadata.h" +#include "connections/payload.h" #include "connections/status.h" +#include "connections/strategy.h" #include "internal/flags/nearby_flags.h" +#include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" +#include "internal/platform/input_stream.h" #include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" #include "internal/platform/output_stream.h" #include "internal/platform/pipe.h" -#include "internal/platform/system_clock.h" +#include "proto/connections_enums.proto.h" namespace nearby { namespace connections { namespace { using ::testing::Eq; - +constexpr size_t kChunkSize = 64 * 1024; constexpr std::array kFakeMacAddress = {'a', 'b', 'c', 'd', 'e', 'f'}; constexpr absl::string_view kServiceId = "service-id"; constexpr absl::string_view kDeviceA = "device-a"; @@ -83,6 +94,9 @@ class OfflineServiceControllerTest void SetUp() override { NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature::kEnableBleV2, true); + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature:: + kEnableSafeToDisconnect, false); } bool SetupConnection(OfflineSimulationUser& user_a, OfflineSimulationUser& user_b) { @@ -284,10 +298,10 @@ TEST_P(OfflineServiceControllerTest, CanSendBytePayload) { env_.Start(); OfflineSimulationUser user_a(kDeviceA, GetParam()); OfflineSimulationUser user_b(kDeviceB, GetParam()); + user_b.ExpectPayload(payload_latch_); ASSERT_TRUE(SetupConnection(user_a, user_b)); ByteArray message(std::string{kMessage}); user_a.SendPayload(Payload(message)); - user_b.ExpectPayload(payload_latch_); EXPECT_TRUE(payload_latch_.Await(kLongTimeout)); EXPECT_EQ(user_b.GetPayload().AsBytes(), message); user_a.Stop(); @@ -299,15 +313,12 @@ TEST_P(OfflineServiceControllerTest, CanSendStreamPayload) { env_.Start(); OfflineSimulationUser user_a(kDeviceA, GetParam()); OfflineSimulationUser user_b(kDeviceB, GetParam()); + user_b.ExpectPayload(payload_latch_); ASSERT_TRUE(SetupConnection(user_a, user_b)); ByteArray message(std::string{kMessage}); - auto pipe = std::make_shared(); - OutputStream& tx = pipe->GetOutputStream(); - user_a.SendPayload(Payload([pipe]() -> InputStream& { - return pipe->GetInputStream(); // NOLINT - })); - user_b.ExpectPayload(payload_latch_); - tx.Write(message); + auto [input, tx] = CreatePipe(); + user_a.SendPayload(Payload(std::move(input))); + tx->Write(message); EXPECT_TRUE(payload_latch_.Await(kLongTimeout)); ASSERT_NE(user_b.GetPayload().AsStream(), nullptr); InputStream& rx = *user_b.GetPayload().AsStream(); @@ -316,7 +327,7 @@ TEST_P(OfflineServiceControllerTest, CanSendStreamPayload) { return info.bytes_transferred >= size; }, kLongTimeout)); - EXPECT_EQ(rx.Read(Pipe::kChunkSize).result(), message); + EXPECT_EQ(rx.Read(kChunkSize).result(), message); user_a.Stop(); user_b.Stop(); env_.Stop(); @@ -326,15 +337,12 @@ TEST_P(OfflineServiceControllerTest, CanCancelStreamPayload) { env_.Start(); OfflineSimulationUser user_a(kDeviceA, GetParam()); OfflineSimulationUser user_b(kDeviceB, GetParam()); + user_b.ExpectPayload(payload_latch_); ASSERT_TRUE(SetupConnection(user_a, user_b)); ByteArray message(std::string{kMessage}); - auto pipe = std::make_shared(); - OutputStream& tx = pipe->GetOutputStream(); - user_a.SendPayload(Payload([pipe]() -> InputStream& { - return pipe->GetInputStream(); // NOLINT - })); - user_b.ExpectPayload(payload_latch_); - tx.Write(message); + auto [input, tx] = CreatePipe(); + user_a.SendPayload(Payload(std::move(input))); + tx->Write(message); EXPECT_TRUE(payload_latch_.Await(kLongTimeout)); ASSERT_NE(user_b.GetPayload().AsStream(), nullptr); InputStream& rx = *user_b.GetPayload().AsStream(); @@ -343,11 +351,11 @@ TEST_P(OfflineServiceControllerTest, CanCancelStreamPayload) { return info.bytes_transferred >= size; }, kLongTimeout)); - EXPECT_EQ(rx.Read(Pipe::kChunkSize).result(), message); + EXPECT_EQ(rx.Read(kChunkSize).result(), message); user_b.CancelPayload(); absl::Time start_time = SystemClock::ElapsedRealtime(); while (true) { - if (!tx.Write(message).Ok()) break; + if (!tx->Write(message).Ok()) break; absl::Duration run_time = SystemClock::ElapsedRealtime() - start_time; if (run_time >= kLongTimeout) { EXPECT_LT(run_time, kLongTimeout); diff --git a/connections/implementation/offline_simulation_user.cc b/connections/implementation/offline_simulation_user.cc index 03cfaa80..ae31da9f 100644 --- a/connections/implementation/offline_simulation_user.cc +++ b/connections/implementation/offline_simulation_user.cc @@ -14,6 +14,7 @@ #include "connections/implementation/offline_simulation_user.h" +#include "absl/functional/any_invocable.h" #include "absl/functional/bind_front.h" #include "connections/listeners.h" #include "internal/platform/byte_array.h" @@ -86,7 +87,7 @@ void OfflineSimulationUser::OnPayloadProgress(absl::string_view endpoint_id, } bool OfflineSimulationUser::WaitForProgress( - std::function predicate, + absl::AnyInvocable predicate, absl::Duration timeout) { Future future; { diff --git a/connections/implementation/offline_simulation_user.h b/connections/implementation/offline_simulation_user.h index af92d05b..12e46d60 100644 --- a/connections/implementation/offline_simulation_user.h +++ b/connections/implementation/offline_simulation_user.h @@ -18,6 +18,7 @@ #include #include "gtest/gtest.h" +#include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/offline_service_controller.h" @@ -131,8 +132,9 @@ class OfflineSimulationUser { const DiscoveredInfo& GetDiscovered() const { return discovered_; } ByteArray GetInfo() const { return info_; } - bool WaitForProgress(std::function pred, - absl::Duration timeout); + bool WaitForProgress( + absl::AnyInvocable pred, + absl::Duration timeout); Payload& GetPayload() { return payload_; } void SendPayload(Payload payload) { @@ -203,7 +205,7 @@ class OfflineSimulationUser { CountDownLatch* payload_latch_ = nullptr; CountDownLatch* disconnect_latch_ = nullptr; Future* future_ = nullptr; - std::function predicate_; + absl::AnyInvocable predicate_; ClientProxy client_; OfflineServiceController ctrl_; }; diff --git a/connections/implementation/p2p_cluster_pcp_handler.cc b/connections/implementation/p2p_cluster_pcp_handler.cc index ba7155d5..da91affa 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.cc +++ b/connections/implementation/p2p_cluster_pcp_handler.cc @@ -298,78 +298,77 @@ void P2pClusterPcpHandler::BluetoothNameChangedHandler( BluetoothDevice device) { RunOnPcpHandlerThread( "p2p-bt-name-changed", - [this, client, service_id, device]() - RUN_ON_PCP_HANDLER_THREAD() { - // Make sure we are still discovering before proceeding. - if (!client->IsDiscovering()) { - NEARBY_LOGS(WARNING) - << "Ignoring lost BluetoothDevice " << device.GetName() - << " because Connections is no longer discovering."; - return; - } + [this, client, service_id, device]() RUN_ON_PCP_HANDLER_THREAD() { + // Make sure we are still discovering before proceeding. + if (!client->IsDiscovering()) { + NEARBY_LOGS(WARNING) + << "Ignoring lost BluetoothDevice " << device.GetName() + << " because Connections is no longer discovering."; + return; + } - // Parse the Bluetooth device name. - const std::string device_name_string = device.GetName(); - BluetoothDeviceName device_name(device_name_string); - NEARBY_LOGS(INFO) - << "BT discovery handler (CHANGED) [client_id=" - << client->GetClientId() << ", service_id=" << service_id - << "]: processing new name " << device_name_string; + // Parse the Bluetooth device name. + const std::string device_name_string = device.GetName(); + BluetoothDeviceName device_name(device_name_string); + NEARBY_LOGS(INFO) << "BT discovery handler (CHANGED) [client_id=" + << client->GetClientId() + << ", service_id=" << service_id + << "]: processing new name " << device_name_string; - // By this point, the BluetoothDevice passed to us has a different - // name than what we may have discovered before. We need to iterate - // over the found BluetoothEndpoints and compare their addresses to - // see the devices are the same. We are not guaranteed to discover a - // match, since the old name may not have been formatted for Nearby - // Connections. - for (auto endpoint : GetDiscoveredEndpoints(Medium::BLUETOOTH)) { - BluetoothEndpoint* bluetoothEndpoint = - static_cast(endpoint); - NEARBY_LOGS(INFO) - << "BT discovery handler (CHANGED) [client_id=" - << client->GetClientId() << ", service_id=" << service_id - << "]: comparing MAC addresses with existing endpoint " - << bluetoothEndpoint->bluetooth_device.GetName() - << ". They have MAC address " - << bluetoothEndpoint->bluetooth_device.GetMacAddress() - << " and the new endpoint has MAC address " - << device.GetMacAddress(); - if (bluetoothEndpoint->bluetooth_device.GetMacAddress() == - device.GetMacAddress()) { - // Report the BluetoothEndpoint as lost to the client. - NEARBY_LOGS(INFO) - << "Reporting lost BluetoothDevice " - << bluetoothEndpoint->bluetooth_device.GetName() - << ", due to device name change."; - OnEndpointLost(client, *endpoint); - break; - } - } + // By this point, the BluetoothDevice passed to us has a different + // name than what we may have discovered before. We need to iterate + // over the found BluetoothEndpoints and compare their addresses to + // see the devices are the same. We are not guaranteed to discover a + // match, since the old name may not have been formatted for Nearby + // Connections. + for (auto endpoint : GetDiscoveredEndpoints(Medium::BLUETOOTH)) { + BluetoothEndpoint* bluetoothEndpoint = + static_cast(endpoint); + NEARBY_LOGS(INFO) + << "BT discovery handler (CHANGED) [client_id=" + << client->GetClientId() << ", service_id=" << service_id + << "]: comparing MAC addresses with existing endpoint " + << bluetoothEndpoint->bluetooth_device.GetName() + << ". They have MAC address " + << bluetoothEndpoint->bluetooth_device.GetMacAddress() + << " and the new endpoint has MAC address " + << device.GetMacAddress(); + if (bluetoothEndpoint->bluetooth_device.GetMacAddress() == + device.GetMacAddress()) { + // Report the BluetoothEndpoint as lost to the client. + NEARBY_LOGS(INFO) << "Reporting lost BluetoothDevice " + << bluetoothEndpoint->bluetooth_device.GetName() + << ", due to device name change."; + OnEndpointLost(client, *endpoint); + break; + } + } - // Make sure the Bluetooth device name points to a valid - // endpoint we're discovering. - if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id, - device_name)) { - NEARBY_LOGS(INFO) << "Found unrecognized BluetoothDeviceName " - << device_name_string; - return; - } + // Make sure the Bluetooth device name points to a valid + // endpoint we're discovering. + if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id, + device_name)) { + NEARBY_LOGS(INFO) << "Found unrecognized BluetoothDeviceName " + << device_name_string; + return; + } - // Report the discovered endpoint to the client. - NEARBY_LOGS(INFO) - << "Found BluetoothDeviceName " << device_name_string - << " (with endpoint_id=" << device_name.GetEndpointId() - << " and endpoint_info=" - << absl::BytesToHexString(device_name.GetEndpointInfo().data()) - << ")."; - OnEndpointFound( - client, std::make_shared(BluetoothEndpoint{ - {device_name.GetEndpointId(), - device_name.GetEndpointInfo(), service_id, - Medium::BLUETOOTH, device_name.GetWebRtcState()}, - device, - })); - }); + // Report the discovered endpoint to the client. + NEARBY_LOGS(INFO) << "Found BluetoothDeviceName " << device_name_string + << " (with endpoint_id=" + << device_name.GetEndpointId() + << " and endpoint_info=" + << absl::BytesToHexString( + device_name.GetEndpointInfo().data()) + << ")."; + OnEndpointFound( + client, + std::make_shared(BluetoothEndpoint{ + {device_name.GetEndpointId(), device_name.GetEndpointInfo(), + service_id, Medium::BLUETOOTH, device_name.GetWebRtcState()}, + device, + })); + }); } void P2pClusterPcpHandler::BluetoothDeviceLostHandler( @@ -1088,10 +1087,10 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl( !bluetooth_medium_.IsAcceptingConnections(std::string(service_id))) { if (!bluetooth_medium_.StartAcceptingConnections( std::string(service_id), - {.accepted_cb = absl::bind_front( - &P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, - this, client_proxy, local_endpoint_id, - options.listening_endpoint_type)})) { + absl::bind_front( + &P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, this, + client_proxy, local_endpoint_id, + options.listening_endpoint_type))) { NEARBY_LOGS(WARNING) << "Failed to start listening for incoming connections on Bluetooth"; } else { @@ -1107,10 +1106,10 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl( !ble_v2_medium_.IsAcceptingConnections(std::string(service_id))) { if (!ble_v2_medium_.StartAcceptingConnections( std::string(service_id), - {.accepted_cb = absl::bind_front( - &P2pClusterPcpHandler::BleV2ConnectionAcceptedHandler, this, - client_proxy, local_endpoint_id, - options.listening_endpoint_type)})) { + absl::bind_front( + &P2pClusterPcpHandler::BleV2ConnectionAcceptedHandler, this, + client_proxy, local_endpoint_id, + options.listening_endpoint_type))) { NEARBY_LOGS(WARNING) << "Failed to start listening for incoming connections on ble_v2"; } else { @@ -1123,10 +1122,10 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl( !ble_medium_.IsAcceptingConnections(std::string(service_id))) { if (!ble_medium_.StartAcceptingConnections( std::string(service_id), - {.accepted_cb = absl::bind_front( - &P2pClusterPcpHandler::BleConnectionAcceptedHandler, this, - client_proxy, local_endpoint_id, - options.listening_endpoint_type)})) { + absl::bind_front( + &P2pClusterPcpHandler::BleConnectionAcceptedHandler, this, + client_proxy, local_endpoint_id, + options.listening_endpoint_type))) { NEARBY_LOGS(WARNING) << "Failed to start listening for incoming connections on ble"; } else { @@ -1138,10 +1137,10 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl( !wifi_lan_medium_.IsAcceptingConnections(std::string(service_id))) { if (!wifi_lan_medium_.StartAcceptingConnections( std::string(service_id), - {.accepted_cb = absl::bind_front( - &P2pClusterPcpHandler::WifiLanConnectionAcceptedHandler, this, - client_proxy, local_endpoint_id, "", - options.listening_endpoint_type)})) { + absl::bind_front( + &P2pClusterPcpHandler::WifiLanConnectionAcceptedHandler, this, + client_proxy, local_endpoint_id, "", + options.listening_endpoint_type))) { NEARBY_LOGS(WARNING) << "Failed to start listening for incoming connections on wifi_lan"; } else { @@ -1459,10 +1458,10 @@ Medium P2pClusterPcpHandler::StartBluetoothAdvertising( if (!bluetooth_radio_.Enable() || !bluetooth_medium_.StartAcceptingConnections( service_id, - {.accepted_cb = absl::bind_front( - &P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, - this, client, local_endpoint_info.AsStringView(), - NearbyDevice::Type::kConnectionsDevice)})) { + absl::bind_front( + &P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, this, + client, local_endpoint_info.AsStringView(), + NearbyDevice::Type::kConnectionsDevice))) { NEARBY_LOGS(WARNING) << "In StartBluetoothAdvertising(" << absl::BytesToHexString(local_endpoint_info.data()) @@ -1636,11 +1635,10 @@ Medium P2pClusterPcpHandler::StartBleAdvertising( if (!ble_medium_.IsAcceptingConnections(service_id)) { if (!bluetooth_radio_.Enable() || !ble_medium_.StartAcceptingConnections( - service_id, - {.accepted_cb = absl::bind_front( - &P2pClusterPcpHandler::BleConnectionAcceptedHandler, this, - client, local_endpoint_info.AsStringView(), - NearbyDevice::Type::kConnectionsDevice)})) { + service_id, absl::bind_front( + &P2pClusterPcpHandler::BleConnectionAcceptedHandler, + this, client, local_endpoint_info.AsStringView(), + NearbyDevice::Type::kConnectionsDevice))) { NEARBY_LOGS(WARNING) << "In StartBleAdvertising(" << absl::BytesToHexString(local_endpoint_info.data()) @@ -1665,10 +1663,10 @@ Medium P2pClusterPcpHandler::StartBleAdvertising( if (!bluetooth_radio_.Enable() || !bluetooth_medium_.StartAcceptingConnections( service_id, - {.accepted_cb = absl::bind_front( - &P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, - this, client, local_endpoint_info.AsStringView(), - NearbyDevice::Type::kConnectionsDevice)})) { + absl::bind_front( + &P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, + this, client, local_endpoint_info.AsStringView(), + NearbyDevice::Type::kConnectionsDevice))) { NEARBY_LOGS(WARNING) << "In BT StartBleAdvertising(" << absl::BytesToHexString(local_endpoint_info.data()) @@ -1846,10 +1844,10 @@ Medium P2pClusterPcpHandler::StartBleV2Advertising( if (!bluetooth_radio_.Enable() || !ble_v2_medium_.StartAcceptingConnections( service_id, - {.accepted_cb = absl::bind_front( - &P2pClusterPcpHandler::BleV2ConnectionAcceptedHandler, this, - client, local_endpoint_info.AsStringView(), - NearbyDevice::Type::kConnectionsDevice)})) { + absl::bind_front( + &P2pClusterPcpHandler::BleV2ConnectionAcceptedHandler, this, + client, local_endpoint_info.AsStringView(), + NearbyDevice::Type::kConnectionsDevice))) { NEARBY_LOGS(WARNING) << "In StartBleAdvertising(" << absl::BytesToHexString(local_endpoint_info.data()) @@ -1877,10 +1875,10 @@ Medium P2pClusterPcpHandler::StartBleV2Advertising( if (!bluetooth_radio_.Enable() || !bluetooth_medium_.StartAcceptingConnections( service_id, - {.accepted_cb = absl::bind_front( - &P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, - this, client, local_endpoint_info.AsStringView(), - NearbyDevice::Type::kConnectionsDevice)})) { + absl::bind_front( + &P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, + this, client, local_endpoint_info.AsStringView(), + NearbyDevice::Type::kConnectionsDevice))) { NEARBY_LOGS(WARNING) << "In BT StartBleAdvertising(" << absl::BytesToHexString(local_endpoint_info.data()) @@ -2058,10 +2056,10 @@ Medium P2pClusterPcpHandler::StartWifiLanAdvertising( if (!wifi_lan_medium_.IsAcceptingConnections(service_id)) { if (!wifi_lan_medium_.StartAcceptingConnections( service_id, - {.accepted_cb = absl::bind_front( - &P2pClusterPcpHandler::WifiLanConnectionAcceptedHandler, this, - client, local_endpoint_id, local_endpoint_info.AsStringView(), - NearbyDevice::Type::kConnectionsDevice)})) { + absl::bind_front( + &P2pClusterPcpHandler::WifiLanConnectionAcceptedHandler, this, + client, local_endpoint_id, local_endpoint_info.AsStringView(), + NearbyDevice::Type::kConnectionsDevice))) { NEARBY_LOGS(WARNING) << "In StartWifiLanAdvertising(" << absl::BytesToHexString(local_endpoint_info.data()) @@ -2165,9 +2163,6 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WifiLanConnectImpl( WifiLanSocket socket = wifi_lan_medium_.Connect( endpoint->service_id, endpoint->service_info, client->GetCancellationFlag(endpoint->endpoint_id)); - NEARBY_LOGS(INFO) << "In WifiLanConnectImpl(), connect to service " - << " socket=" << &socket.GetImpl() - << " for endpoint(id=" << endpoint->endpoint_id << ")."; if (!socket.IsValid()) { NEARBY_LOGS(ERROR) << "In WifiLanConnectImpl(), failed to connect to service " @@ -2177,6 +2172,9 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WifiLanConnectImpl( .status = {Status::kWifiLanError}, }; } + NEARBY_LOGS(INFO) << "In WifiLanConnectImpl(), connect to service " + << " socket=" << &socket.GetImpl() + << " for endpoint(id=" << endpoint->endpoint_id << ")."; auto channel = std::make_unique( endpoint->service_id, /*channel_name=*/endpoint->endpoint_id, socket); diff --git a/connections/implementation/p2p_cluster_pcp_handler.h b/connections/implementation/p2p_cluster_pcp_handler.h index a53fc8fd..aa1c3950 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.h +++ b/connections/implementation/p2p_cluster_pcp_handler.h @@ -113,7 +113,8 @@ class P2pClusterPcpHandler : public BasePcpHandler { ClientProxy* client, absl::string_view service_id, absl::string_view local_endpoint_id, absl::string_view local_endpoint_info, - const DiscoveryOptions& discovery_options) override; + const DiscoveryOptions& discovery_options) + RUN_ON_PCP_HANDLER_THREAD() override; private: // Holds the state required to re-create a BleEndpoint we see on a diff --git a/connections/implementation/p2p_cluster_pcp_handler_test.cc b/connections/implementation/p2p_cluster_pcp_handler_test.cc index 689536ce..5ca45ecf 100644 --- a/connections/implementation/p2p_cluster_pcp_handler_test.cc +++ b/connections/implementation/p2p_cluster_pcp_handler_test.cc @@ -16,6 +16,7 @@ #include #include +#include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" @@ -690,6 +691,7 @@ TEST_P(P2pClusterPcpHandlerTest, CanConnect) { EXPECT_EQ(client_a_.GetIPAddress(client_b_local_endpoint), mediums_b.GetWifi().GetInformation().ip_address_4_bytes); + handler_b.StopDiscovery(&client_b_); bwu_a.Shutdown(); bwu_b.Shutdown(); env_.Stop(); diff --git a/connections/implementation/payload_manager.cc b/connections/implementation/payload_manager.cc index fe42ce23..349b8cb2 100644 --- a/connections/implementation/payload_manager.cc +++ b/connections/implementation/payload_manager.cc @@ -15,30 +15,39 @@ #include "connections/implementation/payload_manager.h" #include -#include +#include #include #include #include #include #include -#include "absl/memory/memory.h" +#include "absl/functional/any_invocable.h" +#include "absl/functional/bind_front.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" #include "absl/time/time.h" #include "connections/implementation/analytics/throughput_recorder.h" +#include "connections/implementation/client_proxy.h" +#include "connections/implementation/endpoint_channel_manager.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/internal_payload_factory.h" +#include "connections/payload_type.h" #include "internal/flags/nearby_flags.h" #include "internal/platform/count_down_latch.h" +#include "internal/platform/exception.h" +#include "internal/platform/feature_flags.h" #include "internal/platform/logging.h" #include "internal/platform/mutex_lock.h" #include "internal/platform/single_thread_executor.h" +#include "proto/connections_enums.pb.h" namespace nearby { namespace connections { using ::location::nearby::connections::OfflineFrame; using ::location::nearby::connections::V1Frame; +using ::location::nearby::proto::connections::PayloadStatus; using ::nearby::analytics::PacketMetaData; using ::nearby::analytics::ThroughputRecorderContainer; using ::nearby::connections::PayloadDirection; @@ -155,7 +164,7 @@ bool PayloadManager::SendPayloadLoop( location::nearby::proto::connections:: PayloadStatus::ENDPOINT_IO_ERROR); } - + bool is_last_chunk = IsLastChunk(payload_chunk); // Check whether at least one endpoint succeeded -- if they all failed, // we'll just go right back to the top of the loop and break out when // availableEndpointIds is re-synced and found to be empty at that point. @@ -163,6 +172,12 @@ bool PayloadManager::SendPayloadLoop( for (const auto& endpoint_id : available_endpoint_ids) { if (std::find(failed_endpoint_ids.begin(), failed_endpoint_ids.end(), endpoint_id) == failed_endpoint_ids.end()) { + if (!WaitForReceivedAck(client, endpoint_id, pending_payload, + payload_header, next_chunk_offset, + is_last_chunk)) { + continue; + } + HandleSuccessfulOutgoingChunk( client, endpoint_id, payload_header, payload_chunk.flags(), payload_chunk.offset(), payload_chunk.body().size()); @@ -279,9 +294,11 @@ Payload::Id PayloadManager::CreateOutgoingPayload( NEARBY_LOGS(INFO) << "CreateOutgoingPayload: payload_id=" << payload_id; MutexLock lock(&mutex_); pending_payloads_.StartTrackingPayload( - payload_id, absl::make_unique(std::move(internal_payload), - endpoint_ids, - /*is_incoming=*/false)); + payload_id, + std::make_unique( + std::move(internal_payload), endpoint_ids, + /*is_incoming=*/false, + absl::bind_front(&PayloadManager::OnPendingPayloadDestroy, this))); return payload_id; } @@ -297,18 +314,17 @@ void PayloadManager::CancelAllPayloads() { { MutexLock lock(&mutex_); int pending_outgoing_payloads = 0; - for (const auto& pending_id : pending_payloads_.GetAllPayloads()) { - auto* pending = pending_payloads_.GetPayload(pending_id); + pending_payloads_.ForEachPayload([&](PendingPayload* pending) { if (!pending->IsIncoming()) pending_outgoing_payloads++; pending->MarkLocallyCanceled(); pending->Close(); // To unblock the sender thread, if there is no data. - } + }); + if (pending_outgoing_payloads) { shutdown_barrier_ = - absl::make_unique(pending_outgoing_payloads); + std::make_unique(pending_outgoing_payloads); } } - if (shutdown_barrier_) { NEARBY_LOG(INFO, "PayloadManager: waiting for pending outgoing payloads; self=%p", @@ -342,9 +358,7 @@ PayloadManager::~PayloadManager() { NEARBY_LOG(INFO, "PayloadManager: stop tracking payloads; self=%p", this); MutexLock lock(&mutex_); - for (const auto& pending_id : pending_payloads_.GetAllPayloads()) { - pending_payloads_.StopTrackingPayload(pending_id); - } + pending_payloads_.StopTrackingAllPayloads(); stop_latch.CountDown(); }); stop_latch.Await(); @@ -419,7 +433,7 @@ void PayloadManager::SendPayload(ClientProxy* client, "send-payload", [this, client, endpoint_ids, payload_id, payload_type, resume_offset, payload_total_size]() { if (shutdown_.Get()) return; - PendingPayload* pending_payload = GetPayload(payload_id); + PendingPayloadHandle pending_payload = GetPayload(payload_id); if (!pending_payload) { RecordInvalidPayloadAnalytics(client, endpoint_ids, payload_id, payload_type, resume_offset, @@ -455,8 +469,6 @@ void PayloadManager::SendPayload(ClientProxy* client, next_chunk_offset, resume_offset); } - ThroughputRecorderContainer::GetInstance().StopTPRecorder( - payload_id, PayloadDirection::OUTGOING_PAYLOAD); RunOnStatusUpdateThread("destroy-payload", [this, payload_id]() RUN_ON_PAYLOAD_STATUS_UPDATE_THREAD() { @@ -468,15 +480,14 @@ void PayloadManager::SendPayload(ClientProxy* client, << ", payload_type=" << ToString(payload_type); } -PayloadManager::PendingPayload* PayloadManager::GetPayload( +PayloadManager::PendingPayloadHandle PayloadManager::GetPayload( Payload::Id payload_id) const { - MutexLock lock(&mutex_); return pending_payloads_.GetPayload(payload_id); } Status PayloadManager::CancelPayload(ClientProxy* client, Payload::Id payload_id) { - PendingPayload* canceled_payload = GetPayload(payload_id); + PendingPayloadHandle canceled_payload = GetPayload(payload_id); if (!canceled_payload) { NEARBY_LOGS(INFO) << "Client requested cancel for unknown payload_id=" << payload_id << ", ignoring."; @@ -525,58 +536,70 @@ void PayloadManager::OnIncomingFrame( void PayloadManager::OnEndpointDisconnect(ClientProxy* client, const std::string& service_id, const std::string& endpoint_id, - CountDownLatch barrier) { + CountDownLatch barrier, + DisconnectionReason reason) { if (shutdown_.Get()) { barrier.CountDown(); return; } RunOnStatusUpdateThread( "payload-manager-on-disconnect", - [this, client, endpoint_id, barrier]() - RUN_ON_PAYLOAD_STATUS_UPDATE_THREAD() mutable { - // Iterate through all our payloads and look for payloads associated - // with this endpoint. - MutexLock lock(&mutex_); - for (const auto& payload_id : pending_payloads_.GetAllPayloads()) { - auto* pending_payload = pending_payloads_.GetPayload(payload_id); - if (!pending_payload) continue; - auto endpoint_info = pending_payload->GetEndpoint(endpoint_id); - if (!endpoint_info) continue; - std::int64_t endpoint_offset = endpoint_info->offset; - // Stop tracking the endpoint for this payload. - pending_payload->RemoveEndpoints({endpoint_id}); - // |endpoint_info| is longer valid after calling RemoveEndpoints. - endpoint_info = nullptr; + [this, client, endpoint_id, + barrier, reason]() RUN_ON_PAYLOAD_STATUS_UPDATE_THREAD() mutable { + // Iterate through all our payloads and look for payloads associated + // with this endpoint. + MutexLock lock(&mutex_); + pending_payloads_.ForEachPayload([&](PendingPayload* pending_payload) { + auto endpoint_info = pending_payload->GetEndpoint(endpoint_id); + if (!endpoint_info) return; + std::int64_t endpoint_offset = endpoint_info->offset; + // Stop tracking the endpoint for this payload. + pending_payload->RemoveEndpoints({endpoint_id}); + // |endpoint_info| is longer valid after calling + // RemoveEndpoints. + endpoint_info = nullptr; - std::int64_t payload_total_size = - pending_payload->GetInternalPayload()->GetTotalSize(); + std::int64_t payload_total_size = + pending_payload->GetInternalPayload()->GetTotalSize(); - // If no endpoints are left for this payload, close it. - if (pending_payload->GetEndpoints().empty()) { - pending_payload->Close(); + // If no endpoints are left for this payload, close it. + if (pending_payload->GetEndpoints().empty()) { + pending_payload->Close(); + } + // Create the payload transfer update. + PayloadProgressInfo update{pending_payload->GetId(), + PayloadProgressInfo::Status::kFailure, + payload_total_size, endpoint_offset}; + + // Send a client notification of a payload transfer failure. + client->OnPayloadProgress(endpoint_id, update); + + PayloadStatus payload_status; + switch (reason) { + case DisconnectionReason::LOCAL_DISCONNECTION: + payload_status = PayloadStatus::LOCAL_CLIENT_DISCONNECTION; + break; + case DisconnectionReason::REMOTE_DISCONNECTION: + payload_status = PayloadStatus::REMOTE_CLIENT_DISCONNECTION; + break; + case DisconnectionReason::IO_ERROR: + default: + payload_status = PayloadStatus::ENDPOINT_IO_ERROR; + break; } - // Create the payload transfer update. - PayloadProgressInfo update{payload_id, - PayloadProgressInfo::Status::kFailure, - payload_total_size, endpoint_offset}; - // Send a client notification of a payload transfer failure. - client->OnPayloadProgress(endpoint_id, update); + if (pending_payload->IsIncoming()) { + client->GetAnalyticsRecorder().OnIncomingPayloadDone( + endpoint_id, pending_payload->GetId(), payload_status); + } else { + client->GetAnalyticsRecorder().OnOutgoingPayloadDone( + endpoint_id, pending_payload->GetId(), payload_status); + } + }); - if (pending_payload->IsIncoming()) { - client->GetAnalyticsRecorder().OnIncomingPayloadDone( - endpoint_id, pending_payload->GetId(), - location::nearby::proto::connections::ENDPOINT_IO_ERROR); - } else { - client->GetAnalyticsRecorder().OnOutgoingPayloadDone( - endpoint_id, pending_payload->GetId(), - location::nearby::proto::connections::ENDPOINT_IO_ERROR); - } - } - - barrier.CountDown(); - }); + barrier.CountDown(); + }); } location::nearby::proto::connections::PayloadStatus @@ -686,25 +709,37 @@ PayloadTransferFrame::PayloadChunk PayloadManager::CreatePayloadChunk( return payload_chunk; } -PayloadManager::PendingPayload* PayloadManager::CreateIncomingPayload( +PayloadManager::PendingPayloadHandle PayloadManager::CreateIncomingPayload( const PayloadTransferFrame& frame, const std::string& endpoint_id) { auto internal_payload = CreateIncomingInternalPayload(frame, custom_save_path_); if (!internal_payload) { - return nullptr; + return PendingPayloadHandle(); } Payload::Id payload_id = internal_payload->GetId(); NEARBY_LOGS(INFO) << "CreateIncomingPayload: payload_id=" << payload_id; - MutexLock lock(&mutex_); pending_payloads_.StartTrackingPayload( payload_id, - absl::make_unique(std::move(internal_payload), - EndpointIds{endpoint_id}, true)); - + std::make_unique( + std::move(internal_payload), EndpointIds{endpoint_id}, true, + absl::bind_front(&PayloadManager::OnPendingPayloadDestroy, this))); return pending_payloads_.GetPayload(payload_id); } +void PayloadManager::OnPendingPayloadDestroy(const PendingPayload* payload) { + NEARBY_LOGS(INFO) << "PayloadManager: destroying " << payload->ToString() + << " self=" << this; + ThroughputRecorderContainer::GetInstance().StopTPRecorder( + payload->GetId(), payload->IsIncoming() + ? PayloadDirection::INCOMING_PAYLOAD + : PayloadDirection::OUTGOING_PAYLOAD); + if (payload->IsIncoming()) return; + RunOnStatusUpdateThread( + "~PendingPayload", + [this]() RUN_ON_PAYLOAD_STATUS_UPDATE_THREAD() { NotifyShutdown(); }); +} + void PayloadManager::SendClientCallbacksForFinishedOutgoingPayload( ClientProxy* client, const EndpointIds& finished_endpoint_ids, const PayloadTransferFrame::PayloadHeader& payload_header, @@ -716,7 +751,7 @@ void PayloadManager::SendClientCallbacksForFinishedOutgoingPayload( num_bytes_successfully_transferred, status]() RUN_ON_PAYLOAD_STATUS_UPDATE_THREAD() { // Make sure we're still tracking this payload. - PendingPayload* pending_payload = GetPayload(payload_header.id()); + PendingPayloadHandle pending_payload = GetPayload(payload_header.id()); if (!pending_payload) { return; } @@ -760,13 +795,14 @@ void PayloadManager::SendClientCallbacksForFinishedIncomingPayload( [this, client, endpoint_id, payload_header, offset_bytes, status]() RUN_ON_PAYLOAD_STATUS_UPDATE_THREAD() { // Make sure we're still tracking this payload. - PendingPayload* pending_payload = GetPayload(payload_header.id()); + PendingPayloadHandle pending_payload = GetPayload(payload_header.id()); if (!pending_payload) { return; } - // Unless we never started tracking this payload (meaning we failed to - // even create the InternalPayload), notify the client (and close it). + // Unless we never started tracking this payload (meaning we + // failed to even create the InternalPayload), notify the client + // (and close it). PayloadProgressInfo update{ payload_header.id(), PayloadManager::PayloadStatusToTransferUpdateStatus(status), @@ -793,6 +829,99 @@ void PayloadManager::SendControlMessage( endpoint_ids); } +void PayloadManager::SendPayloadReceivedAck( + ClientProxy* client, PendingPayload& pending_payload, + const std::string& endpoint_id, + const PayloadTransferFrame::PayloadHeader& payload_header, + std::int64_t chunk_size, bool is_last_chunk) { + if (!is_last_chunk || + !IsPayloadReceivedAckEnabled(client, endpoint_id, pending_payload)) { + return; + } + // Send the PAYLOAD_RECEIVED_ACK to the remote endpoint for the sender asap. + NEARBY_LOGS(INFO) + << "[PAYLOAD_RECEIVED_ACK] isLastChunk, receiver send ack to " + << endpoint_id; + + SendControlMessage( + {endpoint_id}, payload_header, chunk_size, + PayloadTransferFrame::ControlMessage::PAYLOAD_RECEIVED_ACK); +} + +bool PayloadManager::WaitForReceivedAck( + ClientProxy* client, const std::string& endpoint_id, + PendingPayload& pending_payload, + const PayloadTransferFrame::PayloadHeader& payload_header, + std::int64_t payload_chunk_offset, bool is_last_chunk) { + if (!is_last_chunk || + !IsPayloadReceivedAckEnabled(client, endpoint_id, pending_payload)) { + return true; + } + + NEARBY_LOGS(INFO) << "[safe-to-disconnect] Last Chunk, sender wait for " + "PAYLOAD_RECEIVED_ACK frame from: " + << endpoint_id; + while (true) { + PendingPayloadHandle latest_pending_payload = + GetPayload(payload_header.id()); + // Make sure we're still tracking this payload and its associated endpoint. + if (!latest_pending_payload) { + return false; + } + + auto* endpoint_info = latest_pending_payload->GetEndpoint(endpoint_id); + if (endpoint_info == nullptr) { + return false; + } + + // Local payload cancellation + if (latest_pending_payload->IsLocallyCanceled()) { + HandleFinishedOutgoingPayload(client, {endpoint_id}, payload_header, + payload_chunk_offset, + location::nearby::proto::connections:: + PayloadStatus::LOCAL_CANCELLATION); + return false; + } + // Remote payload cancellation, etc + if (!endpoint_info->IsEndpointAvailable(client, + endpoint_info->status.Get())) { + HandleFinishedOutgoingPayload( + client, {endpoint_id}, payload_header, payload_chunk_offset, + EndpointInfoStatusToPayloadStatus(endpoint_info->status.Get())); + return false; + } + { + MutexLock lock(&endpoint_info->payload_received_ack_mutex); + if (endpoint_info->is_payload_received_ack) { + endpoint_info->is_payload_received_ack = false; + return true; + } + Exception wait_exception = endpoint_info->payload_received_ack_cond.Wait( + FeatureFlags::GetInstance() + .GetFlags() + .wait_payload_received_ack_millis); + endpoint_info->is_payload_received_ack = false; + if (!wait_exception.Ok()) { + return false; + } + return true; + } + } + return true; +} + +bool PayloadManager::IsPayloadReceivedAckEnabled( + ClientProxy* client, const std::string& endpoint_id, + PendingPayload& pending_payload) { + return NearbyFlags::GetInstance().GetBoolFlag( + config_package_nearby::nearby_connections_feature:: + kEnablePayloadReceivedAck) && + client->IsPayloadReceivedAckEnabled(endpoint_id) && + (pending_payload.GetInternalPayload()->GetType() != + nearby::connections::PayloadTransferFrame::PayloadTransferFrame:: + PayloadHeader::BYTES); +} + void PayloadManager::HandleFinishedOutgoingPayload( ClientProxy* client, const EndpointIds& finished_endpoint_ids, const PayloadTransferFrame::PayloadHeader& payload_header, @@ -823,7 +952,8 @@ void PayloadManager::HandleFinishedOutgoingPayload( // Unregister these endpoints, since we had an IO error on the physical // connection. for (const auto& endpoint_id : finished_endpoint_ids) { - endpoint_manager_->DiscardEndpoint(client, endpoint_id); + endpoint_manager_->DiscardEndpoint(client, endpoint_id, + DisconnectionReason::IO_ERROR); } break; case location::nearby::proto::connections::PayloadStatus::REMOTE_ERROR: @@ -845,8 +975,6 @@ void PayloadManager::HandleFinishedIncomingPayload( const PayloadTransferFrame::PayloadHeader& payload_header, std::int64_t offset_bytes, location::nearby::proto::connections::PayloadStatus status) { - ThroughputRecorderContainer::GetInstance().StopTPRecorder( - payload_header.id(), PayloadDirection::INCOMING_PAYLOAD); SendClientCallbacksForFinishedIncomingPayload( client, endpoint_id, payload_header, offset_bytes, status); @@ -903,12 +1031,14 @@ void PayloadManager::HandleSuccessfulOutgoingChunk( if (!is_last_chunk && payload_chunk_offset != 0) { NEARBY_LOGS(INFO) << "Skip the outgoing chunk update with offset=" << payload_chunk_offset; + client->GetAnalyticsRecorder().OnPayloadChunkSent( + endpoint_id, payload_header.id(), payload_chunk_body_size); return; } } } - PendingPayload* pending_payload = GetPayload(payload_header.id()); + PendingPayloadHandle pending_payload = GetPayload(payload_header.id()); if (!pending_payload || !pending_payload->GetEndpoint(endpoint_id)) { NEARBY_LOGS(INFO) << "HandleSuccessfulOutgoingChunk: endpoint not found: " @@ -949,20 +1079,7 @@ void PayloadManager::HandleSuccessfulOutgoingChunk( // @PayloadManagerStatusUpdateThread void PayloadManager::DestroyPendingPayload(Payload::Id payload_id) { - bool is_incoming = false; - { - MutexLock lock(&mutex_); - auto pending = pending_payloads_.StopTrackingPayload(payload_id); - if (!pending) return; - is_incoming = pending->IsIncoming(); - const char* direction = is_incoming ? "incoming" : "outgoing"; - NEARBY_LOGS(INFO) << "PayloadManager: destroying " << direction - << " pending payload: self=" << this - << "; payload_id=" << payload_id; - pending->Close(); - pending.reset(); - } - if (!is_incoming) NotifyShutdown(); + pending_payloads_.StopTrackingPayload(payload_id); } void PayloadManager::HandleSuccessfulIncomingChunk( @@ -998,12 +1115,14 @@ void PayloadManager::HandleSuccessfulIncomingChunk( if (!is_last_chunk && payload_chunk_offset != 0) { NEARBY_LOGS(INFO) << "Skip the incoming chunk update with offset=" << payload_chunk_offset; + client->GetAnalyticsRecorder().OnPayloadChunkReceived( + endpoint_id, payload_header.id(), payload_chunk_body_size); return; } } } - PendingPayload* pending_payload = GetPayload(payload_header.id()); + PendingPayloadHandle pending_payload = GetPayload(payload_header.id()); if (!pending_payload) { return; } @@ -1044,11 +1163,11 @@ void PayloadManager::ProcessDataPacket( << payload_header.id() << " from endpoint_id=" << from_endpoint_id << " at offset " << payload_chunk.offset(); - - PendingPayload* pending_payload; + Payload::Id payload_id = payload_header.id(); + PendingPayloadHandle pending_payload; if (payload_chunk.offset() == 0) { ThroughputRecorderContainer::GetInstance() - .GetTPRecorder(payload_header.id(), PayloadDirection::INCOMING_PAYLOAD) + .GetTPRecorder(payload_id, PayloadDirection::INCOMING_PAYLOAD) ->Start((PayloadType)payload_header.type(), PayloadDirection::INCOMING_PAYLOAD); packet_meta_data.Reset(); @@ -1077,12 +1196,13 @@ void PayloadManager::ProcessDataPacket( PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR); return; } - // Also, let the client know of this new incoming payload. RunOnStatusUpdateThread( "process-data-packet", - [to_client, from_endpoint_id, pending_payload]() + [to_client, from_endpoint_id, + pending_payload = GetPayload(payload_id)]() RUN_ON_PAYLOAD_STATUS_UPDATE_THREAD() { + if (!pending_payload) return; NEARBY_LOGS(INFO) << "PayloadManager received new payload_id=" << pending_payload->GetInternalPayload()->GetId() @@ -1093,17 +1213,17 @@ void PayloadManager::ProcessDataPacket( }); } else { pending_payload = GetPayload(payload_header.id()); - if (!pending_payload) { - NEARBY_LOGS(WARNING) << "ProcessDataPacket: [missing] endpoint_id=" - << from_endpoint_id - << "; payload_id=" << payload_header.id(); - return; - } } + if (!pending_payload) { + NEARBY_LOGS(WARNING) << "ProcessDataPacket: [missing] endpoint_id=" + << from_endpoint_id + << "; payload_id=" << payload_header.id(); + return; + } if (pending_payload->IsLocallyCanceled()) { - // This incoming payload was canceled by the client. Drop this frame and do - // all the cleanup. See go/nc-cancel-payload + // This incoming payload was canceled by the client. Drop this frame and + // do all the cleanup. See go/nc-cancel-payload NEARBY_LOGS(INFO) << "ProcessDataPacket: [cancel] endpoint_id=" << from_endpoint_id << "; payload_id=" << pending_payload->GetId(); @@ -1115,15 +1235,16 @@ void PayloadManager::ProcessDataPacket( } // Update the offset for this payload. An endpoint disconnection might occur - // from another thread and we would need to know the current offset to report - // back to the client. For the sake of accuracy, we update the pending payload - // here because it's after all payload terminating events are handled, but - // right before we actually start attaching the next chunk. + // from another thread and we would need to know the current offset to + // report back to the client. For the sake of accuracy, we update the + // pending payload here because it's after all payload terminating events + // are handled, but right before we actually start attaching the next chunk. pending_payload->SetOffsetForEndpoint(from_endpoint_id, payload_chunk.offset()); // Save size of packet before we move it. std::int64_t payload_body_size = payload_chunk.body().size(); + packet_meta_data.StartFileIo(); if (pending_payload->GetInternalPayload() ->AttachNextChunk(ByteArray(std::move(*payload_chunk.mutable_body()))) @@ -1137,6 +1258,11 @@ void PayloadManager::ProcessDataPacket( return; } packet_meta_data.StopFileIo(); + bool is_last_chunk = (payload_chunk.flags() & + PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0; + SendPayloadReceivedAck( + to_client, *pending_payload, from_endpoint_id, payload_header, + payload_chunk.offset() + payload_body_size, is_last_chunk); HandleSuccessfulIncomingChunk(to_client, from_endpoint_id, payload_header, payload_chunk.flags(), payload_chunk.offset(), @@ -1145,15 +1271,10 @@ void PayloadManager::ProcessDataPacket( ThroughputRecorderContainer::GetInstance() .GetTPRecorder(payload_header.id(), PayloadDirection::INCOMING_PAYLOAD) ->OnFrameReceived(medium, packet_meta_data); - bool is_last_chunk = (payload_chunk.flags() & - PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0; if (is_last_chunk) { ThroughputRecorderContainer::GetInstance() .GetTPRecorder(payload_header.id(), PayloadDirection::INCOMING_PAYLOAD) ->MarkAsSuccess(); - - ThroughputRecorderContainer::GetInstance().StopTPRecorder( - payload_header.id(), PayloadDirection::INCOMING_PAYLOAD); } } @@ -1165,7 +1286,7 @@ void PayloadManager::ProcessControlPacket( payload_transfer_frame.payload_header(); const PayloadTransferFrame::ControlMessage& control_message = payload_transfer_frame.control_message(); - PendingPayload* pending_payload = GetPayload(payload_header.id()); + PendingPayloadHandle pending_payload = GetPayload(payload_header.id()); if (!pending_payload) { NEARBY_LOGS(INFO) << "Got ControlMessage for unknown payload_id=" << payload_header.id() @@ -1209,6 +1330,17 @@ void PayloadManager::ProcessControlPacket( control_message); } break; + case PayloadTransferFrame::ControlMessage::PAYLOAD_RECEIVED_ACK: + if (!pending_payload->IsIncoming() && + IsPayloadReceivedAckEnabled(to_client, from_endpoint_id, + *pending_payload)) { + NEARBY_LOGS(INFO) << "[safe-to-disconnect]Sender received " + "PAYLOAD_RECEIVED_ACK frame with id:" + << pending_payload->GetInternalPayload()->GetId() + << " from endpoint_id=" << from_endpoint_id; + pending_payload->MarkReceivedAckFromEndpoint(from_endpoint_id); + } + break; default: NEARBY_LOGS(INFO) << "Unhandled control message " << control_message.event() << " for payload_id=" @@ -1266,7 +1398,8 @@ void PayloadManager::SetCustomSavePath(ClientProxy* client, custom_save_path_ = path; } -///////////////////////////////// EndpointInfo ///////////////////////////////// +///////////////////////////////// EndpointInfo +//////////////////////////////////// PayloadManager::EndpointInfo::Status PayloadManager::EndpointInfo::ControlMessageEventToEndpointInfoStatus( @@ -1292,19 +1425,40 @@ void PayloadManager::EndpointInfo::SetStatusFromControlMessage( << " based on OOB ControlMessage"; } +void PayloadManager::EndpointInfo::MarkReceivedAckFromEndpoint() { + MutexLock lock(&payload_received_ack_mutex); + is_payload_received_ack = true; + payload_received_ack_cond.Notify(); +} + +bool PayloadManager::EndpointInfo::IsEndpointAvailable( + ClientProxy* clientProxy, EndpointInfo::Status status) { + // Pending endpointIds would be removed from the payload after + // onPayloadTransferUpdate, but there is the racing problem that gets the + // available endpoints before update. Here force to remove those endpoints + // (b/227419433). + bool is_pending_endpoint = false; + if (clientProxy->HasPendingConnectionToEndpoint(id)) { + is_pending_endpoint = true; + } + return (status == EndpointInfo::Status::kAvailable) && !is_pending_endpoint; +} + //////////////////////////////// PendingPayload //////////////////////////////// PayloadManager::PendingPayload::PendingPayload( std::unique_ptr internal_payload, - const EndpointIds& endpoint_ids, bool is_incoming) + const EndpointIds& endpoint_ids, bool is_incoming, + DestroyCallback destroy_callback) : is_incoming_(is_incoming), - internal_payload_(std::move(internal_payload)) { + internal_payload_(std::move(internal_payload)), + destroy_callback_(std::move(destroy_callback)) { // Initially we mark all endpoints as available. // Later on some may become canceled, some may experience data transfer // failures. Any of these situations will cause endpoint to be marked as // unavailable. for (const auto& id : endpoint_ids) { - EndpointInfo endpoint_info{}; + EndpointInfo endpoint_info; endpoint_info.id = id; endpoint_info.status.Set(EndpointInfo::Status::kAvailable); @@ -1328,6 +1482,13 @@ void PayloadManager::PendingPayload::MarkLocallyCanceled() { is_locally_canceled_.Set(true); } +void PayloadManager::PendingPayload::MarkReceivedAckFromEndpoint( + const std::string& from_endpoint_id) { + auto info = GetEndpoint(from_endpoint_id); + if (!info) return; + info->MarkReceivedAckFromEndpoint(); +} + bool PayloadManager::PendingPayload::IsIncoming() const { return is_incoming_; } std::vector @@ -1384,66 +1545,123 @@ void PayloadManager::PendingPayload::SetOffsetForEndpoint( } void PayloadManager::PendingPayload::Close() { + bool was_closed = is_closed_.Set(true); + if (was_closed) return; if (internal_payload_) internal_payload_->Close(); - close_event_.CountDown(); } -bool PayloadManager::PendingPayload::WaitForClose() { - return close_event_.Await(kWaitCloseTimeout).result(); -} - -bool PayloadManager::PendingPayload::IsClosed() { - return close_event_.Await(absl::ZeroDuration()).result(); -} - -void PayloadManager::RunOnStatusUpdateThread(const std::string& name, - std::function runnable) { +void PayloadManager::RunOnStatusUpdateThread( + const std::string& name, absl::AnyInvocable runnable) { payload_status_update_executor_.Execute(name, std::move(runnable)); } -/////////////////////////////// PendingPayloads /////////////////////////////// +/////////////////////////////// PendingPayloads +////////////////////////////////// void PayloadManager::PendingPayloads::StartTrackingPayload( Payload::Id payload_id, std::unique_ptr pending_payload) { MutexLock lock(&mutex_); // If the |payload_id| is being re-used, always prefer the newer payload. - auto it = pending_payloads_.find(payload_id); - if (it != pending_payloads_.end()) { - pending_payloads_.erase(payload_id); - } - auto pair = pending_payloads_.emplace(payload_id, std::move(pending_payload)); - NEARBY_LOGS(INFO) << "StartTrackingPayload: payload_id=" << payload_id - << "; inserted=" << pair.second; + Remove(pending_payloads_.find(payload_id)); + NEARBY_LOGS(INFO) << "StartTrackingPayload: " << pending_payload->ToString(); + pending_payload->IncRefCount(); + pending_payloads_[payload_id] = std::move(pending_payload); } -std::unique_ptr -PayloadManager::PendingPayloads::StopTrackingPayload(Payload::Id payload_id) { +void PayloadManager::PendingPayloads::StopTrackingPayload( + Payload::Id payload_id) { MutexLock lock(&mutex_); - - auto it = pending_payloads_.find(payload_id); - if (it == pending_payloads_.end()) return {}; - - auto item = pending_payloads_.extract(it); - return std::move(item.mapped()); + NEARBY_LOGS(INFO) << "StopTrackingPayload " << payload_id; + Remove(pending_payloads_.find(payload_id)); } -PayloadManager::PendingPayload* PayloadManager::PendingPayloads::GetPayload( - Payload::Id payload_id) const { +void PayloadManager::PendingPayloads::Remove( + absl::flat_hash_map>::iterator + it) { + if (it != pending_payloads_.end()) { + int refcount = it->second->DecRefCount(); + if (refcount == 0) { + // Nobody is using the payload, we can remove it. + NEARBY_LOGS(VERBOSE) << "Erase payload " << it->second->ToString(); + pending_payloads_.erase(it); + } else { + // Someone is still using the payload. Move it to the garbage bin. The + // payload will be removed when they release it. + NEARBY_LOGS(VERBOSE) << "Bin payload " << it->second->ToString(); + payload_garbage_bin_.push_back( + std::move(pending_payloads_.extract(it).mapped())); + } + } +} + +PayloadManager::PendingPayloadHandle +PayloadManager::PendingPayloads::GetPayload(Payload::Id payload_id) const { MutexLock lock(&mutex_); auto item = pending_payloads_.find(payload_id); - return item != pending_payloads_.end() ? item->second.get() : nullptr; + if (item == pending_payloads_.end()) { + return PendingPayloadHandle(); + } + PendingPayload* payload = item->second.get(); + payload->IncRefCount(); + return PendingPayloadHandle( + payload, absl::bind_front(&PendingPayloads::Release, + const_cast(this))); } -std::vector PayloadManager::PendingPayloads::GetAllPayloads() { +void PayloadManager::PendingPayloads::StopTrackingAllPayloads() { MutexLock lock(&mutex_); - std::vector result; - for (const auto& item : pending_payloads_) { - result.push_back(item.first); + for (auto it = pending_payloads_.begin(); it != pending_payloads_.end();) { + Remove(it++); } - return result; +} + +void PayloadManager::PendingPayloads::ForEachPayload( + absl::AnyInvocable callback) { + MutexLock lock(&mutex_); + + for (const auto& item : pending_payloads_) { + callback(item.second.get()); + } +} + +void PayloadManager::PendingPayloads::Release(PendingPayload* payload) { + // Called when `PendingPayloadHandle` is destroyed. + MutexLock lock(&mutex_); + NEARBY_LOGS(VERBOSE) << __func__ << " " << payload->ToString(); + auto it = pending_payloads_.find(payload->GetId()); + if (it != pending_payloads_.end() && it->second.get() == payload) { + // The payload is still tracked. + payload->DecRefCount(); + return; + } + auto bin_it = + std::find_if(payload_garbage_bin_.begin(), payload_garbage_bin_.end(), + [payload](auto& item) { return item.get() == payload; }); + if (bin_it != payload_garbage_bin_.end()) { + int refcount = payload->DecRefCount(); + if (refcount == 0) { + // The payload is not tracked and it was the last reference. + payload_garbage_bin_.erase(bin_it); + } + } +} + +PayloadManager::PendingPayloadHandle::PendingPayloadHandle( + PendingPayload* payload, DestroyCallback destroy_callback) + : payload_(payload), destroy_callback_(std::move(destroy_callback)) {} + +PayloadManager::PendingPayloadHandle::~PendingPayloadHandle() { + if (destroy_callback_) { + std::move(destroy_callback_)(payload_); + } +} + +std::string PayloadManager::PendingPayload::ToString() const { + return absl::StrFormat("Payload(%s, %d)", + IsIncoming() ? "incoming" : "outgoing", GetId()); } } // namespace connections diff --git a/connections/implementation/payload_manager.h b/connections/implementation/payload_manager.h index 6be21457..768841d1 100644 --- a/connections/implementation/payload_manager.h +++ b/connections/implementation/payload_manager.h @@ -15,6 +15,7 @@ #ifndef CORE_INTERNAL_PAYLOAD_MANAGER_H_ #define CORE_INTERNAL_PAYLOAD_MANAGER_H_ +#include #include #include #include @@ -23,6 +24,7 @@ #include #include "absl/container/flat_hash_map.h" +#include "absl/functional/any_invocable.h" #include "connections/implementation/analytics/packet_meta_data.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_manager.h" @@ -33,6 +35,7 @@ #include "internal/platform/atomic_boolean.h" #include "internal/platform/atomic_reference.h" #include "internal/platform/byte_array.h" +#include "internal/platform/condition_variable.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/mutex.h" @@ -68,7 +71,8 @@ class PayloadManager : public EndpointManager::FrameProcessor { // @EndpointManagerThread void OnEndpointDisconnect(ClientProxy* client, const std::string& service_id, const std::string& endpoint_id, - CountDownLatch barrier) override; + CountDownLatch barrier, + DisconnectionReason reason) override; void DisconnectFromEndpointManager(); @@ -90,21 +94,35 @@ class PayloadManager : public EndpointManager::FrameProcessor { static Status ControlMessageEventToEndpointInfoStatus( PayloadTransferFrame::ControlMessage::EventType event); + void MarkReceivedAckFromEndpoint(); + bool IsEndpointAvailable(ClientProxy* clientProxy, + EndpointInfo::Status status); std::string id; AtomicReference status{Status::kUnknown}; std::int64_t offset = 0; + mutable Mutex payload_received_ack_mutex; + ConditionVariable payload_received_ack_cond{&payload_received_ack_mutex}; + bool is_payload_received_ack ABSL_GUARDED_BY(payload_received_ack_mutex) = + false; }; // Tracks state for an InternalPayload and the endpoints associated with it. class PendingPayload { public: + using DestroyCallback = absl::AnyInvocable; PendingPayload(std::unique_ptr internal_payload, - const EndpointIds& endpoint_ids, bool is_incoming); + const EndpointIds& endpoint_ids, bool is_incoming, + DestroyCallback destroy_callback); PendingPayload(PendingPayload&&) = default; PendingPayload& operator=(PendingPayload&&) = default; - ~PendingPayload() { Close(); } + ~PendingPayload() { + Close(); + if (destroy_callback_) { + std::move(destroy_callback_)(this); + } + } Payload::Id GetId() const; @@ -112,6 +130,7 @@ class PayloadManager : public EndpointManager::FrameProcessor { bool IsLocallyCanceled() const; void MarkLocallyCanceled(); + void MarkReceivedAckFromEndpoint(const std::string& from_endpoint_id); bool IsIncoming() const; // Gets the EndpointInfo objects for the endpoints (still) associated with @@ -137,24 +156,65 @@ class PayloadManager : public EndpointManager::FrameProcessor { void SetOffsetForEndpoint(const std::string& endpoint_id, std::int64_t offset) ABSL_LOCKS_EXCLUDED(mutex_); - // Closes internal_payload_ and triggers close_event_. + // Closes internal_payload_. // Close is called when a pending peyload does not have associated // endpoints. void Close(); - // Waits for close_event_ or for timeout to happen. - // Returns true, if event happened, false otherwise. - bool WaitForClose(); - bool IsClosed(); + std::string ToString() const; + + // Ref counting for `PendingPayloads` use only. `PendingPayloads` class owns + // all instances of `PendingPayload`. + int IncRefCount() { return ++refcount_; } + int DecRefCount() { return --refcount_; } private: mutable Mutex mutex_; bool is_incoming_; AtomicBoolean is_locally_canceled_{false}; - CountDownLatch close_event_{1}; + AtomicBoolean is_closed_; std::unique_ptr internal_payload_; + DestroyCallback destroy_callback_; absl::flat_hash_map endpoints_ ABSL_GUARDED_BY(mutex_); + int refcount_ = 0; + }; + + // A RAII handle to `PendingPayload`. Holding a `PendingPayloadHandle` + // guarantees that `PendingPaylaod` won't be destroyed while in use. + // Create instances with `GetPayload(Payload::Id)`. + class PendingPayloadHandle { + public: + using DestroyCallback = absl::AnyInvocable; + PendingPayloadHandle() = default; + PendingPayloadHandle(PendingPayload* payload, + DestroyCallback destroy_callback); + PendingPayloadHandle(const PendingPayloadHandle&) = delete; + PendingPayloadHandle(PendingPayloadHandle&& other) { + payload_ = other.payload_; + other.payload_ = nullptr; + destroy_callback_ = std::move(other.destroy_callback_); + } + ~PendingPayloadHandle(); + PendingPayloadHandle& operator=(const PendingPayloadHandle&) = delete; + PendingPayloadHandle& operator=(PendingPayloadHandle&& other) { + if (payload_ != nullptr && destroy_callback_) { + std::move(destroy_callback_)(payload_); + } + payload_ = other.payload_; + other.payload_ = nullptr; + destroy_callback_ = std::move(other.destroy_callback_); + return *this; + } + explicit operator bool() const { return payload_ != nullptr; } + + PendingPayload* operator->() const { return payload_; } + + PendingPayload& operator*() const { return *payload_; } + + private: + PendingPayload* payload_ = nullptr; + DestroyCallback destroy_callback_; }; // Tracks and manages PendingPayload objects in a synchronized manner. @@ -166,16 +226,30 @@ class PayloadManager : public EndpointManager::FrameProcessor { void StartTrackingPayload(Payload::Id payload_id, std::unique_ptr pending_payload) ABSL_LOCKS_EXCLUDED(mutex_); - std::unique_ptr StopTrackingPayload(Payload::Id payload_id) + void StopTrackingPayload(Payload::Id payload_id) ABSL_LOCKS_EXCLUDED(mutex_); - PendingPayload* GetPayload(Payload::Id payload_id) const + void StopTrackingAllPayloads() ABSL_LOCKS_EXCLUDED(mutex_); + PendingPayloadHandle GetPayload(Payload::Id payload_id) const + ABSL_LOCKS_EXCLUDED(mutex_); + // Calls `callback` for each tracked payload. The callback must not call + // other `PendingPayloads` methods. + void ForEachPayload(absl::AnyInvocable callback) ABSL_LOCKS_EXCLUDED(mutex_); - std::vector GetAllPayloads() ABSL_LOCKS_EXCLUDED(mutex_); private: + void Release(PendingPayload* payload) ABSL_LOCKS_EXCLUDED(mutex_); + void Remove(absl::flat_hash_map< + Payload::Id, std::unique_ptr>::iterator it) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); mutable Mutex mutex_; absl::flat_hash_map> pending_payloads_ ABSL_GUARDED_BY(mutex_); + // When we stop tracking a payload but someone is still holding a handle to + // the payload, we can't delete it just yet. Instead, we move it to the + // garbage bin. When the `PendingPayloadHandle` is released, the payload + // will be removed from the bin. + std::vector> payload_garbage_bin_ + ABSL_GUARDED_BY(mutex_); }; using Endpoints = std::vector; @@ -185,8 +259,8 @@ class PayloadManager : public EndpointManager::FrameProcessor { static std::string ToString(EndpointInfo::Status status); // Splits the endpoints for this payload by availability. - // Returns a pair of lists of EndpointInfo*, with the first being the list of - // still-available endpoints, and the second for unavailable endpoints. + // Returns a pair of lists of EndpointInfo*, with the first being the list + // of still-available endpoints, and the second for unavailable endpoints. static std::pair GetAvailableAndUnavailableEndpoints( const PendingPayload& pending_payload); @@ -203,14 +277,14 @@ class PayloadManager : public EndpointManager::FrameProcessor { std::int64_t offset_bytes, location::nearby::proto::connections::PayloadStatus status); - // Converts the status of an endpoint that's been set out-of-band via a remote - // ControlMessage to the PayloadStatus for handling of that endpoint-payload - // pair. + // Converts the status of an endpoint that's been set out-of-band via a + // remote ControlMessage to the PayloadStatus for handling of that + // endpoint-payload pair. static location::nearby::proto::connections::PayloadStatus EndpointInfoStatusToPayloadStatus(EndpointInfo::Status status); // Converts a ControlMessage::EventType for a particular payload to a - // PayloadStatus. Called when we've received a ControlMessage with this event - // from a remote endpoint; thus the PayloadStatuses are REMOTE_*. + // PayloadStatus. Called when we've received a ControlMessage with this + // event from a remote endpoint; thus the PayloadStatuses are REMOTE_*. static location::nearby::proto::connections::PayloadStatus ControlMessageEventToPayloadStatus( PayloadTransferFrame::ControlMessage::EventType event); @@ -225,9 +299,13 @@ class PayloadManager : public EndpointManager::FrameProcessor { PayloadTransferFrame::PayloadChunk CreatePayloadChunk(std::int64_t offset, ByteArray body); + bool IsLastChunk(PayloadTransferFrame::PayloadChunk payload_chunk) { + return ((payload_chunk.flags() & + PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0); + } - PendingPayload* CreateIncomingPayload(const PayloadTransferFrame& frame, - const std::string& endpoint_id) + PendingPayloadHandle CreateIncomingPayload(const PayloadTransferFrame& frame, + const std::string& endpoint_id) ABSL_LOCKS_EXCLUDED(mutex_); Payload::Id CreateOutgoingPayload(Payload payload, @@ -251,8 +329,23 @@ class PayloadManager : public EndpointManager::FrameProcessor { std::int64_t num_bytes_successfully_transferred, PayloadTransferFrame::ControlMessage::EventType event_type); - // Handles a finished outgoing payload for the given endpointIds. All statuses - // except for SUCCESS are handled here. + void SendPayloadReceivedAck( + ClientProxy* client, PendingPayload& pending_payload, + const std::string& endpoint_id, + const PayloadTransferFrame::PayloadHeader& payload_header, + std::int64_t chunk_size, bool is_last_chunk); + + bool WaitForReceivedAck( + ClientProxy* client, const std::string& endpoint_id, + PendingPayload& pending_payload, + const PayloadTransferFrame::PayloadHeader& payload_header, + std::int64_t payload_chunk_offset, bool is_last_chunk); + bool IsPayloadReceivedAckEnabled(ClientProxy* client, + const std::string& endpoint_id, + PendingPayload& pending_payload); + + // Handles a finished outgoing payload for the given endpointIds. All + // statuses except for SUCCESS are handled here. void HandleFinishedOutgoingPayload( ClientProxy* client, const EndpointIds& finished_endpoint_ids, const PayloadTransferFrame::PayloadHeader& payload_header, @@ -293,11 +386,11 @@ class PayloadManager : public EndpointManager::FrameProcessor { SingleThreadExecutor* GetOutgoingPayloadExecutor(PayloadType payload_type); void RunOnStatusUpdateThread(const std::string& name, - std::function runnable); + absl::AnyInvocable runnable); bool NotifyShutdown() ABSL_LOCKS_EXCLUDED(mutex_); void DestroyPendingPayload(Payload::Id payload_id) ABSL_LOCKS_EXCLUDED(mutex_); - PendingPayload* GetPayload(Payload::Id payload_id) const + PendingPayloadHandle GetPayload(Payload::Id payload_id) const ABSL_LOCKS_EXCLUDED(mutex_); void CancelAllPayloads() ABSL_LOCKS_EXCLUDED(mutex_); @@ -317,23 +410,23 @@ class PayloadManager : public EndpointManager::FrameProcessor { PayloadType FramePayloadTypeToPayloadType( PayloadTransferFrame::PayloadHeader::PayloadType type); + void OnPendingPayloadDestroy(const PendingPayload* payload); mutable Mutex mutex_; std::string custom_save_path_; AtomicBoolean shutdown_{false}; std::unique_ptr shutdown_barrier_; int send_payload_count_ = 0; - PendingPayloads pending_payloads_ ABSL_GUARDED_BY(mutex_); SingleThreadExecutor bytes_payload_executor_; SingleThreadExecutor file_payload_executor_; SingleThreadExecutor stream_payload_executor_; SingleThreadExecutor payload_status_update_executor_; - + PendingPayloads pending_payloads_; EndpointManager* endpoint_manager_; // When callback processing cannot keep the speed of callback update, the // callback thread will be lag to the real transfer. In order to keep sync - // between callback and sending/receiving threads, we will skip non-important - // callbacks during file transfer. + // between callback and sending/receiving threads, we will skip + // non-important callbacks during file transfer. mutable Mutex chunk_update_mutex_; int outgoing_chunk_update_count_ ABSL_GUARDED_BY(chunk_update_mutex_) = 0; int incoming_chunk_update_count_ ABSL_GUARDED_BY(chunk_update_mutex_) = 0; diff --git a/connections/implementation/payload_manager_test.cc b/connections/implementation/payload_manager_test.cc index 2c2c5f9f..f1984264 100644 --- a/connections/implementation/payload_manager_test.cc +++ b/connections/implementation/payload_manager_test.cc @@ -14,19 +14,29 @@ #include "connections/implementation/payload_manager.h" -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" +#include +#include +#include + #include "gtest/gtest.h" #include "absl/strings/string_view.h" +#include "absl/time/time.h" #include "connections/implementation/simulation_user.h" +#include "connections/listeners.h" +#include "connections/medium_selector.h" +#include "connections/payload.h" +#include "connections/status.h" #include "internal/platform/byte_array.h" +#include "internal/platform/count_down_latch.h" +#include "internal/platform/logging.h" +#include "internal/platform/medium_environment.h" #include "internal/platform/pipe.h" -#include "internal/platform/system_clock.h" namespace nearby { namespace connections { namespace { +constexpr size_t kChunkSize = 64 * 1024; constexpr absl::string_view kServiceId = "service-id"; constexpr absl::string_view kDeviceA = "device-a"; constexpr absl::string_view kDeviceB = "device-b"; @@ -165,18 +175,14 @@ TEST_P(PayloadManagerTest, CanSendStreamPayload) { PayloadSimulationUser user_b(kDeviceB, GetParam()); ASSERT_TRUE(SetupConnection(user_a, user_b)); - auto pipe = std::make_shared(); - OutputStream& tx = pipe->GetOutputStream(); - + auto [input, tx] = CreatePipe(); user_a.ExpectPayload(payload_latch_); const ByteArray message{std::string(kMessage)}; // The first write to the output stream will send the first PAYLOAD_TRANSFER // packet with payload info and message data. - tx.Write(message); + tx->Write(message); - user_b.SendPayload(Payload([pipe]() -> InputStream& { - return pipe->GetInputStream(); // NOLINT - })); + user_b.SendPayload(Payload(std::move(input))); ASSERT_TRUE(payload_latch_.Await(kDefaultTimeout).result()); ASSERT_NE(user_a.GetPayload().AsStream(), nullptr); InputStream& rx = *user_a.GetPayload().AsStream(); @@ -187,22 +193,22 @@ TEST_P(PayloadManagerTest, CanSendStreamPayload) { return info.bytes_transferred >= message.size(); }, kProgressTimeout)); - ByteArray result = rx.Read(Pipe::kChunkSize).result(); + ByteArray result = rx.Read(kChunkSize).result(); EXPECT_EQ(result, message); NEARBY_LOG(INFO, "Packet 1 handled."); - tx.Write(message); + tx->Write(message); EXPECT_TRUE(user_a.WaitForProgress( [&message](const PayloadProgressInfo& info) { return info.bytes_transferred >= 2 * message.size(); }, kProgressTimeout)); - ByteArray result2 = rx.Read(Pipe::kChunkSize).result(); + ByteArray result2 = rx.Read(kChunkSize).result(); EXPECT_EQ(result2, message); NEARBY_LOG(INFO, "Packet 2 handled."); rx.Close(); - tx.Close(); + tx->Close(); NEARBY_LOG(INFO, "Test completed."); user_a.Stop(); user_b.Stop(); @@ -214,17 +220,12 @@ TEST_P(PayloadManagerTest, CanCancelPayloadOnReceiverSide) { PayloadSimulationUser user_a(kDeviceA, GetParam()); PayloadSimulationUser user_b(kDeviceB, GetParam()); ASSERT_TRUE(SetupConnection(user_a, user_b)); - - auto pipe = std::make_shared(); - OutputStream& tx = pipe->GetOutputStream(); - + auto [input, tx] = CreatePipe(); user_a.ExpectPayload(payload_latch_); const ByteArray message{std::string(kMessage)}; - tx.Write(message); + tx->Write(message); - user_b.SendPayload(Payload([pipe]() -> InputStream& { - return pipe->GetInputStream(); // NOLINT - })); + user_b.SendPayload(Payload(std::move(input))); ASSERT_TRUE(payload_latch_.Await(kDefaultTimeout).result()); ASSERT_NE(user_a.GetPayload().AsStream(), nullptr); InputStream& rx = *user_a.GetPayload().AsStream(); @@ -235,7 +236,7 @@ TEST_P(PayloadManagerTest, CanCancelPayloadOnReceiverSide) { return info.bytes_transferred >= message.size(); }, kProgressTimeout)); - ByteArray result = rx.Read(Pipe::kChunkSize).result(); + ByteArray result = rx.Read(kChunkSize).result(); EXPECT_EQ(result, message); NEARBY_LOG(INFO, "Packet 1 handled."); @@ -246,7 +247,7 @@ TEST_P(PayloadManagerTest, CanCancelPayloadOnReceiverSide) { // Once cancel is handled, write will fail. int count = 0; while (true) { - if (!tx.Write(message).Ok()) break; + if (!tx->Write(message).Ok()) break; SystemClock::Sleep(kDefaultTimeout); count++; } @@ -258,7 +259,7 @@ TEST_P(PayloadManagerTest, CanCancelPayloadOnReceiverSide) { kProgressTimeout)); NEARBY_LOG(INFO, "Stream cancelation received."); - tx.Close(); + tx->Close(); rx.Close(); NEARBY_LOG(INFO, "Test completed."); @@ -272,17 +273,12 @@ TEST_P(PayloadManagerTest, CanCancelPayloadOnSenderSide) { PayloadSimulationUser user_a(kDeviceA, GetParam()); PayloadSimulationUser user_b(kDeviceB, GetParam()); ASSERT_TRUE(SetupConnection(user_a, user_b)); - - auto pipe = std::make_shared(); - OutputStream& tx = pipe->GetOutputStream(); - + auto [input, tx] = CreatePipe(); user_a.ExpectPayload(payload_latch_); const ByteArray message{std::string(kMessage)}; - tx.Write(message); + tx->Write(message); - user_b.SendPayload(Payload([pipe]() -> InputStream& { - return pipe->GetInputStream(); // NOLINT - })); + user_b.SendPayload(Payload(std::move(input))); ASSERT_TRUE(payload_latch_.Await(kDefaultTimeout).result()); ASSERT_NE(user_a.GetPayload().AsStream(), nullptr); InputStream& rx = *user_a.GetPayload().AsStream(); @@ -293,7 +289,7 @@ TEST_P(PayloadManagerTest, CanCancelPayloadOnSenderSide) { return info.bytes_transferred >= message.size(); }, kProgressTimeout)); - ByteArray result = rx.Read(Pipe::kChunkSize).result(); + ByteArray result = rx.Read(kChunkSize).result(); EXPECT_EQ(result, message); NEARBY_LOG(INFO, "Packet 1 handled."); @@ -304,7 +300,7 @@ TEST_P(PayloadManagerTest, CanCancelPayloadOnSenderSide) { // Once cancel is handled, write will fail. int count = 0; while (true) { - if (!tx.Write(message).Ok()) break; + if (!tx->Write(message).Ok()) break; SystemClock::Sleep(kDefaultTimeout); count++; } @@ -316,7 +312,7 @@ TEST_P(PayloadManagerTest, CanCancelPayloadOnSenderSide) { kProgressTimeout)); NEARBY_LOG(INFO, "Stream cancelation received."); - tx.Close(); + tx->Close(); rx.Close(); NEARBY_LOG(INFO, "Test completed."); @@ -331,19 +327,14 @@ TEST_P(PayloadManagerTest, SendPayloadWithSkip_StreamPayload) { PayloadSimulationUser user_a(kDeviceA, GetParam()); PayloadSimulationUser user_b(kDeviceB, GetParam()); ASSERT_TRUE(SetupConnection(user_a, user_b)); - - auto pipe = std::make_shared(); - OutputStream& tx = pipe->GetOutputStream(); - + auto [input, tx] = CreatePipe(); user_a.ExpectPayload(payload_latch_); const ByteArray message{std::string(kMessage)}; // The first write to the output stream will send the first PAYLOAD_TRANSFER // packet with payload info and message data. - tx.Write(message); + tx->Write(message); - Payload payload([pipe]() -> InputStream& { - return pipe->GetInputStream(); // NOLINT - }); + Payload payload(std::move(input)); payload.SetOffset(kOffset); user_b.SendPayload(std::move(payload)); ASSERT_TRUE(payload_latch_.Await(kDefaultTimeout).result()); @@ -356,22 +347,22 @@ TEST_P(PayloadManagerTest, SendPayloadWithSkip_StreamPayload) { return info.bytes_transferred >= message.size() - kOffset; }, kProgressTimeout)); - ByteArray result = rx.Read(Pipe::kChunkSize).result(); + ByteArray result = rx.Read(kChunkSize).result(); EXPECT_EQ(result, ByteArray("sage")); NEARBY_LOG(INFO, "Packet 1 handled."); - tx.Write(message); + tx->Write(message); EXPECT_TRUE(user_a.WaitForProgress( [&message](const PayloadProgressInfo& info) { return info.bytes_transferred >= 2 * message.size() - kOffset; }, kProgressTimeout)); - ByteArray result2 = rx.Read(Pipe::kChunkSize).result(); + ByteArray result2 = rx.Read(kChunkSize).result(); EXPECT_EQ(result2, message); NEARBY_LOG(INFO, "Packet 2 handled."); rx.Close(); - tx.Close(); + tx->Close(); NEARBY_LOG(INFO, "Test completed."); user_a.Stop(); user_b.Stop(); diff --git a/connections/implementation/proto/offline_wire_formats.proto b/connections/implementation/proto/offline_wire_formats.proto index 018d4e18..d0d226bd 100644 --- a/connections/implementation/proto/offline_wire_formats.proto +++ b/connections/implementation/proto/offline_wire_formats.proto @@ -47,6 +47,7 @@ message V1Frame { AUTHENTICATION_RESULT = 9; AUTO_RESUME = 10; AUTO_RECONNECT = 11; + BANDWIDTH_UPGRADE_RETRY = 12; } optional FrameType type = 1; @@ -62,6 +63,7 @@ message V1Frame { optional AuthenticationResultFrame authentication_result = 10; optional AutoResumeFrame auto_resume = 11; optional AutoReconnectFrame auto_reconnect = 12; + optional BandwidthUpgradeRetryFrame bandwidth_upgrade_retry = 13; } message ConnectionRequestFrame { @@ -307,9 +309,39 @@ message BandwidthUpgradeNegotiationFrame { optional ClientIntroductionAck client_introduction_ack = 4; } +message BandwidthUpgradeRetryFrame { + // Should always match cs/symbol:location.nearby.proto.connections.Medium + // LINT.IfChange + enum Medium { + UNKNOWN_MEDIUM = 0; + // 1 is reserved. + BLUETOOTH = 2; + WIFI_HOTSPOT = 3; + BLE = 4; + WIFI_LAN = 5; + WIFI_AWARE = 6; + NFC = 7; + WIFI_DIRECT = 8; + WEB_RTC = 9; + BLE_L2CAP = 10; + USB = 11; + } + // LINT.ThenChange(//depot/google3/third_party/nearby/proto/connections_enums.proto) + + // The mediums this device supports upgrading to. This list should be filtered + // by both the strategy and this device's individual limitations. + repeated Medium supported_medium = 1; + + // If true, expect the remote endpoint to send back the latest + // supported_medium. + optional bool is_request = 2; +} + message KeepAliveFrame { // And ack will be sent after receiving KEEP_ALIVE frame. optional bool ack = 1; + // The sequence number + optional uint32 seq_num = 2; } // Informs the remote side to immediately severe the socket connection. diff --git a/connections/implementation/service_controller_router.cc b/connections/implementation/service_controller_router.cc index 5b2447b1..e50a3999 100644 --- a/connections/implementation/service_controller_router.cc +++ b/connections/implementation/service_controller_router.cc @@ -98,101 +98,103 @@ ServiceControllerRouter::~ServiceControllerRouter() { void ServiceControllerRouter::StartAdvertising( ClientProxy* client, absl::string_view service_id, const AdvertisingOptions& advertising_options, - const ConnectionRequestInfo& info, const ResultCallback& callback) { + const ConnectionRequestInfo& info, ResultCallback callback) { RouteToServiceController( "scr-start-advertising", [this, client, service_id = std::string(service_id), advertising_options, - info, callback]() { + info, callback = std::move(callback)]() mutable { if (client->IsAdvertising()) { - callback.result_cb({Status::kAlreadyAdvertising}); + callback({Status::kAlreadyAdvertising}); return; } - callback.result_cb(GetServiceController()->StartAdvertising( + callback(GetServiceController()->StartAdvertising( client, service_id, advertising_options, info)); }); } void ServiceControllerRouter::StopAdvertising(ClientProxy* client, - const ResultCallback& callback) { - RouteToServiceController("scr-stop-advertising", [this, client, callback]() { - if (client->IsAdvertising()) { - GetServiceController()->StopAdvertising(client); - } - callback.result_cb({Status::kSuccess}); - }); + ResultCallback callback) { + RouteToServiceController( + "scr-stop-advertising", + [this, client, callback = std::move(callback)]() mutable { + if (client->IsAdvertising()) { + GetServiceController()->StopAdvertising(client); + } + callback({Status::kSuccess}); + }); } void ServiceControllerRouter::StartDiscovery( ClientProxy* client, absl::string_view service_id, const DiscoveryOptions& discovery_options, - const DiscoveryListener& listener, const ResultCallback& callback) { + const DiscoveryListener& listener, ResultCallback callback) { RouteToServiceController( "scr-start-discovery", [this, client, service_id = std::string(service_id), discovery_options, - listener, callback]() { + listener, callback = std::move(callback)]() mutable { if (client->IsDiscovering()) { - callback.result_cb({Status::kAlreadyDiscovering}); + callback({Status::kAlreadyDiscovering}); return; } - callback.result_cb(GetServiceController()->StartDiscovery( + callback(GetServiceController()->StartDiscovery( client, service_id, discovery_options, listener)); }); } void ServiceControllerRouter::StopDiscovery(ClientProxy* client, - const ResultCallback& callback) { - RouteToServiceController("scr-stop-discovery", [this, client, callback]() { - if (client->IsDiscovering()) { - GetServiceController()->StopDiscovery(client); - } - callback.result_cb({Status::kSuccess}); - }); + ResultCallback callback) { + RouteToServiceController( + "scr-stop-discovery", + [this, client, callback = std::move(callback)]() mutable { + if (client->IsDiscovering()) { + GetServiceController()->StopDiscovery(client); + } + callback({Status::kSuccess}); + }); } void ServiceControllerRouter::InjectEndpoint( ClientProxy* client, absl::string_view service_id, - const OutOfBandConnectionMetadata& metadata, - const ResultCallback& callback) { + const OutOfBandConnectionMetadata& metadata, ResultCallback callback) { RouteToServiceController( "scr-inject-endpoint", [this, client, service_id = std::string(service_id), metadata, - callback]() { + callback = std::move(callback)]() mutable { // Currently, Bluetooth is the only supported medium for endpoint // injection. if (metadata.medium != Medium::BLUETOOTH || metadata.remote_bluetooth_mac_address.size() != kMacAddressLength) { - callback.result_cb({Status::kError}); + callback({Status::kError}); return; } if (metadata.endpoint_id.size() != kEndpointIdLength) { - callback.result_cb({Status::kError}); + callback({Status::kError}); return; } if (metadata.endpoint_info.Empty() || metadata.endpoint_info.size() > kMaxEndpointInfoLength) { - callback.result_cb({Status::kError}); + callback({Status::kError}); return; } if (!client->IsDiscovering()) { - callback.result_cb({Status::kOutOfOrderApiCall}); + callback({Status::kOutOfOrderApiCall}); return; } GetServiceController()->InjectEndpoint(client, service_id, metadata); - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); } void ServiceControllerRouter::RequestConnection( ClientProxy* client, absl::string_view endpoint_id, const ConnectionRequestInfo& info, - const ConnectionOptions& connection_options, - const ResultCallback& callback) { + const ConnectionOptions& connection_options, ResultCallback callback) { // Cancellations can be fired from clients anytime, need to add the // CancellationListener as soon as possible. client->AddCancellationFlag(std::string(endpoint_id)); @@ -200,10 +202,10 @@ void ServiceControllerRouter::RequestConnection( RouteToServiceController( "scr-request-connection", [this, client, endpoint_id = std::string(endpoint_id), info, - connection_options, callback]() { + connection_options, callback = std::move(callback)]() mutable { if (client->HasPendingConnectionToEndpoint(endpoint_id) || client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kAlreadyConnectedToEndpoint}); + callback({Status::kAlreadyConnectedToEndpoint}); return; } @@ -212,20 +214,21 @@ void ServiceControllerRouter::RequestConnection( if (!status.Ok()) { client->CancelEndpoint(endpoint_id); } - callback.result_cb(status); + callback(status); }); } void ServiceControllerRouter::AcceptConnection(ClientProxy* client, absl::string_view endpoint_id, PayloadListener listener, - const ResultCallback& callback) { + ResultCallback callback) { RouteToServiceController( "scr-accept-connection", [this, client, endpoint_id = std::string(endpoint_id), - listener = std::move(listener), callback]() mutable { + listener = std::move(listener), + callback = std::move(callback)]() mutable { if (client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kAlreadyConnectedToEndpoint}); + callback({Status::kAlreadyConnectedToEndpoint}); return; } @@ -235,25 +238,26 @@ void ServiceControllerRouter::AcceptConnection(ClientProxy* client, << " invoked acceptConnectionRequest() after having already " "accepted/rejected the connection to endpoint(id=" << endpoint_id << ")"; - callback.result_cb({Status::kOutOfOrderApiCall}); + callback({Status::kOutOfOrderApiCall}); return; } - callback.result_cb(GetServiceController()->AcceptConnection( - client, endpoint_id, std::move(listener))); + callback(GetServiceController()->AcceptConnection(client, endpoint_id, + std::move(listener))); }); } void ServiceControllerRouter::RejectConnection(ClientProxy* client, absl::string_view endpoint_id, - const ResultCallback& callback) { + ResultCallback callback) { client->CancelEndpoint(std::string(endpoint_id)); RouteToServiceController( "scr-reject-connection", - [this, client, endpoint_id = std::string(endpoint_id), callback]() { + [this, client, endpoint_id = std::string(endpoint_id), + callback = std::move(callback)]() mutable { if (client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kAlreadyConnectedToEndpoint}); + callback({Status::kAlreadyConnectedToEndpoint}); return; } @@ -263,23 +267,22 @@ void ServiceControllerRouter::RejectConnection(ClientProxy* client, << " invoked rejectConnectionRequest() after having already " "accepted/rejected the connection to endpoint(id=" << endpoint_id << ")"; - callback.result_cb({Status::kOutOfOrderApiCall}); + callback({Status::kOutOfOrderApiCall}); return; } - callback.result_cb( - GetServiceController()->RejectConnection(client, endpoint_id)); + callback(GetServiceController()->RejectConnection(client, endpoint_id)); }); } void ServiceControllerRouter::InitiateBandwidthUpgrade( ClientProxy* client, absl::string_view endpoint_id, - const ResultCallback& callback) { + ResultCallback callback) { RouteToServiceController( - "scr-init-bwu", - [this, client, endpoint_id = std::string(endpoint_id), callback]() { + "scr-init-bwu", [this, client, endpoint_id = std::string(endpoint_id), + callback = std::move(callback)]() mutable { if (!client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kOutOfOrderApiCall}); + callback({Status::kOutOfOrderApiCall}); return; } @@ -287,62 +290,65 @@ void ServiceControllerRouter::InitiateBandwidthUpgrade( // Operation is triggered; the caller can listen to // ConnectionListener::OnBandwidthChanged() to determine its success. - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); } void ServiceControllerRouter::SendPayload( ClientProxy* client, absl::Span endpoint_ids, - Payload payload, const ResultCallback& callback) { + Payload payload, ResultCallback callback) { const std::vector endpoints = std::vector(endpoint_ids.begin(), endpoint_ids.end()); - RouteToServiceController("scr-send-payload", [this, client, - payload = std::move(payload), - endpoints, callback]() mutable { - if (!ClientHasConnectionToAtLeastOneEndpoint(client, endpoints)) { - callback.result_cb({Status::kEndpointUnknown}); - return; - } + RouteToServiceController( + "scr-send-payload", + [this, client, payload = std::move(payload), endpoints, + callback = std::move(callback)]() mutable { + if (!ClientHasConnectionToAtLeastOneEndpoint(client, endpoints)) { + callback({Status::kEndpointUnknown}); + return; + } - GetServiceController()->SendPayload(client, endpoints, std::move(payload)); + GetServiceController()->SendPayload(client, endpoints, + std::move(payload)); - // At this point, we've queued up the send Payload request with the - // ServiceController; any further failures (e.g. one of the endpoints is - // unknown, goes away, or otherwise fails) will be returned to the - // client as a PayloadTransferUpdate. - callback.result_cb({Status::kSuccess}); - }); + // At this point, we've queued up the send Payload request with the + // ServiceController; any further failures (e.g. one of the endpoints is + // unknown, goes away, or otherwise fails) will be returned to the + // client as a PayloadTransferUpdate. + callback({Status::kSuccess}); + }); } void ServiceControllerRouter::CancelPayload(ClientProxy* client, std::uint64_t payload_id, - const ResultCallback& callback) { + ResultCallback callback) { RouteToServiceController( - "scr-cancel-payload", [this, client, payload_id, callback]() { - callback.result_cb( - GetServiceController()->CancelPayload(client, payload_id)); + "scr-cancel-payload", + [this, client, payload_id, callback = std::move(callback)]() mutable { + callback(GetServiceController()->CancelPayload(client, payload_id)); }); } void ServiceControllerRouter::DisconnectFromEndpoint( ClientProxy* client, absl::string_view endpoint_id, - const ResultCallback& callback) { + ResultCallback callback) { // Client can emit the cancellation at anytime, we need to execute the request // without further posting it. client->CancelEndpoint(std::string(endpoint_id)); RouteToServiceController( "scr-disconnect-endpoint", - [this, client, endpoint_id = std::string(endpoint_id), callback]() { + [this, client, endpoint_id = std::string(endpoint_id), + callback = std::move(callback)]() mutable { if (!client->IsConnectedToEndpoint(endpoint_id) && !client->HasPendingConnectionToEndpoint(endpoint_id)) { - callback.result_cb({Status::kOutOfOrderApiCall}); + callback({Status::kOutOfOrderApiCall}); return; } GetServiceController()->DisconnectFromEndpoint(client, endpoint_id); - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); } @@ -388,7 +394,7 @@ void ServiceControllerRouter::StopListeningForIncomingConnectionsV3( void ServiceControllerRouter::RequestConnectionV3( ClientProxy* client, const NearbyDevice& remote_device, v3::ConnectionRequestInfo info, const ConnectionOptions& connection_options, - const ResultCallback& callback) { + ResultCallback callback) { // Cancellations can be fired from clients anytime, need to add the // CancellationListener as soon as possible. client->AddCancellationFlag(remote_device.GetEndpointId()); @@ -396,10 +402,11 @@ void ServiceControllerRouter::RequestConnectionV3( RouteToServiceController( "scr-request-connection", [this, client, endpoint_id = remote_device.GetEndpointId(), - v3_info = std::move(info), connection_options, callback]() mutable { + v3_info = std::move(info), connection_options, + callback = std::move(callback)]() mutable { if (client->HasPendingConnectionToEndpoint(endpoint_id) || client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kAlreadyConnectedToEndpoint}); + callback({Status::kAlreadyConnectedToEndpoint}); return; } @@ -473,19 +480,20 @@ void ServiceControllerRouter::RequestConnectionV3( << endpoint_id << ": " << status.ToString(); client->CancelEndpoint(endpoint_id); } - callback.result_cb(status); + callback(status); }); } void ServiceControllerRouter::AcceptConnectionV3( ClientProxy* client, const NearbyDevice& remote_device, - v3::PayloadListener listener, const ResultCallback& callback) { + v3::PayloadListener listener, ResultCallback callback) { RouteToServiceController( "scr-accept-connection", [this, client, endpoint_id = remote_device.GetEndpointId(), - v3_listener = std::move(listener), callback]() mutable { + v3_listener = std::move(listener), + callback = std::move(callback)]() mutable { if (client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kAlreadyConnectedToEndpoint}); + callback({Status::kAlreadyConnectedToEndpoint}); return; } @@ -495,7 +503,7 @@ void ServiceControllerRouter::AcceptConnectionV3( << " invoked acceptConnectionRequest() after having already " "accepted/rejected the connection to endpoint(id=" << endpoint_id << ")"; - callback.result_cb({Status::kOutOfOrderApiCall}); + callback({Status::kOutOfOrderApiCall}); return; } @@ -513,21 +521,22 @@ void ServiceControllerRouter::AcceptConnectionV3( v3_cb(v3::ConnectionsDevice(endpoint_id, "", {}), info); }}; - callback.result_cb(GetServiceController()->AcceptConnection( + callback(GetServiceController()->AcceptConnection( client, endpoint_id, std::move(old_listener))); }); } void ServiceControllerRouter::RejectConnectionV3( ClientProxy* client, const NearbyDevice& remote_device, - const ResultCallback& callback) { + ResultCallback callback) { client->CancelEndpoint(remote_device.GetEndpointId()); RouteToServiceController( "scr-reject-connection", - [this, client, endpoint_id = remote_device.GetEndpointId(), callback]() { + [this, client, endpoint_id = remote_device.GetEndpointId(), + callback = std::move(callback)]() mutable { if (client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kAlreadyConnectedToEndpoint}); + callback({Status::kAlreadyConnectedToEndpoint}); return; } @@ -537,23 +546,23 @@ void ServiceControllerRouter::RejectConnectionV3( << " invoked rejectConnectionRequest() after having already " "accepted/rejected the connection to endpoint(id=" << endpoint_id << ")"; - callback.result_cb({Status::kOutOfOrderApiCall}); + callback({Status::kOutOfOrderApiCall}); return; } - callback.result_cb( - GetServiceController()->RejectConnection(client, endpoint_id)); + callback(GetServiceController()->RejectConnection(client, endpoint_id)); }); } void ServiceControllerRouter::InitiateBandwidthUpgradeV3( ClientProxy* client, const NearbyDevice& remote_device, - const ResultCallback& callback) { + ResultCallback callback) { RouteToServiceController( "scr-init-bwu", - [this, client, endpoint_id = remote_device.GetEndpointId(), callback]() { + [this, client, endpoint_id = remote_device.GetEndpointId(), + callback = std::move(callback)]() mutable { if (!client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kOutOfOrderApiCall}); + callback({Status::kOutOfOrderApiCall}); return; } @@ -561,19 +570,19 @@ void ServiceControllerRouter::InitiateBandwidthUpgradeV3( // Operation is triggered; the caller can listen to // ConnectionListener::OnBandwidthChanged() to determine its success. - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); } void ServiceControllerRouter::SendPayloadV3( ClientProxy* client, const NearbyDevice& recipient_device, Payload payload, - const ResultCallback& callback) { + ResultCallback callback) { RouteToServiceController( - "scr-send-payload", - [this, client, payload = std::move(payload), - endpoint_id = recipient_device.GetEndpointId(), callback]() mutable { + "scr-send-payload", [this, client, payload = std::move(payload), + endpoint_id = recipient_device.GetEndpointId(), + callback = std::move(callback)]() mutable { if (!client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kEndpointUnknown}); + callback({Status::kEndpointUnknown}); return; } @@ -584,90 +593,94 @@ void ServiceControllerRouter::SendPayloadV3( // ServiceController; any further failures (e.g. one of the endpoints is // unknown, goes away, or otherwise fails) will be returned to the // client as a PayloadTransferUpdate. - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); } void ServiceControllerRouter::CancelPayloadV3( ClientProxy* client, const NearbyDevice& recipient_device, - uint64_t payload_id, const ResultCallback& callback) { + uint64_t payload_id, ResultCallback callback) { RouteToServiceController( - "scr-cancel-payload", [this, client, payload_id, callback]() { - callback.result_cb( - GetServiceController()->CancelPayload(client, payload_id)); + "scr-cancel-payload", + [this, client, payload_id, callback = std::move(callback)]() mutable { + callback(GetServiceController()->CancelPayload(client, payload_id)); }); } void ServiceControllerRouter::DisconnectFromDeviceV3( ClientProxy* client, const NearbyDevice& remote_device, - const ResultCallback& callback) { + ResultCallback callback) { // Client can emit the cancellation at anytime, we need to execute the request // without further posting it. client->CancelEndpoint(remote_device.GetEndpointId()); RouteToServiceController( "scr-disconnect-endpoint", - [this, client, endpoint_id = remote_device.GetEndpointId(), callback]() { + [this, client, endpoint_id = remote_device.GetEndpointId(), + callback = std::move(callback)]() mutable { if (!client->IsConnectedToEndpoint(endpoint_id) && !client->HasPendingConnectionToEndpoint(endpoint_id)) { - callback.result_cb({Status::kOutOfOrderApiCall}); + callback({Status::kOutOfOrderApiCall}); return; } GetServiceController()->DisconnectFromEndpoint(client, endpoint_id); - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); } void ServiceControllerRouter::UpdateAdvertisingOptionsV3( ClientProxy* client, absl::string_view service_id, - const AdvertisingOptions& options, const ResultCallback& callback) { + const AdvertisingOptions& options, ResultCallback callback) { RouteToServiceController( "scr-update-advertising-options", - [this, client, options, callback, service_id]() { - callback.result_cb(GetServiceController()->UpdateAdvertisingOptions( + [this, client, options, callback = std::move(callback), + service_id]() mutable { + callback(GetServiceController()->UpdateAdvertisingOptions( client, service_id, options)); }); } void ServiceControllerRouter::UpdateDiscoveryOptionsV3( ClientProxy* client, absl::string_view service_id, - const DiscoveryOptions& options, const ResultCallback& callback) { + const DiscoveryOptions& options, ResultCallback callback) { RouteToServiceController( "scr-update-discovery-options", - [this, client, options, callback, service_id]() { - callback.result_cb(GetServiceController()->UpdateDiscoveryOptions( + [this, client, options, callback = std::move(callback), + service_id]() mutable { + callback(GetServiceController()->UpdateDiscoveryOptions( client, service_id, options)); }); } void ServiceControllerRouter::StopAllEndpoints(ClientProxy* client, - const ResultCallback& callback) { + ResultCallback callback) { // Client can emit the cancellation at anytime, we need to execute the request // without further posting it. client->CancelAllEndpoints(); RouteToServiceController( - "scr-stop-all-endpoints", [this, client, callback]() { + "scr-stop-all-endpoints", + [this, client, callback = std::move(callback)]() mutable { NEARBY_LOGS(INFO) << "Client " << client->GetClientId() << " has requested us to stop all endpoints. We will " "now reset the client."; FinishClientSession(client); - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); } -void ServiceControllerRouter::SetCustomSavePath( - ClientProxy* client, absl::string_view path, - const ResultCallback& callback) { +void ServiceControllerRouter::SetCustomSavePath(ClientProxy* client, + absl::string_view path, + ResultCallback callback) { RouteToServiceController( - "scr-set-custom-save-path", - [this, client, path = std::string(path), callback]() { + "scr-set-custom-save-path", [this, client, path = std::string(path), + callback = std::move(callback)]() mutable { NEARBY_LOGS(INFO) << "Client " << client->GetClientId() << " has requested us to set custom save path to " << path; GetServiceController()->SetCustomSavePath(client, path); - callback.result_cb({Status::kSuccess}); + callback({Status::kSuccess}); }); } diff --git a/connections/implementation/service_controller_router.h b/connections/implementation/service_controller_router.h index 064274e7..9b3ee470 100644 --- a/connections/implementation/service_controller_router.h +++ b/connections/implementation/service_controller_router.h @@ -70,52 +70,50 @@ class ServiceControllerRouter { absl::string_view service_id, const AdvertisingOptions& advertising_options, const ConnectionRequestInfo& info, - const ResultCallback& callback); + ResultCallback callback); - virtual void StopAdvertising(ClientProxy* client, - const ResultCallback& callback); + virtual void StopAdvertising(ClientProxy* client, ResultCallback callback); virtual void StartDiscovery(ClientProxy* client, absl::string_view service_id, const DiscoveryOptions& discovery_options, const DiscoveryListener& listener, - const ResultCallback& callback); + ResultCallback callback); - virtual void StopDiscovery(ClientProxy* client, - const ResultCallback& callback); + virtual void StopDiscovery(ClientProxy* client, ResultCallback callback); virtual void InjectEndpoint(ClientProxy* client, absl::string_view service_id, const OutOfBandConnectionMetadata& metadata, - const ResultCallback& callback); + ResultCallback callback); virtual void RequestConnection(ClientProxy* client, absl::string_view endpoint_id, const ConnectionRequestInfo& info, const ConnectionOptions& connection_options, - const ResultCallback& callback); + ResultCallback callback); virtual void AcceptConnection(ClientProxy* client, absl::string_view endpoint_id, PayloadListener listener, - const ResultCallback& callback); + ResultCallback callback); virtual void RejectConnection(ClientProxy* client, absl::string_view endpoint_id, - const ResultCallback& callback); + ResultCallback callback); virtual void InitiateBandwidthUpgrade(ClientProxy* client, absl::string_view endpoint_id, - const ResultCallback& callback); + ResultCallback callback); virtual void SendPayload(ClientProxy* client, absl::Span endpoint_ids, - Payload payload, const ResultCallback& callback); + Payload payload, ResultCallback callback); virtual void CancelPayload(ClientProxy* client, std::uint64_t payload_id, - const ResultCallback& callback); + ResultCallback callback); virtual void DisconnectFromEndpoint(ClientProxy* client, absl::string_view endpoint_id, - const ResultCallback& callback); + ResultCallback callback); ////////////////////////////// V3 //////////////////////////////////////////// virtual void StartListeningForIncomingConnectionsV3( @@ -130,50 +128,47 @@ class ServiceControllerRouter { const NearbyDevice& remote_device, v3::ConnectionRequestInfo info, const ConnectionOptions& connection_options, - const ResultCallback& callback); + ResultCallback callback); virtual void AcceptConnectionV3(ClientProxy* client, const NearbyDevice& remote_device, v3::PayloadListener listener, - const ResultCallback& callback); + ResultCallback callback); virtual void RejectConnectionV3(ClientProxy* client, const NearbyDevice& remote_device, - const ResultCallback& callback); + ResultCallback callback); virtual void InitiateBandwidthUpgradeV3(ClientProxy* client, const NearbyDevice& remote_device, - const ResultCallback& callback); + ResultCallback callback); virtual void SendPayloadV3(ClientProxy* client, const NearbyDevice& recipient_device, - Payload payload, const ResultCallback& callback); + Payload payload, ResultCallback callback); virtual void CancelPayloadV3(ClientProxy* client, const NearbyDevice& recipient_device, std::uint64_t payload_id, - const ResultCallback& callback); + ResultCallback callback); virtual void DisconnectFromDeviceV3(ClientProxy* client, const NearbyDevice& remote_device, - const ResultCallback& callback); + ResultCallback callback); virtual void UpdateAdvertisingOptionsV3( ClientProxy* client, absl::string_view service_id, - const AdvertisingOptions& advertising_options, - const ResultCallback& callback); + const AdvertisingOptions& advertising_options, ResultCallback callback); virtual void UpdateDiscoveryOptionsV3( ClientProxy* client, absl::string_view service_id, - const DiscoveryOptions& discovery_options, - const ResultCallback& callback); + const DiscoveryOptions& discovery_options, ResultCallback callback); /////////////////////////////// END V3 /////////////////////////////////////// - virtual void StopAllEndpoints(ClientProxy* client, - const ResultCallback& callback); + virtual void StopAllEndpoints(ClientProxy* client, ResultCallback callback); virtual void SetCustomSavePath(ClientProxy* client, absl::string_view path, - const ResultCallback& callback); + ResultCallback callback); void SetServiceControllerForTesting( std::unique_ptr service_controller); diff --git a/connections/implementation/service_controller_router_test.cc b/connections/implementation/service_controller_router_test.cc index 2d235850..be3c7e0a 100644 --- a/connections/implementation/service_controller_router_test.cc +++ b/connections/implementation/service_controller_router_test.cc @@ -81,7 +81,7 @@ class ServiceControllerRouterTest : public testing::Test { MutexLock lock(&mutex_); complete_ = false; router_.StartAdvertising(client, service_id, advertising_options, info, - callback); + std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -95,7 +95,7 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.StopAdvertising(client, callback); + router_.StopAdvertising(client, std::move(callback)); while (!complete_) cond_.Wait(); } client->StoppedAdvertising(); @@ -105,14 +105,14 @@ class ServiceControllerRouterTest : public testing::Test { void StartDiscovery(ClientProxy* client, std::string service_id, DiscoveryOptions discovery_options, const DiscoveryListener& listener, - const ResultCallback& callback) { + ResultCallback callback) { EXPECT_CALL(*mock_, StartDiscovery) .WillOnce(Return(Status{Status::kSuccess})); { MutexLock lock(&mutex_); complete_ = false; router_.StartDiscovery(client, kServiceId, discovery_options, listener, - callback); + std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -126,7 +126,7 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.StopDiscovery(client, callback); + router_.StopDiscovery(client, std::move(callback)); while (!complete_) cond_.Wait(); } client->StoppedDiscovery(); @@ -140,7 +140,7 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.InjectEndpoint(client, service_id, metadata, callback); + router_.InjectEndpoint(client, service_id, metadata, std::move(callback)); while (!complete_) cond_.Wait(); } } @@ -155,7 +155,7 @@ class ServiceControllerRouterTest : public testing::Test { MutexLock lock(&mutex_); complete_ = false; router_.RequestConnection(client, endpoint_id, request_info, - connection_options, callback); + connection_options, std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -173,7 +173,7 @@ class ServiceControllerRouterTest : public testing::Test { } void AcceptConnection(ClientProxy* client, const std::string endpoint_id, - const ResultCallback& callback) { + ResultCallback callback) { EXPECT_CALL(*mock_, AcceptConnection) .WillOnce(Return(Status{Status::kSuccess})); // Pre-condition for successful Accept is: connection must exist. @@ -181,8 +181,7 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.AcceptConnection(client, endpoint_id, {}, - callback); + router_.AcceptConnection(client, endpoint_id, {}, std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -203,7 +202,7 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.RejectConnection(client, endpoint_id, callback); + router_.RejectConnection(client, endpoint_id, std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -219,7 +218,8 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.InitiateBandwidthUpgrade(client, endpoint_id, callback); + router_.InitiateBandwidthUpgrade(client, endpoint_id, + std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -239,7 +239,7 @@ class ServiceControllerRouterTest : public testing::Test { MutexLock lock(&mutex_); complete_ = false; router_.SendPayload(client, absl::MakeSpan(endpoint_ids), - std::move(payload), callback); + std::move(payload), std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -252,7 +252,7 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.CancelPayload(client, payload_id, callback); + router_.CancelPayload(client, payload_id, std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -266,7 +266,7 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.DisconnectFromEndpoint(client, endpoint_id, callback); + router_.DisconnectFromEndpoint(client, endpoint_id, std::move(callback)); while (!complete_) cond_.Wait(); } client->OnDisconnected(endpoint_id, false); @@ -306,7 +306,7 @@ class ServiceControllerRouterTest : public testing::Test { complete_ = false; router_.RequestConnectionV3(client, kRemoteDevice, std::move(request_info), connection_options, - callback); + std::move(callback)); while (!complete_) cond_.Wait(); if (check_result) { EXPECT_EQ(result_, Status{Status::kSuccess}); @@ -330,7 +330,7 @@ class ServiceControllerRouterTest : public testing::Test { void AcceptConnectionV3(ClientProxy* client, const NearbyDevice& kRemoteDevice, - const ResultCallback& callback) { + ResultCallback callback) { EXPECT_CALL(*mock_, AcceptConnection) .WillOnce(Return(Status{Status::kSuccess})); // Pre-condition for successful Accept is: connection must exist. @@ -339,7 +339,8 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.AcceptConnectionV3(client, kRemoteDevice, {}, callback); + router_.AcceptConnectionV3(client, kRemoteDevice, {}, + std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -360,7 +361,7 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.RejectConnectionV3(client, device, callback); + router_.RejectConnectionV3(client, device, std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -376,7 +377,7 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.InitiateBandwidthUpgradeV3(client, device, callback); + router_.InitiateBandwidthUpgradeV3(client, device, std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -393,7 +394,7 @@ class ServiceControllerRouterTest : public testing::Test { MutexLock lock(&mutex_); complete_ = false; router_.SendPayloadV3(client, recipient_device, std::move(payload), - callback); + std::move(callback)); while (!complete_) cond_.Wait(); EXPECT_EQ(result_, Status{Status::kSuccess}); } @@ -401,13 +402,14 @@ class ServiceControllerRouterTest : public testing::Test { void CancelPayloadV3(ClientProxy* client, const NearbyDevice& recipient_device, - uint64_t payload_id, const ResultCallback& callback) { + uint64_t payload_id, ResultCallback callback) { EXPECT_CALL(*mock_, CancelPayload).Times(1); EXPECT_TRUE( client->IsConnectedToEndpoint(recipient_device.GetEndpointId())); { MutexLock lock(&mutex_); - router_.CancelPayloadV3(client, recipient_device, payload_id, callback); + router_.CancelPayloadV3(client, recipient_device, payload_id, + std::move(callback)); } } @@ -419,7 +421,8 @@ class ServiceControllerRouterTest : public testing::Test { { MutexLock lock(&mutex_); complete_ = false; - router_.DisconnectFromDeviceV3(client, kRemoteDevice, callback); + router_.DisconnectFromDeviceV3(client, kRemoteDevice, + std::move(callback)); while (!complete_) cond_.Wait(); } client->OnDisconnected(kRemoteDevice.GetEndpointId(), false); @@ -455,15 +458,6 @@ class ServiceControllerRouterTest : public testing::Test { } protected: - const ResultCallback kCallback{ - .result_cb = - [this](Status status) { - MutexLock lock(&mutex_); - result_ = status; - complete_ = true; - cond_.Notify(); - }, - }; const std::string kServiceId = "service id"; const std::string kRequestorName = "requestor name"; const std::string kRemoteEndpointId = "remote endpoint id"; @@ -542,122 +536,293 @@ TEST_F(ServiceControllerRouterTest, QualityConversionWorks) { TEST_F(ServiceControllerRouterTest, StartAdvertisingCalled) { StartAdvertising(&client_, kServiceId, kAdvertisingOptions, - kConnectionRequestInfo, kCallback); + kConnectionRequestInfo, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, StopAdvertisingCalled) { StartAdvertising(&client_, kServiceId, kAdvertisingOptions, - kConnectionRequestInfo, kCallback); - StopAdvertising(&client_, kCallback); + kConnectionRequestInfo, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); + StopAdvertising(&client_, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, StartDiscoveryCalled) { StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, StopDiscoveryCalled) { StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); - StopDiscovery(&client_, kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); + StopDiscovery(&client_, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, InjectEndpointCalled) { StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); - InjectEndpoint(&client_, kServiceId, kOutOfBandConnectionMetadata, kCallback); - StopDiscovery(&client_, kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); + InjectEndpoint(&client_, kServiceId, kOutOfBandConnectionMetadata, + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); + StopDiscovery(&client_, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, RequestConnectionCalled) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); RequestConnection(&client_, kRemoteEndpointId, kConnectionRequestInfo, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, AcceptConnectionCalled) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. RequestConnection(&client_, kRemoteEndpointId, kConnectionRequestInfo, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Now, we can accept connection. - AcceptConnection(&client_, kRemoteEndpointId, kCallback); + AcceptConnection(&client_, kRemoteEndpointId, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, RejectConnectionCalled) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. RequestConnection(&client_, kRemoteEndpointId, kConnectionRequestInfo, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Now, we can reject connection. - RejectConnection(&client_, kRemoteEndpointId, kCallback); + RejectConnection(&client_, kRemoteEndpointId, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, InitiateBandwidthUpgradeCalled) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. RequestConnection(&client_, kRemoteEndpointId, kConnectionRequestInfo, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Now, we can accept connection. - AcceptConnection(&client_, kRemoteEndpointId, kCallback); + AcceptConnection(&client_, kRemoteEndpointId, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Now we can change connection bandwidth. - InitiateBandwidthUpgrade(&client_, kRemoteEndpointId, kCallback); + InitiateBandwidthUpgrade(&client_, kRemoteEndpointId, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, SendPayloadCalled) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. RequestConnection(&client_, kRemoteEndpointId, kConnectionRequestInfo, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Now, we can accept connection. - AcceptConnection(&client_, kRemoteEndpointId, kCallback); + AcceptConnection(&client_, kRemoteEndpointId, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Now we can send payload. SendPayload(&client_, std::vector{kRemoteEndpointId}, - Payload{ByteArray("data")}, kCallback); + Payload{ByteArray("data")}, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, CancelPayloadCalled) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. RequestConnection(&client_, kRemoteEndpointId, kConnectionRequestInfo, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Now, we can accept connection. - AcceptConnection(&client_, kRemoteEndpointId, kCallback); + AcceptConnection(&client_, kRemoteEndpointId, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // We have to know payload id, before we can cancel payload transfer. // It is either after a call to SendPayload, or after receiving // PayloadProgress callback. Let's assume we have it, and proceed. - CancelPayload(&client_, kPayloadId, kCallback); + CancelPayload(&client_, kPayloadId, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, DisconnectFromEndpointCalled) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. RequestConnection(&client_, kRemoteEndpointId, kConnectionRequestInfo, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Now, we can accept connection. - AcceptConnection(&client_, kRemoteEndpointId, kCallback); + AcceptConnection(&client_, kRemoteEndpointId, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // We can disconnect at any time after RequestConnection. - DisconnectFromEndpoint(&client_, kRemoteEndpointId, kCallback); + DisconnectFromEndpoint(&client_, kRemoteEndpointId, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, RequestConnectionCalledV3) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. auto local_device = v3::ConnectionsDevice(client_.GetLocalEndpointId(), kRequestorName, {}); @@ -690,7 +855,13 @@ TEST_F(ServiceControllerRouterTest, RequestConnectionCalledV3) { bandwidth_changed_latch.CountDown(); }}, }, - kCallback, true); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }, + true); EXPECT_TRUE(initiated_latch.Await().Ok()); EXPECT_TRUE(result_latch.Await().Ok()); EXPECT_TRUE(disconnected_latch.Await().Ok()); @@ -700,7 +871,12 @@ TEST_F(ServiceControllerRouterTest, RequestConnectionCalledV3) { TEST_F(ServiceControllerRouterTest, RequestConnectionV3FakeDevice) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. auto local_device = FakeNearbyDevice(); // Testing callback wrapping as well. @@ -732,7 +908,13 @@ TEST_F(ServiceControllerRouterTest, RequestConnectionV3FakeDevice) { bandwidth_changed_latch.CountDown(); }}, }, - kCallback, true, true, false); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }, + true, true, false); EXPECT_TRUE(initiated_latch.Await().Ok()); EXPECT_TRUE(result_latch.Await().Ok()); EXPECT_TRUE(disconnected_latch.Await().Ok()); @@ -742,22 +924,41 @@ TEST_F(ServiceControllerRouterTest, RequestConnectionV3FakeDevice) { TEST_F(ServiceControllerRouterTest, RequestConnectionV3TwiceFails) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. auto local_device = v3::ConnectionsDevice(client_.GetLocalEndpointId(), kRequestorName, {}); - RequestConnectionV3(&client_, kRemoteDevice, - v3::ConnectionRequestInfo{ - .local_device = local_device, - .listener = {}, - }, - kCallback, false); - RequestConnectionV3(&client_, kRemoteDevice, - v3::ConnectionRequestInfo{ - .local_device = local_device, - .listener = {}, - }, - kCallback, false, false); + RequestConnectionV3( + &client_, kRemoteDevice, + v3::ConnectionRequestInfo{ + .local_device = local_device, + .listener = {}, + }, + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }, + false); + RequestConnectionV3( + &client_, kRemoteDevice, + v3::ConnectionRequestInfo{ + .local_device = local_device, + .listener = {}, + }, + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }, + false, false); { MutexLock lock(&mutex_); EXPECT_EQ(result_.value, Status::kAlreadyConnectedToEndpoint); @@ -767,113 +968,236 @@ TEST_F(ServiceControllerRouterTest, RequestConnectionV3TwiceFails) { TEST_F(ServiceControllerRouterTest, AcceptConnectionCalledV3) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. auto local_device = v3::ConnectionsDevice(client_.GetLocalEndpointId(), kRequestorName, {}); - RequestConnectionV3(&client_, kRemoteDevice, - v3::ConnectionRequestInfo{ - .local_device = local_device, - .listener = {}, - }, - kCallback, false); + RequestConnectionV3( + &client_, kRemoteDevice, + v3::ConnectionRequestInfo{ + .local_device = local_device, + .listener = {}, + }, + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }, + false); // Now, we can accept connection. - AcceptConnectionV3(&client_, kRemoteDevice, kCallback); + AcceptConnectionV3(&client_, kRemoteDevice, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, RejectConnectionCalledV3) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. auto local_device = v3::ConnectionsDevice(client_.GetLocalEndpointId(), kRequestorName, {}); - RequestConnectionV3(&client_, kRemoteDevice, - v3::ConnectionRequestInfo{ - .local_device = local_device, - .listener = {}, - }, - kCallback, false); + RequestConnectionV3( + &client_, kRemoteDevice, + v3::ConnectionRequestInfo{ + .local_device = local_device, + .listener = {}, + }, + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }, + false); // Now, we can reject connection. - RejectConnectionV3(&client_, kRemoteDevice, kCallback); + RejectConnectionV3(&client_, kRemoteDevice, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, InitiateBandwidthUpgradeCalledV3) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. auto local_device = v3::ConnectionsDevice(client_.GetLocalEndpointId(), kRequestorName, {}); - RequestConnectionV3(&client_, kRemoteDevice, - v3::ConnectionRequestInfo{ - .local_device = local_device, - .listener = {}, - }, - kCallback, false); + RequestConnectionV3( + &client_, kRemoteDevice, + v3::ConnectionRequestInfo{ + .local_device = local_device, + .listener = {}, + }, + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }, + false); // Now, we can accept connection. - AcceptConnectionV3(&client_, kRemoteDevice, kCallback); + AcceptConnectionV3(&client_, kRemoteDevice, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Now we can change connection bandwidth. - InitiateBandwidthUpgradeV3(&client_, kRemoteDevice, kCallback); + InitiateBandwidthUpgradeV3(&client_, kRemoteDevice, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, SendPayloadCalledV3) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. auto local_device = v3::ConnectionsDevice(client_.GetLocalEndpointId(), kRequestorName, {}); - RequestConnectionV3(&client_, kRemoteDevice, - v3::ConnectionRequestInfo{ - .local_device = local_device, - .listener = {}, - }, - kCallback, false); + RequestConnectionV3( + &client_, kRemoteDevice, + v3::ConnectionRequestInfo{ + .local_device = local_device, + .listener = {}, + }, + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }, + false); // Now, we can accept connection. - AcceptConnectionV3(&client_, kRemoteDevice, kCallback); + AcceptConnectionV3(&client_, kRemoteDevice, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Now we can send payload. - SendPayloadV3(&client_, kRemoteDevice, Payload{ByteArray("data")}, kCallback); + SendPayloadV3(&client_, kRemoteDevice, Payload{ByteArray("data")}, + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, DisconnectFromDeviceCalledV3) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. auto local_device = v3::ConnectionsDevice(client_.GetLocalEndpointId(), kRequestorName, {}); - RequestConnectionV3(&client_, kRemoteDevice, - v3::ConnectionRequestInfo{ - .local_device = local_device, - .listener = {}, - }, - kCallback, false); + RequestConnectionV3( + &client_, kRemoteDevice, + v3::ConnectionRequestInfo{ + .local_device = local_device, + .listener = {}, + }, + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }, + false); // Now, we can accept connection. - AcceptConnectionV3(&client_, kRemoteDevice, kCallback); + AcceptConnectionV3(&client_, kRemoteDevice, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // We can disconnect at any time after RequestConnection. - DisconnectFromDeviceV3(&client_, kRemoteDevice, kCallback); + DisconnectFromDeviceV3(&client_, kRemoteDevice, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, CancelPayloadV3Called) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kDiscoveryOptions, discovery_listener_, - kCallback); + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // Establish connection. auto local_device = v3::ConnectionsDevice(client_.GetLocalEndpointId(), kRequestorName, {}); - RequestConnectionV3(&client_, kRemoteDevice, - v3::ConnectionRequestInfo{ - .local_device = local_device, - .listener = {}, - }, - kCallback, false); + RequestConnectionV3( + &client_, kRemoteDevice, + v3::ConnectionRequestInfo{ + .local_device = local_device, + .listener = {}, + }, + [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }, + false); // Now, we can accept connection. - AcceptConnectionV3(&client_, kRemoteDevice, kCallback); + AcceptConnectionV3(&client_, kRemoteDevice, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); // We have to know payload id, before we can cancel payload transfer. // It is either after a call to SendPayload, or after receiving // PayloadProgress callback. Let's assume we have it, and proceed. - CancelPayloadV3(&client_, kRemoteDevice, kPayloadId, kCallback); + CancelPayloadV3(&client_, kRemoteDevice, kPayloadId, [this](Status status) { + MutexLock lock(&mutex_); + result_ = status; + complete_ = true; + cond_.Notify(); + }); } TEST_F(ServiceControllerRouterTest, diff --git a/connections/implementation/simulation_user.cc b/connections/implementation/simulation_user.cc index ea8798b2..0c6dd570 100644 --- a/connections/implementation/simulation_user.cc +++ b/connections/implementation/simulation_user.cc @@ -76,7 +76,7 @@ void SimulationUser::OnPayloadProgress(absl::string_view endpoint_id, } bool SimulationUser::WaitForProgress( - std::function predicate, + absl::AnyInvocable predicate, absl::Duration timeout) { Future future; { diff --git a/connections/implementation/simulation_user.h b/connections/implementation/simulation_user.h index 487fca46..7a66e4b7 100644 --- a/connections/implementation/simulation_user.h +++ b/connections/implementation/simulation_user.h @@ -15,6 +15,7 @@ #ifndef CORE_INTERNAL_SIMULATION_USER_H_ #define CORE_INTERNAL_SIMULATION_USER_H_ +#include #include #include "gtest/gtest.h" @@ -22,13 +23,15 @@ #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel_manager.h" #include "connections/implementation/endpoint_manager.h" +#include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/injected_bluetooth_device_store.h" #include "connections/implementation/payload_manager.h" #include "connections/implementation/pcp_manager.h" +#include "internal/flags/nearby_flags.h" #include "internal/platform/condition_variable.h" #include "internal/platform/count_down_latch.h" +#include "internal/platform/feature_flags.h" #include "internal/platform/future.h" -#include "internal/platform/medium_environment.h" // Test-only class to help run end-to-end simulations for nearby connections // protocol. @@ -39,6 +42,26 @@ namespace nearby { namespace connections { +class SetSafeToDisconnect { + public: + explicit SetSafeToDisconnect(bool safe_to_disconnect, + bool payload_received_ack, + std::int32_t safe_to_disconnect_version) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature:: + kEnableSafeToDisconnect, + safe_to_disconnect); + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature:: + kEnablePayloadReceivedAck, + payload_received_ack); + NearbyFlags::GetInstance().OverrideInt64FlagValue( + config_package_nearby::nearby_connections_feature:: + kSafeToDisconnectVersion, + safe_to_disconnect_version); + } +}; + class SimulationUser { public: struct DiscoveredInfo { @@ -134,8 +157,9 @@ class SimulationUser { const DiscoveredInfo& GetDiscovered() const { return discovered_; } ByteArray GetInfo() const { return info_; } - bool WaitForProgress(std::function pred, - absl::Duration timeout); + bool WaitForProgress( + absl::AnyInvocable pred, + absl::Duration timeout); protected: // ConnectionListener callbacks @@ -169,12 +193,13 @@ class SimulationUser { CountDownLatch* lost_latch_ = nullptr; CountDownLatch* payload_latch_ = nullptr; Future* future_ = nullptr; - std::function predicate_; + absl::AnyInvocable predicate_; ByteArray info_; Mediums mediums_; AdvertisingOptions advertising_options_; ConnectionOptions connection_options_; DiscoveryOptions discovery_options_; + SetSafeToDisconnect set_safe_to_disconnect_{true, true, 2}; ClientProxy client_; EndpointChannelManager ecm_; EndpointManager em_{&ecm_}; diff --git a/connections/implementation/webrtc_bwu_handler.cc b/connections/implementation/webrtc_bwu_handler.cc index 535d2bc1..1fbdbb21 100644 --- a/connections/implementation/webrtc_bwu_handler.cc +++ b/connections/implementation/webrtc_bwu_handler.cc @@ -20,6 +20,7 @@ #include #include "absl/functional/bind_front.h" +#include "connections/implementation/base_bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/mediums/utils.h" #include "connections/implementation/mediums/webrtc_peer_id.h" @@ -39,9 +40,9 @@ void WebrtcBwuHandler::WebrtcIncomingSocket::Close() { socket_.Close(); } std::string WebrtcBwuHandler::WebrtcIncomingSocket::ToString() { return name_; } -WebrtcBwuHandler::WebrtcBwuHandler(Mediums& mediums, - BwuNotifications notifications) - : BaseBwuHandler(std::move(notifications)), +WebrtcBwuHandler::WebrtcBwuHandler( + Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) + : BaseBwuHandler(std::move(incoming_connection_callback)), mediums_(mediums) {} // Called by BWU target. Retrieves a new medium info from incoming message, @@ -114,11 +115,8 @@ ByteArray WebrtcBwuHandler::HandleInitializeUpgradedMediumForEndpoint( if (!webrtc_.IsAcceptingConnections(upgrade_service_id)) { if (!webrtc_.StartAcceptingConnections( upgrade_service_id, self_id, location_hint, - { - .accepted_cb = absl::bind_front( - &WebrtcBwuHandler::OnIncomingWebrtcConnection, this, - client), - })) { + absl::bind_front(&WebrtcBwuHandler::OnIncomingWebrtcConnection, + this, client))) { NEARBY_LOG(ERROR, "WebRtcBwuHandler couldn't initiate the WEB_RTC upgrade for " "endpoint %s because it failed to start listening for " @@ -149,7 +147,7 @@ void WebrtcBwuHandler::OnIncomingWebrtcConnection( new IncomingSocketConnection{std::move(webrtc_socket), std::move(channel)}); - bwu_notifications_.incoming_connection_cb(client, std::move(connection)); + NotifyOnIncomingConnection(client, std::move(connection)); } } // namespace connections diff --git a/connections/implementation/webrtc_bwu_handler.h b/connections/implementation/webrtc_bwu_handler.h index 46faae34..c45f7946 100644 --- a/connections/implementation/webrtc_bwu_handler.h +++ b/connections/implementation/webrtc_bwu_handler.h @@ -32,7 +32,9 @@ namespace connections { // per-Medium-specific operations needed to upgrade an EndpointChannel. class WebrtcBwuHandler : public BaseBwuHandler { public: - explicit WebrtcBwuHandler(Mediums& mediums, BwuNotifications notifications); + explicit WebrtcBwuHandler( + Mediums& mediums, + IncomingConnectionCallback incoming_connection_callback); private: class WebrtcIncomingSocket : public BwuHandler::IncomingSocket { diff --git a/connections/implementation/webrtc_bwu_handler_stub.cc b/connections/implementation/webrtc_bwu_handler_stub.cc index f4590027..91f19c1f 100644 --- a/connections/implementation/webrtc_bwu_handler_stub.cc +++ b/connections/implementation/webrtc_bwu_handler_stub.cc @@ -37,9 +37,9 @@ void WebrtcBwuHandler::WebrtcIncomingSocket::Close() {} std::string WebrtcBwuHandler::WebrtcIncomingSocket::ToString() { return ""; } -WebrtcBwuHandler::WebrtcBwuHandler(Mediums& mediums, - BwuNotifications notifications) - : BaseBwuHandler(std::move(notifications)), +WebrtcBwuHandler::WebrtcBwuHandler( + Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) + : BaseBwuHandler(std::move(incoming_connection_callback)), mediums_(mediums) {} // Called by BWU target. Retrieves a new medium info from incoming message, diff --git a/connections/implementation/webrtc_bwu_handler_stub.h b/connections/implementation/webrtc_bwu_handler_stub.h index f4aec1ac..de0a9ff1 100644 --- a/connections/implementation/webrtc_bwu_handler_stub.h +++ b/connections/implementation/webrtc_bwu_handler_stub.h @@ -36,7 +36,9 @@ namespace connections { // per-Medium-specific operations needed to upgrade an EndpointChannel. class WebrtcBwuHandler : public BaseBwuHandler { public: - explicit WebrtcBwuHandler(Mediums& mediums, BwuNotifications notifications); + explicit WebrtcBwuHandler( + Mediums& mediums, + IncomingConnectionCallback incoming_connection_callback); private: class WebrtcIncomingSocket : public BwuHandler::IncomingSocket { diff --git a/connections/implementation/wifi_direct_bwu_handler.cc b/connections/implementation/wifi_direct_bwu_handler.cc index c7ed4317..0ff387c1 100644 --- a/connections/implementation/wifi_direct_bwu_handler.cc +++ b/connections/implementation/wifi_direct_bwu_handler.cc @@ -28,9 +28,10 @@ namespace nearby { namespace connections { -WifiDirectBwuHandler::WifiDirectBwuHandler(Mediums& mediums, - BwuNotifications notifications) - : BaseBwuHandler(std::move(notifications)), mediums_(mediums) {} +WifiDirectBwuHandler::WifiDirectBwuHandler( + Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) + : BaseBwuHandler(std::move(incoming_connection_callback)), + mediums_(mediums) {} ByteArray WifiDirectBwuHandler::HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, @@ -44,11 +45,9 @@ ByteArray WifiDirectBwuHandler::HandleInitializeUpgradedMediumForEndpoint( if (!wifi_direct_medium_.IsAcceptingConnections(upgrade_service_id)) { if (!wifi_direct_medium_.StartAcceptingConnections( upgrade_service_id, - { - .accepted_cb = absl::bind_front( - &WifiDirectBwuHandler::OnIncomingWifiDirectConnection, this, - client), - })) { + absl::bind_front( + &WifiDirectBwuHandler::OnIncomingWifiDirectConnection, this, + client))) { NEARBY_LOGS(ERROR) << "WifiDirectBwuHandler couldn't initiate WifiDirect upgrade for " << "service " << upgrade_service_id << " and endpoint " << endpoint_id @@ -149,7 +148,7 @@ void WifiDirectBwuHandler::OnIncomingWifiDirectConnection( upgrade_service_id, socket), .channel = std::move(channel), }); - bwu_notifications_.incoming_connection_cb(client, std::move(connection)); + NotifyOnIncomingConnection(client, std::move(connection)); } } // namespace connections diff --git a/connections/implementation/wifi_direct_bwu_handler.h b/connections/implementation/wifi_direct_bwu_handler.h index 47424259..e7f159ea 100644 --- a/connections/implementation/wifi_direct_bwu_handler.h +++ b/connections/implementation/wifi_direct_bwu_handler.h @@ -29,14 +29,15 @@ namespace connections { // per-Medium-specific operations needed to upgrade an EndpointChannel. class WifiDirectBwuHandler : public BaseBwuHandler { public: - explicit WifiDirectBwuHandler(Mediums& mediums, - BwuNotifications notifications); + explicit WifiDirectBwuHandler( + Mediums& mediums, + IncomingConnectionCallback incoming_connection_callback); private: class WifiDirectIncomingSocket : public BwuHandler::IncomingSocket { public: explicit WifiDirectIncomingSocket(const std::string& name, - WifiDirectSocket socket) + WifiDirectSocket socket) : name_(name), socket_(socket) {} std::string ToString() override { return name_; } @@ -73,8 +74,8 @@ class WifiDirectBwuHandler : public BaseBwuHandler { // Accept Connection Callback. void OnIncomingWifiDirectConnection(ClientProxy* client, - const std::string& upgrade_service_id, - WifiDirectSocket socket); + const std::string& upgrade_service_id, + WifiDirectSocket socket); Mediums& mediums_; Wifi& wifi_medium_ = mediums_.GetWifi(); diff --git a/connections/implementation/wifi_direct_bwu_test.cc b/connections/implementation/wifi_direct_bwu_test.cc index 127065f2..b01d9998 100644 --- a/connections/implementation/wifi_direct_bwu_test.cc +++ b/connections/implementation/wifi_direct_bwu_test.cc @@ -38,11 +38,10 @@ class WifiDirectTest : public testing::Test { }; TEST_F(WifiDirectTest, CanCreateBwuHandler) { - BwuHandler::BwuNotifications notifications = {.incoming_connection_cb = {}}; ClientProxy client; Mediums mediums; - auto handler = std::make_unique(mediums, notifications); + auto handler = std::make_unique(mediums, nullptr); handler->InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"B", /*endpoint_id=*/"2"); @@ -56,29 +55,23 @@ TEST_F(WifiDirectTest, WFDGOBWUInit_GCCreateEndpointChannel) { CountDownLatch accept_latch(1); CountDownLatch end_latch(1); - BwuHandler::BwuNotifications notifications_1{ - .incoming_connection_cb = - [&accept_latch, &end_latch]( - ClientProxy* client, - std::unique_ptr - mutable_connection) { - NEARBY_LOGS(WARNING) << "Server socket connection accept call back"; - std::shared_ptr connection( - mutable_connection.release()); - accept_latch.CountDown(); - EXPECT_TRUE(end_latch.Await(kWaitDuration).result()); - NEARBY_LOGS(WARNING) << "Test is done. Close the socket"; - connection->channel->Close(); - connection->socket->Close(); - }, - }; - BwuHandler::BwuNotifications notifications_2 = {.incoming_connection_cb = {}}; ClientProxy wifi_direct_go, wifi_direct_gc; Mediums mediums_1, mediums_2; ExceptionOr upgrade_frame; - auto handler_1 = - std::make_unique(mediums_1, notifications_1); + auto handler_1 = std::make_unique( + mediums_1, [&](ClientProxy* client, + std::unique_ptr + mutable_connection) { + NEARBY_LOGS(WARNING) << "Server socket connection accept call back"; + std::shared_ptr connection( + mutable_connection.release()); + accept_latch.CountDown(); + EXPECT_TRUE(end_latch.Await(kWaitDuration).result()); + NEARBY_LOGS(WARNING) << "Test is done. Close the socket"; + connection->channel->Close(); + connection->socket->Close(); + }); SingleThreadExecutor server_executor; server_executor.Execute( @@ -98,10 +91,9 @@ TEST_F(WifiDirectTest, WFDGOBWUInit_GCCreateEndpointChannel) { EXPECT_TRUE(start_latch.Await(kWaitDuration).result()); EXPECT_FALSE(mediums_2.GetWifiDirect().IsConnectedToGO()); std::unique_ptr handler_2 = - std::make_unique(mediums_2, notifications_2); + std::make_unique(mediums_2, nullptr); - client_executor.Execute([&handler_2, &wifi_direct_gc, &upgrade_frame, - &accept_latch, &end_latch, &mediums_2]() { + client_executor.Execute([&]() { auto bwu_frame = upgrade_frame.result().v1().bandwidth_upgrade_negotiation(); diff --git a/connections/implementation/wifi_hotspot_bwu_handler.cc b/connections/implementation/wifi_hotspot_bwu_handler.cc index 58acf86d..9479924d 100644 --- a/connections/implementation/wifi_hotspot_bwu_handler.cc +++ b/connections/implementation/wifi_hotspot_bwu_handler.cc @@ -29,9 +29,10 @@ namespace nearby { namespace connections { -WifiHotspotBwuHandler::WifiHotspotBwuHandler(Mediums& mediums, - BwuNotifications notifications) - : BaseBwuHandler(std::move(notifications)), mediums_(mediums) {} +WifiHotspotBwuHandler::WifiHotspotBwuHandler( + Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) + : BaseBwuHandler(std::move(incoming_connection_callback)), + mediums_(mediums) {} // Called by BWU initiator. Set up WifiHotspot upgraded medium for this // endpoint, and returns a upgrade path info (SSID, Password, Gateway used as @@ -48,11 +49,9 @@ ByteArray WifiHotspotBwuHandler::HandleInitializeUpgradedMediumForEndpoint( if (!wifi_hotspot_medium_.IsAcceptingConnections(upgrade_service_id)) { if (!wifi_hotspot_medium_.StartAcceptingConnections( upgrade_service_id, - { - .accepted_cb = absl::bind_front( - &WifiHotspotBwuHandler::OnIncomingWifiHotspotConnection, - this, client), - })) { + absl::bind_front( + &WifiHotspotBwuHandler::OnIncomingWifiHotspotConnection, this, + client))) { NEARBY_LOGS(ERROR) << "WifiHotspotBwuHandler couldn't initiate WifiHotspot upgrade for " << "service " << upgrade_service_id << " and endpoint " << endpoint_id @@ -157,7 +156,7 @@ void WifiHotspotBwuHandler::OnIncomingWifiHotspotConnection( upgrade_service_id, socket), .channel = std::move(channel), }); - bwu_notifications_.incoming_connection_cb(client, std::move(connection)); + NotifyOnIncomingConnection(client, std::move(connection)); } } // namespace connections diff --git a/connections/implementation/wifi_hotspot_bwu_handler.h b/connections/implementation/wifi_hotspot_bwu_handler.h index f7668c45..3e4fd611 100644 --- a/connections/implementation/wifi_hotspot_bwu_handler.h +++ b/connections/implementation/wifi_hotspot_bwu_handler.h @@ -29,14 +29,15 @@ namespace connections { // per-Medium-specific operations needed to upgrade an EndpointChannel. class WifiHotspotBwuHandler : public BaseBwuHandler { public: - explicit WifiHotspotBwuHandler(Mediums& mediums, - BwuNotifications notifications); + explicit WifiHotspotBwuHandler( + Mediums& mediums, + IncomingConnectionCallback incoming_connection_callback); private: class WifiHotspotIncomingSocket : public BwuHandler::IncomingSocket { public: explicit WifiHotspotIncomingSocket(const std::string& name, - WifiHotspotSocket socket) + WifiHotspotSocket socket) : name_(name), socket_(socket) {} std::string ToString() override { return name_; } @@ -64,8 +65,8 @@ class WifiHotspotBwuHandler : public BaseBwuHandler { const std::string& upgrade_service_id) final; void OnIncomingWifiHotspotConnection(ClientProxy* client, - const std::string& upgrade_service_id, - WifiHotspotSocket socket); + const std::string& upgrade_service_id, + WifiHotspotSocket socket); Mediums& mediums_; WifiHotspot& wifi_hotspot_medium_{mediums_.GetWifiHotspot()}; diff --git a/connections/implementation/wifi_hotspot_test.cc b/connections/implementation/wifi_hotspot_test.cc index c24a2988..091087c3 100644 --- a/connections/implementation/wifi_hotspot_test.cc +++ b/connections/implementation/wifi_hotspot_test.cc @@ -37,12 +37,10 @@ class WifiHotspotTest : public testing::Test { }; TEST_F(WifiHotspotTest, CanCreateBwuHandler) { - BwuHandler::BwuNotifications notifications{.incoming_connection_cb = {}}; ClientProxy client; Mediums mediums; - auto handler = - std::make_unique(mediums, notifications); + auto handler = std::make_unique(mediums, nullptr); handler->InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"B", /*endpoint_id=*/"2"); @@ -56,48 +54,40 @@ TEST_F(WifiHotspotTest, SoftAPBWUInit_STACreateEndpointChannel) { CountDownLatch accept_latch(1); CountDownLatch end_latch(1); - BwuHandler::BwuNotifications notifications_1{ - .incoming_connection_cb = - [&accept_latch, &end_latch]( - ClientProxy* client, - std::unique_ptr - mutable_connection) { - NEARBY_LOGS(WARNING) << "Server socket connection accept call back"; - accept_latch.CountDown(); - EXPECT_TRUE(end_latch.Await(kWaitDuration).result()); - }, - }; - BwuHandler::BwuNotifications notifications_2{.incoming_connection_cb = {}}; ClientProxy client_1, client_2; Mediums mediums_1, mediums_2; ExceptionOr upgrade_frame; - auto handler_1 = - std::make_unique(mediums_1, notifications_1); + auto handler_1 = std::make_unique( + mediums_1, [&](ClientProxy* client, + std::unique_ptr + mutable_connection) { + NEARBY_LOGS(WARNING) << "Server socket connection accept call back"; + accept_latch.CountDown(); + EXPECT_TRUE(end_latch.Await(kWaitDuration).result()); + }); // client_1 works as Hotspot SoftAP SingleThreadExecutor server_executor; - server_executor.Execute( - [&handler_1, &client_1, &upgrade_frame, &start_latch]() { - ByteArray upgrade_path_available_frame = - handler_1->InitializeUpgradedMediumForEndpoint(&client_1, - /*service_id=*/"A", - /*endpoint_id=*/"1"); - EXPECT_FALSE(upgrade_path_available_frame.Empty()); + server_executor.Execute([&]() { + ByteArray upgrade_path_available_frame = + handler_1->InitializeUpgradedMediumForEndpoint(&client_1, + /*service_id=*/"A", + /*endpoint_id=*/"1"); + EXPECT_FALSE(upgrade_path_available_frame.Empty()); - upgrade_frame = parser::FromBytes(upgrade_path_available_frame); - start_latch.CountDown(); - }); + upgrade_frame = parser::FromBytes(upgrade_path_available_frame); + start_latch.CountDown(); + }); // client_2 works as Hotspot STA which will connect to client_1 SingleThreadExecutor client_executor; // Wait till client_1 started as hotspot and then connect to it EXPECT_TRUE(start_latch.Await(kWaitDuration).result()); std::unique_ptr handler_2 = - std::make_unique(mediums_2, notifications_2); + std::make_unique(mediums_2, nullptr); - client_executor.Execute([&handler_2, &client_2, &upgrade_frame, &accept_latch, - &end_latch, &mediums_2]() { + client_executor.Execute([&]() { auto bwu_frame = upgrade_frame.result().v1().bandwidth_upgrade_negotiation(); diff --git a/connections/implementation/wifi_lan_bwu_handler.cc b/connections/implementation/wifi_lan_bwu_handler.cc index 3c74764d..2a455e0c 100644 --- a/connections/implementation/wifi_lan_bwu_handler.cc +++ b/connections/implementation/wifi_lan_bwu_handler.cc @@ -28,9 +28,10 @@ namespace nearby { namespace connections { -WifiLanBwuHandler::WifiLanBwuHandler(Mediums& mediums, - BwuNotifications notifications) - : BaseBwuHandler(std::move(notifications)), mediums_(mediums) {} +WifiLanBwuHandler::WifiLanBwuHandler( + Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) + : BaseBwuHandler(std::move(incoming_connection_callback)), + mediums_(mediums) {} // Called by BWU target. Retrieves a new medium info from incoming message, // and establishes connection over WifiLan using this info. @@ -94,11 +95,8 @@ ByteArray WifiLanBwuHandler::HandleInitializeUpgradedMediumForEndpoint( if (!wifi_lan_medium_.IsAcceptingConnections(upgrade_service_id)) { if (!wifi_lan_medium_.StartAcceptingConnections( upgrade_service_id, - { - .accepted_cb = absl::bind_front( - &WifiLanBwuHandler::OnIncomingWifiLanConnection, this, - client), - })) { + absl::bind_front(&WifiLanBwuHandler::OnIncomingWifiLanConnection, + this, client))) { NEARBY_LOGS(ERROR) << "WifiLanBwuHandler couldn't initiate the WifiLan upgrade for " << "service " << upgrade_service_id << " and endpoint " << endpoint_id @@ -153,7 +151,7 @@ void WifiLanBwuHandler::OnIncomingWifiLanConnection( socket), .channel = std::move(channel), }); - bwu_notifications_.incoming_connection_cb(client, std::move(connection)); + NotifyOnIncomingConnection(client, std::move(connection)); } } // namespace connections diff --git a/connections/implementation/wifi_lan_bwu_handler.h b/connections/implementation/wifi_lan_bwu_handler.h index 13d3626b..aee1ae01 100644 --- a/connections/implementation/wifi_lan_bwu_handler.h +++ b/connections/implementation/wifi_lan_bwu_handler.h @@ -29,7 +29,9 @@ namespace connections { // per-Medium-specific operations needed to upgrade an EndpointChannel. class WifiLanBwuHandler : public BaseBwuHandler { public: - explicit WifiLanBwuHandler(Mediums& mediums, BwuNotifications notifications); + explicit WifiLanBwuHandler( + Mediums& mediums, + IncomingConnectionCallback incoming_connection_callback); private: class WifiLanIncomingSocket : public BwuHandler::IncomingSocket { diff --git a/connections/listeners.h b/connections/listeners.h index 92bb76b3..15ed72f7 100644 --- a/connections/listeners.h +++ b/connections/listeners.h @@ -42,12 +42,9 @@ namespace connections { // This is not the same as completion of the associated process, // which may have many states, and multiple async jobs, and be still ongoing. // Progress on the overall process is reported by the associated listener. -struct ResultCallback { - // Callback to access the status of the operation when available. - // status - result of job execution; - // Status::kSuccess, if successful; anything else indicates failure. - std::function result_cb = [](Status) {}; -}; +// status - result of job execution; +// Status::kSuccess, if successful; anything else indicates failure. +using ResultCallback = absl::AnyInvocable; struct ConnectionResponseInfo { std::string GetAuthenticationDigits() { diff --git a/connections/payload.cc b/connections/payload.cc index 81cd9015..8b43133f 100644 --- a/connections/payload.cc +++ b/connections/payload.cc @@ -15,7 +15,18 @@ #include "connections/payload.h" #include +#include +#include +#include #include +#include +#include + +#include "connections/payload_type.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/file.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/prng.h" namespace nearby { namespace connections { @@ -43,8 +54,7 @@ Payload::~Payload() = default; Payload& Payload::operator=(Payload&& other) noexcept = default; // Default (invalid) payload. -Payload::Payload() - : type_(PayloadType::kUnknown), content_(absl::monostate()) {} +Payload::Payload() : type_(PayloadType::kUnknown), content_(std::monostate()) {} // Constructors for outgoing payloads. Payload::Payload(ByteArray&& bytes) @@ -73,7 +83,7 @@ Payload::Payload(std::string parent_folder, std::string file_name, type_(PayloadType::kFile), content_(std::move(input_file)) {} -Payload::Payload(std::function stream) +Payload::Payload(std::unique_ptr stream) : type_(PayloadType::kStream), content_(std::move(stream)) {} // Constructors for incoming payloads. @@ -91,22 +101,23 @@ Payload::Payload(Id id, std::string parent_folder, std::string file_name, type_(PayloadType::kFile), content_(std::move(input_file)) {} -Payload::Payload(Id id, std::function stream) +Payload::Payload(Id id, std::unique_ptr stream) : id_(id), type_(PayloadType::kStream), content_(std::move(stream)) {} // Returns ByteArray payload, if it has been defined, or empty ByteArray. const ByteArray& Payload::AsBytes() const& { static const ByteArray empty; // NOLINT: function-level static is OK. - auto* result = absl::get_if(&content_); + auto* result = std::get_if(&content_); return result ? *result : empty; } // Returns InputStream* payload, if it has been defined, or nullptr. InputStream* Payload::AsStream() { - auto* result = absl::get_if>(&content_); - return result ? &(*result)() : nullptr; + auto* result = std::get_if>(&content_); + return result ? result->get() : nullptr; } + // Returns InputFile* payload, if it has been defined, or nullptr. -InputFile* Payload::AsFile() { return absl::get_if(&content_); } +InputFile* Payload::AsFile() { return std::get_if(&content_); } // Returns Payload unique ID. Payload::Id Payload::GetId() const { return id_; } diff --git a/connections/payload.h b/connections/payload.h index f5a01d42..4c554828 100644 --- a/connections/payload.h +++ b/connections/payload.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "absl/types/variant.h" #include "connections/payload_type.h" @@ -40,8 +41,8 @@ class Payload { using Id = PayloadId; // Order of types in variant, and values in Type enum is important. // Enum values must match respective variant types. - using Content = absl::variant, InputFile>; + using Content = std::variant, InputFile>; Payload(Payload&& other) noexcept; ~Payload(); @@ -71,7 +72,7 @@ class Payload { explicit Payload(std::string parent_folder, std::string file_name, InputFile file); - explicit Payload(std::function stream); + explicit Payload(std::unique_ptr stream); // Constructors for incoming payloads. Payload(Id id, ByteArray&& bytes); @@ -79,7 +80,7 @@ class Payload { Payload(Id id, InputFile file); Payload(Id id, std::string parent_folder, std::string file_name, InputFile input_file); - Payload(Id id, std::function stream); + Payload(Id id, std::unique_ptr stream); // Returns ByteArray payload, if it has been defined, or empty ByteArray. const ByteArray& AsBytes() const&; diff --git a/connections/payload_test.cc b/connections/payload_test.cc index 06d126cd..7a3aad02 100644 --- a/connections/payload_test.cc +++ b/connections/payload_test.cc @@ -16,6 +16,7 @@ #include #include +#include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" @@ -95,19 +96,14 @@ TEST(PayloadTest, TEST(PayloadTest, SupportsStreamType) { constexpr size_t kOffset = 1234456; - auto pipe = std::make_shared(); + auto [input, output] = CreatePipe(); + InputStream* input_stream = input.get(); - Payload payload([streamable = pipe]() -> InputStream& { - // For some reason, linter warns us that we return a dangling reference. - // This is not true: we return a reference to internal variable of a - // shared_ptr which remains valid while Payload is valid, since - // shared_ptr is captured by value. - return streamable->GetInputStream(); // NOLINT - }); + Payload payload(std::move(input)); payload.SetOffset(kOffset); EXPECT_EQ(payload.GetType(), PayloadType::kStream); - EXPECT_EQ(payload.AsStream(), &pipe->GetInputStream()); + EXPECT_EQ(payload.AsStream(), input_stream); EXPECT_EQ(payload.AsFile(), nullptr); EXPECT_EQ(payload.AsBytes(), ByteArray{}); EXPECT_EQ(payload.GetOffset(), kOffset); diff --git a/connections/status.cc b/connections/status.cc index 976f455e..46216ab3 100644 --- a/connections/status.cc +++ b/connections/status.cc @@ -53,6 +53,12 @@ std::string Status::ToString() const { return "kWifiLanError"; case Status::kPayloadUnknown: return "kPayloadUnknown"; + case Status::kReset: + return "kReset"; + case Status::kTimeout: + return "kTimeout"; + case Status::kUnknown: + // fall through default: return "Unknown"; } diff --git a/connections/status.h b/connections/status.h index cc40005c..0c2c1fa0 100644 --- a/connections/status.h +++ b/connections/status.h @@ -22,7 +22,7 @@ namespace connections { // Protocol operation result: kSuccess, if operation was successful; // descriptive error code otherwise. -// LINT.IfChange +// LINT.IfChange(status_enum) struct Status { // Status is a struct, so it is possible to pass some context about failure, // by adding extra fields to it when necessary, and not change any of the @@ -44,6 +44,9 @@ struct Status { kBleError, kWifiLanError, kPayloadUnknown, + kReset, + kTimeout, + kUnknown, kNextValue, }; Value value{kError}; @@ -53,9 +56,9 @@ struct Status { std::string ToString() const; }; // LINT.ThenChange( -// //depot/google3/location/nearby/cpp/sharing/implementation/nearby_connections_manager.cc:24 -// //depot/google3/location/nearby/cpp/sharing/implementation/nearby_connections_types.h:46 -// //depot/google3/location/nearby/cpp/sharing/implementation/nearby_connections_types_test.cc +// ../sharing/nearby_connections_manager.cc:status_enum, +// ../sharing/nearby_connections_types.h:status_enum, +// ../sharing/nearby_connections_types_test.cc:status_enum // ) inline bool operator==(const Status& a, const Status& b) { diff --git a/connections/swift/NearbyCoreAdapter/BUILD b/connections/swift/NearbyCoreAdapter/BUILD index d92ec9c2..e6103c51 100644 --- a/connections/swift/NearbyCoreAdapter/BUILD +++ b/connections/swift/NearbyCoreAdapter/BUILD @@ -36,7 +36,6 @@ objc_library( "//internal/platform:base", "//internal/platform/implementation/apple", # buildcleaner: keep "//third_party/apple_frameworks:Foundation", - "//third_party/apple_frameworks:ObjectiveC", "//third_party/objective_c/google_toolbox_for_mac:GTM_Logger", ], ) diff --git a/connections/swift/NearbyCoreAdapter/Sources/CPPInputStream.h b/connections/swift/NearbyCoreAdapter/Sources/CPPInputStream.h new file mode 100644 index 00000000..67be0b85 --- /dev/null +++ b/connections/swift/NearbyCoreAdapter/Sources/CPPInputStream.h @@ -0,0 +1,45 @@ +// Copyright 2022 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. + +// Note: File language is detected using heuristics. Many Objective-C++ headers +// are incorrectly classified as C++ resulting in invalid linter errors. The use +// of "NSArray" and other Foundation classes like "NSData", "NSDictionary" and +// "NSUUID" are highly weighted for Objective-C and Objective-C++ scores. Oddly, +// "#import " does not contribute any points. This +// comment alone should be enough to trick the IDE in to believing this is +// actually some sort of Objective-C file. See: +// cs/google3/devtools/search/lang/recognize_language_classifiers_data + +#import + +#ifdef __cplusplus + +// TODO(b/239758418): Change this to the non-internal version when available. +#include "internal/platform/input_stream.h" + +class CPPInputStream : public nearby::InputStream { + public: + explicit CPPInputStream(NSInputStream *iStream); + + ~CPPInputStream() override; + + nearby::ExceptionOr Read(std::int64_t size) override; + + nearby::Exception Close() override; + + private: + NSInputStream *iStream_; +}; + +#endif diff --git a/connections/swift/NearbyCoreAdapter/Sources/CPPInputStream.mm b/connections/swift/NearbyCoreAdapter/Sources/CPPInputStream.mm new file mode 100644 index 00000000..a3fe9728 --- /dev/null +++ b/connections/swift/NearbyCoreAdapter/Sources/CPPInputStream.mm @@ -0,0 +1,46 @@ +// Copyright 2022 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. + +#import "connections/swift/NearbyCoreAdapter/Sources/CPPInputStream.h" + +#import + +#include +#include + +using ::nearby::ByteArray; +using ::nearby::Exception; +using ::nearby::ExceptionOr; + +CPPInputStream::CPPInputStream(NSInputStream *iStream) : iStream_(iStream) { [iStream_ open]; } + +CPPInputStream::~CPPInputStream() { Close(); } + +ExceptionOr CPPInputStream::Read(std::int64_t size) { + std::vector buffer; + buffer.reserve(size); + NSInteger numberOfBytesRead = [iStream_ read:buffer.data() maxLength:size]; + if (numberOfBytesRead == 0) { + return ExceptionOr(); + } + if (numberOfBytesRead < 0) { + return ExceptionOr(Exception::kIo); + } + return ExceptionOr(ByteArray((const char *)buffer.data(), numberOfBytesRead)); +} + +Exception CPPInputStream::Close() { + [iStream_ close]; + return Exception{Exception::kSuccess}; +} diff --git a/connections/swift/NearbyCoreAdapter/Sources/CPPInputStreamBinding.h b/connections/swift/NearbyCoreAdapter/Sources/CPPInputStreamBinding.h deleted file mode 100644 index 06aac0d9..00000000 --- a/connections/swift/NearbyCoreAdapter/Sources/CPPInputStreamBinding.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2022 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. - -#import - -#ifdef __cplusplus - -namespace nearby { -class InputStream; -} - -#endif - -@interface CPPInputStreamBinding : NSObject - -/** - * Creates and attaches a @c CPPInputStreamBinding object to the provided stream as an associated - * object. - * - * This association makes it possible for a c++ pointer to live as long as the original user - * provided @c NSInputStream object. - * - * @param stream The stream to become associated with. - */ -+ (void)bindToStream:(NSInputStream *)stream; - -#ifdef __cplusplus -/** - * Retreives a reference to the c++ pointer associated to the provided stream. - * - * CPPInputStreamBinding::bindToStream: must be called on the this stream before calling this - * function. - * - * @param stream The stream that has a c++ pointer associated with it. - */ -+ (nearby::InputStream &)getRefFromStream:(NSInputStream *)stream; -#endif - -@end diff --git a/connections/swift/NearbyCoreAdapter/Sources/CPPInputStreamBinding.mm b/connections/swift/NearbyCoreAdapter/Sources/CPPInputStreamBinding.mm deleted file mode 100644 index d546ba5c..00000000 --- a/connections/swift/NearbyCoreAdapter/Sources/CPPInputStreamBinding.mm +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2022 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. - -#import "connections/swift/NearbyCoreAdapter/Sources/CPPInputStreamBinding.h" - -#import -#import - -#include -#include - -// TODO(b/239758418): Change this to the non-internal version when available. -#include "internal/platform/input_stream.h" - -using ::nearby::ByteArray; -using ::nearby::Exception; -using ::nearby::ExceptionOr; -using ::nearby::InputStream; - -class CPPInputStream : public InputStream { - public: - explicit CPPInputStream(NSInputStream *iStream) : iStream_(iStream) { [iStream_ open]; } - - ~CPPInputStream() override { Close(); } - - ExceptionOr Read(std::int64_t size) override { - std::vector buffer; - buffer.reserve(size); - NSInteger numberOfBytesRead = [iStream_ read:buffer.data() maxLength:size]; - if (numberOfBytesRead == 0) { - return ExceptionOr(); - } - if (numberOfBytesRead < 0) { - return ExceptionOr(Exception::kIo); - } - return ExceptionOr(ByteArray((const char *)buffer.data(), numberOfBytesRead)); - } - - Exception Close() override { - [iStream_ close]; - return Exception{Exception::kSuccess}; - } - - private: - // Prevent a retain cycle since NSInputStream will have a strong reference to this object. - __weak NSInputStream *iStream_; -}; - -// Wrap a c++ InputStream subclass in objective-c so it can be associated with the original -// NSInputStream object. The association makes it possible for the unique_ptr to live as long as -// the original user provided NSInputStream. -@implementation CPPInputStreamBinding { - @public - std::unique_ptr _cppStream; -} - -// This field's address is used as a unique identifier. -static char gAssociatedStreamKey; - -- (instancetype)initWithStream:(NSInputStream *)stream { - self = [super init]; - if (self) { - _cppStream = std::make_unique(stream); - } - return self; -} - -+ (void)bindToStream:(NSInputStream *)stream { - CPPInputStreamBinding *binding = [[CPPInputStreamBinding alloc] initWithStream:stream]; - objc_setAssociatedObject(stream, &gAssociatedStreamKey, binding, - OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -+ (InputStream &)getRefFromStream:(NSInputStream *)stream { - CPPInputStreamBinding *binding = objc_getAssociatedObject(stream, &gAssociatedStreamKey); - return *binding->_cppStream; -} - -@end diff --git a/connections/swift/NearbyCoreAdapter/Sources/GNCCoreAdapter.mm b/connections/swift/NearbyCoreAdapter/Sources/GNCCoreAdapter.mm index a62da260..ef72eded 100644 --- a/connections/swift/NearbyCoreAdapter/Sources/GNCCoreAdapter.mm +++ b/connections/swift/NearbyCoreAdapter/Sources/GNCCoreAdapter.mm @@ -87,6 +87,12 @@ GNCStatus GNCStatusFromCppStatus(Status status) { return GNCStatusWifiLanError; case Status::kPayloadUnknown: return GNCStatusPayloadUnknown; + case Status::kReset: + return GNCStatusReset; + case Status::kTimeout: + return GNCStatusTimeout; + case Status::kUnknown: + return GNCStatusUnknown; case Status::kNextValue: return GNCStatusUnknown; } @@ -162,27 +168,26 @@ GNCStatus GNCStatusFromCppStatus(Status status) { ByteArray((const char *)endpointInfo.bytes, endpointInfo.length); connection_request_info.listener = std::move(listener); - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->StartAdvertising(service_id, advertising_options, connection_request_info, result); + _core->StartAdvertising(service_id, advertising_options, connection_request_info, + std::move(result)); } - (void)stopAdvertisingWithCompletionHandler:(void (^)(NSError *error))completionHandler { - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->StopAdvertising(result); + _core->StopAdvertising(std::move(result)); } - (void)startDiscoveryAsService:(NSString *)serviceID @@ -205,27 +210,25 @@ GNCStatus GNCStatusFromCppStatus(Status status) { [delegate lostEndpoint:endpointID]; }; - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->StartDiscovery(service_id, discovery_options, std::move(listener), result); + _core->StartDiscovery(service_id, discovery_options, std::move(listener), std::move(result)); } - (void)stopDiscoveryWithCompletionHandler:(void (^)(NSError *error))completionHandler { - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->StopDiscovery(result); + _core->StopDiscovery(std::move(result)); } - (void)requestConnectionToEndpoint:(NSString *)endpointID @@ -265,15 +268,15 @@ GNCStatus GNCStatusFromCppStatus(Status status) { ConnectionOptions connection_options = [connectionOptions toCpp]; - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->RequestConnection(endpoint_id, connection_request_info, connection_options, result); + _core->RequestConnection(endpoint_id, connection_request_info, connection_options, + std::move(result)); } - (void)acceptConnectionRequestFromEndpoint:(NSString *)endpointID @@ -312,30 +315,28 @@ GNCStatus GNCStatusFromCppStatus(Status status) { totalBytes:info.total_bytes]; }; - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->AcceptConnection(endpoint_id, std::move(listener), result); + _core->AcceptConnection(endpoint_id, std::move(listener), std::move(result)); } - (void)rejectConnectionRequestFromEndpoint:(NSString *)endpointID withCompletionHandler:(void (^)(NSError *error))completionHandler { std::string endpoint_id = [endpointID cStringUsingEncoding:[NSString defaultCStringEncoding]]; - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->RejectConnection(endpoint_id, result); + _core->RejectConnection(endpoint_id, std::move(result)); } - (void)sendPayload:(GNCPayload *)payload @@ -348,69 +349,64 @@ GNCStatus GNCStatusFromCppStatus(Status status) { endpoint_ids.push_back(endpoint_id); } - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->SendPayload(endpoint_ids, [payload toCpp], result); + _core->SendPayload(endpoint_ids, [payload toCpp], std::move(result)); } - (void)cancelPayload:(int64_t)payloadID withCompletionHandler:(void (^)(NSError *error))completionHandler { - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->CancelPayload(payloadID, result); + _core->CancelPayload(payloadID, std::move(result)); } - (void)disconnectFromEndpoint:(NSString *)endpointID withCompletionHandler:(void (^)(NSError *error))completionHandler { std::string endpoint_id = [endpointID cStringUsingEncoding:[NSString defaultCStringEncoding]]; - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->DisconnectFromEndpoint(endpoint_id, result); + _core->DisconnectFromEndpoint(endpoint_id, std::move(result)); } - (void)stopAllEndpointsWithCompletionHandler:(void (^)(NSError *error))completionHandler { - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->StopAllEndpoints(result); + _core->StopAllEndpoints(std::move(result)); } - (void)initiateBandwidthUpgrade:(NSString *)endpointID withCompletionHandler:(void (^)(NSError *error))completionHandler { std::string endpoint_id = [endpointID cStringUsingEncoding:[NSString defaultCStringEncoding]]; - ResultListener result; - result.result_cb = ^(Status status) { + ResultListener result = [completionHandler](Status status) { NSError *err = NSErrorFromCppStatus(status); if (completionHandler) { completionHandler(err); } }; - _core->InitiateBandwidthUpgrade(endpoint_id, result); + _core->InitiateBandwidthUpgrade(endpoint_id, std::move(result)); } - (NSString *)localEndpointID { diff --git a/connections/swift/NearbyCoreAdapter/Sources/GNCError.mm b/connections/swift/NearbyCoreAdapter/Sources/GNCError.mm index 36c6d43e..db10fee7 100644 --- a/connections/swift/NearbyCoreAdapter/Sources/GNCError.mm +++ b/connections/swift/NearbyCoreAdapter/Sources/GNCError.mm @@ -65,6 +65,12 @@ NSError *NSErrorFromCppStatus(Status status) { return [NSError errorWithDomain:GNCErrorDomain code:GNCErrorWifiLanError userInfo:nil]; case Status::kPayloadUnknown: return [NSError errorWithDomain:GNCErrorDomain code:GNCErrorPayloadUnknown userInfo:nil]; + case Status::kReset: + return [NSError errorWithDomain:GNCErrorDomain code:GNCErrorReset userInfo:nil]; + case Status::kTimeout: + return [NSError errorWithDomain:GNCErrorDomain code:GNCErrorTimeout userInfo:nil]; + case Status::kUnknown: + return [NSError errorWithDomain:GNCErrorDomain code:GNCErrorUnknown userInfo:nil]; case Status::kNextValue: return [NSError errorWithDomain:GNCErrorDomain code:GNCErrorUnknown userInfo:nil]; } diff --git a/connections/swift/NearbyCoreAdapter/Sources/GNCInputStream.h b/connections/swift/NearbyCoreAdapter/Sources/GNCInputStream.h index bdd698e1..151a1a52 100644 --- a/connections/swift/NearbyCoreAdapter/Sources/GNCInputStream.h +++ b/connections/swift/NearbyCoreAdapter/Sources/GNCInputStream.h @@ -17,8 +17,10 @@ #ifdef __cplusplus namespace nearby { -class InputStream; +namespace connections { +class Payload; } +} // namespace nearby #endif @@ -29,7 +31,7 @@ class InputStream; - (nonnull instancetype)initWithURL:(nonnull NSURL *)url NS_UNAVAILABLE; #ifdef __cplusplus -- (nonnull instancetype)initWithCppInputStream:(nonnull nearby::InputStream *)stream +- (nonnull instancetype)initWithPayload:(nearby::connections::Payload)payload NS_DESIGNATED_INITIALIZER; #endif diff --git a/connections/swift/NearbyCoreAdapter/Sources/GNCInputStream.mm b/connections/swift/NearbyCoreAdapter/Sources/GNCInputStream.mm index d4c3096f..2b697a5f 100644 --- a/connections/swift/NearbyCoreAdapter/Sources/GNCInputStream.mm +++ b/connections/swift/NearbyCoreAdapter/Sources/GNCInputStream.mm @@ -18,31 +18,30 @@ #include -// TODO(b/239758418): Change this to the non-internal version when available. -#include "internal/platform/input_stream.h" +#include "connections/payload.h" #import "connections/swift/NearbyCoreAdapter/Sources/GNCException+Internal.h" #import "connections/swift/NearbyCoreAdapter/Sources/Public/NearbyCoreAdapter/GNCException.h" using ::nearby::ByteArray; using ::nearby::ExceptionOr; -using ::nearby::InputStream; using ::nearby::connections::NSErrorFromCppException; +using ::nearby::connections::Payload; @implementation GNCInputStream { NSStreamStatus _streamStatus; NSError *_streamError; id _delegate; - InputStream *_stream; + Payload _payload; } -- (instancetype)initWithCppInputStream:(InputStream *)stream { +- (instancetype)initWithPayload:(Payload)payload { // Init with empty data because init is not a designated initializer. self = [super initWithData:[[NSData alloc] init]]; if (self) { _streamStatus = NSStreamStatusNotOpen; _delegate = self; - _stream = stream; + _payload = std::move(payload); } return self; @@ -53,7 +52,7 @@ using ::nearby::connections::NSErrorFromCppException; } - (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)maxLen { - ExceptionOr readResult = _stream->Read(maxLen); + ExceptionOr readResult = _payload.AsStream()->Read(maxLen); if (!readResult.ok()) { _streamError = NSErrorFromCppException(readResult.GetException()); @@ -87,7 +86,7 @@ using ::nearby::connections::NSErrorFromCppException; - (void)close { _streamStatus = NSStreamStatusClosed; - _stream->Close(); + _payload.AsStream()->Close(); } - (NSStreamStatus)streamStatus { diff --git a/connections/swift/NearbyCoreAdapter/Sources/GNCPayload+CppConversions.h b/connections/swift/NearbyCoreAdapter/Sources/GNCPayload+CppConversions.h index 7d265e97..97e54e1f 100644 --- a/connections/swift/NearbyCoreAdapter/Sources/GNCPayload+CppConversions.h +++ b/connections/swift/NearbyCoreAdapter/Sources/GNCPayload+CppConversions.h @@ -29,10 +29,20 @@ class Payload; @interface GNCPayload (CppConversions) #ifdef __cplusplus +/** + * @note @c fromCpp should not be used to convert a @c Payload created from @c toCpp. For some + * payload types, each conversion creates a new object holding a reference to the previous, + * resulting in potentially endless nesting of objects. + */ + (nonnull GNCPayload *)fromCpp:(nearby::connections::Payload)payload; #endif #ifdef __cplusplus +/** + * @note @c toCPP should not be used to convert a @c GNCPayload created from @c fromCpp. For some + * payload types, each conversion creates a new object holding a reference to the previous, + * resulting in potentially endless nesting of objects. + */ - (nearby::connections::Payload)toCpp; #endif diff --git a/connections/swift/NearbyCoreAdapter/Sources/GNCPayload+CppConversions.mm b/connections/swift/NearbyCoreAdapter/Sources/GNCPayload+CppConversions.mm index 71956a9b..6cc8aa4b 100644 --- a/connections/swift/NearbyCoreAdapter/Sources/GNCPayload+CppConversions.mm +++ b/connections/swift/NearbyCoreAdapter/Sources/GNCPayload+CppConversions.mm @@ -20,13 +20,12 @@ #include "connections/payload.h" -#import "connections/swift/NearbyCoreAdapter/Sources/CPPInputStreamBinding.h" +#import "connections/swift/NearbyCoreAdapter/Sources/CPPInputStream.h" #import "connections/swift/NearbyCoreAdapter/Sources/GNCInputStream.h" #import "connections/swift/NearbyCoreAdapter/Sources/GNCPayload+CppConversions.h" using ::nearby::ByteArray; using ::nearby::InputFile; -using ::nearby::InputStream; using ::nearby::connections::Payload; @implementation GNCPayload (CppConversions) @@ -51,7 +50,7 @@ using ::nearby::connections::Payload; identifier:payloadId]; } case nearby::connections::PayloadType::kStream: { - GNCInputStream *stream = [[GNCInputStream alloc] initWithCppInputStream:payload.AsStream()]; + GNCInputStream *stream = [[GNCInputStream alloc] initWithPayload:std::move(payload)]; return [[GNCStreamPayload alloc] initWithStream:stream identifier:payloadId]; } case nearby::connections::PayloadType::kUnknown: @@ -76,14 +75,7 @@ using ::nearby::connections::Payload; @implementation GNCStreamPayload (CppConversions) - (Payload)toCpp { - // GNCStreamPayload will most likely be destroyed almost immediately, so a weak self would be - // useless and a strong self will cause a retain cycle. This is why we are keeping a weak - // reference of the stream instead. The input stream should be kept alive by a strong reference - // on the user end. - __weak NSInputStream *stream = self.stream; - return Payload(self.identifier, [stream]() -> InputStream & { - return [CPPInputStreamBinding getRefFromStream:stream]; - }); + return Payload(self.identifier, std::make_unique(self.stream)); } @end diff --git a/connections/swift/NearbyCoreAdapter/Sources/GNCPayload.mm b/connections/swift/NearbyCoreAdapter/Sources/GNCPayload.mm index 7c8415a2..58d6c032 100644 --- a/connections/swift/NearbyCoreAdapter/Sources/GNCPayload.mm +++ b/connections/swift/NearbyCoreAdapter/Sources/GNCPayload.mm @@ -20,8 +20,6 @@ #include "connections/payload.h" -#import "connections/swift/NearbyCoreAdapter/Sources/CPPInputStreamBinding.h" - using ::nearby::connections::Payload; @implementation GNCPayload @@ -62,7 +60,6 @@ using ::nearby::connections::Payload; self = [super initWithIdentifier:identifier]; if (self) { _stream = stream; - [CPPInputStreamBinding bindToStream:stream]; } return self; } diff --git a/connections/swift/NearbyCoreAdapter/Sources/Public/NearbyCoreAdapter/GNCConnectionDelegate.h b/connections/swift/NearbyCoreAdapter/Sources/Public/NearbyCoreAdapter/GNCConnectionDelegate.h index 85c6aed6..84d22a27 100644 --- a/connections/swift/NearbyCoreAdapter/Sources/Public/NearbyCoreAdapter/GNCConnectionDelegate.h +++ b/connections/swift/NearbyCoreAdapter/Sources/Public/NearbyCoreAdapter/GNCConnectionDelegate.h @@ -35,6 +35,8 @@ typedef NS_CLOSED_ENUM(NSInteger, GNCStatus) { GNCStatusWifiLanError, GNCStatusPayloadUnknown, GNCStatusUnknown, + GNCStatusReset, + GNCStatusTimeout, }; /** diff --git a/connections/swift/NearbyCoreAdapter/Sources/Public/NearbyCoreAdapter/GNCError.h b/connections/swift/NearbyCoreAdapter/Sources/Public/NearbyCoreAdapter/GNCError.h index 4242b676..76952324 100644 --- a/connections/swift/NearbyCoreAdapter/Sources/Public/NearbyCoreAdapter/GNCError.h +++ b/connections/swift/NearbyCoreAdapter/Sources/Public/NearbyCoreAdapter/GNCError.h @@ -38,4 +38,6 @@ typedef NS_ERROR_ENUM(GNCErrorDomain, GNCErrorCode){ GNCErrorBleError, GNCErrorWifiLanError, GNCErrorPayloadUnknown, + GNCErrorReset, + GNCErrorTimeout, } NS_SWIFT_NAME(NearbyError); diff --git a/connections/v3/BUILD b/connections/v3/BUILD index 00b143d9..9b6d02e6 100644 --- a/connections/v3/BUILD +++ b/connections/v3/BUILD @@ -4,11 +4,13 @@ cc_library( "connections_device.cc", ], hdrs = [ + "advertising_options.h", "bandwidth_info.h", "connection_listening_options.h", "connection_result.h", "connections_device.h", "connections_device_provider.h", + "discovery_options.h", "listeners.h", "listening_result.h", "params.h", diff --git a/connections/v3/advertising_options.h b/connections/v3/advertising_options.h new file mode 100644 index 00000000..4e22c552 --- /dev/null +++ b/connections/v3/advertising_options.h @@ -0,0 +1,51 @@ +// 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_CONNECTIONS_V3_ADVERTISING_OPTIONS_H_ +#define THIRD_PARTY_NEARBY_CONNECTIONS_V3_ADVERTISING_OPTIONS_H_ + +#include + +#include "connections/medium_selector.h" +#include "connections/power_level.h" +#include "connections/strategy.h" + +namespace nearby { +namespace connections { +namespace v3 { + +struct AdvertisingOptions { + Strategy strategy; + PowerLevel power_level = PowerLevel::kHighPower; + // If the device should listen to Bluetooth connections during BLE advertising + bool enable_bluetooth_listening = true; + // Allow Nearby Connections to toggle the Bluetooth radio before starting + // advertising. + bool allow_bluetooth_radio_toggling = true; + // Allow Nearby Connections to toggle the WiFi radio before starting + // advertising + bool allow_wifi_radio_toggling = true; + // If Nearby Connections should auto-upgrade bandwidth. + bool auto_upgrade_bandwidth = true; + bool enforce_topology_constraints = true; + std::string fast_advertisement_service_uuid; + BooleanMediumSelector advertising_mediums; + BooleanMediumSelector upgrade_mediums; +}; + +} // namespace v3 +} // namespace connections +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_CONNECTIONS_V3_ADVERTISING_OPTIONS_H_ diff --git a/connections/v3/discovery_options.h b/connections/v3/discovery_options.h new file mode 100644 index 00000000..d55021da --- /dev/null +++ b/connections/v3/discovery_options.h @@ -0,0 +1,45 @@ +// 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_CONNECTIONS_V3_DISCOVERY_OPTIONS_H_ +#define THIRD_PARTY_NEARBY_CONNECTIONS_V3_DISCOVERY_OPTIONS_H_ + +#include + +#include "connections/medium_selector.h" +#include "connections/power_level.h" +#include "connections/strategy.h" + +namespace nearby { +namespace connections { +namespace v3 { + +struct DiscoveryOptions { + // Must match advertising strategy to see advertisements. + Strategy strategy; + PowerLevel power_level = PowerLevel::kHighPower; + // Allow Nearby Connections to toggle on Bluetooth radio before starting + // discovery. + bool allow_bluetooth_radio_toggling = true; + // Allow Nearby Connections to toggle on WiFi radio before starting discovery. + bool allow_wifi_radio_toggling = true; + std::string fast_advertisement_service_uuid; + BooleanMediumSelector discovery_mediums; +}; + +} // namespace v3 +} // namespace connections +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_CONNECTIONS_V3_DISCOVERY_OPTIONS_H_ diff --git a/fastpair/BUILD b/fastpair/BUILD index ec101847..453b6db5 100644 --- a/fastpair/BUILD +++ b/fastpair/BUILD @@ -134,7 +134,6 @@ cc_test( "//fastpair/plugins:fake_fast_pair_plugin", "//internal/account:test_support", "//internal/network:types", - "//internal/platform:logging", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep diff --git a/fastpair/common/BUILD b/fastpair/common/BUILD index c657c1c4..c377b405 100644 --- a/fastpair/common/BUILD +++ b/fastpair/common/BUILD @@ -33,7 +33,7 @@ cc_library( deps = [ "//fastpair/proto:fastpair_cc_proto", "//internal/crypto_cros", - "//internal/platform:logging", + "//internal/platform:types", "//internal/preferences", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_map", diff --git a/fastpair/common/fast_pair_device.h b/fastpair/common/fast_pair_device.h index be02d25f..cf255312 100644 --- a/fastpair/common/fast_pair_device.h +++ b/fastpair/common/fast_pair_device.h @@ -105,6 +105,12 @@ class FastPairDevice { return should_show_ui_notification_; } + void StartedPairing(bool started_pairing) { + has_started_pairing_ = started_pairing; + } + + bool HasStartedPairing() const { return has_started_pairing_; } + private: std::string model_id_; @@ -135,6 +141,7 @@ class FastPairDevice { std::optional metadata_; std::optional should_show_ui_notification_; + bool has_started_pairing_ = false; }; std::ostream& operator<<(std::ostream& stream, const FastPairDevice& device); diff --git a/fastpair/crypto/BUILD b/fastpair/crypto/BUILD index cac861f5..674826a6 100644 --- a/fastpair/crypto/BUILD +++ b/fastpair/crypto/BUILD @@ -21,7 +21,7 @@ cc_library( "//fastpair/common", "//internal/base:bluetooth_address", "//internal/platform:base", - "//internal/platform:logging", + "//internal/platform:types", "@boringssl//:crypto", "@com_google_absl//absl/log:check", ], diff --git a/fastpair/dataparser/BUILD b/fastpair/dataparser/BUILD index 58a5f9b6..76f520e6 100644 --- a/fastpair/dataparser/BUILD +++ b/fastpair/dataparser/BUILD @@ -17,7 +17,7 @@ cc_library( "//fastpair/crypto", "//internal/base:bluetooth_address", "//internal/platform:base", - "//internal/platform:logging", + "//internal/platform:types", "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/strings", ], diff --git a/fastpair/fast_pair_seeker.h b/fastpair/fast_pair_seeker.h index bc9677d9..38458750 100644 --- a/fastpair/fast_pair_seeker.h +++ b/fastpair/fast_pair_seeker.h @@ -38,6 +38,13 @@ struct SubsequentPairingParam {}; // Retroactive Pairing parameters. struct RetroactivePairingParam {}; +// Finish Retroactive Pairing parameters. +struct FinishRetroactivePairingParam { + // Save the negotiated Account Key or abandon it and forget the Fast Pair + // Device. + bool save_account_key = false; +}; + // Fast Pair Seeker API available to plugins. class FastPairSeeker { public: @@ -67,12 +74,28 @@ class FastPairSeeker { // when the user has paired manually with a new device and we want to // retroactively exchange an Account Key. See: // https://developers.google.com/nearby/fast-pair/specifications/extensions/retroactiveacctkey + // The retroactive pairing flow should be started immediately after the + // pairing event, before we had a chance to ask for the user for permission. + // Therefore, the retroactive is split into two stages. The client should call + // `StartRetroactivePairing()` first. When the pairing result returned via + // `callback` is successful, the client should ask the user for permission to + // save the account key. Finally, the client should call + // `FinishRetroactivePairing()` with the user's decision to complete the + // retroactive pairing flow. // // Returns an error if pairing flow could not be started. Otherwise, the // pairing result will be returned via the `callback`. virtual absl::Status StartRetroactivePairing( const FastPairDevice& device, const RetroactivePairingParam& param, PairingCallback callback) = 0; + + // Finishes the retroactive pairing flow. + // + // Returns an error if the flow could not be started. Otherwise, the + // result will be returned via the `callback`. + virtual absl::Status FinishRetroactivePairing( + const FastPairDevice& device, const FinishRetroactivePairingParam& param, + PairingCallback callback) = 0; }; } // namespace fastpair } // namespace nearby diff --git a/fastpair/fast_pair_service.cc b/fastpair/fast_pair_service.cc index f57eabd5..87eb2dde 100644 --- a/fastpair/fast_pair_service.cc +++ b/fastpair/fast_pair_service.cc @@ -23,9 +23,9 @@ #include "fastpair/common/fast_pair_prefs.h" #include "fastpair/fast_pair_plugin.h" #include "fastpair/internal/fast_pair_seeker_impl.h" +#include "fastpair/repository/fast_pair_repository_impl.h" #include "fastpair/server_access/fast_pair_client_impl.h" #include "fastpair/server_access/fast_pair_http_notifier.h" -#include "fastpair/repository/fast_pair_repository_impl.h" #include "internal/account/account_manager_impl.h" #include "internal/auth/authentication_manager_impl.h" #include "internal/flags/nearby_flags.h" @@ -43,6 +43,7 @@ namespace { constexpr char kFastPairPreferencesFilePath[] = "Google/Nearby/FastPair"; constexpr FeatureFlags::Flags fast_pair_feature_flags = FeatureFlags::Flags{ .enable_scan_for_fast_pair_advertisement = true, + .skip_service_discovery_before_connecting_to_rfcomm = true, }; constexpr absl::Duration kTimeout = absl::Seconds(3); } // namespace @@ -106,7 +107,8 @@ FastPairService::FastPairService( [this](const FastPairDevice& device, RingEvent event) { OnRingEvent(device, std::move(event)); }}, - &executor_, &devices_); + &executor_, account_manager_.get(), &devices_, + fast_pair_repository_.get()); } FastPairService::~FastPairService() { executor_.Shutdown(); } diff --git a/fastpair/handshake/BUILD b/fastpair/handshake/BUILD index 1e44021b..c845dac1 100644 --- a/fastpair/handshake/BUILD +++ b/fastpair/handshake/BUILD @@ -43,7 +43,6 @@ cc_library( "//fastpair/repository", "//internal/base:bluetooth_address", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform:uuid", "@boringssl//:crypto", @@ -89,7 +88,6 @@ cc_test( "//fastpair/internal/mediums", "//fastpair/repository:test_support", "//fastpair/testing", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep "@com_github_protobuf_matchers//protobuf-matchers", @@ -164,7 +162,6 @@ cc_test( ":handshake", "//fastpair/common", "//fastpair/internal/mediums", - "//internal/platform:logging", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep diff --git a/fastpair/internal/BUILD b/fastpair/internal/BUILD index 45fbbb91..3742f983 100644 --- a/fastpair/internal/BUILD +++ b/fastpair/internal/BUILD @@ -14,8 +14,10 @@ cc_library( "//fastpair:fast_pair_controller", "//fastpair:fast_pair_events", "//fastpair:fast_pair_seeker", + "//fastpair/common", "//fastpair/internal/mediums", "//fastpair/pairing", + "//fastpair/repository", "//fastpair/repository:device_repository", "//fastpair/retroactive", "//fastpair/scanning:scanner", @@ -34,14 +36,22 @@ cc_test( deps = [ ":internal", "//fastpair:fast_pair_events", + "//fastpair:fast_pair_seeker", + "//fastpair/common", "//fastpair/message_stream:fake_gatt_callbacks", "//fastpair/message_stream:fake_provider", + "//fastpair/proto:fastpair_cc_proto", + "//fastpair/repository", + "//fastpair/repository:device_repository", "//fastpair/repository:test_support", + "//internal/account:test_support", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep + "//internal/test/google3_only:test", "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_absl//absl/time", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", "@com_google_googletest//:gtest_main", ], ) diff --git a/fastpair/internal/fast_pair_seeker_impl.cc b/fastpair/internal/fast_pair_seeker_impl.cc index c59ac65d..30b27f95 100644 --- a/fastpair/internal/fast_pair_seeker_impl.cc +++ b/fastpair/internal/fast_pair_seeker_impl.cc @@ -21,11 +21,13 @@ #include "absl/status/status.h" #include "absl/strings/str_format.h" +#include "fastpair/common/account_key.h" #include "fastpair/fast_pair_controller.h" #include "fastpair/fast_pair_events.h" #include "fastpair/pairing/pairer_broker_impl.h" #include "fastpair/scanning/scanner_broker_impl.h" #include "internal/platform/count_down_latch.h" +#include "internal/platform/logging.h" #include "internal/platform/pending_job_registry.h" #include "internal/platform/single_thread_executor.h" @@ -38,13 +40,20 @@ constexpr absl::Duration kCleanupTimeout = absl::Seconds(3); FastPairSeekerImpl::FastPairSeekerImpl(ServiceCallbacks callbacks, SingleThreadExecutor* executor, - FastPairDeviceRepository* devices) - : callbacks_(std::move(callbacks)), executor_(executor), devices_(devices) { - pairer_broker_ = std::make_unique(mediums_, executor_); + AccountManager* account_manager, + FastPairDeviceRepository* devices, + FastPairRepository* repository) + : callbacks_(std::move(callbacks)), + executor_(executor), + account_manager_(account_manager), + devices_(devices), + repository_(repository) { + pairer_broker_ = + std::make_unique(mediums_, executor_, account_manager_); pairer_broker_->AddObserver(this); mediums_.GetBluetoothClassic().AddObserver(this); retro_detector_ = std::make_unique( - mediums_, devices, executor); + mediums_, devices, account_manager_, executor); retro_detector_->AddObserver(this); } @@ -75,6 +84,7 @@ absl::Status FastPairSeekerImpl::StartInitialPairing( pairing_callback_ = std::make_unique(std::move(callback)); device_under_pairing_ = &const_cast(device); + device_under_pairing_->StartedPairing(true); pairer_broker_->PairDevice(*device_under_pairing_); return absl::OkStatus(); } @@ -93,12 +103,17 @@ absl::Status FastPairSeekerImpl::StartRetroactivePairing( } device_under_pairing_ = &const_cast(device); + device_under_pairing_->StartedPairing(true); controller_ = std::make_unique( &mediums_, device_under_pairing_, executor_); retroactive_pair_ = std::make_unique(controller_.get()); pairing_callback_ = std::make_unique(std::move(callback)); retroactive_pair_->Pair().AddListener( [this](ExceptionOr result) { + // TODO(jsobczak): We could/should keep controller_ alive until the + // client calls FinishRetroactivePairing(), verify that they called + // Finish for the correct device, and if the user has given consent, we + // should keep the MessageStream connection open. retroactive_pair_.reset(); controller_.reset(); FinishPairing(result.result()); @@ -107,6 +122,41 @@ absl::Status FastPairSeekerImpl::StartRetroactivePairing( return absl::OkStatus(); } +absl::Status FastPairSeekerImpl::FinishRetroactivePairing( + const FastPairDevice& device, const FinishRetroactivePairingParam& param, + PairingCallback callback) { + if (device.GetProtocol() != Protocol::kFastPairRetroactivePairing) { + return absl::InvalidArgumentError( + "Fast Pair Device is not a retroactive pairing device"); + } + if (!device.GetAccountKey()) { + return absl::InvalidArgumentError( + "Fast Pair Device does not have an account key"); + } + if (!param.save_account_key) { + executor_->Execute( + "abandon retro device", + [this, &device, callback = std::move(callback)]() mutable { + NEARBY_LOGS(INFO) << "Abandon device on retroactive pairing path"; + callback.on_pairing_result(device, absl::OkStatus()); + devices_->RemoveDevice(&device); + }); + } else { + executor_->Execute( + "save account key", + [this, &device, callback = std::move(callback)]() mutable { + NEARBY_LOGS(INFO) << "Save account key for " << device; + repository_->WriteAccountAssociationToFootprints( + const_cast(device), + [&device, + callback = std::move(callback)](absl::Status status) mutable { + callback.on_pairing_result(device, status); + }); + }); + } + return absl::OkStatus(); +} + absl::Status FastPairSeekerImpl::StartFastPairScan() { if (scanning_session_ != nullptr) { return absl::AlreadyExistsError("already scanning"); @@ -255,5 +305,23 @@ void FastPairSeekerImpl::OnRetroactivePairFound(FastPairDevice& device) { callbacks_.on_pair_event(device, PairEvent{.is_paired = true}); } +void FastPairSeekerImpl::ForgetDeviceByAccountKey( + const AccountKey& account_key) { + NEARBY_LOGS(VERBOSE) << __func__; + auto opt_device = devices_->FindDevice(account_key); + if (!opt_device.has_value()) { + NEARBY_LOGS(INFO) << __func__ << "No FP device matching the account key."; + } else { + devices_->RemoveDevice(opt_device.value()); + } + + repository_->DeleteAssociatedDeviceByAccountKey( + account_key, [&](absl::Status success) { + if (!success.ok()) return; + NEARBY_LOGS(VERBOSE) << "Deleted associated devcie by account key"; + // Temporary solution to refresh the saved_devices_sheet. + repository_->GetUserSavedDevices(); + }); +} } // namespace fastpair } // namespace nearby diff --git a/fastpair/internal/fast_pair_seeker_impl.h b/fastpair/internal/fast_pair_seeker_impl.h index 968828ed..bf096f2b 100644 --- a/fastpair/internal/fast_pair_seeker_impl.h +++ b/fastpair/internal/fast_pair_seeker_impl.h @@ -25,6 +25,7 @@ #include "fastpair/internal/mediums/mediums.h" #include "fastpair/pairing/pairer_broker_impl.h" #include "fastpair/repository/fast_pair_device_repository.h" +#include "fastpair/repository/fast_pair_repository.h" #include "fastpair/retroactive/retroactive.h" #include "fastpair/retroactive/retroactive_pairing_detector_impl.h" #include "fastpair/scanning/scanner_broker_impl.h" @@ -42,6 +43,7 @@ class FastPairSeekerExt : public FastPairSeeker { // Handle the state changes of screen lock. virtual void SetIsScreenLocked(bool is_locked) = 0; + virtual void ForgetDeviceByAccountKey(const AccountKey& account_key) = 0; }; class FastPairSeekerImpl : public FastPairSeekerExt, @@ -63,7 +65,9 @@ class FastPairSeekerImpl : public FastPairSeekerExt, }; FastPairSeekerImpl(ServiceCallbacks callbacks, SingleThreadExecutor* executor, - FastPairDeviceRepository* devices); + AccountManager* account_manager, + FastPairDeviceRepository* devices, + FastPairRepository* repository); ~FastPairSeekerImpl() override; @@ -80,10 +84,15 @@ class FastPairSeekerImpl : public FastPairSeekerExt, const RetroactivePairingParam& param, PairingCallback callback) override; + absl::Status FinishRetroactivePairing( + const FastPairDevice& device, const FinishRetroactivePairingParam& param, + PairingCallback callback) override; + // From FastPairSeekerExt. absl::Status StartFastPairScan() override; absl::Status StopFastPairScan() override; void SetIsScreenLocked(bool is_locked) override; + void ForgetDeviceByAccountKey(const AccountKey& account_key) override; // From BluetoothClassicMedium::Observer. void DeviceAdded(BluetoothDevice& device) override; @@ -117,7 +126,9 @@ class FastPairSeekerImpl : public FastPairSeekerExt, ServiceCallbacks callbacks_; SingleThreadExecutor* executor_; + AccountManager* account_manager_; FastPairDeviceRepository* devices_; + FastPairRepository* repository_; Mediums mediums_; std::unique_ptr scanner_; std::unique_ptr scanning_session_; diff --git a/fastpair/internal/fast_pair_seeker_impl_test.cc b/fastpair/internal/fast_pair_seeker_impl_test.cc index 2d015969..09556b8e 100644 --- a/fastpair/internal/fast_pair_seeker_impl_test.cc +++ b/fastpair/internal/fast_pair_seeker_impl_test.cc @@ -18,19 +18,31 @@ #include #include +#include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" +#include "absl/status/status.h" +#include "absl/strings/escaping.h" +#include "fastpair/common/fast_pair_device.h" +#include "fastpair/common/fast_pair_prefs.h" #include "fastpair/fast_pair_events.h" +#include "fastpair/fast_pair_seeker.h" #include "fastpair/message_stream/fake_gatt_callbacks.h" #include "fastpair/message_stream/fake_provider.h" +#include "fastpair/proto/data.proto.h" +#include "fastpair/proto/enum.proto.h" #include "fastpair/repository/fake_fast_pair_repository.h" +#include "fastpair/repository/fast_pair_device_repository.h" +#include "fastpair/repository/fast_pair_repository.h" +#include "internal/account/fake_account_manager.h" #include "internal/platform/count_down_latch.h" +#include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" #include "internal/platform/single_thread_executor.h" +#include "internal/platform/task_runner_impl.h" +#include "internal/test/google3_only/fake_authentication_manager.h" namespace nearby { namespace fastpair { @@ -46,8 +58,9 @@ constexpr absl::string_view kBobPublicKey = "F7D496A62ECA416351540AA343BC690A6109F551500666B83B1251FB84FA2860795EBD63D3" "B8836F44A9A3E28BB34017E015F5979305D849FDF8DE10123B61D2"; constexpr absl::string_view kPasskey = "123456"; - -constexpr absl::Duration kTaskWaitTimeout = absl::Milliseconds(100); +constexpr absl::string_view kFastPairPreferencesFilePath = + "Google/Nearby/FastPair"; +constexpr absl::string_view kTestAccountId = "test_account_id"; using ::testing::status::StatusIs; @@ -57,18 +70,56 @@ class MediumEnvironmentStarter { ~MediumEnvironmentStarter() { MediumEnvironment::Instance().Stop(); } }; +class FastPairRepositoryObserver : public FastPairRepository::Observer { + public: + explicit FastPairRepositoryObserver(CountDownLatch* latch) { latch_ = latch; } + + void OnGetUserSavedDevices( + const proto::OptInStatus& opt_in_status, + const std::vector& devices) override { + latch_->CountDown(); + } + + CountDownLatch* latch_ = nullptr; +}; + class FastPairSeekerImplTest : public testing::Test { protected: + FastPairSeekerImplTest() { + task_runner_ = std::make_unique(1); + preferences_manager_ = std::make_unique( + kFastPairPreferencesFilePath); + authentication_manager_ = std::make_unique(); + } + void SetUp() override { NEARBY_LOG_SET_SEVERITY(VERBOSE); repository_ = FakeFastPairRepository::Create( kModelId, absl::HexStringToBytes(kBobPublicKey)); + repository_->SetResultOfIsDeviceSavedToAccount( + absl::NotFoundError("not found")); + account_manager_ = std::make_unique( + preferences_manager_.get(), prefs::kNearbyFastPairUsersName, + authentication_manager_.get(), task_runner_.get()); + AccountManager::Account account; + account.id = kTestAccountId; + account_manager_->SetAccount(account); } void TearDown() override { executor_.Shutdown(); } + void WaitForBackgroundTasks() { + CountDownLatch latch(1); + executor_.Execute([&]() { latch.CountDown(); }); + latch.Await(); + } + MediumEnvironmentStarter env_; SingleThreadExecutor executor_; + std::unique_ptr preferences_manager_; + std::unique_ptr authentication_manager_; + std::unique_ptr task_runner_; + std::unique_ptr account_manager_; FastPairDeviceRepository devices_{&executor_}; std::unique_ptr repository_; std::unique_ptr fast_pair_seeker_; @@ -77,7 +128,8 @@ class FastPairSeekerImplTest : public testing::Test { TEST_F(FastPairSeekerImplTest, StartAndStopFastPairScan) { fast_pair_seeker_ = std::make_unique( - FastPairSeekerImpl::ServiceCallbacks{}, &executor_, &devices_); + FastPairSeekerImpl::ServiceCallbacks{}, &executor_, + account_manager_.get(), &devices_, repository_.get()); EXPECT_OK(fast_pair_seeker_->StartFastPairScan()); EXPECT_OK(fast_pair_seeker_->StopFastPairScan()); @@ -93,7 +145,7 @@ TEST_F(FastPairSeekerImplTest, DiscoverDevice) { EXPECT_EQ(device.GetModelId(), kModelId); latch.CountDown(); }}, - &executor_, &devices_); + &executor_, account_manager_.get(), &devices_, repository_.get()); EXPECT_OK(fast_pair_seeker_->StartFastPairScan()); provider.StartDiscoverableAdvertisement(kModelId); @@ -104,7 +156,8 @@ TEST_F(FastPairSeekerImplTest, DiscoverDevice) { TEST_F(FastPairSeekerImplTest, StartFastPairScanTwiceFails) { fast_pair_seeker_ = std::make_unique( - FastPairSeekerImpl::ServiceCallbacks{}, &executor_, &devices_); + FastPairSeekerImpl::ServiceCallbacks{}, &executor_, + account_manager_.get(), &devices_, repository_.get()); EXPECT_OK(fast_pair_seeker_->StartFastPairScan()); EXPECT_THAT(fast_pair_seeker_->StartFastPairScan(), @@ -113,7 +166,8 @@ TEST_F(FastPairSeekerImplTest, StartFastPairScanTwiceFails) { TEST_F(FastPairSeekerImplTest, StopFastPairScanTwiceFails) { fast_pair_seeker_ = std::make_unique( - FastPairSeekerImpl::ServiceCallbacks{}, &executor_, &devices_); + FastPairSeekerImpl::ServiceCallbacks{}, &executor_, + account_manager_.get(), &devices_, repository_.get()); EXPECT_OK(fast_pair_seeker_->StartFastPairScan()); EXPECT_OK(fast_pair_seeker_->StopFastPairScan()); @@ -134,7 +188,7 @@ TEST_F(FastPairSeekerImplTest, ScreenLocksDuringAdvertising) { EXPECT_TRUE(event.is_locked); latch.CountDown(); }}, - &executor_, &devices_); + &executor_, account_manager_.get(), &devices_, repository_.get()); // Create Advertiser and startAdvertising Mediums mediums_2; std::string service_id(kServiceID); @@ -170,7 +224,7 @@ TEST_F(FastPairSeekerImplTest, InitialPairing) { }})); discover_latch.CountDown(); }}, - &executor_, &devices_); + &executor_, account_manager_.get(), &devices_, repository_.get()); EXPECT_OK(fast_pair_seeker_->StartFastPairScan()); provider.PrepareForInitialPairing( @@ -190,7 +244,64 @@ TEST_F(FastPairSeekerImplTest, InitialPairing) { fast_pair_seeker_.reset(); } -TEST_F(FastPairSeekerImplTest, RetroactivePairing) { +TEST_F(FastPairSeekerImplTest, ForgetDeviceByAccountKey) { + NEARBY_LOG_SET_SEVERITY(VERBOSE); + FakeProvider provider; + CountDownLatch discover_latch(1); + CountDownLatch pair_latch(1); + fast_pair_seeker_ = std::make_unique( + FastPairSeekerImpl::ServiceCallbacks{ + .on_initial_discovery = + [&](const FastPairDevice& device, InitialDiscoveryEvent event) { + EXPECT_EQ(device.GetModelId(), kModelId); + EXPECT_OK(fast_pair_seeker_->StartInitialPairing( + device, {}, + {.on_pairing_result = [&](const FastPairDevice& device, + absl::Status status) { + EXPECT_EQ(device.GetBleAddress(), + provider.GetMacAddress()); + EXPECT_OK(status); + pair_latch.CountDown(); + }})); + discover_latch.CountDown(); + }}, + &executor_, account_manager_.get(), &devices_, repository_.get()); + + EXPECT_OK(fast_pair_seeker_->StartFastPairScan()); + provider.PrepareForInitialPairing( + { + .private_key = absl::HexStringToBytes(kBobPrivateKey), + .public_key = absl::HexStringToBytes(kBobPublicKey), + .model_id = std::string(kModelId), + .pass_key = std::string(kPasskey), + }, + &fake_gatt_callbacks_); + + discover_latch.Await(); + pair_latch.Await(); + auto fp_device = devices_.FindDevice(provider.GetMacAddress()); + ASSERT_TRUE(fp_device.has_value()); + EXPECT_EQ(provider.GetAccountKey(), fp_device.value()->GetAccountKey()); + + // Adds FastPairRepository observer. + CountDownLatch repository_latch(1); + FastPairRepositoryObserver observer(&repository_latch); + repository_->AddObserver(&observer); + // Adds FastPairDeviceRepository observer. + CountDownLatch devices_latch(1); + FastPairDeviceRepository::RemoveDeviceCallback callback = + [&](const FastPairDevice& device) { devices_latch.CountDown(); }; + devices_.AddObserver(&callback); + + fast_pair_seeker_->ForgetDeviceByAccountKey( + fp_device.value()->GetAccountKey()); + repository_latch.Await(); + devices_latch.Await(); + EXPECT_FALSE(devices_.FindDevice(provider.GetMacAddress()).has_value()); + fast_pair_seeker_.reset(); +} + +TEST_F(FastPairSeekerImplTest, RetroactivePairingWithUserConsent) { NEARBY_LOG_SET_SEVERITY(VERBOSE); FakeProvider provider; CountDownLatch pair_latch(1); @@ -209,7 +320,7 @@ TEST_F(FastPairSeekerImplTest, RetroactivePairing) { retro_latch.CountDown(); }})); }}, - &executor_, &devices_); + &executor_, account_manager_.get(), &devices_, repository_.get()); provider.PrepareForRetroactivePairing( {.private_key = absl::HexStringToBytes(kBobPrivateKey), @@ -222,6 +333,63 @@ TEST_F(FastPairSeekerImplTest, RetroactivePairing) { auto fp_device = devices_.FindDevice(provider.GetMacAddress()); ASSERT_TRUE(fp_device.has_value()); EXPECT_EQ(provider.GetAccountKey(), fp_device.value()->GetAccountKey()); + + // The client asks the user for consent, the user grants it. + CountDownLatch finish_latch(1); + EXPECT_OK(fast_pair_seeker_->FinishRetroactivePairing( + **fp_device, FinishRetroactivePairingParam{.save_account_key = true}, + {.on_pairing_result = [&](const FastPairDevice&, absl::Status status) { + EXPECT_OK(status); + finish_latch.CountDown(); + }})); + EXPECT_TRUE(finish_latch.Await()); +} + +TEST_F(FastPairSeekerImplTest, RetroactivePairingNoUserConsent) { + NEARBY_LOG_SET_SEVERITY(VERBOSE); + FakeProvider provider; + CountDownLatch pair_latch(1); + CountDownLatch retro_latch(1); + fast_pair_seeker_ = std::make_unique( + FastPairSeekerImpl::ServiceCallbacks{ + .on_pair_event = + [&](const FastPairDevice& device, PairEvent event) { + NEARBY_LOGS(INFO) << "Pair callback"; + pair_latch.CountDown(); + EXPECT_OK(fast_pair_seeker_->StartRetroactivePairing( + device, RetroactivePairingParam{}, + {.on_pairing_result = [&](const FastPairDevice&, + absl::Status status) { + EXPECT_OK(status); + retro_latch.CountDown(); + }})); + }}, + &executor_, account_manager_.get(), &devices_, repository_.get()); + + provider.PrepareForRetroactivePairing( + {.private_key = absl::HexStringToBytes(kBobPrivateKey), + .public_key = absl::HexStringToBytes(kBobPublicKey), + .model_id = std::string(kModelId)}, + &fake_gatt_callbacks_); + + EXPECT_TRUE(pair_latch.Await().Ok()); + EXPECT_TRUE(retro_latch.Await().Ok()); + auto fp_device = devices_.FindDevice(provider.GetMacAddress()); + ASSERT_TRUE(fp_device.has_value()); + EXPECT_EQ(provider.GetAccountKey(), fp_device.value()->GetAccountKey()); + + // The client asks the user for consent, the user rejects it. + CountDownLatch finish_latch(1); + EXPECT_OK(fast_pair_seeker_->FinishRetroactivePairing( + **fp_device, FinishRetroactivePairingParam{.save_account_key = false}, + {.on_pairing_result = [&](const FastPairDevice&, absl::Status status) { + EXPECT_OK(status); + finish_latch.CountDown(); + }})); + EXPECT_TRUE(finish_latch.Await()); + // The device should be deleted. + WaitForBackgroundTasks(); + EXPECT_FALSE(devices_.FindDevice(provider.GetMacAddress()).has_value()); } } // namespace diff --git a/fastpair/internal/mediums/BUILD b/fastpair/internal/mediums/BUILD index 561b6f1e..589e6004 100644 --- a/fastpair/internal/mediums/BUILD +++ b/fastpair/internal/mediums/BUILD @@ -37,7 +37,6 @@ cc_library( deps = [ "//fastpair/common", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform/implementation:comm", "@com_google_absl//absl/base:core_headers", diff --git a/fastpair/keyed_service/BUILD b/fastpair/keyed_service/BUILD deleted file mode 100644 index b5046e28..00000000 --- a/fastpair/keyed_service/BUILD +++ /dev/null @@ -1,79 +0,0 @@ -# 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. - -licenses(["notice"]) - -cc_library( - name = "keyed_service", - srcs = [ - "fast_pair_mediator.cc", - "fast_pair_mediator_factory.cc", - ], - hdrs = [ - "fast_pair_mediator.h", - "fast_pair_mediator_factory.h", - ], - visibility = [ - "//fastpair:__subpackages__", - ], - deps = [ - "//fastpair/common", - "//fastpair/internal/mediums", - "//fastpair/pairing", - "//fastpair/repository", - "//fastpair/repository:device_repository", - "//fastpair/repository:repository_impl", - "//fastpair/scanning:scanner", - "//fastpair/server_access", - "//fastpair/ui:fast_pair_ui", - "//internal/account", - "//internal/auth:oauth_lib", - "//internal/auth:types", - "//internal/flags:nearby_flags", - "//internal/network:nearby_http_client", - "//internal/network:types", - "//internal/platform:base", - "//internal/platform:logging", - "//internal/platform:types", - "//internal/platform/flags:platform_flags", - "//internal/preferences", - "@com_google_absl//absl/status", - ], -) - -cc_test( - name = "fast_pair_mediator_test", - size = "small", - srcs = [ - "fast_pair_mediator_factory_test.cc", - "fast_pair_mediator_test.cc", - ], - shard_count = 16, - deps = [ - ":keyed_service", - "//fastpair/testing", - "//fastpair/ui:fast_pair_ui", - "//fastpair/ui:mock_fast_pair_ui", - "//internal/account:test_support", - "//internal/network:nearby_http_client", - "//internal/platform:test_util", - "//internal/platform:types", - "//internal/platform/implementation/g3", # build_cleaner: keep - "//internal/test", - "//internal/test/google3_only:test", - "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_absl//absl/strings", - "@com_google_googletest//:gtest_main", - ], -) diff --git a/fastpair/keyed_service/fast_pair_mediator.cc b/fastpair/keyed_service/fast_pair_mediator.cc deleted file mode 100644 index 44913753..00000000 --- a/fastpair/keyed_service/fast_pair_mediator.cc +++ /dev/null @@ -1,262 +0,0 @@ -// 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/keyed_service/fast_pair_mediator.h" - -#include -#include -#include -#include -#include - -#include "absl/status/status.h" -#include "fastpair/common/fast_pair_prefs.h" -#include "fastpair/common/protocol.h" -#include "fastpair/internal/mediums/mediums.h" -#include "fastpair/pairing/pairer_broker_impl.h" -#include "fastpair/repository/fast_pair_device_repository.h" -#include "fastpair/scanning/scanner_broker_impl.h" -#include "fastpair/server_access/fast_pair_client_impl.h" -#include "fastpair/repository/fast_pair_repository_impl.h" -#include "fastpair/ui/actions.h" -#include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" -#include "fastpair/ui/ui_broker_impl.h" -#include "internal/account/account_manager_impl.h" -#include "internal/flags/nearby_flags.h" -#include "internal/platform/feature_flags.h" -#include "internal/platform/flags/nearby_platform_feature_flags.h" -#include "internal/platform/logging.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/platform/task_runner_impl.h" -#include "internal/preferences/preferences_manager.h" - -namespace nearby { -namespace fastpair { -namespace { -constexpr char kFastPairPreferencesFilePath[] = "Google/Nearby/FastPair"; -constexpr FeatureFlags::Flags fast_pair_feature_flags = FeatureFlags::Flags{ - .enable_scan_for_fast_pair_advertisement = true, -}; -} - -Mediator::Mediator( - std::unique_ptr executor, - std::unique_ptr mediums, std::unique_ptr ui_broker, - std::unique_ptr notification_controller, - std::unique_ptr authentication_manager, - std::unique_ptr http_client, - std::unique_ptr device_info) - : executor_(std::move(executor)), - mediums_(std::move(mediums)), - ui_broker_(std::move(ui_broker)), - notification_controller_(std::move(notification_controller)), - authentication_manager_(std::move(authentication_manager)), - http_client_(std::move(http_client)), - device_info_(std::move(device_info)) { - NearbyFlags::GetInstance().OverrideBoolFlagValue( - platform::config_package_nearby::nearby_platform_feature:: - kEnableBleV2Gatt, - true); - const_cast(FeatureFlags::GetInstance()) - .SetFlags(fast_pair_feature_flags); - - devices_ = std::make_unique(executor_.get()); - scanner_broker_ = std::make_unique( - *mediums_, executor_.get(), devices_.get()); - pairer_broker_ = - std::make_unique(*mediums_, executor_.get()); - task_runner_ = std::make_unique(1); - preferences_manager_ = std::make_unique( - kFastPairPreferencesFilePath); - account_manager_ = AccountManagerImpl::Factory::Create( - preferences_manager_.get(), prefs::kNearbyFastPairUsersName, - authentication_manager_.get(), task_runner_.get()); - fast_pair_client_ = std::make_unique( - authentication_manager_.get(), account_manager_.get(), http_client_.get(), - &fast_pair_http_notifier_, device_info_.get()); - fast_pair_repository_ = - std::make_unique(fast_pair_client_.get()); - scanner_broker_->AddObserver(this); - ui_broker_->AddObserver(this); - pairer_broker_->AddObserver(this); -} - -void Mediator::OnDeviceFound(FastPairDevice& device) { - NEARBY_LOGS(INFO) << __func__ << ": " << device; - if (device.ShouldShowUiNotification().value_or(false)) { - NEARBY_LOGS(INFO) << __func__ << ": Ignoring because show UI flag is false"; - return; - } - if (IsDeviceCurrentlyShowingNotification(device)) { - NEARBY_LOGS(VERBOSE) << __func__ - << ": Extending notification for re-discovered device=" - << *device_currently_showing_notification_; - // TODO(b/278768167): Add ui_broker_->ExtendNotification(); - return; - } else if (device_currently_showing_notification_) { - NEARBY_LOGS(VERBOSE) - << __func__ - << ": Already showing a notification for a different device= " - << *device_currently_showing_notification_; - return; - } - // Show discovery notification - device_currently_showing_notification_ = &device; - ui_broker_->ShowDiscovery(device, *notification_controller_); -} - -void Mediator::OnDeviceLost(FastPairDevice& device) { - NEARBY_LOGS(INFO) << __func__ << ": " << device; -} - -void Mediator::OnDiscoveryAction(FastPairDevice& device, - DiscoveryAction action) { - switch (action) { - case DiscoveryAction::kPairToDevice: - NEARBY_LOGS(INFO) << __func__ << ": Action = kPairToDevice"; - // TODO(285451051): Adding show pairing for higher than v1 version in ui - // broker - pairer_broker_->PairDevice(device); - break; - case DiscoveryAction::kDismissedByOs: - NEARBY_LOGS(INFO) << __func__ << ": Action = kDismissedByOs"; - break; - case DiscoveryAction::kDismissedByUser: - // When the user explicitly dismisses the discovery notification, update - // the device's block-list value accordingly. - NEARBY_LOGS(INFO) << __func__ << ": Action = kDismissedByUser"; - // TODO(285453663): update discovery block list - [[fallthrough]]; - case DiscoveryAction::kDismissedByTimeout: - NEARBY_LOGS(INFO) << __func__ << ": Action = kDismissedByTimeout"; - device_currently_showing_notification_ = nullptr; - break; - case DiscoveryAction::kLearnMore: - NEARBY_LOGS(INFO) << __func__ << ": Action = kLearnMore"; - break; - default: - NEARBY_LOGS(INFO) << __func__ << ": Action = kUnknow"; - break; - } -} - -void Mediator::OnDevicePaired(FastPairDevice& device) { - NEARBY_LOGS(INFO) << __func__ << ": " << device; -} - -void Mediator::OnAccountKeyWrite(FastPairDevice& device, - std::optional error) { - if (error.has_value()) { - NEARBY_LOGS(INFO) << __func__ << ": Device=" << device - << ",Error=" << error.value(); - return; - } - - NEARBY_LOGS(INFO) << __func__ << ": Device=" << device; - if (device.GetProtocol() == Protocol::kFastPairRetroactivePairing) { - // TODO: UI ShowAssociateAccount - } -} - -void Mediator::OnPairingComplete(FastPairDevice& device) { - NEARBY_LOGS(INFO) << __func__ << ": " << device; -} - -void Mediator::OnPairFailure(FastPairDevice& device, PairFailure failure) { - NEARBY_LOGS(INFO) << __func__ << ": " << device - << " with PairFailure: " << failure; - // TODO: UI showPairingFailed -} - -void Mediator::StartScanning() { - NEARBY_LOGS(VERBOSE) << __func__; - if (IsFastPairEnabled()) { - if (scanning_session_ != nullptr) { - return; - } - scanner_broker_ = std::make_unique( - *mediums_, executor_.get(), devices_.get()); - scanner_broker_->AddObserver(this); - scanning_session_ = - scanner_broker_->StartScanning(Protocol::kFastPairInitialPairing); - return; - } - scanning_session_.reset(); -} - -void Mediator::StopScanning() { - NEARBY_LOGS(VERBOSE) << __func__; - if (scanning_session_ == nullptr) { - return; - } - scanning_session_.reset(); - scanner_broker_->RemoveObserver(this); - DestroyOnExecutor(std::move(scanner_broker_), executor_.get()); -} - -bool Mediator::IsFastPairEnabled() { - // TODO(b/275452353): Add feature_status_tracker IsFastPairEnabled() - // Currently default to true. - NEARBY_LOGS(VERBOSE) << __func__ << ": " << true; - return true; -} - -bool Mediator::IsDeviceCurrentlyShowingNotification( - const FastPairDevice& device) { - // BLE addresses could have rotated, causing this check to return false for - // the same device. Fast Pair considers a device different if they have - // different BLE addresses. Similarly, the this check will fail if it is the - // same physical device under different scenarios: for example, if a device - // is found via the initial scenario and via the subsequent scenario, Fast - // Pair does not consider them the same device. - - return device_currently_showing_notification_ && - device_currently_showing_notification_->GetModelId() == - device.GetModelId() && - device_currently_showing_notification_->GetBleAddress() == - device.GetBleAddress() && - device_currently_showing_notification_->GetProtocol() != - device.GetProtocol(); -} - -void Mediator::SetIsScreenLocked(bool locked) { - executor_->Execute( - "on_lock_state_changed", - [this, locked]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { - NEARBY_LOGS(INFO) << __func__ << ": Screen lock state changed. (" - << std::boolalpha << locked << ")"; - is_screen_locked_ = locked; - InvalidateScanningState(); - }); -} - -void Mediator::InvalidateScanningState() { - NEARBY_LOGS(INFO) << __func__; - // Stop scanning when screen is off. - if (is_screen_locked_) { - StopScanning(); - NEARBY_LOGS(VERBOSE) << __func__ - << ": Stopping scanning because the screen is locked."; - return; - } - - // TODO(b/275452353): Check if bluetooth and fast pair is enabled - - // Screen is on, Bluetooth is enabled, and Fast Pair is enabled, start - // scanning. - StartScanning(); -} - -} // namespace fastpair -} // namespace nearby diff --git a/fastpair/keyed_service/fast_pair_mediator.h b/fastpair/keyed_service/fast_pair_mediator.h deleted file mode 100644 index 7b2fbeef..00000000 --- a/fastpair/keyed_service/fast_pair_mediator.h +++ /dev/null @@ -1,131 +0,0 @@ -// 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_KEYED_SERVICE_FAST_PAIR_MEDIATOR_H_ -#define THIRD_PARTY_NEARBY_FASTPAIR_KEYED_SERVICE_FAST_PAIR_MEDIATOR_H_ - -#include -#include -#include - -#include "fastpair/common/fast_pair_device.h" -#include "fastpair/internal/mediums/mediums.h" -#include "fastpair/pairing/pairer_broker.h" -#include "fastpair/repository/fast_pair_device_repository.h" -#include "fastpair/scanning/scanner_broker.h" -#include "fastpair/server_access/fast_pair_client.h" -#include "fastpair/server_access/fast_pair_http_notifier.h" -#include "fastpair/repository/fast_pair_repository.h" -#include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" -#include "fastpair/ui/ui_broker.h" -#include "internal/account/account_manager.h" -#include "internal/auth/authentication_manager.h" -#include "internal/network/http_client.h" -#include "internal/platform/device_info.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/platform/task_runner.h" -#include "internal/preferences/preferences_manager.h" - -namespace nearby { -namespace fastpair { - -// Implements the Mediator design pattern for the components in the Fast Pair -class Mediator final : public ScannerBroker::Observer, - public UIBroker::Observer, - public PairerBroker::Observer { - public: - Mediator( - std::unique_ptr executor, - std::unique_ptr mediums, std::unique_ptr ui_broker, - std::unique_ptr notification_controller, - std::unique_ptr authentication_manager, - std::unique_ptr http_client, - std::unique_ptr device_info); - Mediator(const Mediator&) = delete; - Mediator& operator=(const Mediator&) = delete; - ~Mediator() override { - if (scanning_session_ == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << "scanner is not running"; - } - scanning_session_.reset(); - scanner_broker_->RemoveObserver(this); - DestroyOnExecutor(std::move(scanner_broker_), executor_.get()); - scanner_broker_.reset(); - ui_broker_->RemoveObserver(this); - ui_broker_.reset(); - }; - - AccountManager* GetAccountManager() { return account_manager_.get(); } - - FastPairNotificationController* GetNotificationController() { - return notification_controller_.get(); - } - - FastPairRepository* GetFastPairRepository() { - return fast_pair_repository_.get(); - } - - void StartScanning(); - void StopScanning(); - - // ScannerBroker::Observer - void OnDeviceFound(FastPairDevice& device) override; - void OnDeviceLost(FastPairDevice& device) override; - - // UIBroker::Observer - void OnDiscoveryAction(FastPairDevice& device, - DiscoveryAction action) override; - - // PairBroker:Observer - void OnDevicePaired(FastPairDevice& device) override; - void OnAccountKeyWrite(FastPairDevice& device, - std::optional error) override; - void OnPairingComplete(FastPairDevice& device) override; - void OnPairFailure(FastPairDevice& device, PairFailure failure) override; - - // Handle the state changes of screen lock. - void SetIsScreenLocked(bool is_locked); - - private: - bool IsFastPairEnabled(); - void InvalidateScanningState() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - bool IsDeviceCurrentlyShowingNotification(const FastPairDevice& device); - - // |device_currently_showing_notification_| can be null if there is no - // notification currently displayed to the user. - FastPairDevice* device_currently_showing_notification_ = nullptr; - FastPairHttpNotifier fast_pair_http_notifier_; - std::unique_ptr executor_; - std::unique_ptr mediums_; - std::unique_ptr scanner_broker_; - std::unique_ptr scanning_session_; - std::unique_ptr ui_broker_; - std::unique_ptr pairer_broker_; - std::unique_ptr notification_controller_; - std::unique_ptr fast_pair_repository_; - std::unique_ptr task_runner_; - std::unique_ptr devices_; - std::unique_ptr account_manager_; - std::unique_ptr preferences_manager_; - std::unique_ptr authentication_manager_; - std::unique_ptr fast_pair_client_; - std::unique_ptr http_client_; - std::unique_ptr device_info_; - bool is_screen_locked_ = false; -}; - -} // namespace fastpair -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_FASTPAIR_KEYED_SERVICE_FAST_PAIR_MEDIATOR_H_ diff --git a/fastpair/keyed_service/fast_pair_mediator_factory.cc b/fastpair/keyed_service/fast_pair_mediator_factory.cc deleted file mode 100644 index 5e87f8f1..00000000 --- a/fastpair/keyed_service/fast_pair_mediator_factory.cc +++ /dev/null @@ -1,47 +0,0 @@ -// 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/keyed_service/fast_pair_mediator_factory.h" - -#include - -#include "fastpair/internal/mediums/mediums.h" -#include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" -#include "fastpair/ui/ui_broker_impl.h" -#include "internal/auth/authentication_manager_impl.h" -#include "internal/network/http_client_impl.h" -#include "internal/platform/device_info_impl.h" -#include "internal/platform/single_thread_executor.h" - -namespace nearby { -namespace fastpair { - -MediatorFactory* MediatorFactory::GetInstance() { - static MediatorFactory* instance = new MediatorFactory(); - return instance; -} - -Mediator* MediatorFactory::CreateMediator() { - mediator_ = std::make_unique( - std::make_unique(), std::make_unique(), - std::make_unique(), - std::make_unique(), - std::make_unique(), - std::make_unique(), - std::make_unique()); - return mediator_.get(); -} - -} // namespace fastpair -} // namespace nearby diff --git a/fastpair/keyed_service/fast_pair_mediator_factory.h b/fastpair/keyed_service/fast_pair_mediator_factory.h deleted file mode 100644 index f1117aed..00000000 --- a/fastpair/keyed_service/fast_pair_mediator_factory.h +++ /dev/null @@ -1,39 +0,0 @@ -// 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_KEYED_SERVICE_FAST_PAIR_MEDIATOR_FACTORY_H_ -#define THIRD_PARTY_NEARBY_FASTPAIR_KEYED_SERVICE_FAST_PAIR_MEDIATOR_FACTORY_H_ - -#include - -#include "fastpair/keyed_service/fast_pair_mediator.h" - -namespace nearby { -namespace fastpair { - -class MediatorFactory { - public: - // Return a singleton instance of Mediator Factory - static MediatorFactory* GetInstance(); - - Mediator* CreateMediator(); - - private: - std::unique_ptr mediator_; -}; - -} // namespace fastpair -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_FASTPAIR_KEYED_SERVICE_FAST_PAIR_MEDIATOR_FACTORY_H_ diff --git a/fastpair/keyed_service/fast_pair_mediator_factory_test.cc b/fastpair/keyed_service/fast_pair_mediator_factory_test.cc deleted file mode 100644 index 234112a2..00000000 --- a/fastpair/keyed_service/fast_pair_mediator_factory_test.cc +++ /dev/null @@ -1,37 +0,0 @@ -// 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/keyed_service/fast_pair_mediator_factory.h" - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "fastpair/keyed_service/fast_pair_mediator.h" - -namespace nearby { -namespace fastpair { -namespace { - -TEST(MediatorFactoryTest, checkMediatorCreateWithFactory) { - MediatorFactory *factory_ = nullptr; - Mediator *mediator_ = nullptr; - factory_ = MediatorFactory::GetInstance(); - EXPECT_THAT(factory_, testing::NotNull()); - mediator_ = factory_->CreateMediator(); - EXPECT_THAT(mediator_, testing::NotNull()); -} - -} // namespace -} // namespace fastpair -} // namespace nearby diff --git a/fastpair/keyed_service/fast_pair_mediator_test.cc b/fastpair/keyed_service/fast_pair_mediator_test.cc deleted file mode 100644 index bd832bb7..00000000 --- a/fastpair/keyed_service/fast_pair_mediator_test.cc +++ /dev/null @@ -1,290 +0,0 @@ -// 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/keyed_service/fast_pair_mediator.h" - -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/strings/escaping.h" -#include "absl/strings/string_view.h" -#include "fastpair/testing/fast_pair_service_data_creator.h" -#include "fastpair/ui/actions.h" -#include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" -#include "fastpair/ui/mock_ui_broker.h" -#include "fastpair/ui/ui_broker.h" -#include "internal/account/fake_account_manager.h" -#include "internal/network/http_client_impl.h" -#include "internal/platform/device_info_impl.h" -#include "internal/platform/medium_environment.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/test/fake_device_info.h" -#include "internal/test/fake_http_client.h" -#include "internal/test/google3_only/fake_authentication_manager.h" - -namespace nearby { -namespace fastpair { -namespace { - -constexpr absl::string_view kModelId = "718c17"; -constexpr absl::string_view kServiceID = "Fast Pair"; -constexpr absl::string_view kFastPairServiceUuid = - "0000FE2C-0000-1000-8000-00805F9B34FB"; -constexpr int kNotDiscoverableAdvHeader = 0b00000110; -constexpr int kAccountKeyFilterHeader = 0b01100000; -constexpr int kSaltHeader = 0b00010001; -constexpr absl::string_view kAccountKeyFilter("112233445566"); -constexpr absl::string_view kSalt("01"); - -constexpr absl::string_view kModelId2 = "9adb11"; -constexpr absl::string_view kAddress = "74:74:46:01:6C:21"; - -class MediatorTest : public testing::Test { - public: - MediatorTest() { - AccountManagerImpl::Factory::SetFactoryForTesting( - &account_manager_factory_); - http_client_ = std::make_unique(); - device_info_ = std::make_unique(); - authentication_manager_ = - std::make_unique(); - } - void SetUp() override { - env_.Start(); - GetAuthManager()->EnableSyncMode(); - mediums_ = std::make_unique(); - ui_broker_ = std::make_unique(); - mock_ui_broker_ = static_cast(ui_broker_.get()); - - notification_controller_ = - std::make_unique(); - - executor_ = std::make_unique(); - } - - void TearDown() override { - executor_.reset(); - mediums_.reset(); - ui_broker_.reset(); - mock_ui_broker_ = nullptr; - notification_controller_.reset(); - mediator_.reset(); - env_.Stop(); - } - - nearby::FakeAuthenticationManager* GetAuthManager() { - return reinterpret_cast( - authentication_manager_.get()); - } - - network::FakeHttpClient* GetHttpClient() { - return reinterpret_cast(http_client_.get()); - } - - void SetUpDeviceMetadata() { - proto::GetObservedDeviceResponse response_proto; - auto* device = response_proto.mutable_device(); - int64_t device_id; - CHECK(absl::SimpleHexAtoi(kModelId, &device_id)); - device->set_id(device_id); - network::HttpResponse response; - response.SetStatusCode(network::HttpStatusCode::kHttpOk); - response.SetBody(response_proto.SerializeAsString()); - GetHttpClient()->SetResponseForSyncRequest(response); - } - - protected: - MediumEnvironment& env_{MediumEnvironment::Instance()}; - std::unique_ptr mediums_; - std::unique_ptr ui_broker_; - std::unique_ptr notification_controller_; - std::unique_ptr executor_; - MockUIBroker* mock_ui_broker_; - std::unique_ptr mediator_; - FakeAccountManager::Factory account_manager_factory_; - std::unique_ptr authentication_manager_; - std::unique_ptr http_client_; - std::unique_ptr device_info_; -}; - -TEST_F(MediatorTest, StartScanningFoundDevice) { - SetUpDeviceMetadata(); - // Create Fast Pair Mediator - mediator_ = std::make_unique( - std::move(executor_), std::move(mediums_), std::move(ui_broker_), - std::move(notification_controller_), std::move(authentication_manager_), - std::move(http_client_), std::move(device_info_)); - absl::Notification done; - EXPECT_CALL(*mock_ui_broker_, ShowDiscovery).WillOnce([&done] { - done.Notify(); - }); - - // Create Advertiser and startAdvertising - Mediums mediums_advertiser; - std::string service_id(kServiceID); - ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; - std::string fast_pair_service_uuid(kFastPairServiceUuid); - mediums_advertiser.GetBle().GetMedium().StartAdvertising( - service_id, advertisement_bytes, fast_pair_service_uuid); - - mediator_->StartScanning(); - done.WaitForNotification(); -} - -TEST_F(MediatorTest, StartScanningFoundDifferentDeviceWhenDisplaying) { - SetUpDeviceMetadata(); - // Create Fast Pair Mediator - mediator_ = std::make_unique( - std::move(executor_), std::move(mediums_), std::move(ui_broker_), - std::move(notification_controller_), std::move(authentication_manager_), - std::move(http_client_), std::move(device_info_)); - absl::Notification done; - EXPECT_CALL(*mock_ui_broker_, ShowDiscovery).Times(1).WillOnce([&done] { - done.Notify(); - }); - - // Create Advertiser and startAdvertising - Mediums mediums_advertiser; - std::string service_id(kServiceID); - ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; - std::string fast_pair_service_uuid(kFastPairServiceUuid); - mediums_advertiser.GetBle().GetMedium().StartAdvertising( - service_id, advertisement_bytes, fast_pair_service_uuid); - - // Create a different Advertiser and startAdvertising to cause confliction - Mediums mediums_advertiser2; - ByteArray advertisement_bytes2{absl::HexStringToBytes(kModelId2)}; - mediums_advertiser2.GetBle().GetMedium().StartAdvertising( - service_id, advertisement_bytes2, fast_pair_service_uuid); - - mediator_->StartScanning(); - done.WaitForNotification(); -} - -TEST_F(MediatorTest, StartScanningFoundSameDeviceWhenDisplaying) { - SetUpDeviceMetadata(); - // Create Fast Pair Mediator - mediator_ = std::make_unique( - std::move(executor_), std::move(mediums_), std::move(ui_broker_), - std::move(notification_controller_), std::move(authentication_manager_), - std::move(http_client_), std::move(device_info_)); - absl::Notification done; - EXPECT_CALL(*mock_ui_broker_, ShowDiscovery).Times(1).WillOnce([&done] { - done.Notify(); - }); - - // Create Advertiser and startAdvertising - Mediums mediums_advertiser; - std::string service_id(kServiceID); - ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; - std::string fast_pair_service_uuid(kFastPairServiceUuid); - mediums_advertiser.GetBle().GetMedium().StartAdvertising( - service_id, advertisement_bytes, fast_pair_service_uuid); - - // Create another same Advertiser and startAdvertising to cause confliction - Mediums mediums_advertiser2; - ByteArray advertisement_bytes2{absl::HexStringToBytes(kModelId)}; - mediums_advertiser2.GetBle().GetMedium().StartAdvertising( - service_id, advertisement_bytes2, fast_pair_service_uuid); - - mediator_->StartScanning(); - done.WaitForNotification(); -} - -TEST_F(MediatorTest, - StartScanningForSubsequentPairingFoundSameDeviceWhenDisplaying) { - SetUpDeviceMetadata(); - // Create Fast Pair Mediator - mediator_ = std::make_unique( - std::move(executor_), std::move(mediums_), std::move(ui_broker_), - std::move(notification_controller_), std::move(authentication_manager_), - std::move(http_client_), std::move(device_info_)); - absl::Notification done; - EXPECT_CALL(*mock_ui_broker_, ShowDiscovery).Times(1).WillOnce([&done] { - done.Notify(); - }); - - // Create Advertiser and advertising discoverable advertisement - Mediums mediums_advertiser; - std::string service_id(kServiceID); - ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; - std::string fast_pair_service_uuid(kFastPairServiceUuid); - mediums_advertiser.GetBle().GetMedium().StartAdvertising( - service_id, advertisement_bytes, fast_pair_service_uuid); - - // Create another same Advertiser and advertising non-discoverable - // advertisement to cause confliction - Mediums mediums_advertiser2; - std::vector bytes = FastPairServiceDataCreator::Builder() - .SetHeader(kNotDiscoverableAdvHeader) - .SetModelId(kModelId) - .AddExtraFieldHeader(kAccountKeyFilterHeader) - .AddExtraField(kAccountKeyFilter) - .AddExtraFieldHeader(kSaltHeader) - .AddExtraField(kSalt) - .Build() - ->CreateServiceData(); - ByteArray advertisement_bytes2{std::string(bytes.begin(), bytes.end())}; - mediums_advertiser2.GetBle().GetMedium().StartAdvertising( - service_id, advertisement_bytes2, fast_pair_service_uuid); - - mediator_->StartScanning(); - done.WaitForNotification(); -} - -TEST_F(MediatorTest, OnDiscoveryActionClicked) { - SetUpDeviceMetadata(); - SetUpDeviceMetadata(); - // Create Fast Pair Mediator - mediator_ = std::make_unique( - std::move(executor_), std::move(mediums_), std::move(ui_broker_), - std::move(notification_controller_), std::move(authentication_manager_), - std::move(http_client_), std::move(device_info_)); - - absl::Notification done; - EXPECT_CALL(*mock_ui_broker_, ShowDiscovery).Times(2).WillOnce([&done] { - done.Notify(); - }); - - // Create Advertiser and startAdvertising - Mediums mediums_advertiser; - std::string service_id(kServiceID); - ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; - std::string fast_pair_service_uuid(kFastPairServiceUuid); - mediums_advertiser.GetBle().GetMedium().StartAdvertising( - service_id, advertisement_bytes, fast_pair_service_uuid); - - mediator_->StartScanning(); - done.WaitForNotification(); - - FastPairDevice device(kModelId, kAddress, Protocol::kFastPairInitialPairing); - mock_ui_broker_->NotifyDiscoveryAction(device, - DiscoveryAction::kDismissedByTimeout); - // Create another same Advertiser and startAdvertising to cause confliction - Mediums mediums_advertiser2; - ByteArray advertisement_bytes2{absl::HexStringToBytes(kModelId)}; - mediums_advertiser2.GetBle().GetMedium().StartAdvertising( - service_id, advertisement_bytes2, fast_pair_service_uuid); - - done.WaitForNotification(); -} - -} // namespace -} // namespace fastpair -} // namespace nearby diff --git a/fastpair/message_stream/BUILD b/fastpair/message_stream/BUILD index 41969904..0ec782b2 100644 --- a/fastpair/message_stream/BUILD +++ b/fastpair/message_stream/BUILD @@ -60,7 +60,6 @@ cc_library( "//fastpair/common", "//internal/platform:base", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform:uuid", @@ -106,7 +105,6 @@ cc_library( ":message_stream", "//fastpair/common", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:test_util", "//internal/platform:types", "@com_google_absl//absl/status", @@ -128,7 +126,6 @@ cc_test( ":message_stream", "//fastpair/common", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep @@ -153,7 +150,6 @@ cc_test( ":message_stream", "//fastpair/common", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform/implementation:types", diff --git a/fastpair/mock_fast_pair_seeker.h b/fastpair/mock_fast_pair_seeker.h index cd9b19f7..4bc4badd 100644 --- a/fastpair/mock_fast_pair_seeker.h +++ b/fastpair/mock_fast_pair_seeker.h @@ -38,6 +38,11 @@ class MockFastPairSeeker : public FastPairSeeker { (const FastPairDevice& device, const RetroactivePairingParam& param, PairingCallback callback), (override)); + MOCK_METHOD(absl::Status, FinishRetroactivePairing, + (const FastPairDevice& device, + const FinishRetroactivePairingParam& param, + PairingCallback callback), + (override)); }; } // namespace fastpair diff --git a/fastpair/pairing/BUILD b/fastpair/pairing/BUILD index 44cb524c..65a485aa 100644 --- a/fastpair/pairing/BUILD +++ b/fastpair/pairing/BUILD @@ -33,6 +33,7 @@ cc_library( "//fastpair/handshake", "//fastpair/internal/mediums", "//fastpair/pairing/fastpair:pairing", + "//internal/account", "//internal/base", "//internal/platform:types", "@com_google_absl//absl/container:flat_hash_map", @@ -58,11 +59,15 @@ cc_test( "//fastpair/pairing/fastpair:pairing", "//fastpair/proto:fastpair_cc_proto", "//fastpair/repository:test_support", + "//internal/account", + "//internal/account:test_support", + "//internal/auth:credential", "//internal/base:bluetooth_address", "//internal/platform:comm", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep + "//internal/test/google3_only:test", "@boringssl//:crypto", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/functional:bind_front", diff --git a/fastpair/pairing/fastpair/BUILD b/fastpair/pairing/fastpair/BUILD index eb6a212b..c748b211 100644 --- a/fastpair/pairing/fastpair/BUILD +++ b/fastpair/pairing/fastpair/BUILD @@ -34,6 +34,7 @@ cc_library( "//fastpair/handshake", "//fastpair/internal/mediums", "//fastpair/repository", + "//internal/account", "//internal/platform:comm", "//internal/platform:types", "@com_google_absl//absl/functional:any_invocable", @@ -56,11 +57,15 @@ cc_test( "//fastpair/handshake:test_support", "//fastpair/proto:fastpair_cc_proto", "//fastpair/repository:test_support", + "//internal/account", + "//internal/account:test_support", + "//internal/auth:credential", "//internal/base:bluetooth_address", "//internal/platform:comm", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep + "//internal/test/google3_only:test", "@boringssl//:crypto", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/functional:any_invocable", diff --git a/fastpair/pairing/fastpair/fast_pair_pairer_impl.cc b/fastpair/pairing/fastpair/fast_pair_pairer_impl.cc index b1ca0724..e2c21138 100644 --- a/fastpair/pairing/fastpair/fast_pair_pairer_impl.cc +++ b/fastpair/pairing/fastpair/fast_pair_pairer_impl.cc @@ -44,17 +44,18 @@ FastPairPairerImpl::Factory* FastPairPairerImpl::Factory::g_test_factory_ = // static std::unique_ptr FastPairPairerImpl::Factory::Create( FastPairDevice& device, Mediums& medium, SingleThreadExecutor* executor, - OnPairedCallback on_paired_cb, OnPairingFailedCallback on_pair_failed_cb, + AccountManager* account_manager, OnPairedCallback on_paired_cb, + OnPairingFailedCallback on_pair_failed_cb, OnAccountKeyFailureCallback on_account_failure_cb, OnPairingCompletedCallback on_pairing_completed_cb) { if (g_test_factory_) { return g_test_factory_->CreateInstance( - device, medium, executor, std::move(on_paired_cb), + device, medium, executor, account_manager, std::move(on_paired_cb), std::move(on_pair_failed_cb), std::move(on_account_failure_cb), std::move(on_pairing_completed_cb)); } return std::make_unique( - device, medium, executor, std::move(on_paired_cb), + device, medium, executor, account_manager, std::move(on_paired_cb), std::move(on_pair_failed_cb), std::move(on_account_failure_cb), std::move(on_pairing_completed_cb)); } @@ -67,12 +68,14 @@ void FastPairPairerImpl::Factory::SetFactoryForTesting( FastPairPairerImpl::FastPairPairerImpl( FastPairDevice& device, Mediums& medium, SingleThreadExecutor* executor, - OnPairedCallback on_paired_cb, OnPairingFailedCallback on_pair_failed_cb, + AccountManager* account_manager, OnPairedCallback on_paired_cb, + OnPairingFailedCallback on_pair_failed_cb, OnAccountKeyFailureCallback on_account_failure_cb, OnPairingCompletedCallback on_pairing_completed_cb) : device_(device), mediums_(medium), executor_(executor), + account_manager_(account_manager), on_paired_cb_(std::move(on_paired_cb)), on_pair_failed_cb_(std::move(on_pair_failed_cb)), on_account_key_failure_cb_(std::move(on_account_failure_cb)), @@ -279,8 +282,37 @@ void FastPairPairerImpl::AttemptSendAccountKey() { return; } - // TODO(b/281781730) : Check if we need to send account key - // TODO(b/281782018) : Handle BLE address rotation + if (!account_manager_->GetCurrentAccount().has_value()) { + NEARBY_LOGS(INFO) + << __func__ + << ": No need to write accountkey because no logged in user."; + NotifyPairingCompleted(); + return; + } + + // It's possible that the user has opted to initial pair to a device that + // already has an account key saved. We check to see if this is the case + // before writing a new account key. + if (device_.GetProtocol() == Protocol::kFastPairInitialPairing) { + FastPairRepository::Get()->IsDeviceSavedToAccount( + device_.GetPublicAddress().value(), [this](absl::Status status) { + if (status.ok()) { + NEARBY_LOGS(VERBOSE) + << __func__ + << ": Device is already saved, skipping write account key. " + "Pairing procedure complete."; + NotifyPairingCompleted(); + return; + } + WriteAccountKey(); + }); + } else { + // TODO(b/281782018) : Handle BLE address rotation + WriteAccountKey(); + } +} + +void FastPairPairerImpl::WriteAccountKey() { fast_pair_gatt_service_client_->WriteAccountKey( *fast_pair_handshake_->fast_pair_data_encryptor(), [&](const std::optional account_key, diff --git a/fastpair/pairing/fastpair/fast_pair_pairer_impl.h b/fastpair/pairing/fastpair/fast_pair_pairer_impl.h index a3fe538b..9024e636 100644 --- a/fastpair/pairing/fastpair/fast_pair_pairer_impl.h +++ b/fastpair/pairing/fastpair/fast_pair_pairer_impl.h @@ -26,6 +26,7 @@ #include "fastpair/handshake/fast_pair_handshake.h" #include "fastpair/internal/mediums/mediums.h" #include "fastpair/pairing/fastpair/fast_pair_pairer.h" +#include "internal/account/account_manager.h" #include "internal/platform/bluetooth_classic.h" #include "internal/platform/single_thread_executor.h" #include "internal/platform/timer_impl.h" @@ -39,7 +40,7 @@ class FastPairPairerImpl : public FastPairPairer { public: static std::unique_ptr Create( FastPairDevice& device, Mediums& medium, SingleThreadExecutor* executor, - OnPairedCallback on_paired_cb, + AccountManager* account_manager, OnPairedCallback on_paired_cb, OnPairingFailedCallback on_pair_failed_cb, OnAccountKeyFailureCallback on_account_failure_cb, OnPairingCompletedCallback on_pairing_completed_cb); @@ -51,7 +52,7 @@ class FastPairPairerImpl : public FastPairPairer { virtual std::unique_ptr CreateInstance( FastPairDevice& device, Mediums& medium, SingleThreadExecutor* executor, - OnPairedCallback on_paired_cb, + AccountManager* account_manager, OnPairedCallback on_paired_cb, OnPairingFailedCallback on_pair_failed_cb, OnAccountKeyFailureCallback on_account_failure_cb, OnPairingCompletedCallback on_pairing_completed_cb) = 0; @@ -62,6 +63,7 @@ class FastPairPairerImpl : public FastPairPairer { FastPairPairerImpl(FastPairDevice& device, Mediums& medium, SingleThreadExecutor* executor, + AccountManager* account_manager, OnPairedCallback on_paired_cb, OnPairingFailedCallback on_pair_failed_cb, OnAccountKeyFailureCallback on_account_failure_cb, @@ -86,6 +88,7 @@ class FastPairPairerImpl : public FastPairPairer { // Attempts to write account key to remote device void AttemptSendAccountKey() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); + void WriteAccountKey(); // FastPairDataEncryptor::WriteAccountKey callback void OnWriteAccountKey(std::optional account_key, std::optional failure); @@ -103,6 +106,7 @@ class FastPairPairerImpl : public FastPairPairer { FastPairDevice& device_; Mediums& mediums_; SingleThreadExecutor* executor_; + AccountManager* account_manager_; OnPairedCallback on_paired_cb_ ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); OnPairingFailedCallback on_pair_failed_cb_ ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); diff --git a/fastpair/pairing/fastpair/fast_pair_pairer_impl_test.cc b/fastpair/pairing/fastpair/fast_pair_pairer_impl_test.cc index 729d70c1..d2eac0e5 100644 --- a/fastpair/pairing/fastpair/fast_pair_pairer_impl_test.cc +++ b/fastpair/pairing/fastpair/fast_pair_pairer_impl_test.cc @@ -34,6 +34,7 @@ #include "fastpair/common/account_key.h" #include "fastpair/common/device_metadata.h" #include "fastpair/common/fast_pair_device.h" +#include "fastpair/common/fast_pair_prefs.h" #include "fastpair/common/fast_pair_version.h" #include "fastpair/common/protocol.h" #include "fastpair/crypto/decrypted_passkey.h" @@ -46,12 +47,15 @@ #include "fastpair/pairing/fastpair/fast_pair_pairer.h" #include "fastpair/proto/fastpair_rpcs.proto.h" #include "fastpair/repository/fake_fast_pair_repository.h" +#include "internal/account/fake_account_manager.h" #include "internal/base/bluetooth_address.h" #include "internal/platform/ble_v2.h" #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/medium_environment.h" #include "internal/platform/single_thread_executor.h" +#include "internal/platform/task_runner_impl.h" +#include "internal/test/google3_only/fake_authentication_manager.h" namespace nearby { namespace fastpair { @@ -62,6 +66,9 @@ using ::nearby::api::ble_v2::GattCharacteristic; using DiscoveryCallback = BluetoothClassicMedium::DiscoveryCallback; constexpr absl::Duration kWaitTimeout = absl::Milliseconds(200); +constexpr absl::string_view kFastPairPreferencesFilePath = + "Google/Nearby/FastPair"; +constexpr absl::string_view kTestAccountId = "test_account_id"; constexpr absl::string_view kMetadataId("718c17"); constexpr absl::string_view kPublicAntiSpoof = "Wuyr48lD3txnUhGiMF1IfzlTwRxxe+wMB1HLzP+" @@ -130,11 +137,18 @@ class FastPairPairerImplTest : public testing::Test { FastPairPairerImplTest() { FastPairDataEncryptorImpl::Factory::SetFactoryForTesting( &fake_data_encryptor_factory_); + task_runner_ = std::make_unique(1); + preferences_manager_ = std::make_unique( + kFastPairPreferencesFilePath); + authentication_manager_ = std::make_unique(); } void SetUp() override { env_.Start(); // Setups seeker device. mediums_ = std::make_unique(); + account_manager_ = std::make_unique( + preferences_manager_.get(), prefs::kNearbyFastPairUsersName, + authentication_manager_.get(), task_runner_.get()); // Setups provider device. adapter_provider_ = std::make_unique(); @@ -162,6 +176,7 @@ class FastPairPairerImplTest : public testing::Test { fast_pair_pairer_.reset(); FastPairHandshakeLookup::GetInstance()->Clear(); mediums_.reset(); + account_manager_.reset(); device_.reset(); remote_device_ = nullptr; key_based_characteristic_ = std::nullopt; @@ -178,6 +193,12 @@ class FastPairPairerImplTest : public testing::Test { env_.Stop(); } + void LogInAccount() { + AccountManager::Account account; + account.id = kTestAccountId; + account_manager_->SetAccount(account); + } + void CreateMockDevice(DeviceFastPairVersion version, Protocol protocol) { device_ = std::make_unique( kMetadataId, remote_device_->GetMacAddress(), protocol); @@ -354,6 +375,7 @@ class FastPairPairerImplTest : public testing::Test { std::unique_ptr fast_pair_pairer_; FastPairFakeDataEncryptorImplFactory fake_data_encryptor_factory_; SingleThreadExecutor executor_; + std::unique_ptr account_manager_; std::optional key_based_characteristic_; std::optional passkey_characteristic_; std::optional accountkey_characteristic_; @@ -362,6 +384,9 @@ class FastPairPairerImplTest : public testing::Test { private: MediumEnvironment& env_{MediumEnvironment::Instance()}; Mutex mutex_; + std::unique_ptr preferences_manager_; + std::unique_ptr authentication_manager_; + std::unique_ptr task_runner_; std::unique_ptr bt_provider_; std::unique_ptr adapter_provider_; std::unique_ptr gatt_server_; @@ -375,7 +400,10 @@ class FastPairPairerImplTest : public testing::Test { TEST_F(FastPairPairerImplTest, SuccessInitialPairingWithDeviceVersionHigherThanV1) { + LogInAccount(); auto repository = std::make_unique(); + repository->SetResultOfIsDeviceSavedToAccount( + absl::NotFoundError("not found")); repository->SetResultOfWriteAccountAssociationToFootprints(absl::OkStatus()); ConfigurePairingContext(); SetPairingResult(std::nullopt); @@ -393,7 +421,7 @@ TEST_F(FastPairPairerImplTest, EXPECT_FALSE(device_->GetAccountKey().Ok()); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { paired_latch.CountDown(); }, [&](FastPairDevice& device, PairFailure failure) { FAIL() << "Unexpected pairing failure " << failure; @@ -414,6 +442,7 @@ TEST_F(FastPairPairerImplTest, } TEST_F(FastPairPairerImplTest, SuccessInitialPairingWithDeviceV1) { + LogInAccount(); ConfigurePairingContext(); SetPairingResult(std::nullopt); CreateMockDevice(DeviceFastPairVersion::kV1, @@ -424,7 +453,7 @@ TEST_F(FastPairPairerImplTest, SuccessInitialPairingWithDeviceV1) { CountDownLatch complete_latch(1); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { paired_latch.CountDown(); }, [&](FastPairDevice& device, PairFailure failure) { FAIL() << "Unexpected pairing failure " << failure; @@ -444,6 +473,7 @@ TEST_F(FastPairPairerImplTest, SuccessInitialPairingWithDeviceV1) { } TEST_F(FastPairPairerImplTest, SuccessSubsequentPairingWithDevice) { + LogInAccount(); ConfigurePairingContext(); SetPairingResult(std::nullopt); CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, @@ -459,7 +489,7 @@ TEST_F(FastPairPairerImplTest, SuccessSubsequentPairingWithDevice) { CountDownLatch complete_latch(1); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { paired_latch.CountDown(); }, [&](FastPairDevice& device, PairFailure failure) { FAIL() << "Unexpected pairing failure " << failure; @@ -479,6 +509,7 @@ TEST_F(FastPairPairerImplTest, SuccessSubsequentPairingWithDevice) { } TEST_F(FastPairPairerImplTest, SuccessRetroactivePairingWithDevice) { + LogInAccount(); ConfigurePairingContext(); SetPairingResult(std::nullopt); CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, @@ -493,7 +524,7 @@ TEST_F(FastPairPairerImplTest, SuccessRetroactivePairingWithDevice) { EXPECT_FALSE(device_->GetAccountKey().Ok()); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { FAIL() << "Unexpected callback"; }, [&](FastPairDevice& device, PairFailure failure) { FAIL() << "Unexpected pairing failure " << failure; @@ -523,7 +554,7 @@ TEST_F(FastPairPairerImplTest, FailedToUnPair) { EXPECT_FALSE(device_->GetAccountKey().Ok()); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { FAIL() << "Unexpected callback"; }, [&](FastPairDevice& device, PairFailure failure) { EXPECT_EQ(failure, PairFailure::kPairingAndConnect); @@ -561,7 +592,7 @@ TEST_F(FastPairPairerImplTest, FailedToPairingWithAuthTimeout) { EXPECT_FALSE(device_->GetAccountKey().Ok()); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { FAIL() << "Unexpected callback"; }, [&](FastPairDevice& device, PairFailure failure) { EXPECT_EQ(failure, PairFailure::kPairingAndConnect); @@ -594,7 +625,7 @@ TEST_F(FastPairPairerImplTest, NoPasskeyResponse) { EXPECT_FALSE(device_->GetAccountKey().Ok()); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { FAIL() << "Unexpected callback"; }, [&](FastPairDevice& device, PairFailure failure) { EXPECT_EQ(failure, PairFailure::kPasskeyResponseTimeout); @@ -629,7 +660,7 @@ TEST_F(FastPairPairerImplTest, PasskeyMismatch) { EXPECT_FALSE(device_->GetAccountKey().Ok()); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { FAIL() << "Unexpected callback"; }, [&](FastPairDevice& device, PairFailure failure) { EXPECT_EQ(failure, PairFailure::kPasskeyMismatch); @@ -665,7 +696,7 @@ TEST_F(FastPairPairerImplTest, ReceiveWithWrongPasskeyResponse) { EXPECT_FALSE(device_->GetAccountKey().Ok()); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { FAIL() << "Unexpected callback"; }, [&](FastPairDevice& device, PairFailure failure) { EXPECT_EQ(failure, PairFailure::kPasskeyDecryptFailure); @@ -702,7 +733,7 @@ TEST_F(FastPairPairerImplTest, ReceiveWithWrongPasskeyMessageType) { EXPECT_FALSE(device_->GetAccountKey().Ok()); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { FAIL() << "Unexpected callback"; }, [&](FastPairDevice& device, PairFailure failure) { EXPECT_EQ(failure, PairFailure::kIncorrectPasskeyResponseType); @@ -720,8 +751,88 @@ TEST_F(FastPairPairerImplTest, ReceiveWithWrongPasskeyMessageType) { EXPECT_FALSE(device_->GetAccountKey().Ok()); } +TEST_F(FastPairPairerImplTest, SkipWriteAccountKeyBecauseNoLoggedInUser) { + ConfigurePairingContext(); + SetPairingResult(std::nullopt); + CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, + Protocol::kFastPairInitialPairing); + SetupProviderGattServer(); + SetNotifyResponse(*key_based_characteristic_, kKeyBasedResponse); + SetNotifyResponse(*passkey_characteristic_, kPasskeyResponse); + SetDecryptedResponse(); + SetDecryptedPasskey(); + CreateFastPairHandshakeInstanceForDevice(); + + CountDownLatch paired_latch(1); + CountDownLatch complete_latch(1); + + EXPECT_FALSE(device_->GetAccountKey().Ok()); + + fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( + *device_, *mediums_, &executor_, account_manager_.get(), + [&](FastPairDevice& cb_device) { paired_latch.CountDown(); }, + [&](FastPairDevice& device, PairFailure failure) { + FAIL() << "Unexpected pairing failure " << failure; + }, + [&](FastPairDevice& device, PairFailure failure) { + FAIL() << "Unexpected pairing failure " << failure; + }, + [&](FastPairDevice& device) { + EXPECT_FALSE(device.GetAccountKey().Ok()); + complete_latch.CountDown(); + }); + fast_pair_pairer_->StartPairing(); + paired_latch.Await(); + complete_latch.Await(kWaitTimeout).result(); + EXPECT_TRUE(fast_pair_pairer_->IsPaired()); + EXPECT_FALSE(device_->GetAccountKey().Ok()); +} + +TEST_F(FastPairPairerImplTest, + SkipWriteAccountKeyBecauseDeviceAlreadySavedToAccount) { + LogInAccount(); + auto repository = std::make_unique(); + repository->SetResultOfIsDeviceSavedToAccount(absl::OkStatus()); + ConfigurePairingContext(); + SetPairingResult(std::nullopt); + CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, + Protocol::kFastPairInitialPairing); + SetupProviderGattServer(); + SetNotifyResponse(*key_based_characteristic_, kKeyBasedResponse); + SetNotifyResponse(*passkey_characteristic_, kPasskeyResponse); + SetDecryptedResponse(); + SetDecryptedPasskey(); + CreateFastPairHandshakeInstanceForDevice(); + + CountDownLatch paired_latch(1); + CountDownLatch complete_latch(1); + + fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( + *device_, *mediums_, &executor_, account_manager_.get(), + [&](FastPairDevice& cb_device) { paired_latch.CountDown(); }, + [&](FastPairDevice& device, PairFailure failure) { + FAIL() << "Unexpected pairing failure " << failure; + }, + [&](FastPairDevice& device, PairFailure failure) { + FAIL() << "Unexpected pairing failure " << failure; + }, + [&](FastPairDevice& device) { + EXPECT_FALSE(device.GetAccountKey().Ok()); + complete_latch.CountDown(); + }); + fast_pair_pairer_->StartPairing(); + paired_latch.Await(); + complete_latch.Await(); + EXPECT_TRUE(fast_pair_pairer_->IsPaired()); + EXPECT_FALSE(device_->GetAccountKey().Ok()); +} + TEST_F(FastPairPairerImplTest, SuccessPairingWithDeviceButFailedToWriteAccountkeyToRemoteDevice) { + LogInAccount(); + auto repository = std::make_unique(); + repository->SetResultOfIsDeviceSavedToAccount( + absl::NotFoundError("not found")); ConfigurePairingContext(); SetPairingResult(std::nullopt); CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, @@ -742,7 +853,7 @@ TEST_F(FastPairPairerImplTest, EXPECT_FALSE(device_->GetAccountKey().Ok()); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { paired_latch.CountDown(); }, [&](FastPairDevice& device, PairFailure failure) { failure_latch.CountDown(); @@ -766,7 +877,10 @@ TEST_F(FastPairPairerImplTest, TEST_F(FastPairPairerImplTest, SuccessPairingWithDeviceButFailedToWriteAccountkeyToFootprints) { + LogInAccount(); auto repository = std::make_unique(); + repository->SetResultOfIsDeviceSavedToAccount( + absl::NotFoundError("not found")); repository->SetResultOfWriteAccountAssociationToFootprints( absl::InternalError("Failed to write account key to foot prints")); ConfigurePairingContext(); @@ -785,7 +899,7 @@ TEST_F(FastPairPairerImplTest, EXPECT_FALSE(device_->GetAccountKey().Ok()); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { paired_latch.CountDown(); }, [&](FastPairDevice& device, PairFailure failure) { FAIL() << "Unexpected pairing failure " << failure; @@ -819,7 +933,7 @@ TEST_F(FastPairPairerImplTest, TestCancelPairing) { EXPECT_FALSE(device_->GetAccountKey().Ok()); fast_pair_pairer_ = FastPairPairerImpl::Factory::Create( - *device_, *mediums_, &executor_, + *device_, *mediums_, &executor_, account_manager_.get(), [&](FastPairDevice& cb_device) { FAIL() << "Unexpected callback"; }, [&](FastPairDevice& device, PairFailure failure) { EXPECT_EQ(failure, PairFailure::kPairingAndConnect); diff --git a/fastpair/pairing/pairer_broker_impl.cc b/fastpair/pairing/pairer_broker_impl.cc index 8fa67982..12ba5a19 100644 --- a/fastpair/pairing/pairer_broker_impl.cc +++ b/fastpair/pairing/pairer_broker_impl.cc @@ -36,8 +36,9 @@ constexpr absl::Duration kRetryHandshakeDelay = absl::Seconds(1); } // namespace PairerBrokerImpl::PairerBrokerImpl(Mediums& medium, - SingleThreadExecutor* executor) - : medium_(medium), executor_(executor) {} + SingleThreadExecutor* executor, + AccountManager* account_manager) + : medium_(medium), executor_(executor), account_manager_(account_manager) {} void PairerBrokerImpl::AddObserver(Observer* observer) { observers_.AddObserver(observer); @@ -191,7 +192,7 @@ void PairerBrokerImpl::StartPairingAttempt(FastPairDevice& device) { MutexLock lock(&mutex_); // Create FastPairPairer instance and start pairing. fast_pair_pairers_[device.GetModelId()] = FastPairPairerImpl::Factory::Create( - device, medium_, executor_, + device, medium_, executor_, account_manager_, [&](FastPairDevice& cb_device) { executor_->Execute("OnFastPairDevicePaired", [&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { @@ -232,42 +233,44 @@ void PairerBrokerImpl::OnFastPairDevicePaired(FastPairDevice& device) { void PairerBrokerImpl::OnFastPairPairingFailure(FastPairDevice& device, PairFailure failure) { - MutexLock lock(&mutex_); - ++pair_failure_counts_[device.GetModelId()]; - NEARBY_LOGS(INFO) << __func__ << ": Device=" << device - << ", Failure=" << failure << ", Failure Count = " - << pair_failure_counts_[device.GetModelId()]; - if (pair_failure_counts_[device.GetModelId()] == kMaxFailureRetryCount) { - if (!fast_pair_pairers_[device.GetModelId()]->IsPaired()) { - fast_pair_pairers_[device.GetModelId()]->CancelPairing(); + { + MutexLock lock(&mutex_); + ++pair_failure_counts_[device.GetModelId()]; + NEARBY_LOGS(INFO) << __func__ << ": Device=" << device + << ", Failure=" << failure << ", Failure Count = " + << pair_failure_counts_[device.GetModelId()]; + if (pair_failure_counts_[device.GetModelId()] == kMaxFailureRetryCount) { + if (!fast_pair_pairers_[device.GetModelId()]->IsPaired()) { + fast_pair_pairers_[device.GetModelId()]->CancelPairing(); + } + executor_->Execute("EraseHandshakeAndPairers", + [&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { + EraseHandshakeAndPairers(device); + }); + NEARBY_LOGS(INFO) << __func__ + << ": Reached max failure count. Notifying observers."; + for (auto& observer : observers_.GetObservers()) { + observer->OnPairFailure(device, failure); + } + return; } - executor_->Execute("EraseHandshakeAndPairers", - [&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { - EraseHandshakeAndPairers(device); - }); - NEARBY_LOGS(INFO) << __func__ - << ": Reached max failure count. Notifying observers."; - for (auto& observer : observers_.GetObservers()) { - observer->OnPairFailure(device, failure); - } - return; - } - if (!fast_pair_pairers_[device.GetModelId()]->IsPaired()) { - NEARBY_LOGS(INFO) << __func__ - << ": Cancelling pairing and scheduling retry " - "for failed pair attempt."; - fast_pair_pairers_[device.GetModelId()]->CancelPairing(); + if (!fast_pair_pairers_[device.GetModelId()]->IsPaired()) { + NEARBY_LOGS(INFO) << __func__ + << ": Cancelling pairing and scheduling retry " + "for failed pair attempt."; + fast_pair_pairers_[device.GetModelId()]->CancelPairing(); + fast_pair_pairers_.erase(device.GetModelId()); + // Create a timer to wait |kCancelPairingRetryDelay| after cancelling + // pairing to retry the pairing attempt. + cancel_pairing_timer_ = std::make_unique(); + cancel_pairing_timer_->Start( + kCancelPairingRetryDelay / absl::Milliseconds(1), 0, + [&]() { PairFastPairDevice(device); }); + return; + } fast_pair_pairers_.erase(device.GetModelId()); - // Create a timer to wait |kCancelPairingRetryDelay| after cancelling - // pairing to retry the pairing attempt. - cancel_pairing_timer_ = std::make_unique(); - cancel_pairing_timer_->Start( - kCancelPairingRetryDelay / absl::Milliseconds(1), 0, - [&]() { PairFastPairDevice(device); }); - return; } - fast_pair_pairers_.erase(device.GetModelId()); PairFastPairDevice(device); } @@ -298,10 +301,11 @@ void PairerBrokerImpl::OnFastPairProcedureComplete(FastPairDevice& device) { // been written for devices with a version of V2 or higher. if (device.GetVersion().has_value() && device.GetVersion().value() == DeviceFastPairVersion::kHigherThanV1 && + device.GetAccountKey().Ok() && (device.GetProtocol() == Protocol::kFastPairInitialPairing || device.GetProtocol() == Protocol::kFastPairRetroactivePairing)) { for (auto& observer : observers_.GetObservers()) { - observer->OnAccountKeyWrite(device, /*error=*/absl::nullopt); + observer->OnAccountKeyWrite(device, /*error=*/std::nullopt); } } } diff --git a/fastpair/pairing/pairer_broker_impl.h b/fastpair/pairing/pairer_broker_impl.h index 0da1e316..0c88d975 100644 --- a/fastpair/pairing/pairer_broker_impl.h +++ b/fastpair/pairing/pairer_broker_impl.h @@ -24,6 +24,7 @@ #include "fastpair/internal/mediums/mediums.h" #include "fastpair/pairing/fastpair/fast_pair_pairer.h" #include "fastpair/pairing/pairer_broker.h" +#include "internal/account/account_manager.h" #include "internal/base/observer_list.h" #include "internal/platform/single_thread_executor.h" #include "internal/platform/timer_impl.h" @@ -33,7 +34,8 @@ namespace fastpair { class PairerBrokerImpl : public PairerBroker { public: - explicit PairerBrokerImpl(Mediums& medium, SingleThreadExecutor* executor); + explicit PairerBrokerImpl(Mediums& medium, SingleThreadExecutor* executor, + AccountManager* account_manager); PairerBrokerImpl(const PairerBrokerImpl&) = delete; PairerBrokerImpl& operator=(const PairerBrokerImpl&) = delete; @@ -74,6 +76,7 @@ class PairerBrokerImpl : public PairerBroker { Mediums& medium_; SingleThreadExecutor* executor_; + AccountManager* account_manager_; // The key for all the following maps is a device model id. absl::flat_hash_map> diff --git a/fastpair/pairing/pairer_broker_impl_test.cc b/fastpair/pairing/pairer_broker_impl_test.cc index 9db64e52..d1d98648 100644 --- a/fastpair/pairing/pairer_broker_impl_test.cc +++ b/fastpair/pairing/pairer_broker_impl_test.cc @@ -24,6 +24,7 @@ #include "gtest/gtest.h" #include "absl/functional/bind_front.h" #include "fastpair//handshake/fast_pair_handshake_lookup.h" +#include "fastpair/common/fast_pair_prefs.h" #include "fastpair/common/pair_failure.h" #include "fastpair/crypto/decrypted_passkey.h" #include "fastpair/crypto/decrypted_response.h" @@ -36,10 +37,13 @@ #include "fastpair/internal/mediums/mediums.h" #include "fastpair/proto/fastpair_rpcs.proto.h" #include "fastpair/repository/fake_fast_pair_repository.h" +#include "internal/account/fake_account_manager.h" #include "internal/base/bluetooth_address.h" #include "internal/platform/ble_v2.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/medium_environment.h" +#include "internal/platform/task_runner_impl.h" +#include "internal/test/google3_only/fake_authentication_manager.h" namespace nearby { namespace fastpair { @@ -49,6 +53,9 @@ using Permission = nearby::api::ble_v2::GattCharacteristic::Permission; using ::nearby::api::ble_v2::GattCharacteristic; using DiscoveryCallback = BluetoothClassicMedium::DiscoveryCallback; +constexpr absl::string_view kFastPairPreferencesFilePath = + "Google/Nearby/FastPair"; +constexpr absl::string_view kTestAccountId = "test_account_id"; constexpr absl::string_view kMetadataId("718c17"); constexpr absl::string_view kPublicAntiSpoof = "Wuyr48lD3txnUhGiMF1IfzlTwRxxe+wMB1HLzP+" @@ -173,12 +180,19 @@ class PairerBrokerImplTest : public testing::Test { PairerBrokerImplTest() { FastPairDataEncryptorImpl::Factory::SetFactoryForTesting( &fake_data_encryptor_factory_); + task_runner_ = std::make_unique(1); + preferences_manager_ = std::make_unique( + kFastPairPreferencesFilePath); + authentication_manager_ = std::make_unique(); } void SetUp() override { env_.Start(); // Setups seeker device. mediums_ = std::make_unique(); + account_manager_ = std::make_unique( + preferences_manager_.get(), prefs::kNearbyFastPairUsersName, + authentication_manager_.get(), task_runner_.get()); // Setups provider device. adapter_provider_ = std::make_unique(); @@ -205,6 +219,7 @@ class PairerBrokerImplTest : public testing::Test { pairer_broker_.reset(); FastPairHandshakeLookup::GetInstance()->Clear(); mediums_.reset(); + account_manager_.reset(); device_.reset(); remote_device_ = nullptr; key_based_characteristic_ = std::nullopt; @@ -220,6 +235,12 @@ class PairerBrokerImplTest : public testing::Test { env_.Stop(); } + void LogInAccount() { + AccountManager::Account account; + account.id = kTestAccountId; + account_manager_->SetAccount(account); + } + void CreateMockDevice(DeviceFastPairVersion version, Protocol protocol) { device_ = std::make_unique( kMetadataId, remote_device_->GetMacAddress(), protocol); @@ -385,6 +406,7 @@ class PairerBrokerImplTest : public testing::Test { std::unique_ptr device_; BluetoothDevice* remote_device_ = nullptr; SingleThreadExecutor executor_; + std::unique_ptr account_manager_; std::unique_ptr pairer_broker_; std::optional key_based_characteristic_; std::optional passkey_characteristic_; @@ -394,6 +416,9 @@ class PairerBrokerImplTest : public testing::Test { private: MediumEnvironment& env_{MediumEnvironment::Instance()}; Mutex mutex_; + std::unique_ptr preferences_manager_; + std::unique_ptr authentication_manager_; + std::unique_ptr task_runner_; std::unique_ptr bt_provider_; std::unique_ptr adapter_provider_; std::unique_ptr gatt_server_; @@ -405,6 +430,7 @@ class PairerBrokerImplTest : public testing::Test { }; TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDeviceV1) { + LogInAccount(); ConfigurePairingContext(); SetPairingResult(std::nullopt); CreateMockDevice(DeviceFastPairVersion::kV1, @@ -415,7 +441,8 @@ TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDeviceV1) { CountDownLatch account_key_writed_latch(1); CountDownLatch pairing_completed_latch(1); CountDownLatch pairing_failure_latch(1); - pairer_broker_ = std::make_unique(*mediums_, &executor_); + pairer_broker_ = std::make_unique(*mediums_, &executor_, + account_manager_.get()); PairerBrokerObserver pairer_broker_observer( pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch, &pairing_completed_latch, &pairing_failure_latch); @@ -428,7 +455,10 @@ TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDeviceV1) { } TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDevice) { + LogInAccount(); auto repository = std::make_unique(); + repository->SetResultOfIsDeviceSavedToAccount( + absl::NotFoundError("not found")); repository->SetResultOfWriteAccountAssociationToFootprints(absl::OkStatus()); ConfigurePairingContext(); SetPairingResult(std::nullopt); @@ -448,7 +478,8 @@ TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDevice) { CountDownLatch pairing_completed_latch(1); CountDownLatch pairing_failure_latch(1); - pairer_broker_ = std::make_unique(*mediums_, &executor_); + pairer_broker_ = std::make_unique(*mediums_, &executor_, + account_manager_.get()); PairerBrokerObserver pairer_broker_observer( pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch, &pairing_completed_latch, &pairing_failure_latch); @@ -465,6 +496,7 @@ TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDevice) { } TEST_F(PairerBrokerImplTest, SuccessSubsequentPairingWithDevice) { + LogInAccount(); ConfigurePairingContext(); SetPairingResult(std::nullopt); CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, @@ -480,7 +512,8 @@ TEST_F(PairerBrokerImplTest, SuccessSubsequentPairingWithDevice) { CountDownLatch pairing_completed_latch(1); CountDownLatch pairing_failure_latch(1); - pairer_broker_ = std::make_unique(*mediums_, &executor_); + pairer_broker_ = std::make_unique(*mediums_, &executor_, + account_manager_.get()); PairerBrokerObserver pairer_broker_observer( pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch, &pairing_completed_latch, &pairing_failure_latch); @@ -494,6 +527,7 @@ TEST_F(PairerBrokerImplTest, SuccessSubsequentPairingWithDevice) { } TEST_F(PairerBrokerImplTest, SuccessRetroactivePairingWithDevice) { + LogInAccount(); ConfigurePairingContext(); SetPairingResult(std::nullopt); CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, @@ -509,7 +543,8 @@ TEST_F(PairerBrokerImplTest, SuccessRetroactivePairingWithDevice) { EXPECT_FALSE(device_->GetAccountKey().Ok()); - pairer_broker_ = std::make_unique(*mediums_, &executor_); + pairer_broker_ = std::make_unique(*mediums_, &executor_, + account_manager_.get()); PairerBrokerObserver pairer_broker_observer( pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch, &pairing_completed_latch, &pairing_failure_latch); @@ -533,7 +568,8 @@ TEST_F(PairerBrokerImplTest, FaileToCreateHandshakeRetryThreeTimes) { CountDownLatch pairing_completed_latch(1); CountDownLatch pairing_failure_latch(1); - pairer_broker_ = std::make_unique(*mediums_, &executor_); + pairer_broker_ = std::make_unique(*mediums_, &executor_, + account_manager_.get()); PairerBrokerObserver pairer_broker_observer( pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch, &pairing_completed_latch, &pairing_failure_latch); @@ -549,7 +585,78 @@ TEST_F(PairerBrokerImplTest, FaileToCreateHandshakeRetryThreeTimes) { PairFailure::kKeyBasedPairingResponseTimeout); } +TEST_F(PairerBrokerImplTest, SkipWriteAccountKeyBecauseNoLoggedInUser) { + ConfigurePairingContext(); + SetPairingResult(std::nullopt); + CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, + Protocol::kFastPairInitialPairing); + SetupProviderGattServer(); + SetNotifyResponse(*key_based_characteristic_, kKeyBasedResponse); + SetNotifyResponse(*passkey_characteristic_, kPasskeyResponse); + SetDecryptedResponse(); + SetDecryptedPasskey(); + CreateFastPairHandshakeInstanceForDevice(); + + CountDownLatch device_paired_latch(1); + CountDownLatch account_key_writed_latch(1); + CountDownLatch pairing_completed_latch(1); + CountDownLatch pairing_failure_latch(1); + + EXPECT_FALSE(device_->GetAccountKey().Ok()); + + pairer_broker_ = std::make_unique(*mediums_, &executor_, + account_manager_.get()); + PairerBrokerObserver pairer_broker_observer( + pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch, + &pairing_completed_latch, &pairing_failure_latch); + pairer_broker_->PairDevice(*device_); + + device_paired_latch.Await(); + pairing_completed_latch.Await(); + EXPECT_FALSE(account_key_writed_latch.Await(kWaitTimeout).result()); + EXPECT_FALSE(pairing_failure_latch.Await(kWaitTimeout).result()); + EXPECT_FALSE(device_->GetAccountKey().Ok()); +} + +TEST_F(PairerBrokerImplTest, + SkipWriteAccountKeyBecauseDeviceAlreadySavedToAccount) { + LogInAccount(); + auto repository = std::make_unique(); + repository->SetResultOfIsDeviceSavedToAccount(absl::OkStatus()); + ConfigurePairingContext(); + SetPairingResult(std::nullopt); + CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, + Protocol::kFastPairInitialPairing); + SetupProviderGattServer(); + SetNotifyResponse(*key_based_characteristic_, kKeyBasedResponse); + SetNotifyResponse(*passkey_characteristic_, kPasskeyResponse); + SetDecryptedResponse(); + SetDecryptedPasskey(); + CreateFastPairHandshakeInstanceForDevice(); + + CountDownLatch device_paired_latch(1); + CountDownLatch account_key_writed_latch(1); + CountDownLatch pairing_completed_latch(1); + CountDownLatch pairing_failure_latch(1); + + pairer_broker_ = std::make_unique(*mediums_, &executor_, + account_manager_.get()); + PairerBrokerObserver pairer_broker_observer( + pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch, + &pairing_completed_latch, &pairing_failure_latch); + pairer_broker_->PairDevice(*device_); + + device_paired_latch.Await(); + pairing_completed_latch.Await(); + EXPECT_FALSE(account_key_writed_latch.Await(kWaitTimeout).result()); + EXPECT_FALSE(pairing_failure_latch.Await(kWaitTimeout).result()); +} + TEST_F(PairerBrokerImplTest, FaileToWriteAccountkeyToRemoteDevice) { + LogInAccount(); + auto repository = std::make_unique(); + repository->SetResultOfIsDeviceSavedToAccount( + absl::NotFoundError("not found")); ConfigurePairingContext(); SetPairingResult(std::nullopt); CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, @@ -569,7 +676,8 @@ TEST_F(PairerBrokerImplTest, FaileToWriteAccountkeyToRemoteDevice) { EXPECT_FALSE(device_->GetAccountKey().Ok()); - pairer_broker_ = std::make_unique(*mediums_, &executor_); + pairer_broker_ = std::make_unique(*mediums_, &executor_, + account_manager_.get()); PairerBrokerObserver pairer_broker_observer( pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch, &pairing_completed_latch, &pairing_failure_latch); @@ -585,7 +693,10 @@ TEST_F(PairerBrokerImplTest, FaileToWriteAccountkeyToRemoteDevice) { } TEST_F(PairerBrokerImplTest, FaileToWriteAccountkeyToFootprints) { + LogInAccount(); auto repository = std::make_unique(); + repository->SetResultOfIsDeviceSavedToAccount( + absl::NotFoundError("not found")); repository->SetResultOfWriteAccountAssociationToFootprints( absl::InternalError("Failed to write account key to foot prints")); ConfigurePairingContext(); @@ -606,7 +717,8 @@ TEST_F(PairerBrokerImplTest, FaileToWriteAccountkeyToFootprints) { EXPECT_FALSE(device_->GetAccountKey().Ok()); - pairer_broker_ = std::make_unique(*mediums_, &executor_); + pairer_broker_ = std::make_unique(*mediums_, &executor_, + account_manager_.get()); PairerBrokerObserver pairer_broker_observer( pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch, &pairing_completed_latch, &pairing_failure_latch); @@ -622,6 +734,7 @@ TEST_F(PairerBrokerImplTest, FaileToWriteAccountkeyToFootprints) { } TEST_F(PairerBrokerImplTest, FailToPairRetryThreeTimes) { + LogInAccount(); ConfigurePairingContext(); SetPairingResult(std::nullopt); CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, @@ -640,7 +753,8 @@ TEST_F(PairerBrokerImplTest, FailToPairRetryThreeTimes) { EXPECT_FALSE(device_->GetAccountKey().Ok()); - pairer_broker_ = std::make_unique(*mediums_, &executor_); + pairer_broker_ = std::make_unique(*mediums_, &executor_, + account_manager_.get()); PairerBrokerObserver pairer_broker_observer( pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch, &pairing_completed_latch, &pairing_failure_latch); diff --git a/fastpair/plugins/windows_admin_plugin.cc b/fastpair/plugins/windows_admin_plugin.cc index 99430c11..4877309b 100644 --- a/fastpair/plugins/windows_admin_plugin.cc +++ b/fastpair/plugins/windows_admin_plugin.cc @@ -22,13 +22,57 @@ namespace fastpair { void WindowsAdminPlugin::PluginState::DiscoveryClicked(DiscoveryAction action) { NEARBY_LOGS(INFO) << __func__; if (device == nullptr || fast_pair_service == nullptr) return; - absl::Status status = fast_pair_service->GetSeeker()->StartInitialPairing( - *device, InitialPairingParam{}, - {.on_pairing_result = [](const FastPairDevice& device, - absl::Status status) { - NEARBY_LOGS(INFO) << "Pairing result: " << status; - }}); - NEARBY_LOGS(INFO) << "StartInitialPairing: " << status; + switch (action) { + case DiscoveryAction::kPairToDevice: { + NEARBY_LOGS(INFO) << __func__ << ": Action = kPairToDevice"; + absl::Status status = fast_pair_service->GetSeeker()->StartInitialPairing( + *device, InitialPairingParam{}, + {.on_pairing_result = [this](const FastPairDevice& callback_device, + absl::Status status) { + NEARBY_LOGS(INFO) << "Show pairing result: " << status; + for (auto* observer : observers.GetObservers()) { + observer->OnPairingResult( + const_cast(callback_device), status.ok()); + } + }}); + NEARBY_LOGS(INFO) << "StartInitialPairing: " << status; + } break; + case DiscoveryAction::kSaveDeviceToAccount: { + NEARBY_LOGS(INFO) << __func__ << ": Action = kSaveDeviceToAccount"; + absl::Status status = + fast_pair_service->GetSeeker()->FinishRetroactivePairing( + *device, FinishRetroactivePairingParam{.save_account_key = true}, + {.on_pairing_result = [](const FastPairDevice& device, + absl::Status status) { + NEARBY_LOGS(INFO) << "Finish retro result: " << status; + }}); + foreground_currently_showing_notification = false; + NEARBY_LOGS(INFO) << "FinishRetroactivePairing: " << status; + } break; + case DiscoveryAction::kDismissedByOs: + NEARBY_LOGS(INFO) << __func__ << ": Action = kDismissedByOs"; + break; + case DiscoveryAction::kDismissedByUser: + // When the user explicitly dismisses the discovery notification, update + // the device's block-list value accordingly. + NEARBY_LOGS(INFO) << __func__ << ": Action = kDismissedByUser"; + foreground_currently_showing_notification = false; + break; + case DiscoveryAction::kDismissedByTimeout: + NEARBY_LOGS(INFO) << __func__ << ": Action = kDismissedByTimeout"; + foreground_currently_showing_notification = false; + break; + case DiscoveryAction::kLearnMore: + NEARBY_LOGS(INFO) << __func__ << ": Action = kLearnMore"; + break; + case DiscoveryAction::kDone: + NEARBY_LOGS(INFO) << __func__ << ": Action = kDone"; + foreground_currently_showing_notification = false; + break; + default: + NEARBY_LOGS(INFO) << __func__ << ": Action = Unknown"; + break; + } } void WindowsAdminPlugin::PluginState::SetIsScreenLocked(bool is_locked) { @@ -48,24 +92,39 @@ void WindowsAdminPlugin::OnInitialDiscoveryEvent( << "Ignoring initial discovery event because metadata is missing"; return; } - state_->device = device_; - for (auto* observer : state_->observers.GetObservers()) { - observer->OnUpdateDevice(*metadata); + if (device_->ShouldShowUiNotification().has_value() && + !device_->ShouldShowUiNotification().value()) { + NEARBY_LOGS(INFO) << __func__ << ": Ignoring because show UI flag is false"; + return; } + if (state_->foreground_currently_showing_notification) { + NEARBY_LOGS(VERBOSE) << __func__ + << ": Already showing a notification for a device"; + return; + } + NotifyShowNotification(*device_); } void WindowsAdminPlugin::OnPairEvent(const PairEvent& event) { NEARBY_LOGS(INFO) << "Received on pair event"; absl::Status status = seeker_->StartRetroactivePairing( *device_, RetroactivePairingParam{}, - {.on_pairing_result = [](const FastPairDevice& device, - absl::Status status) { - NEARBY_LOGS(INFO) << "Pairing result: " << status; - // TODO(jsobczak): Ask for user constent and save the Account Key to - // user's account. + {.on_pairing_result = [this](const FastPairDevice& device, + absl::Status status) { + NEARBY_LOGS(INFO) << "Retroactive Pairing result: " << status; + if (!status.ok()) return; + NotifyShowNotification(device); }}); NEARBY_LOGS(INFO) << "StartRetroactivePairing: " << status; } +void WindowsAdminPlugin::NotifyShowNotification(const FastPairDevice& device) { + NEARBY_LOGS(INFO) << __func__; + state_->foreground_currently_showing_notification = true; + state_->device = &device; + for (auto* observer : state_->observers.GetObservers()) { + observer->OnUpdateDevice(const_cast(device)); + } +} } // namespace fastpair } // namespace nearby diff --git a/fastpair/plugins/windows_admin_plugin.h b/fastpair/plugins/windows_admin_plugin.h index 5d2ce3d3..673ae2e2 100644 --- a/fastpair/plugins/windows_admin_plugin.h +++ b/fastpair/plugins/windows_admin_plugin.h @@ -37,7 +37,9 @@ class WindowsAdminPlugin : public FastPairPlugin { ObserverList observers; const FastPairDevice* device = nullptr; std::unique_ptr fast_pair_service; + bool foreground_currently_showing_notification = false; }; + class Provider : public FastPairPluginProvider { public: explicit Provider(PluginState* state) : state_(state) {} @@ -58,6 +60,7 @@ class WindowsAdminPlugin : public FastPairPlugin { void OnPairEvent(const PairEvent& event) override; private: + void NotifyShowNotification(const FastPairDevice& device); FastPairSeeker* seeker_; const FastPairDevice* device_; PluginState* state_; diff --git a/fastpair/proto/BUILD b/fastpair/proto/BUILD index ea2c5e6c..1ef59ebb 100644 --- a/fastpair/proto/BUILD +++ b/fastpair/proto/BUILD @@ -37,7 +37,7 @@ cc_library( deps = [ ":fastpair_cc_proto", "//fastpair/common", - "//internal/platform:logging", + "//internal/platform:types", "@com_google_absl//absl/strings", "@nlohmann_json//:json", ], @@ -57,7 +57,7 @@ cc_library( ":fastpair_cc_proto", "//fastpair/common", "//fastpair/repository", - "//internal/platform:logging", + "//internal/platform:types", "@com_google_absl//absl/time", ], ) diff --git a/fastpair/repository/BUILD b/fastpair/repository/BUILD index c6b3dff2..1f1afc60 100644 --- a/fastpair/repository/BUILD +++ b/fastpair/repository/BUILD @@ -42,7 +42,6 @@ cc_library( "//fastpair/proto:proto_builder", "//fastpair/server_access", "//internal/base", - "//internal/platform:logging", "//internal/platform:types", "@com_google_absl//absl/status", "@com_google_absl//absl/strings", @@ -62,7 +61,6 @@ cc_library( deps = [ "//fastpair/common", "//internal/base", - "//internal/platform:logging", "//internal/platform:types", "@com_google_absl//absl/functional:any_invocable", ], @@ -81,6 +79,7 @@ cc_library( ":repository", "//fastpair/common", "//fastpair/proto:fastpair_cc_proto", + "//internal/base", "//internal/platform:types", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/status", @@ -115,6 +114,7 @@ cc_test( "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/strings:string_view", "@com_google_googletest//:gtest_main", ], ) diff --git a/fastpair/repository/fake_fast_pair_repository.cc b/fastpair/repository/fake_fast_pair_repository.cc index 31da9be8..713a615d 100644 --- a/fastpair/repository/fake_fast_pair_repository.cc +++ b/fastpair/repository/fake_fast_pair_repository.cc @@ -18,16 +18,31 @@ #include #include #include +#include +#include "absl/status/status.h" #include "absl/strings/escaping.h" #include "absl/strings/string_view.h" #include "fastpair/common/account_key.h" +#include "fastpair/common/account_key_filter.h" #include "fastpair/common/constant.h" +#include "fastpair/common/device_metadata.h" #include "fastpair/common/fast_pair_device.h" +#include "fastpair/proto/data.proto.h" +#include "fastpair/proto/enum.proto.h" #include "fastpair/proto/fastpair_rpcs.proto.h" +#include "fastpair/repository/fast_pair_repository.h" namespace nearby { namespace fastpair { +void FakeFastPairRepository::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void FakeFastPairRepository::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + void FakeFastPairRepository::SetFakeMetadata(absl::string_view hex_model_id, proto::Device metadata) { proto::GetObservedDeviceResponse response; @@ -56,6 +71,11 @@ void FakeFastPairRepository::SetResultOfDeleteAssociatedDeviceByAccountKey( deleted_associated_device_ = status; } +void FakeFastPairRepository::SetResultOfIsDeviceSavedToAccount( + absl::Status status) { + is_device_saved_to_account_ = status; +} + void FakeFastPairRepository::GetDeviceMetadata( absl::string_view hex_model_id, DeviceMetadataCallback callback) { executor_.Execute([this, callback = std::move(callback), @@ -68,15 +88,23 @@ void FakeFastPairRepository::GetDeviceMetadata( }); } +void FakeFastPairRepository::GetUserSavedDevices() { + proto::OptInStatus opt_in_status = proto::OptInStatus::OPT_IN_STATUS_UNKNOWN; + std::vector saved_devices; + for (auto& observer : observers_.GetObservers()) { + observer->OnGetUserSavedDevices(opt_in_status, saved_devices); + } +} + void FakeFastPairRepository::WriteAccountAssociationToFootprints( - FastPairDevice& device, OperationToFootprintsCallback callback) { + FastPairDevice& device, OperationCallback callback) { executor_.Execute([callback = std::move(callback), this]() mutable { callback(write_account_association_to_footprints_); }); } void FakeFastPairRepository::DeleteAssociatedDeviceByAccountKey( - const AccountKey& account_key, OperationToFootprintsCallback callback) { + const AccountKey& account_key, OperationCallback callback) { executor_.Execute([callback = std::move(callback), this]() mutable { callback(deleted_associated_device_); }); @@ -89,6 +117,13 @@ void FakeFastPairRepository::CheckIfAssociatedWithCurrentAccount( }); } +void FakeFastPairRepository::IsDeviceSavedToAccount( + absl::string_view mac_address, OperationCallback callback) { + executor_.Execute([callback = std::move(callback), this]() mutable { + callback(is_device_saved_to_account_); + }); +} + std::unique_ptr FakeFastPairRepository::Create( absl::string_view model_id, absl::string_view public_anti_spoof_key) { proto::Device metadata; diff --git a/fastpair/repository/fake_fast_pair_repository.h b/fastpair/repository/fake_fast_pair_repository.h index a1ca8428..ef1a7619 100644 --- a/fastpair/repository/fake_fast_pair_repository.h +++ b/fastpair/repository/fake_fast_pair_repository.h @@ -25,6 +25,7 @@ #include "fastpair/common/account_key.h" #include "fastpair/common/device_metadata.h" #include "fastpair/repository/fast_pair_repository.h" +#include "internal/base/observer_list.h" #include "internal/platform/single_thread_executor.h" namespace nearby { @@ -46,27 +47,30 @@ class FakeFastPairRepository : public FastPairRepository { void SetResultOfCheckIfAssociatedWithCurrentAccount( std::optional account_key, std::optional model_id); + void SetResultOfIsDeviceSavedToAccount(absl::Status status); // FastPairRepository:: - void AddObserver(Observer* observer) override{}; - void RemoveObserver(Observer* observer) override{}; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; void GetDeviceMetadata(absl::string_view hex_model_id, DeviceMetadataCallback callback) override; - void GetUserSavedDevices() override{}; + void GetUserSavedDevices() override; - void WriteAccountAssociationToFootprints( - FastPairDevice& device, OperationToFootprintsCallback callback) override; + void WriteAccountAssociationToFootprints(FastPairDevice& device, + OperationCallback callback) override; - void DeleteAssociatedDeviceByAccountKey( - const AccountKey& account_key, - OperationToFootprintsCallback callback) override; + void DeleteAssociatedDeviceByAccountKey(const AccountKey& account_key, + OperationCallback callback) override; void CheckIfAssociatedWithCurrentAccount( AccountKeyFilter& account_key_filter, CheckAccountKeysCallback callback) override; + void IsDeviceSavedToAccount(absl::string_view mac_address, + OperationCallback callback) override; + private: absl::flat_hash_map> data_; @@ -77,6 +81,9 @@ class FakeFastPairRepository : public FastPairRepository { absl::Status write_account_association_to_footprints_; // Results of DeleteAssociatedDeviceByAccountKey absl::Status deleted_associated_device_; + // Results of IsDeviceSavedToAccount + absl::Status is_device_saved_to_account_; + ObserverList observers_; SingleThreadExecutor executor_; }; } // namespace fastpair diff --git a/fastpair/repository/fast_pair_device_repository.cc b/fastpair/repository/fast_pair_device_repository.cc index d210d94d..e219a484 100644 --- a/fastpair/repository/fast_pair_device_repository.cc +++ b/fastpair/repository/fast_pair_device_repository.cc @@ -19,6 +19,8 @@ #include #include +#include "fastpair/common/account_key.h" +#include "fastpair/common/fast_pair_device.h" #include "internal/platform/logging.h" #include "internal/platform/mutex_lock.h" @@ -51,7 +53,7 @@ void FastPairDeviceRepository::RemoveDevice(const FastPairDevice* device) { for (auto* callback : observers_.GetObservers()) { (*callback)(*fast_pair_device); } - NEARBY_LOGS(VERBOSE) << "Destroyed FP device: " << fast_pair_device; + NEARBY_LOGS(VERBOSE) << "Destroyed FP device: " << *fast_pair_device; }); } @@ -70,6 +72,20 @@ std::optional FastPairDeviceRepository::FindDevice( } } +std::optional FastPairDeviceRepository::FindDevice( + const AccountKey& account_key) { + MutexLock lock(&mutex_); + auto it = std::find_if(devices_.begin(), devices_.end(), + [&](const std::unique_ptr& device) { + return device->GetAccountKey() == account_key; + }); + if (it != devices_.end()) { + return it->get(); + } else { + return std::nullopt; + } +} + std::unique_ptr FastPairDeviceRepository::ExtractDevice( const FastPairDevice* device) { MutexLock lock(&mutex_); diff --git a/fastpair/repository/fast_pair_device_repository.h b/fastpair/repository/fast_pair_device_repository.h index ad70bb32..5240122f 100644 --- a/fastpair/repository/fast_pair_device_repository.h +++ b/fastpair/repository/fast_pair_device_repository.h @@ -54,6 +54,9 @@ class FastPairDeviceRepository { // or BLE. std::optional FindDevice(absl::string_view mac_address); + // Finds a device matching the account key. + std::optional FindDevice(const AccountKey& account_key); + void AddObserver(RemoveDeviceCallback* observer) { observers_.AddObserver(observer); } diff --git a/fastpair/repository/fast_pair_device_repository_test.cc b/fastpair/repository/fast_pair_device_repository_test.cc index 3418ae4c..e476e1d0 100644 --- a/fastpair/repository/fast_pair_device_repository_test.cc +++ b/fastpair/repository/fast_pair_device_repository_test.cc @@ -17,9 +17,9 @@ #include #include -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "fastpair/common/account_key.h" #include "fastpair/common/fast_pair_device.h" #include "fastpair/common/protocol.h" #include "internal/platform/single_thread_executor.h" @@ -31,6 +31,7 @@ namespace { constexpr absl::string_view kModelId = "123456"; constexpr absl::string_view kBleAddress = "AA:BB:CC:DD:EE:FF"; constexpr absl::string_view kBtAddress = "12:34:56:78:90:AB"; +constexpr absl::string_view kAccountKey = "04b85786180add47fb81a04a8ce6b0de"; TEST(FastPairDeviceRepositoryTest, AddDevice) { SingleThreadExecutor executor; @@ -76,6 +77,24 @@ TEST(FastPairDeviceRepositoryTest, FindDeviceByBtAddress) { executor.Shutdown(); } +TEST(FastPairDeviceRepositoryTest, FindDeviceByAccountKey) { + SingleThreadExecutor executor; + FastPairDeviceRepository repo(&executor); + auto fast_pair_device = + std::make_unique(Protocol::kFastPairInitialPairing); + fast_pair_device->SetPublicAddress(kBtAddress); + fast_pair_device->SetAccountKey(AccountKey(kAccountKey)); + repo.AddDevice(std::move(fast_pair_device)); + + auto opt_device = repo.FindDevice(AccountKey(kAccountKey)); + + ASSERT_TRUE(opt_device.has_value()); + FastPairDevice* device = opt_device.value(); + ASSERT_NE(device, nullptr); + EXPECT_EQ(device->GetAccountKey().GetAsBytes(), kAccountKey); + executor.Shutdown(); +} + TEST(FastPairDeviceRepositoryTest, RemoveDevice) { SingleThreadExecutor executor; FastPairDeviceRepository repo(&executor); diff --git a/fastpair/repository/fast_pair_repository.h b/fastpair/repository/fast_pair_repository.h index 7134c0fe..1f1ea902 100644 --- a/fastpair/repository/fast_pair_repository.h +++ b/fastpair/repository/fast_pair_repository.h @@ -36,8 +36,7 @@ using DeviceMetadataCallback = using CheckAccountKeysCallback = absl::AnyInvocable account_key, std::optional model_id)>; -using OperationToFootprintsCallback = - absl::AnyInvocable; +using OperationCallback = absl::AnyInvocable; class FastPairRepository { public: @@ -72,12 +71,11 @@ class FastPairRepository { // Stores the given |account_key| for a |device| on the Footprints server. virtual void WriteAccountAssociationToFootprints( - FastPairDevice& device, OperationToFootprintsCallback callback) = 0; + FastPairDevice& device, OperationCallback callback) = 0; // Deletes the associated data for a given |account_key|. virtual void DeleteAssociatedDeviceByAccountKey( - const AccountKey& account_key, - OperationToFootprintsCallback callback) = 0; + const AccountKey& account_key, OperationCallback callback) = 0; // Checks all account keys associated with current user's account against the // given filter. If a match is found, return the account key. @@ -85,6 +83,12 @@ class FastPairRepository { AccountKeyFilter& account_key_filter, CheckAccountKeysCallback callback) = 0; + // Checks if a device with an address |mac_address| is already saved to + // the user's account by cross referencing the |mac_address| with any + // associated account keys. + virtual void IsDeviceSavedToAccount(absl::string_view mac_address, + OperationCallback callback) = 0; + protected: static void SetInstance(FastPairRepository* instance); }; diff --git a/fastpair/repository/fast_pair_repository_impl.cc b/fastpair/repository/fast_pair_repository_impl.cc index 2f51044b..8dea41cd 100644 --- a/fastpair/repository/fast_pair_repository_impl.cc +++ b/fastpair/repository/fast_pair_repository_impl.cc @@ -56,6 +56,20 @@ bool DoesDeviceHaveForgetPattern(const proto::FastPairDevice& device) { return (device.sha256_account_key_public_address().compare( 0, kForgetPattern.length(), kForgetPattern) == 0); } + +// Checks if the mac address of a FastPairDevice is the same as the given +// |mac_address| by checking if the SHA256 from the given |device| equals to +// SHA256(concat(account_key of |device|, |mac_address|)). +bool IsDeviceSha256Matched(const proto::FastPairDevice& device, + absl::string_view mac_address) { + if (DoesDeviceHaveForgetPattern(device)) { + return false; + } + + return device.sha256_account_key_public_address() == + FastPairRepository::GenerateSha256OfAccountKeyAndMacAddress( + AccountKey(device.account_key()), mac_address); +} } // namespace FastPairRepositoryImpl::FastPairRepositoryImpl(FastPairClient* fast_pair_client) @@ -98,7 +112,7 @@ void FastPairRepositoryImpl::GetDeviceMetadata( } void FastPairRepositoryImpl::WriteAccountAssociationToFootprints( - FastPairDevice& device, OperationToFootprintsCallback callback) { + FastPairDevice& device, OperationCallback callback) { proto::UserWriteDeviceRequest request; auto* fast_pair_info = request.mutable_fast_pair_info(); BuildFastPairInfo(fast_pair_info, device); @@ -124,7 +138,7 @@ void FastPairRepositoryImpl::WriteAccountAssociationToFootprints( } void FastPairRepositoryImpl::DeleteAssociatedDeviceByAccountKey( - const AccountKey& account_key, OperationToFootprintsCallback callback) { + const AccountKey& account_key, OperationCallback callback) { std::string hex_string = absl::BytesToHexString(account_key.GetAsBytes()); absl::AsciiStrToUpper(&hex_string); executor_.Execute( @@ -230,5 +244,38 @@ void FastPairRepositoryImpl::CheckIfAssociatedWithCurrentAccount( }); } +void FastPairRepositoryImpl::IsDeviceSavedToAccount( + absl::string_view mac_address, OperationCallback callback) { + executor_.Execute( + "Check is device saved to account.", + [this, mac_address = std::string(mac_address), + callback = std::move(callback)]() mutable { + NEARBY_LOGS(INFO) << __func__ + << ": Start to check is device saved to account."; + proto::UserReadDevicesRequest request; + absl::StatusOr response = + fast_pair_client_->UserReadDevices(request); + if (!response.ok()) { + NEARBY_LOGS(WARNING) + << __func__ + << "Failed to get UserDeleteDeviceResponse from backend."; + std::move(callback)(response.status()); + return; + } + for (const auto& info : response->fast_pair_info()) { + if (info.has_device() && + IsDeviceSha256Matched(info.device(), mac_address)) { + NEARBY_LOGS(VERBOSE) + << __func__ << ": found a SHA256 match for device at address = " + << mac_address; + std::move(callback)(absl::OkStatus()); + return; + } + } + std::move(callback)(absl::NotFoundError("Device " + mac_address + + " is not saved to account.")); + }); +} + } // namespace fastpair } // namespace nearby diff --git a/fastpair/repository/fast_pair_repository_impl.h b/fastpair/repository/fast_pair_repository_impl.h index 74fb4abc..6e9327c5 100644 --- a/fastpair/repository/fast_pair_repository_impl.h +++ b/fastpair/repository/fast_pair_repository_impl.h @@ -44,17 +44,19 @@ class FastPairRepositoryImpl : public FastPairRepository { void GetUserSavedDevices() override; - void WriteAccountAssociationToFootprints( - FastPairDevice& device, OperationToFootprintsCallback callback) override; + void WriteAccountAssociationToFootprints(FastPairDevice& device, + OperationCallback callback) override; - void DeleteAssociatedDeviceByAccountKey( - const AccountKey& account_key, - OperationToFootprintsCallback callback) override; + void DeleteAssociatedDeviceByAccountKey(const AccountKey& account_key, + OperationCallback callback) override; void CheckIfAssociatedWithCurrentAccount( AccountKeyFilter& account_key_filter, CheckAccountKeysCallback callback) override; + void IsDeviceSavedToAccount(absl::string_view mac_address, + OperationCallback callback) override; + private: // A thread for running blocking tasks. SingleThreadExecutor executor_; diff --git a/fastpair/repository/fast_pair_repository_impl_test.cc b/fastpair/repository/fast_pair_repository_impl_test.cc index a40f4162..a0374410 100644 --- a/fastpair/repository/fast_pair_repository_impl_test.cc +++ b/fastpair/repository/fast_pair_repository_impl_test.cc @@ -468,6 +468,81 @@ TEST(FastPairRepositoryImplTest, DeviceNotAssociatedWithCurrentAccount) { }); latch.Await(); } + +TEST(FastPairRepositoryImplTest, DeviceIsSavedToCurrentAccount) { + FakeFastPairClient fake_fast_pair_client; + auto fast_pair_repository = + std::make_unique(&fake_fast_pair_client); + + // Sets up two devices to proto::UserReadDevicesResponse. + proto::UserReadDevicesResponse response_proto; + // Device 1 + FastPairDevice device_1(kHexModelId, kBleAddress, + Protocol::kFastPairInitialPairing); + AccountKey account_key_1(absl::HexStringToBytes(kAccountKey)); + device_1.SetAccountKey(account_key_1); + device_1.SetPublicAddress(kPublicAddress); + proto::GetObservedDeviceResponse get_observed_device_response; + DeviceMetadata device_metadata_1(get_observed_device_response); + device_1.SetMetadata(device_metadata_1); + auto* fast_pair_info_1 = response_proto.add_fast_pair_info(); + BuildFastPairInfo(fast_pair_info_1, device_1); + // Device 2 + auto* fast_pair_info_2 = response_proto.add_fast_pair_info(); + fast_pair_info_2->set_opt_in_status( + proto::OptInStatus::OPT_IN_STATUS_OPTED_IN); + fake_fast_pair_client.SetUserReadDevicesResponse(response_proto); + + CountDownLatch latch(1); + fast_pair_repository->IsDeviceSavedToAccount(kPublicAddress, + [&](absl::Status status) { + EXPECT_OK(status); + latch.CountDown(); + }); + latch.Await(); +} + +TEST(FastPairRepositoryImplTest, DeviceIsNotSavedToCurrentAccount) { + FakeFastPairClient fake_fast_pair_client; + auto fast_pair_repository = + std::make_unique(&fake_fast_pair_client); + + // Sets up two devices to proto::UserReadDevicesResponse. + proto::UserReadDevicesResponse response_proto; + FastPairDevice device(kHexModelId, kBleAddress, + Protocol::kFastPairInitialPairing); + AccountKey account_key(absl::HexStringToBytes(kAccountKey)); + device.SetAccountKey(account_key); + device.SetPublicAddress(kPublicAddress); + proto::GetObservedDeviceResponse get_observed_device_response; + DeviceMetadata device_metadata(get_observed_device_response); + device.SetMetadata(device_metadata); + auto* fast_pair_info = response_proto.add_fast_pair_info(); + BuildFastPairInfo(fast_pair_info, device); + fake_fast_pair_client.SetUserReadDevicesResponse(response_proto); + + CountDownLatch latch(1); + fast_pair_repository->IsDeviceSavedToAccount( + "11:22:33:44:55:66", [&](absl::Status status) { + EXPECT_EQ(status.code(), absl::StatusCode::kNotFound); + latch.CountDown(); + }); + latch.Await(); +} + +TEST(FastPairRepositoryImplTest, FailedToCheckDeviceIsSavedToCurrentAccount) { + FakeFastPairClient fake_fast_pair_client; + auto fast_pair_repository = + std::make_unique(&fake_fast_pair_client); + + CountDownLatch latch(1); + fast_pair_repository->IsDeviceSavedToAccount(kPublicAddress, + [&](absl::Status status) { + EXPECT_FALSE(status.ok()); + latch.CountDown(); + }); + latch.Await(); +} } // namespace } // namespace fastpair } // namespace nearby diff --git a/fastpair/retroactive/BUILD b/fastpair/retroactive/BUILD index ec1f012c..63315b12 100644 --- a/fastpair/retroactive/BUILD +++ b/fastpair/retroactive/BUILD @@ -36,7 +36,9 @@ cc_library( "//fastpair/internal/mediums", "//fastpair/message_stream", "//fastpair/pairing", + "//fastpair/repository", "//fastpair/repository:device_repository", + "//internal/account", "//internal/base", "//internal/platform:comm", "//internal/platform:types", @@ -63,8 +65,8 @@ cc_test( "//internal/base:bluetooth_address", "//internal/platform:base", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:test_util", + "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/status", diff --git a/fastpair/retroactive/retroactive_pairing_detector_impl.cc b/fastpair/retroactive/retroactive_pairing_detector_impl.cc index 4aae90c5..40b4c579 100644 --- a/fastpair/retroactive/retroactive_pairing_detector_impl.cc +++ b/fastpair/retroactive/retroactive_pairing_detector_impl.cc @@ -17,18 +17,23 @@ #include #include #include +#include #include #include "fastpair/internal/mediums/mediums.h" -#include "fastpair/pairing/pairer_broker.h" +#include "fastpair/repository/fast_pair_repository.h" +#include "internal/account/account_manager.h" namespace nearby { namespace fastpair { RetroactivePairingDetectorImpl::RetroactivePairingDetectorImpl( Mediums& mediums, FastPairDeviceRepository* repository, - SingleThreadExecutor* executor) - : mediums_(mediums), repository_(repository), executor_(executor) { + AccountManager* account_manager, SingleThreadExecutor* executor) + : mediums_(mediums), + repository_(repository), + account_manager_(account_manager), + executor_(executor) { mediums_.GetBluetoothClassic().AddObserver(this); mediums_.GetBluetoothClassic().StartDiscovery(); } @@ -65,9 +70,11 @@ void RetroactivePairingDetectorImpl::DevicePairedChanged( std::optional existing_device = repository_->FindDevice(device.GetMacAddress()); - if (existing_device.has_value()) { + if (existing_device.has_value() && + existing_device.value()->HasStartedPairing()) { // Both classic paired and Fast paired devices call this function, so we - // have to filter out pairing events for devices that we already know. + // have to filter out pairing events for device that paired from Fast Pair. + NEARBY_LOGS(INFO) << __func__ << ": Ignoring Fast paired devices."; return; } @@ -75,15 +82,33 @@ void RetroactivePairingDetectorImpl::DevicePairedChanged( // first check if it has already been saved to the user's account. If it has // already been saved, we don't want to prompt the user to save a device // again. - // TODO(b/285047010): check if device has already been saved to the user's - // account + if (!account_manager_->GetCurrentAccount().has_value()) { + NEARBY_LOGS(INFO) << __func__ << ": Ignoring because no logged in user."; + return; + } + FastPairRepository::Get()->IsDeviceSavedToAccount( + device.GetMacAddress(), + [this, mac_address = device.GetMacAddress()](absl::Status status) { + if (status.ok()) { + NEARBY_LOGS(VERBOSE) << __func__ + << ": Ignoring because device is already saved " + "to the current account."; + return; + } + NotifyRetroactiveDeviceFound(mac_address); + }); +} + +void RetroactivePairingDetectorImpl::NotifyRetroactiveDeviceFound( + absl::string_view mac_address) { + NEARBY_LOGS(VERBOSE) << __func__ << ": mac_address = " << mac_address; auto fast_pair_device = std::make_unique(Protocol::kFastPairRetroactivePairing); - fast_pair_device->SetPublicAddress(device.GetMacAddress()); + fast_pair_device->SetPublicAddress(mac_address); repository_->AddDevice(std::move(fast_pair_device)); executor_->Execute("notify-retro-candidate", - [this, address = device.GetMacAddress()]() { + [this, address = std::string(mac_address)]() { std::optional fast_pair_device = repository_->FindDevice(address); if (!fast_pair_device) return; diff --git a/fastpair/retroactive/retroactive_pairing_detector_impl.h b/fastpair/retroactive/retroactive_pairing_detector_impl.h index a24d0617..7c876f86 100644 --- a/fastpair/retroactive/retroactive_pairing_detector_impl.h +++ b/fastpair/retroactive/retroactive_pairing_detector_impl.h @@ -14,13 +14,12 @@ #ifndef THIRD_PARTY_NEARBY_FASTPAIR_RETROACTIVE_RETROACTIVE_PAIRING_DETECTOR_IMPL_H_ #define THIRD_PARTY_NEARBY_FASTPAIR_RETROACTIVE_RETROACTIVE_PAIRING_DETECTOR_IMPL_H_ -#include -#include "absl/container/flat_hash_set.h" +#include "absl/strings/string_view.h" #include "fastpair/internal/mediums/mediums.h" -#include "fastpair/pairing/pairer_broker.h" #include "fastpair/repository/fast_pair_device_repository.h" #include "fastpair/retroactive/retroactive_pairing_detector.h" +#include "internal/account/account_manager.h" #include "internal/base/observer_list.h" #include "internal/platform/bluetooth_classic.h" #include "internal/platform/single_thread_executor.h" @@ -34,6 +33,7 @@ class RetroactivePairingDetectorImpl public: RetroactivePairingDetectorImpl(Mediums& mediums, FastPairDeviceRepository* repository, + AccountManager* account_manager, SingleThreadExecutor* executor); RetroactivePairingDetectorImpl(const RetroactivePairingDetectorImpl&) = delete; @@ -50,9 +50,11 @@ class RetroactivePairingDetectorImpl bool new_paired_status) override; private: + void NotifyRetroactiveDeviceFound(absl::string_view mac_address); Mediums& mediums_; ObserverList observers_; FastPairDeviceRepository* repository_; + AccountManager* account_manager_; SingleThreadExecutor* executor_; }; diff --git a/fastpair/rust/Cargo.toml b/fastpair/rust/bluetooth/Cargo.toml similarity index 85% rename from fastpair/rust/Cargo.toml rename to fastpair/rust/bluetooth/Cargo.toml index 20a09107..0c666219 100644 --- a/fastpair/rust/Cargo.toml +++ b/fastpair/rust/bluetooth/Cargo.toml @@ -13,22 +13,28 @@ # limitations under the License. [package] -name = "fastpair" +name = "bluetooth" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0" -futures = { version = "0.3", features = ["executor"] } +futures = { version = "0.3" } tracing = "0.1.37" cfg-if = "1.0.0" async-trait = "0.1" +thiserror = "1.0.43" + +[dev-dependencies] +futures = { version = "0.3", features = ["executor"] } [target.'cfg(windows)'.dependencies] windows = { version = "0.48", features = [ "Devices_Bluetooth", + "Devices_Enumeration", "Devices_Bluetooth_Advertisement", "Foundation", + "Foundation_Collections", + "Storage_Streams", ] } diff --git a/fastpair/rust/bluetooth/examples/fastpair_ui.rs b/fastpair/rust/bluetooth/examples/fastpair_ui.rs new file mode 100644 index 00000000..920ace4c --- /dev/null +++ b/fastpair/rust/bluetooth/examples/fastpair_ui.rs @@ -0,0 +1,118 @@ +// 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. + +use std::{ + collections::HashSet, + error::Error, + io::{self, Write}, + sync::Arc, + thread, +}; + +use futures::{ + executor::{self, block_on}, + lock::Mutex, +}; + +extern crate bluetooth; + +use bluetooth::{ + api::{BleAdapter, BleDevice, ClassicDevice}, + BleDataTypeId, ClassicAddress, Platform, +}; + +async fn get_user_input( + device_vec: Arc>>, +) -> Result<(), Box> { + let mut buffer = String::new(); + loop { + io::stdout().flush()?; + buffer.clear(); + io::stdin().read_line(&mut buffer)?; + + let val = match buffer.trim().parse::() { + Ok(val) => val, + Err(_) => { + println!("Please enter a valid digit."); + continue; + } + }; + + let index_to_device = device_vec.lock().await; + match index_to_device.get(val) { + Some(device) => { + let addr = device.address(); + let classic_addr = ClassicAddress::try_from(addr)?; + + let classic_device = + Platform::new_classic_device(classic_addr).await?; + + match classic_device.pair().await { + Ok(_) => { + println!("Pairing success!"); + } + Err(err) => println!("Error {}", err), + } + break Ok(()); + } + None => println!("Please enter a valid digit."), + } + } +} + +fn main() -> Result<(), Box> { + let run = async { + let mut adapter = Platform::default_adapter().await?; + adapter.start_scan()?; + + let mut addr_set = HashSet::new(); + let device_vec = Arc::new(Mutex::new(Vec::new())); + + { + // Process user input in a separate thread. + let device_vec = device_vec.clone(); + thread::spawn(|| block_on(get_user_input(device_vec)).unwrap()); + } + + let mut counter: u32 = 0; + let datatype_selector = vec![BleDataTypeId::ServiceData16BitUuid]; + // Retrieve incoming device advertisements. + while let Ok(advertisement) = + adapter.next_advertisement(Some(&datatype_selector)).await + { + for service_data in advertisement.service_data_16bit_uuid()? { + let uuid = service_data.uuid(); + + // This is a Fast Pair device. + if uuid == 0x2cfe { + let addr = advertisement.address(); + let ble_device = Platform::new_ble_device(addr).await?; + let name = ble_device.name()?; + + if addr_set.insert(addr) { + // New FP device discovered. + println!("{}: {}", counter, name); + device_vec.lock().await.push(ble_device); + counter += 1; + } + break; + } + } + } + println!("Done scanning"); + Ok(()) + }; + + executor::block_on(run) +} diff --git a/fastpair/rust/rustfmt.toml b/fastpair/rust/bluetooth/rustfmt.toml similarity index 100% rename from fastpair/rust/rustfmt.toml rename to fastpair/rust/bluetooth/rustfmt.toml diff --git a/fastpair/rust/src/bluetooth/common.rs b/fastpair/rust/bluetooth/src/api/adapter.rs similarity index 55% rename from fastpair/rust/src/bluetooth/common.rs rename to fastpair/rust/bluetooth/src/api/adapter.rs index 33ba2c4c..de9bc43f 100644 --- a/fastpair/rust/src/bluetooth/common.rs +++ b/fastpair/rust/bluetooth/src/api/adapter.rs @@ -14,29 +14,24 @@ use async_trait::async_trait; +use crate::common::{BleAdvertisement, BleDataTypeId, BluetoothError}; + /// Concrete types implementing this trait are Bluetooth Central devices. /// They provide methods for retrieving nearby connections and device info. #[async_trait] -pub trait Adapter: Sized { - type Device: Device; - +pub trait BleAdapter: Sized { /// Retrieve the system-default Bluetooth adapter. - async fn default() -> Result; + async fn default() -> Result; - /// Begin scanning for nearby devices. - fn start_scan_devices(&mut self) -> Result<(), anyhow::Error>; + /// Begin scanning for nearby advertisements. + fn start_scan(&mut self) -> Result<(), BluetoothError>; - /// Stop scanning for nearby devices. - fn stop_scan_devices(&mut self) -> Result<(), anyhow::Error>; + /// Stop scanning for nearby advertisements. + fn stop_scan(&mut self) -> Result<(), BluetoothError>; /// Poll next discovered device. - async fn next_device(&mut self) -> Result; -} - -/// Concrete types implementing this trait represent Bluetooth Peripheral devices. -/// They provide methods for retrieving device info and running device actions, -/// such as pairing. -pub trait Device { - /// Retrieve the name advertised by this device. - fn name(&self) -> Result; + async fn next_advertisement( + &mut self, + data_selector: Option<&Vec>, + ) -> Result; } diff --git a/fastpair/rust/bluetooth/src/api/device.rs b/fastpair/rust/bluetooth/src/api/device.rs new file mode 100644 index 00000000..df43ec72 --- /dev/null +++ b/fastpair/rust/bluetooth/src/api/device.rs @@ -0,0 +1,56 @@ +// 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. + +use async_trait::async_trait; + +use crate::common::{ + BleAddress, BluetoothError, ClassicAddress, PairingResult, +}; + +/// Concrete types implementing this trait represent BLE Peripheral devices. +/// They provide methods for retrieving device info and running device actions, +/// such as pairing. +#[async_trait] +pub trait BleDevice: Sized { + /// Create a new `BleDevice` instance from a `BleAddress`, typically + /// enabled through locally cached data retrieved from a Bluetooth adapter's + /// scanning functionality. + async fn new(addr: BleAddress) -> Result; + + /// Retrieve the name advertised by this device. + fn name(&self) -> Result; + + /// Retrieve this device's Bluetooth address information. + fn address(&self) -> BleAddress; +} + +/// Concrete types implementing this trait represent BT Classic Peripheral +/// devices. They provide methods for retrieving device info and running device +/// actions, such as pairing. +#[async_trait] +pub trait ClassicDevice: Sized { + /// Create a new `ClassicDevice` instance from a `ClassicAddress`, typically + /// enabled through locally cached data retrieved from a Bluetooth adapter's + /// scanning functionality. + async fn new(addr: ClassicAddress) -> Result; + + /// Retrieve the name advertised by this device. + fn name(&self) -> Result; + + /// Retrieve this device's Bluetooth address information. + fn address(&self) -> ClassicAddress; + + /// Attempt pairing with the peripheral device. + async fn pair(&self) -> Result; +} diff --git a/fastpair/rust/bluetooth/src/api/mod.rs b/fastpair/rust/bluetooth/src/api/mod.rs new file mode 100644 index 00000000..0e410749 --- /dev/null +++ b/fastpair/rust/bluetooth/src/api/mod.rs @@ -0,0 +1,5 @@ +mod adapter; +mod device; + +pub use adapter::*; +pub use device::*; diff --git a/fastpair/rust/bluetooth/src/common/address.rs b/fastpair/rust/bluetooth/src/common/address.rs new file mode 100644 index 00000000..85f81f04 --- /dev/null +++ b/fastpair/rust/bluetooth/src/common/address.rs @@ -0,0 +1,179 @@ +// 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. + +use super::BluetoothError; + +/// BLE Addresses can either be the peripheral's public MAC address, or various +/// types of random addresses. +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] +pub enum BleAddressKind { + Public, + Random, +} + +/// Struct representing a 48-bit BLE Address and its type. +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] +pub struct BleAddress { + val: [u8; 6], + kind: BleAddressKind, +} + +/// Struct representing a 48-bit BT Classic address. +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] +pub struct ClassicAddress([u8; 6]); + +impl BleAddress { + /// `BleAddress` constructor. + pub fn new(addr: u64, kind: BleAddressKind) -> Self { + let addr = u64_to_6lsb(addr); + + BleAddress { val: addr, kind } + } + + /// Retrieve the type of BLE Address (public or random). + pub fn get_kind(&self) -> BleAddressKind { + self.kind + } +} + +/// Function for converting the six LSB of a u64 into a 6-byte array. +#[inline] +fn u64_to_6lsb(num: u64) -> [u8; 6] { + num.to_le_bytes()[..6] + .try_into() + .expect("Sanity check, slice length matches array length") +} + +impl From for ClassicAddress { + fn from(addr: u64) -> Self { + let addr = u64_to_6lsb(addr); + + ClassicAddress(addr) + } +} + +impl TryFrom for ClassicAddress { + type Error = BluetoothError; + + fn try_from(addr: BleAddress) -> Result { + match addr.kind { + BleAddressKind::Public => Ok(ClassicAddress(addr.val)), + BleAddressKind::Random => Err(BluetoothError::BadTypeConversion(String::from( + "can't convert BLE Random address to Bluetooth Classic address." + ))), + } + } +} + +impl From for u64 { + fn from(addr: BleAddress) -> Self { + let mut bytes = [0u8; 8]; + bytes[..6].copy_from_slice(&addr.val); + + u64::from_le_bytes(bytes) + } +} + +impl From for u64 { + fn from(addr: ClassicAddress) -> Self { + let mut bytes = [0u8; 8]; + bytes[..6].copy_from_slice(&addr.0); + + u64::from_le_bytes(bytes) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ble_address_new() { + let addr = BleAddress::new(0x112233445566, BleAddressKind::Public); + assert_eq!(addr.val, [0x66, 0x55, 0x44, 0x33, 0x22, 0x11]); + assert_eq!(addr.kind, BleAddressKind::Public); + } + + #[test] + fn ble_address_get_kind() { + let addr_public = + BleAddress::new(0x112233445566, BleAddressKind::Public); + assert_eq!(addr_public.get_kind(), BleAddressKind::Public); + + let addr_random = + BleAddress::new(0xAABBCCDDEEFF, BleAddressKind::Random); + assert_eq!(addr_random.get_kind(), BleAddressKind::Random); + } + + #[test] + fn ble_address_into_u64() { + let ble_addr = BleAddress::new(0x112233445566, BleAddressKind::Public); + let u64_addr: u64 = ble_addr.into(); + assert_eq!(u64_addr, 0x112233445566); + } + + #[test] + fn classic_address_from_u64() { + let u64_addr = 0x112233445566; + let classic_addr: ClassicAddress = u64_addr.into(); + assert_eq!(classic_addr.0, [0x66, 0x55, 0x44, 0x33, 0x22, 0x11]); + } + + #[test] + fn try_from_ble_address_to_classic() { + let ble_addr = BleAddress::new(0x112233445566, BleAddressKind::Public); + let result: Result = + ble_addr.try_into(); + assert!(result.is_ok()); + assert_eq!(result.unwrap().0, [0x66, 0x55, 0x44, 0x33, 0x22, 0x11]); + + let ble_addr_random = + BleAddress::new(0xAABBCCDDEEFF, BleAddressKind::Random); + let result: Result = + TryFrom::try_from(ble_addr_random); + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + BluetoothError::BadTypeConversion(_), + )); + } + + #[test] + fn test_u64_to_6lsb() { + // Test a case where the input number is smaller than 6 bytes + let num = 0x123456; + let expected_result = [0x56, 0x34, 0x12, 0, 0, 0]; + let result = u64_to_6lsb(num); + assert_eq!(result, expected_result); + + // Test a case where the input number is exactly 6 bytes + let num = 0xAABBCCDDEEFF; + let expected_result = [0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA]; + let result = u64_to_6lsb(num); + assert_eq!(result, expected_result); + + // Test a case where the number is too large so the two most significant + // bytes get dropped. + let num = 0x1122334455667788; + let expected_result = [0x88, 0x77, 0x66, 0x55, 0x44, 0x33]; + let result = u64_to_6lsb(num); + assert_eq!(result, expected_result); + + // Test a case where the input number is 0 + let num = 0; + let expected_result = [0, 0, 0, 0, 0, 0]; + let result = u64_to_6lsb(num); + assert_eq!(result, expected_result); + } +} diff --git a/fastpair/rust/bluetooth/src/common/advertisement.rs b/fastpair/rust/bluetooth/src/common/advertisement.rs new file mode 100644 index 00000000..00ce6bb3 --- /dev/null +++ b/fastpair/rust/bluetooth/src/common/advertisement.rs @@ -0,0 +1,172 @@ +// 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. + +use super::{BleAddress, BluetoothError}; + +/// Holds data related to an incoming BLE Advertisement. This includes +/// information about the advertisement (e.g. address of sender) as well as +/// data sections extracted from the advertisement. Platform-specific methods +/// should be written to load in data sections from incoming advertisements. +#[derive(Clone, Debug)] +pub struct BleAdvertisement { + address: BleAddress, + rssi: Option, + tx_power: Option, + service_data_16bit_uuid: Option>>, +} + +/// Decibel-milliwatt or dBm is a dimensionless absolute unit expressing the +/// power of a signal relative to one milliwatt (mW). The unit is in log10, i.e. +/// 1 mW is 0 dBm and a 10 dBm increase represents a ten-fold increase in power. +type DecibelMilliwatts = i16; + +impl BleAdvertisement { + /// Construct a new `BleAdvertisement` instance. + pub fn new( + address: BleAddress, + rssi: Option, + tx_power: Option, + ) -> Self { + BleAdvertisement { + address, + rssi, + tx_power, + service_data_16bit_uuid: None, + } + } + + /// Retrieve the `BleAddress` that emitted this advertisement. + pub fn address(&self) -> BleAddress { + self.address + } + + /// Retrieve the Received Signal Strength Indicator (RSSI) value for this + /// advertisement, expressed in dBm. The RSSI might be the raw value or the + /// filtered RSSI, depending on the configured signal strength filter. + pub fn rssi(&self) -> Option { + self.rssi + } + + /// Retrieve the transmit power advertised by this device, if any. + /// For BLE communication, values will range from -127 dBm to 20 dBm. + pub fn tx_power(&self) -> Option { + self.tx_power + } + + /// Setter for `ServiceData` field with 16bit UUID. + pub(crate) fn set_service_data_16bit_uuid( + &mut self, + data_sections: Vec>, + ) { + self.service_data_16bit_uuid = Some(data_sections); + } + + /// Getter for `ServiceData` field with 16bit UUID. + pub fn service_data_16bit_uuid( + &self, + ) -> Result<&Vec>, BluetoothError> { + match &self.service_data_16bit_uuid { + Some(service_data) => Ok(&service_data), + None => Err(BluetoothError::FailedPrecondition(String::from( + "No service data has been loaded into this advertisement.", + ))), + } + } +} + +/// Enum denoting the assigned number of Bluetooth common data types. Used for +/// fetching specific data sections from a Bluetooth advertisement. +/// Bluetooth Assigned Numbers, Section 2.3 +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub enum BleDataTypeId { + ServiceData16BitUuid = 0x16, +} + +/// Struct representing the Bluetooth Service Data common data type. `U` should +/// be one of the valid uuid sizes, specified in: +/// Bluetooth Supplement to the Core Specification, Part A, Section 1.11. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct ServiceData { + uuid: U, + data: Vec, +} + +impl ServiceData { + pub fn new(uuid: U, data: Vec) -> Self { + ServiceData { uuid, data } + } + + pub fn uuid(&self) -> U { + self.uuid + } + + pub fn data(&self) -> &Vec { + &self.data + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::BleAddressKind; + + #[test] + fn ble_advertisement_new() { + let address = BleAddress::new(0x112233445566, BleAddressKind::Public); + let ad = BleAdvertisement::new(address, Some(-60), Some(10)); + assert_eq!(ad.address(), address); + assert_eq!(ad.rssi(), Some(-60)); + assert_eq!(ad.tx_power(), Some(10)); + assert!(ad.service_data_16bit_uuid.is_none()); + } + + #[test] + fn ble_advertisement_set_and_get_service_data() { + let address = BleAddress::new(0x112233445566, BleAddressKind::Public); + let mut ad = BleAdvertisement::new(address, Some(-60), Some(10)); + + let service_data = vec![ + ServiceData::new(0x1234, vec![0x01, 0x02, 0x03]), + ServiceData::new(0x5678, vec![0x04, 0x05]), + ]; + + ad.set_service_data_16bit_uuid(service_data.clone()); + + let retrieved_service_data = ad.service_data_16bit_uuid().unwrap(); + assert_eq!(*retrieved_service_data, service_data); + } + + #[test] + fn ble_advertisement_missing_service_data() { + let address = BleAddress::new(0x112233445566, BleAddressKind::Public); + let ad = BleAdvertisement::new(address, Some(-60), Some(10)); + + let result = ad.service_data_16bit_uuid(); + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + BluetoothError::FailedPrecondition(_) + )); + } + + #[test] + fn service_data_new() { + let uuid = 0x1234; + let data = vec![0x01, 0x02, 0x03]; + + let service_data = ServiceData::new(uuid, data.clone()); + assert_eq!(service_data.uuid(), uuid); + assert_eq!(*service_data.data(), data); + } +} diff --git a/fastpair/rust/bluetooth/src/common/error.rs b/fastpair/rust/bluetooth/src/common/error.rs new file mode 100644 index 00000000..d0d43208 --- /dev/null +++ b/fastpair/rust/bluetooth/src/common/error.rs @@ -0,0 +1,60 @@ +// 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. + +use thiserror::Error; + +/// Library error type. +#[non_exhaustive] +#[derive(Error, Debug, PartialEq)] +pub enum BluetoothError { + /// Reported when the user attempts a bad type conversion, e.g. converting + /// a BLE random address to a BT Classic address. + #[error("bad type conversion: {0}")] + BadTypeConversion(String), + /// Reported when Bluetooth device pairing fails. + #[error("pairing error: {0}")] + PairingFailed(String), + /// Indicates that the operation was rejected because the system is not in + /// a state required for the operation's execution. + /// E.g. The user calls `stop_scan()` or polls the advertisement stream + #[error("failed precondition: {0}")] + FailedPrecondition(String), + /// Reported when the user calls an operation that is supported by their + /// Operating System, but is not supported by their device. + /// E.g. a Windows machine with an old BT Classic adapter that + /// doesn't support BLE). + #[error("bluetooth operation not supported by system: {0}")] + NotSupported(String), + /// Wrapper around OS-level errors, e.g. `windows::core::Error` for Windows. + /// These typically mean something is very wrong with the system (e.g. OOM). + #[error("bluetooth system-level error: {0}")] + System(String), + /// Reported when a bug occurs inside the library. Whenever a seemingly + /// impossible error condition arises where you could call `expect()`, + /// return this error instead. + #[error("internal error: {0}")] + Internal(String), +} + +/// Abstraction around platform-specific pairing status enums. +/// `PairingResult::Failure` should eventually be converted to +/// `BluetoothError::PairingFailed`. +#[non_exhaustive] +#[derive(Debug)] +pub enum PairingResult { + Success, + AlreadyPaired, + AlreadyInProgress, + Failure(String), +} diff --git a/fastpair/rust/bluetooth/src/common/mod.rs b/fastpair/rust/bluetooth/src/common/mod.rs new file mode 100644 index 00000000..1ddd9b30 --- /dev/null +++ b/fastpair/rust/bluetooth/src/common/mod.rs @@ -0,0 +1,22 @@ +// 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. + +/// Module for shared functionality between all Bluetooth platforms. +mod address; +mod advertisement; +mod error; + +pub use address::*; +pub use advertisement::*; +pub use error::*; diff --git a/fastpair/rust/bluetooth/src/lib.rs b/fastpair/rust/bluetooth/src/lib.rs new file mode 100644 index 00000000..99da6362 --- /dev/null +++ b/fastpair/rust/bluetooth/src/lib.rs @@ -0,0 +1,53 @@ +// 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. + +pub mod api; +mod common; + +use api::{BleAdapter, BleDevice, ClassicDevice}; +pub use common::{ + BleAddress, BleAddressKind, BleAdvertisement, BleDataTypeId, + BluetoothError, ClassicAddress, PairingResult, ServiceData, +}; + +cfg_if::cfg_if! { + if #[cfg(windows)] { + mod windows; + use self::windows as platform; + } else { + mod unsupported; + use unsupported as platform; + } +} + +pub struct Platform; + +impl Platform { + pub async fn default_adapter( + ) -> Result { + platform::BleAdapter::default().await + } + + pub async fn new_ble_device( + addr: BleAddress, + ) -> Result { + platform::BleDevice::new(addr).await + } + + pub async fn new_classic_device( + addr: ClassicAddress, + ) -> Result { + platform::ClassicDevice::new(addr).await + } +} diff --git a/fastpair/rust/src/message_stream.rs b/fastpair/rust/bluetooth/src/message_stream.rs similarity index 100% rename from fastpair/rust/src/message_stream.rs rename to fastpair/rust/bluetooth/src/message_stream.rs diff --git a/fastpair/rust/src/types.rs b/fastpair/rust/bluetooth/src/types.rs similarity index 100% rename from fastpair/rust/src/types.rs rename to fastpair/rust/bluetooth/src/types.rs diff --git a/fastpair/rust/src/types/packets.rs b/fastpair/rust/bluetooth/src/types/packets.rs similarity index 100% rename from fastpair/rust/src/types/packets.rs rename to fastpair/rust/bluetooth/src/types/packets.rs diff --git a/fastpair/rust/src/bluetooth/unsupported/adapter.rs b/fastpair/rust/bluetooth/src/unsupported/adapter.rs similarity index 67% rename from fastpair/rust/src/bluetooth/unsupported/adapter.rs rename to fastpair/rust/bluetooth/src/unsupported/adapter.rs index f7395ea5..7ae210e1 100644 --- a/fastpair/rust/src/bluetooth/unsupported/adapter.rs +++ b/fastpair/rust/bluetooth/src/unsupported/adapter.rs @@ -15,30 +15,31 @@ use async_trait::async_trait; use super::BleDevice; -use crate::bluetooth::common::Adapter; +use crate::{api, common::BluetoothError, BleAdvertisement, BleDataTypeId}; /// Concrete type implementing `Adapter`, used for unsupported devices. /// Every method should panic. pub struct BleAdapter; #[async_trait] -impl Adapter for BleAdapter { - type Device = BleDevice; - - async fn default() -> Result { +impl api::BleAdapter for BleAdapter { + async fn default() -> Result { panic!("Unsupported target platform."); } - fn start_scan_devices(&mut self) -> Result<(), anyhow::Error> { + fn start_scan(&mut self) -> Result<(), BluetoothError> { panic!("Unsupported target platform."); } - fn stop_scan_devices(&mut self) -> Result<(), anyhow::Error> { + fn stop_scan(&mut self) -> Result<(), BluetoothError> { panic!("Unsupported target platform."); } - async fn next_device(&mut self) -> Result { - panic!("Unsupported target platform."); + async fn next_advertisement( + &mut self, + datatype_selector: Option<&Vec>, + ) -> Result { + panic!("Unsupported target platform"); } } diff --git a/fastpair/rust/bluetooth/src/unsupported/device.rs b/fastpair/rust/bluetooth/src/unsupported/device.rs new file mode 100644 index 00000000..244ea06c --- /dev/null +++ b/fastpair/rust/bluetooth/src/unsupported/device.rs @@ -0,0 +1,68 @@ +// 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. + +use async_trait::async_trait; + +use crate::{ + api, + common::{BleAddress, BluetoothError, ClassicAddress, PairingResult}, +}; + +/// Concrete type implementing `api::BleDevice` for unsupported platforms. +/// Every method should panic. +pub struct BleDevice; + +#[async_trait] +impl api::BleDevice for BleDevice { + async fn new(addr: BleAddress) -> Result { + panic!("Unsupported target platform."); + } + + fn name(&self) -> Result { + panic!("Unsupported target platform."); + } + + fn address(&self) -> BleAddress { + panic!("Unsupported target platform."); + } +} + +/// Concrete type implementing `api::ClassicDevice` for unsupported platforms. +/// Every method should panic. +pub struct ClassicDevice; + +#[async_trait] +impl api::ClassicDevice for ClassicDevice { + async fn new(addr: ClassicAddress) -> Result { + panic!("Unsupported target platform."); + } + + fn name(&self) -> Result { + panic!("Unsupported target platform."); + } + + fn address(&self) -> ClassicAddress { + panic!("Unsupported target platform."); + } + + async fn pair(&self) -> Result { + panic!("Unsupported target platform."); + } +} + +mod tests { + use super::*; + + // TODO b/288592509 unit tests +} diff --git a/fastpair/rust/src/bluetooth/unsupported/mod.rs b/fastpair/rust/bluetooth/src/unsupported/mod.rs similarity index 100% rename from fastpair/rust/src/bluetooth/unsupported/mod.rs rename to fastpair/rust/bluetooth/src/unsupported/mod.rs diff --git a/fastpair/rust/src/bluetooth/windows_ble/adapter.rs b/fastpair/rust/bluetooth/src/windows/adapter.rs similarity index 66% rename from fastpair/rust/src/bluetooth/windows_ble/adapter.rs rename to fastpair/rust/bluetooth/src/windows/adapter.rs index 6d7af121..81613411 100644 --- a/fastpair/rust/src/bluetooth/windows_ble/adapter.rs +++ b/fastpair/rust/bluetooth/src/windows/adapter.rs @@ -12,12 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::pin::Pin; use std::sync::Arc; use async_trait::async_trait; -use futures::{stream::Stream, StreamExt}; -use tracing::{error, warn}; +use futures::{channel::mpsc::Receiver, StreamExt}; +use tracing::{error, info, warn}; use windows::{ Devices::Bluetooth::{ Advertisement::{ @@ -54,44 +53,49 @@ use windows::{ Foundation::TypedEventHandler, }; -use super::BleDevice; -use crate::bluetooth::common::Adapter; +use crate::{ + api, + common::{BleAdvertisement, BleDataTypeId, BluetoothError}, +}; -/// Concrete type implementing `Adapter`, used for Windows BLE. +/// Struct holding the necessary fields for listening to and handling incoming +/// BLE advertisements. +struct AdvListener { + /// Holds callback for sending received advertisement events to `receiver`. + watcher: BluetoothLEAdvertisementWatcher, + /// Can be polled to consume incoming advertisement events. + receiver: Receiver, +} + +/// Concrete type implementing `api::BleAdapter`, used for Windows BLE. pub struct BleAdapter { inner: BluetoothAdapter, - // NOTE: Using Boxed dyn here is silly because only one concrete type ever - // used. Change this to `impl Stream` once impl trait return types - // stabilized for existential types. - // b/289224233. - device_stream: Option + Send + Sync>>>, + listener: Option, } #[async_trait] -impl Adapter for BleAdapter { - type Device = BleDevice; - - async fn default() -> Result { +impl api::BleAdapter for BleAdapter { + async fn default() -> Result { let inner = BluetoothAdapter::GetDefaultAsync()?.await?; if !inner.IsLowEnergySupported()? { - return Err(anyhow::anyhow!( - "This device's Bluetooth Adapter doesn't support Bluetooth LE Transport type." - )); + return Err(BluetoothError::NotSupported(String::from( + "LE transport type", + ))); } if !inner.IsCentralRoleSupported()? { - return Err(anyhow::anyhow!( - "This device's Bluetooth Adapter doesn't support Bluetooth LE central role." - )); + return Err(BluetoothError::NotSupported(String::from( + "central role", + ))); } Ok(BleAdapter { inner, - device_stream: None, + listener: None, }) } - fn start_scan_devices(&mut self) -> Result<(), anyhow::Error> { + fn start_scan(&mut self) -> Result<(), BluetoothError> { let watcher = BluetoothLEAdvertisementWatcher::new()?; match watcher.SetScanningMode(BluetoothLEScanningMode::Active) { Ok(_) => (), @@ -149,7 +153,7 @@ impl Adapter for BleAdapter { >| { // Drop `sender`, closing the channel. let _sender = sender.take(); - println!("Watcher stopped receiving BLE advertisements."); + info!("Watcher stopped receiving BLE advertisements."); Ok(()) }, ); @@ -158,65 +162,62 @@ impl Adapter for BleAdapter { watcher.Stopped(&stopped_handler)?; watcher.Start()?; - // `receiver` is a `futures::channel::mpsc::Receiver`, which implements - // `futures::stream::Stream`. This is essentially an async Iterator. - // We apply a FilterMap to map from advertisement packet to a future - // returning `BleDevice` and filter out undesired connections. We need a - // pinned box to satisfy trait bounds for `Stream`. - self.device_stream = - Some(Box::pin(receiver.filter_map(move |event_args| { - // Move `watcher` into `FilterMap` closure. This ensures `watcher` - // is only dropped when the stream is closed. - let _watcher = &watcher; - - // Move `event_args` into async block. - async move { - match event_args.AdvertisementType().ok()? { - BluetoothLEAdvertisementType::NonConnectableUndirected => { - None - } - _ => { - let addr = event_args.BluetoothAddress().ok()?; - let kind = event_args.BluetoothAddressType().ok()?; - - match BleDevice::from_addr(addr, kind).await { - Ok(device) => Some(device), - Err(err) => { - warn!("Error creating device: {:?}", err); - None - } - } - } - } - } - }))); + self.listener = Some(AdvListener { watcher, receiver }); Ok(()) } - fn stop_scan_devices(&mut self) -> Result<(), anyhow::Error> { - if let Some(_) = &self.device_stream { - self.device_stream.take(); + fn stop_scan(&mut self) -> Result<(), BluetoothError> { + if let Some(listener) = self.listener.take() { + listener.watcher.Stop()?; Ok(()) } else { - Err(anyhow::anyhow!("Device scanning hasn't started.")) + Err(BluetoothError::FailedPrecondition(String::from( + "device scanning hasn't started, please call `start_scan()`", + ))) } } - async fn next_device(&mut self) -> Result { - if let Some(stream) = &mut self.device_stream { - stream - .next() - .await - .ok_or(anyhow::anyhow!("Device returned from stream is None.")) + async fn next_advertisement( + &mut self, + datatype_selector: Option<&Vec>, + ) -> Result { + if let Some(listener) = &mut self.listener { + let stream = &mut listener.receiver; + // We don't want the end-user to receive empty devices, so this is a + // loop to catch and skip trivial errors from advertisements that + // can't be turned into devices. + loop { + let event_args = + stream.next().await.ok_or(BluetoothError::Internal( + String::from("Event returned from stream is None."), + ))?; + + match event_args.AdvertisementType()? { + BluetoothLEAdvertisementType::NonConnectableUndirected => { + () + } + _ => { + let mut advertisement = + BleAdvertisement::try_from(&event_args)?; + + if let Some(datatype_selector) = datatype_selector { + advertisement + .load_data(&event_args, datatype_selector)?; + } + + break Ok(advertisement); + } + } + } } else { - Err(anyhow::anyhow!("Device scanning hasn't started.")) + Err(BluetoothError::FailedPrecondition(String::from( + "device scanning hasn't started, please call `start_scan()`", + ))) } } } mod tests { - use super::*; - // TODO b/288592509 unit tests } diff --git a/fastpair/rust/bluetooth/src/windows/address.rs b/fastpair/rust/bluetooth/src/windows/address.rs new file mode 100644 index 00000000..5423c429 --- /dev/null +++ b/fastpair/rust/bluetooth/src/windows/address.rs @@ -0,0 +1,52 @@ +// 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. + +// Whether the Bluetooth advertisement is Public, Random or Unspecified. +//https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothaddresstype?view=winrt-22621 +use windows::Devices::Bluetooth::BluetoothAddressType; + +use crate::common::{BleAddressKind, BluetoothError}; + +// Convenience for converting from Windows API to crate API. +impl TryFrom for BleAddressKind { + type Error = BluetoothError; + + fn try_from(kind: BluetoothAddressType) -> Result { + match kind { + BluetoothAddressType::Public => Ok(BleAddressKind::Public), + BluetoothAddressType::Random => Ok(BleAddressKind::Random), + BluetoothAddressType::Unspecified => { + Err(BluetoothError::BadTypeConversion(String::from( + "Attempting to construct `BleAddressKind` with device \ + advertising Unspecified address type.", + ))) + } + _ => Err(BluetoothError::BadTypeConversion(format!( + "Attempting to construct `BleAddressKind` with device \ + advertising invalid address type {}.", + kind.0, + ))), + } + } +} + +// Convenience for converting from crate API to Windows API. +impl From for BluetoothAddressType { + fn from(kind: BleAddressKind) -> Self { + match kind { + BleAddressKind::Public => BluetoothAddressType::Public, + BleAddressKind::Random => BluetoothAddressType::Random, + } + } +} diff --git a/fastpair/rust/bluetooth/src/windows/advertisement.rs b/fastpair/rust/bluetooth/src/windows/advertisement.rs new file mode 100644 index 00000000..bf80b5a3 --- /dev/null +++ b/fastpair/rust/bluetooth/src/windows/advertisement.rs @@ -0,0 +1,115 @@ +// 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. + +use windows::{ + // Struct that receives Bluetooth Low Energy (LE) advertisements. + // https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.advertisement.bluetoothleadvertisementwatcher?view=winrt-22621 + Devices::Bluetooth::Advertisement::{ + BluetoothLEAdvertisementDataSection, + BluetoothLEAdvertisementReceivedEventArgs, + }, + + // Struct representing an immutable view into a vector. + // https://learn.microsoft.com/en-us/uwp/api/windows.foundation.collections.ivectorview-1?view=winrt-22621 + Foundation::Collections::IVectorView, + + // Struct for reading data from a Windows stream, like an IVectorView. + // https://learn.microsoft.com/en-us/uwp/api/windows.storage.streams.datareader?view=winrt-22621 + Storage::Streams::DataReader, +}; + +use crate::common::{ + BleAddress, BleAddressKind, BleAdvertisement, BleDataTypeId, + BluetoothError, ServiceData, +}; + +impl TryFrom<&BluetoothLEAdvertisementReceivedEventArgs> for BleAdvertisement { + type Error = BluetoothError; + + fn try_from( + adv: &BluetoothLEAdvertisementReceivedEventArgs, + ) -> Result { + let addr = adv.BluetoothAddress()?; + let kind = BleAddressKind::try_from(adv.BluetoothAddressType()?)?; + + let addr = BleAddress::new(addr, kind); + // `rssi` and tx_power` aren't always advertised, so convert to None if + // can't extract value. + let rssi = adv.RawSignalStrengthInDBm().ok(); + let tx_power = match adv.TransmitPowerLevelInDBm() { + Ok(val_ref) => val_ref.GetInt16().ok(), + Err(_) => None, + }; + + Ok(BleAdvertisement::new(addr, rssi, tx_power)) + } +} + +impl BleAdvertisement { + /// Load data of selected data types into self by parsing the raw Windows + /// advertisement. + /// See: Supplement to the Bluetooth Core Specification Part A, Section 1. + pub(crate) fn load_data( + &mut self, + adv: &BluetoothLEAdvertisementReceivedEventArgs, + datatype_ids: &[BleDataTypeId], + ) -> Result<(), BluetoothError> { + let adv = adv.Advertisement()?; + + for datatype_id in datatype_ids { + // Note `raw_data_sections` is `!Send` and `!Sync`. This means + // processing must occur in a synchronous environment. The compiler + // will complain if parsing is done in an async function. + let raw_data_sections = + adv.GetSectionsByType((*datatype_id) as u8)?; + match datatype_id { + BleDataTypeId::ServiceData16BitUuid => { + let service_data = + parse_service_data_16bit_uuid(raw_data_sections)?; + self.set_service_data_16bit_uuid(service_data) + } + }; + } + + Ok(()) + } +} + +/// Parse the advertisement's service data. +/// Further Reading: +/// * `BleMedium::AdvertisementReceivedHandler` under +/// github.com/google/nearby/internal/platform/implementation/windows_ble/ble_medium.cc. +/// * Bluetooth Supplement to the Core Specification, Part A, Section 1.11. +/// * go/fast_pair_windows_data_parse. +#[inline] +fn parse_service_data_16bit_uuid( + raw_data_sections: IVectorView, +) -> Result>, BluetoothError> { + let mut data_vec = Vec::new(); + + for raw_data in raw_data_sections { + let data_reader = DataReader::FromBuffer(&raw_data.Data()?)?; + let uuid = data_reader.ReadUInt16()?; + + let unconsumed_buffer_len = + data_reader.UnconsumedBufferLength()? as usize; + + let mut data = vec![0u8; unconsumed_buffer_len]; + data_reader.ReadBytes(&mut data)?; + + data_vec.push(ServiceData::new(uuid, data)); + } + + Ok(data_vec) +} diff --git a/fastpair/rust/bluetooth/src/windows/device.rs b/fastpair/rust/bluetooth/src/windows/device.rs new file mode 100644 index 00000000..c0b96d8d --- /dev/null +++ b/fastpair/rust/bluetooth/src/windows/device.rs @@ -0,0 +1,161 @@ +// 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. + +use async_trait::async_trait; +use tracing::{info, warn}; +use windows::{ + Devices::{ + Bluetooth::{ + // Tuple struct describing the type of address (public, random, unspecified). + // https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothaddresstype?view=winrt-22621 + BluetoothAddressType, + + // Struct for interacting with a discovered BT Classic device. + // https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothdevice?view=winrt-22621 + BluetoothDevice, + + // Struct for interacting with a discovered BLE device. + // https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothledevice?view=winrt-22621 + BluetoothLEDevice, + }, + Enumeration::{ + // Struct for custom pairing with a device. + // https://learn.microsoft.com/en-us/uwp/api/windows.devices.enumeration.deviceinformationcustompairing?view=winrt-22621 + DeviceInformationCustomPairing, + + // Tuple struct to indicate the kinds of pairing supported by the application. + // https://learn.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicepairingkinds?view=winrt-22621 + DevicePairingKinds, + + // Struct for retrieving data about a PairingRequested event. + // https://learn.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicepairingrequestedeventargs?view=winrt-22621 + DevicePairingRequestedEventArgs, + }, + }, + // Wraps a closure for handling events associated with a struct + // (e.g. PairingRequested event in `DeviceInformationCustomPairing`). + // https://learn.microsoft.com/en-us/uwp/api/windows.foundation.typedeventhandler-2?view=winrt-22621 + Foundation::TypedEventHandler, +}; + +use crate::{api, common::{BleAddress, ClassicAddress, BluetoothError, PairingResult}}; + +/// Concrete type implementing `Device`, used for Windows BLE. +pub struct BleDevice { + inner: BluetoothLEDevice, + addr: BleAddress, +} + +/// Concrete type implementing `Device`, used for Windows Bluetooth Classic. +pub struct ClassicDevice { + inner: BluetoothDevice, + addr: ClassicAddress, +} + +#[async_trait] +impl api::BleDevice for BleDevice { + async fn new(addr: BleAddress) -> Result { + let kind = BluetoothAddressType::from(addr.get_kind()); + let raw_addr = u64::from(addr); + + let inner = BluetoothLEDevice::FromBluetoothAddressWithBluetoothAddressTypeAsync( + raw_addr, kind, + )? + .await?; + + Ok(BleDevice { inner, addr }) + } + + fn name(&self) -> Result { + Ok(self.inner.Name()?.to_string()) + } + + fn address(&self) -> BleAddress { + self.addr + } +} + +#[async_trait] +impl api::ClassicDevice for ClassicDevice { + async fn new(addr: ClassicAddress) -> Result { + let raw_addr = u64::from(addr); + + let inner = BluetoothDevice::FromBluetoothAddressAsync( + raw_addr, + )? + .await?; + + Ok(ClassicDevice { inner, addr }) + } + + fn name(&self) -> Result { + Ok(self.inner.Name()?.to_string_lossy()) + } + + fn address(&self) -> ClassicAddress { + self.addr + } + + async fn pair(&self) -> Result { + let pair_info = self.inner.DeviceInformation()?.Pairing()?; + if pair_info.IsPaired()? { + info!("Device already paired"); + Ok(PairingResult::AlreadyPaired) + } else if !pair_info.CanPair()? { + info!("Device can't pair"); + Err(BluetoothError::PairingFailed(String::from("device can't pair"))) + } else { + let custom = pair_info.Custom()?; + custom.PairingRequested(&TypedEventHandler::new( + |_custom: &Option, + event_args: &Option, + | { + if let Some(event_args) = event_args { + match event_args.PairingKind()? { + DevicePairingKinds::ConfirmOnly => { + event_args.Accept() + } + _ => { + warn!("Unsupported pairing kind {:?}", event_args.PairingKind()); + Ok(()) + } + } + } else { + warn!("Empty pairing event arguments"); + Ok(()) + } + + }, + ))?; + let res = custom + .PairAsync( + DevicePairingKinds::ConfirmOnly + | DevicePairingKinds::ProvidePin + | DevicePairingKinds::ConfirmPinMatch + | DevicePairingKinds::DisplayPin, + )? + .await?; + let status = PairingResult::from(res.Status()?); + + match status { + PairingResult::Failure(msg) => Err(BluetoothError::PairingFailed(msg)), + _ => Ok(status), + } + } + } +} + +mod tests { + // TODO b/288592509 unit tests +} diff --git a/fastpair/rust/bluetooth/src/windows/error.rs b/fastpair/rust/bluetooth/src/windows/error.rs new file mode 100644 index 00000000..9a7f6d4c --- /dev/null +++ b/fastpair/rust/bluetooth/src/windows/error.rs @@ -0,0 +1,57 @@ +// 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. + +use windows::Devices::Enumeration::DevicePairingResultStatus; + +use crate::common::{BluetoothError, PairingResult}; + +impl From for BluetoothError { + fn from(err: windows::core::Error) -> Self { + BluetoothError::System(err.to_string()) + } +} + +// https://learn.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicepairingresultstatus?view=winrt-22621 +impl From for PairingResult { + fn from(status: DevicePairingResultStatus) -> Self { + match status { + DevicePairingResultStatus::Paired => PairingResult::Success, + DevicePairingResultStatus::AlreadyPaired => { + PairingResult::AlreadyPaired + } + DevicePairingResultStatus::OperationAlreadyInProgress => { + PairingResult::AlreadyInProgress + } + DevicePairingResultStatus::NotReadyToPair => PairingResult::Failure( + String::from("the device object is not in a state where it can be paired"), + ), + DevicePairingResultStatus::NotPaired => PairingResult::Failure(String::from("the device object is not currently paired.")), + DevicePairingResultStatus::ConnectionRejected => PairingResult::Failure(String::from("the device object rejected the connection.")), + DevicePairingResultStatus::TooManyConnections => PairingResult::Failure(String::from("the device object indicated it cannot accept any more incoming connections.")), + DevicePairingResultStatus::HardwareFailure => PairingResult::Failure(String::from("the device object indicated there was a hardware failure.")), + DevicePairingResultStatus::AuthenticationTimeout => PairingResult::Failure(String::from("the authentication process timed out before it could complete.")), + DevicePairingResultStatus::AuthenticationNotAllowed => PairingResult::Failure(String::from("the authentication protocol is not supported, so the device is not paired.")), + DevicePairingResultStatus::AuthenticationFailure => PairingResult::Failure(String::from("authentication failed, so the device is not paired. Either the device object or the application rejected the authentication.")), + DevicePairingResultStatus::NoSupportedProfiles => PairingResult::Failure(String::from("there are no network profiles for this device object to use.")), + DevicePairingResultStatus::ProtectionLevelCouldNotBeMet => PairingResult::Failure(String::from("the minimum level of protection is not supported by the device object or the application.")), + DevicePairingResultStatus::AccessDenied => PairingResult::Failure(String::from("your application does not have the appropriate permissions level to pair the device object.")), + DevicePairingResultStatus::InvalidCeremonyData => PairingResult::Failure(String::from("the ceremony data was incorrect.")), + DevicePairingResultStatus::PairingCanceled => PairingResult::Failure(String::from("the pairing action was canceled before completion.")), + DevicePairingResultStatus::RequiredHandlerNotRegistered => PairingResult::Failure(String::from("either the event handler wasn't registered or a required DevicePairingKinds was not supported.",)), + DevicePairingResultStatus::RejectedByHandler => PairingResult::Failure(String::from("the application handler rejected the pairing.")), + DevicePairingResultStatus::RemoteDeviceHasAssociation => PairingResult::Failure(String::from("the remote device already has an association.")), + DevicePairingResultStatus::Failed | _ => PairingResult::Failure(String::from("an unknown failure occurred.")), + } + } +} diff --git a/fastpair/rust/src/bluetooth/windows_ble/mod.rs b/fastpair/rust/bluetooth/src/windows/mod.rs similarity index 88% rename from fastpair/rust/src/bluetooth/windows_ble/mod.rs rename to fastpair/rust/bluetooth/src/windows/mod.rs index 7d54d4ef..8003fe00 100644 --- a/fastpair/rust/src/bluetooth/windows_ble/mod.rs +++ b/fastpair/rust/bluetooth/src/windows/mod.rs @@ -14,7 +14,12 @@ /// Bluetooth LE module for Windows devices. mod adapter; +mod address; +mod advertisement; mod device; +mod error; pub use adapter::*; +pub use address::*; +pub use advertisement::*; pub use device::*; diff --git a/fastpair/rust/demo/.gitignore b/fastpair/rust/demo/.gitignore new file mode 100644 index 00000000..24476c5d --- /dev/null +++ b/fastpair/rust/demo/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/fastpair/rust/demo/.metadata b/fastpair/rust/demo/.metadata new file mode 100644 index 00000000..de745e4a --- /dev/null +++ b/fastpair/rust/demo/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + - platform: android + create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + - platform: ios + create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + - platform: linux + create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + - platform: macos + create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + - platform: web + create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + - platform: windows + create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/fastpair/rust/demo/README.md b/fastpair/rust/demo/README.md new file mode 100644 index 00000000..dbd403a0 --- /dev/null +++ b/fastpair/rust/demo/README.md @@ -0,0 +1,16 @@ +# demo + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/fastpair/rust/demo/analysis_options.yaml b/fastpair/rust/demo/analysis_options.yaml new file mode 100644 index 00000000..61b6c4de --- /dev/null +++ b/fastpair/rust/demo/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/fastpair/rust/demo/bindgen.script b/fastpair/rust/demo/bindgen.script new file mode 100644 index 00000000..4533096a --- /dev/null +++ b/fastpair/rust/demo/bindgen.script @@ -0,0 +1,4 @@ +flutter_rust_bridge_codegen --rust-input rust/src/api.rs --dart-output lib/bridge_generated.dart --dart-decl-output lib/bridge_definitions.dart + +# github.com/google/addlicense +addlicense . \ No newline at end of file diff --git a/fastpair/rust/demo/lib/bridge_definitions.dart b/fastpair/rust/demo/lib/bridge_definitions.dart new file mode 100644 index 00000000..b66ccf6b --- /dev/null +++ b/fastpair/rust/demo/lib/bridge_definitions.dart @@ -0,0 +1,42 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// Generated by `flutter_rust_bridge`@ 1.79.0. +// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member, prefer_is_empty, unnecessary_const + +import 'dart:convert'; +import 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; +import 'package:uuid/uuid.dart'; + +import 'package:collection/collection.dart'; + +abstract class Rust { + /// Sets up initial constructs and infinitely polls for advertisements. + Future init({dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kInitConstMeta; + + /// Sets up `StreamSink` for Dart-Rust FFI. + Stream eventStream({dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kEventStreamConstMeta; + + /// Attempt classic pairing with currently displayed device. + Future pair({dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kPairConstMeta; + + /// Remove this device from display and add it to the TTL cache blacklist. + Future dismiss({dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kDismissConstMeta; +} + +class StringArray2 extends NonGrowableListView { + static const arraySize = 2; + StringArray2(List inner) + : assert(inner.length == arraySize), + super(inner); + StringArray2.unchecked(List inner) : super(inner); + StringArray2.init(String fill) : super(List.filled(arraySize, fill)); +} diff --git a/fastpair/rust/demo/lib/bridge_generated.dart b/fastpair/rust/demo/lib/bridge_generated.dart new file mode 100644 index 00000000..9fc5d9db --- /dev/null +++ b/fastpair/rust/demo/lib/bridge_generated.dart @@ -0,0 +1,305 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// Generated by `flutter_rust_bridge`@ 1.79.0. +// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member, prefer_is_empty, unnecessary_const + +import "bridge_definitions.dart"; +import 'dart:convert'; +import 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; +import 'package:uuid/uuid.dart'; + +import 'dart:convert'; +import 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; +import 'package:uuid/uuid.dart'; + +import 'dart:ffi' as ffi; + +class RustImpl implements Rust { + final RustPlatform _platform; + factory RustImpl(ExternalLibrary dylib) => RustImpl.raw(RustPlatform(dylib)); + + /// Only valid on web/WASM platforms. + factory RustImpl.wasm(FutureOr module) => + RustImpl(module as ExternalLibrary); + RustImpl.raw(this._platform); + Future init({dynamic hint}) { + return _platform.executeNormal(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_init(port_), + parseSuccessData: _wire2api_unit, + constMeta: kInitConstMeta, + argValues: [], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kInitConstMeta => + const FlutterRustBridgeTaskConstMeta( + debugName: "init", + argNames: [], + ); + + Stream eventStream({dynamic hint}) { + return _platform.executeStream(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_event_stream(port_), + parseSuccessData: _wire2api_opt_String_array_2, + constMeta: kEventStreamConstMeta, + argValues: [], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kEventStreamConstMeta => + const FlutterRustBridgeTaskConstMeta( + debugName: "event_stream", + argNames: [], + ); + + Future pair({dynamic hint}) { + return _platform.executeNormal(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_pair(port_), + parseSuccessData: _wire2api_String, + constMeta: kPairConstMeta, + argValues: [], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kPairConstMeta => + const FlutterRustBridgeTaskConstMeta( + debugName: "pair", + argNames: [], + ); + + Future dismiss({dynamic hint}) { + return _platform.executeNormal(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_dismiss(port_), + parseSuccessData: _wire2api_unit, + constMeta: kDismissConstMeta, + argValues: [], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kDismissConstMeta => + const FlutterRustBridgeTaskConstMeta( + debugName: "dismiss", + argNames: [], + ); + + void dispose() { + _platform.dispose(); + } +// Section: wire2api + + String _wire2api_String(dynamic raw) { + return raw as String; + } + + StringArray2 _wire2api_String_array_2(dynamic raw) { + return StringArray2((raw as List).map(_wire2api_String).toList()); + } + + List _wire2api_list_String(dynamic raw) { + return (raw as List).map(_wire2api_String).toList(); + } + + StringArray2? _wire2api_opt_String_array_2(dynamic raw) { + return raw == null ? null : _wire2api_String_array_2(raw); + } + + int _wire2api_u8(dynamic raw) { + return raw as int; + } + + Uint8List _wire2api_uint_8_list(dynamic raw) { + return raw as Uint8List; + } + + void _wire2api_unit(dynamic raw) { + return; + } +} + +// Section: api2wire + +// Section: finalizer + +class RustPlatform extends FlutterRustBridgeBase { + RustPlatform(ffi.DynamicLibrary dylib) : super(RustWire(dylib)); + +// Section: api2wire + +// Section: finalizer + +// Section: api_fill_to_wire +} + +// ignore_for_file: camel_case_types, non_constant_identifier_names, avoid_positional_boolean_parameters, annotate_overrides, constant_identifier_names + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +// ignore_for_file: type=lint + +/// generated by flutter_rust_bridge +class RustWire implements FlutterRustBridgeWireBase { + @internal + late final dartApi = DartApiDl(init_frb_dart_api_dl); + + /// Holds the symbol lookup function. + final ffi.Pointer Function(String symbolName) + _lookup; + + /// The symbols are looked up in [dynamicLibrary]. + RustWire(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup; + + /// The symbols are looked up with [lookup]. + RustWire.fromLookup( + ffi.Pointer Function(String symbolName) + lookup) + : _lookup = lookup; + + void store_dart_post_cobject( + DartPostCObjectFnType ptr, + ) { + return _store_dart_post_cobject( + ptr, + ); + } + + late final _store_dart_post_cobjectPtr = + _lookup>( + 'store_dart_post_cobject'); + late final _store_dart_post_cobject = _store_dart_post_cobjectPtr + .asFunction(); + + Object get_dart_object( + int ptr, + ) { + return _get_dart_object( + ptr, + ); + } + + late final _get_dart_objectPtr = + _lookup>( + 'get_dart_object'); + late final _get_dart_object = + _get_dart_objectPtr.asFunction(); + + void drop_dart_object( + int ptr, + ) { + return _drop_dart_object( + ptr, + ); + } + + late final _drop_dart_objectPtr = + _lookup>( + 'drop_dart_object'); + late final _drop_dart_object = + _drop_dart_objectPtr.asFunction(); + + int new_dart_opaque( + Object handle, + ) { + return _new_dart_opaque( + handle, + ); + } + + late final _new_dart_opaquePtr = + _lookup>( + 'new_dart_opaque'); + late final _new_dart_opaque = + _new_dart_opaquePtr.asFunction(); + + int init_frb_dart_api_dl( + ffi.Pointer obj, + ) { + return _init_frb_dart_api_dl( + obj, + ); + } + + late final _init_frb_dart_api_dlPtr = + _lookup)>>( + 'init_frb_dart_api_dl'); + late final _init_frb_dart_api_dl = _init_frb_dart_api_dlPtr + .asFunction)>(); + + void wire_init( + int port_, + ) { + return _wire_init( + port_, + ); + } + + late final _wire_initPtr = + _lookup>('wire_init'); + late final _wire_init = _wire_initPtr.asFunction(); + + void wire_event_stream( + int port_, + ) { + return _wire_event_stream( + port_, + ); + } + + late final _wire_event_streamPtr = + _lookup>( + 'wire_event_stream'); + late final _wire_event_stream = + _wire_event_streamPtr.asFunction(); + + void wire_pair( + int port_, + ) { + return _wire_pair( + port_, + ); + } + + late final _wire_pairPtr = + _lookup>('wire_pair'); + late final _wire_pair = _wire_pairPtr.asFunction(); + + void wire_dismiss( + int port_, + ) { + return _wire_dismiss( + port_, + ); + } + + late final _wire_dismissPtr = + _lookup>('wire_dismiss'); + late final _wire_dismiss = _wire_dismissPtr.asFunction(); + + void free_WireSyncReturn( + WireSyncReturn ptr, + ) { + return _free_WireSyncReturn( + ptr, + ); + } + + late final _free_WireSyncReturnPtr = + _lookup>( + 'free_WireSyncReturn'); + late final _free_WireSyncReturn = + _free_WireSyncReturnPtr.asFunction(); +} + +final class _Dart_Handle extends ffi.Opaque {} + +typedef DartPostCObjectFnType = ffi.Pointer< + ffi.NativeFunction< + ffi.Bool Function(DartPort port_id, ffi.Pointer message)>>; +typedef DartPort = ffi.Int64; diff --git a/fastpair/rust/demo/lib/main.dart b/fastpair/rust/demo/lib/main.dart new file mode 100644 index 00000000..a9995d71 --- /dev/null +++ b/fastpair/rust/demo/lib/main.dart @@ -0,0 +1,130 @@ +// 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. + +import 'package:flutter/material.dart'; +import 'package:demo/rust.dart'; + +void main() { + api.init(); + runApp(const FastPairApp()); +} + +class FastPairApp extends StatelessWidget { + const FastPairApp({super.key}); + @override + Widget build(BuildContext context) => MaterialApp( + title: 'Fast Pair', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const HomePage(), + ); +} + +class HomePage extends StatelessWidget { + const HomePage({super.key}); + + @override + Widget build(BuildContext context) => Scaffold( + appBar: AppBar( + title: const Text("Fast Pair"), + ), + body: Center( + child: StreamBuilder( + // Retrieve device info stream from Rust side. + stream: api.eventStream(), + builder: (context, deviceInfo) { + var deviceName = deviceInfo.data?[0]; + var deviceImageUrl = deviceInfo.data?[1]; + + if (deviceInfo.hasData && + deviceName != null && + deviceImageUrl != null) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Image.network(deviceImageUrl, + fit: BoxFit.contain)), + Text(deviceName), + // Spacing between device name text and buttons. + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + // Spacing between left edge of screen and first button. + const SizedBox(width: 20), + OutlinedButton( + // Invoke pairing dialog. + onPressed: () => pairing(context), + child: const Text('Pair'), + ), + // Spacing between buttons. + const SizedBox(width: 20), + OutlinedButton( + onPressed: () => api.dismiss(), + child: const Text('Dismiss')) + ], + ), + // Spacing between buttons and bottom of screen. + const SizedBox(height: 20), + ]); + } + return const Center( + child: CircularProgressIndicator(), + ); + }, + ), + ), + ); +} + +// Displays pairing dialog box. +Future pairing(BuildContext context) => showDialog( + context: context, + // Rust functions are invoked as futures. + builder: (context) => FutureBuilder( + future: api.pair(), + builder: (context, pairResult) { + var pairResultValue = pairResult.data; + + return pairResult.hasData && pairResultValue != null + ? AlertDialog( + title: const Text('Pairing result'), + content: Text(pairResultValue), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, 'OK'), + child: const Text('OK'), + ) + ], + ) + : const AlertDialog( + title: Text('Pairing...'), + // Ensures the progress indicator has sensible dimensions, + // otherwise it follows the height/width of the alert dialog. + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 50, + height: 50, + child: CircularProgressIndicator(), + ), + ], + ), + ); + })); diff --git a/fastpair/rust/demo/lib/rust.dart b/fastpair/rust/demo/lib/rust.dart new file mode 100644 index 00000000..a525483b --- /dev/null +++ b/fastpair/rust/demo/lib/rust.dart @@ -0,0 +1,32 @@ +// 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. + +// This file initializes the dynamic library and connects it with the stub +// generated by flutter_rust_bridge_codegen. + +import 'dart:ffi'; + +import 'dart:io' as io; + +import 'package:demo/bridge_generated.dart'; + +const _base = 'rust'; + +// On MacOS, the dynamic library is not bundled with the binary, +// but rather directly **linked** against the binary. +final _dylib = io.Platform.isWindows ? '$_base.dll' : 'lib$_base.so'; + +final api = RustImpl(io.Platform.isIOS || io.Platform.isMacOS + ? DynamicLibrary.executable() + : DynamicLibrary.open(_dylib)); diff --git a/fastpair/rust/demo/local/525296.json b/fastpair/rust/demo/local/525296.json new file mode 100644 index 00000000..0404cf7e --- /dev/null +++ b/fastpair/rust/demo/local/525296.json @@ -0,0 +1,40 @@ +{ + "device": { + "id": "525296", + "notificationType": "FAST_PAIR_ONE", + "imageUrl": "https://lh3.googleusercontent.com/M67kfg-lVtqeP0-CLuvR68J4MlY9wixO0Za3urah_5axGRUyi20KSEQiqjvhqxCWTxpsicU1w-TCL3BX", + "name": "LG HBS-1125", + "intentUri": "intent:#Intent;action=com.google.android.gms.nearby.discovery%3AACTION_MAGIC_PAIR;package=com.google.android.gms;component=com.google.android.gms/.nearby.discovery.service.DiscoveryService;S.com.google.android.gms.nearby.discovery%3AEXTRA_COMPANION_APP=com.lge.tonentalkplus.tonentalkfree;end", + "triggerDistance": 0.6, + "antiSpoofingKeyPair": {}, + "status": { + "statusType": "PUBLISHED" + }, + "lastUpdateTimestamp": "2021-12-02T07:11:36.110Z", + "deviceType": "HEADPHONES", + "trueWirelessImages": {}, + "companyName": "LG", + "interactionType": "NOTIFICATION", + "companionDetail": {} + }, + "image": "iVBORw0KGgoAAAANSUhEUgAAAIwAAACMCAYAAACuwEE+AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAABcRAAAXEQHKJvM/AAAAB3RJTUUH4gQEDBoz611DFwAAIABJREFUeNrtfWeYVFW29rv3SXUqdXWszt00SUCCkTuDIzKXa1ZAjAQFESQqwSFIK1EJYkbFgAqIaZwZHFHHa2B0RsfBhOSWaHfTTUOH6q58ztl7fz9OdcO933O/7w7SAa33eeppuqiu2qfWe9Zea+0VgCSSSCKJJJJIIokkOjyEEB36/To6yC+YOGT5ihVZgYbawlg8nsEsnhaLxR2yTNySpDiEEBIhiAIQjBuGJElNDoe7gUDUpKX5j8ybN6eGEMJ/ad/bz4owF11yDv7+1+9afl++fDndu3evommqRiXSPRoNXxKPsd8YRqx/LBbJMi0DhmHBNBg45wAEOBfgnINSgFIJhBBwLiBJFIqqQlVVKIoMSil0h+OYrMhfqor+aXp62t9MM/pDMByKdevS3Zw3r7SFTIMGDcQnn/wVhJAkYdobn376KQYOHPhfnps85Y7+DfXhgY2NjecbhtHTMIxuhhFVLEvANC0IYYFzASEECAEoJQAoKEXieYBzBkplABwASbyGgHOAEAFCCAghkGUFsixDUSTousPUNMcPDoe2V9cd33lTvFtWP7nmi+Z15ebmYv369Rg8eHCSMG2JFStWYM6cOQCAOXN+R1xOD21obOhbVfnjzIbG4PXBYJMWj5ngnNkXSSgEOIQAKCEQQoBS+70kKoNIBBC05TlCJAjB7J+w7K9JAJzb78EYgxAi8f4UQtgkEsL+HRBwOp1wuVxwe9yGy+n9Q35+3iOyLH/bvXt3fttttwEAtm7digsvvDBJmLbC0KFDrohEwyM444ODoXC2ZRotRmiz+re1iK0hJEmBqiYemgJNU6EqDkiSIiSJhCilIUKoKcDigsuCUkDAUgiIxjl3W4y5LZNRwzAQi8UQNwzEY3GYpgXGTAAcjInE59qfL0sSVE2D06mDc35YUZQ3s7Iy39y48bVvkhqmDfD73/+evvrqq+NqamqWB4ONaeFwBG53CnRdS9zlIqFBKGRZhizLcDqd8Hjc8Kb4uNfj2aVpjs8cTvUbn8+3M8XjO9i//6+aFiwstQry8wFIEDAhhAyJSgAsAAJ19XWYNnWGtHPn9ymhcKCgtraubzRqXBCPGxc1Bpp6NTQ0yA0NDYhGo2CMgzGe0EA2YS2LIxyOQksQNTU1dXtRUeGUl15a93cAWLJkCe67774kYX4iOXDDDTcAAMaNG9v1wIGDY6LR2LjGxkZ/LBYDpYCmaXA6nVBVDQIcsiTB4/EixeczXU73tx6P95uUFO9XWVnZ30yePHHX/+TZmKYJRVH+x7UYhgFVVf/H/3/22TU9q44eOjdQH7ogEAheEAqFz28INCihYCNMk8GyDAhBWohEKKA7dHi9KV+7XO5nx48fv3HYsGHRJGFOESUlJTh48CAee+wJ9+bNm9YeO3ZseDxuSjZRKFJTU+FwKGCMA6BQVRXZ2X7k5+fvSEtLXa7r+p/jcTN2zTXXsD59+rRZsKS+/jhWr35GTk1N1RsCdVfX1TbMPXRof5/q6qMwTdZiaDPGYBgmJEmCoijC5XJFcnNzZ7311lvPAsDSpUtRWlqaJMz/FpMmT8zbvWvP1FAoODsYbKSGYUKRFXi8HnjcbjDBITiB2+0WTqfz74WFhR/079//jREjRuxvfo8DBw6gc+fObb72gwcPoqSkpOX3t9/+Y/aWLZ+OKC+vuLaxsXFgINDQYmsZhgnLskCIrS293pS9Ho9nyebNm98ghLCrr74amzdvThLmv2PDhpcxevQYAMC11147//CPB0tNgzkikTAIocjKzILuVCFJMgzDhMftRWFR4dMpPs9Sl9Nbu2DB/Wbzex06dAidOnVq92vatWsXevXq1fL7ypUr5cbGpqz6+prFZWX7xwUaAyAJA900LYQjEWiqBl1XhdudcvD8888fumrVqp3331+KxYuXJgkDAOvWrUOzm3nV1Vf1r6ure6yhof7fLNOCZTGkpHiQmZkBQgk443A49CNZWRlvTpg0Zumv+w+uB4ANG1/C6JFjO7zB+Nprr+GWW24BAHz48Xt569dtXHDkSNWNoWAoxQ4aApFIBJZlQdNUOJ0upKWlruzX75xly5YtCyxfvgxz585LahgAGDx48KPVR49OMo24FolEoTt15OflQdM0OwpLgE6dimZJVH7h6afXNAHAnRPH4Nk1L59xrunwG67BH37/DgDgnntmZQQCgUV79pRNtqwIhJAghEAgEICiqHC5dGiadqR79+7D1q596avJkyfj6aefbre10/b4UCEELr3UjnbecsvNXQYMGLCtvLx8ejQS1qKRKPz+LHTv1hVOpw5CiOX2uN6aMeMu/7NrXniksKioqcUzOQPJAqCFLB999BFWrXq49oUX1k4ZMmTor1JT07+VZRlUosjIyIAQQFNTCNFoNK+s7Ietw4cPnzRs2DAJAFavXv3L0zC33Tb6mm3btr0ajcbc8bgddOvcuQTeFDeYxSHL8lG/P+eKNWvWbCOEYMrUO/HU6mfxc8XGja+rW7Z8NHbfvrI1pmkCIIhGIwgGQ/B6PXA4nPD5fH967733rgOAJ598AtOm3dWma5Ta8sOWLXsQH3/8MQDgyisvn7h3796NsVhMjcViUBQNPXqcBa/XC8tikGTy/rS7J/3b3dNmHhFC4NNPP8VXW7/BzxmmGWOvv/76N2PHjnmjsvLIZUKIdE1ToaoKgsEgCKEwTaNH3779rhk69Jo3S0vvj82ePQuff/6Pn7eGufzyy56srKyYGo8bCIcjSEtPRefOJVAVBYZpwOtJueepFesf9eZK/OTg3S8BS5cuRmnp/ZgzZ463rKzs8bq642Motb2ouroG6LodqHS7XXvHjRt73k03jYrMnv07rFz50M/Hhmk20oQQ5NJLL3uooqJ8ajweRzQaRVq6D926doGmOmBZpuV1e2du2LDx4ZVPL+AAflFkAYDS0vshhMAPP/zQtGnTprE+n+9JQig0TYPfn4F4PA7DMBAOR8566aX1FTNnzvKvXPkQ5s+/9+enYa666qpHy8vLp8diMUQiIWRmZqJzl2JoqhuGEY+l+FKGrn3hxQ+QxH/BdcOHjgk0NLwEUDDGUVNTA4/HA4fDAZfLeeiKK6485+67725cunQRSksXnNkaZsCAXyVslivnV1RUTG++Q3wpPnTu0hmq6kA8HjNTUnzXrX3hxQ/eeOO1JENO1jj3zcMf/7DpZV13TgcgFEVGbm4OgsEgACAajXT68MMPytasWe0uLV2At99++8zVMOPGjcPatWtxyy233FRWVvZaOBwmsVgMsqyg3zlnw+HQYFmW4XKlXP7i2he3JOnx/9E01w0Z29QUfJFKEmLRGI4dq0GW3w9KCLxe9+eTp4+6+NEV68QHH3wgzjgNs2LFCqxduxZTpky5YN++fa9HImHSnHjU75ye0HUHAECRHdNeXPvilueeey7JiP8H5s6djT/+8e2XNIe2DODQHQ5kZPhRX9cATdMQDkcHrH/hnedbkyytpmHsnFiK2bPneL744oud9fV1haZpIhgM4uyzeyEnNxOMMSiKOm/dyxuXJ+nwr+Hqq69+yTDiYwCK+vrjAIDs7CzETQNZGZn3b9z4xpLnn38B48ffcWZoGJrIddy1a8fvGxsbChljiEajyMvLgd/vB4ECStQ3Dx+uWT5n7j1JBvwLGDlyJDZv3jxWUaR/UMqRmZmJSCSKpqYgFElDIBAsnThxQq/x4+/AzBnTOz5hvv/+ewDA0KFDZldXV19mWQYYt+B0OtCtW3dIkgTO2dHios4TP/3rR1ixfFWSBf8CNm7cCABIS8u4DaAWIQR5eXmoq62HQ5dAqFCPHT/2wb5duxyPPPpYxybMww+vRN++fTFy5C2Fx4/XzIvFYgAo4rE4unTpDk3TIQRD9+7d+i99YHHDyy+/nGTAKeCe303Hhg2v7MvJyb9OCAFNU+D1eVFZcRRpqemwLDOvdPHSDQBw332nNz7TKjbMFVdc/pcjRyovY4wjEonA5/OhT9/eidIMLHjpxfWLFy68DwsXLklK/5RjWtfi3Xf/jCFDrn2FMTZSwMT+fYfQ6+we0B1uRKKReLY/61fPPPPcd6FQCG63u2NuSbfeOmr08ePHLhPCLgTjnKHX2WdBkSmEYHUjbx65HECSLD8Rmzfb8RavN3UBgLgsq8jNzcWhgz/C6XJBVVQtHI6+COC0keW0Emb+/PmYN2+eq7y8/H7TNCHLMuJxA0VFxVAVDVwAHnfKDYMvvcxIivs0bA2JMpoNG9YdcDj0VYIDLpcLnAsYRgwerxPRWKTflCmTbu2wW9KNN9502eHDB/9imjFIkoKammMYMODXcLvdIETZ9Pzzzw5Lirp1MHTY1RVCiPxAIIjGQAOuuPJyVB05hngs9kPffv3OvfTS34TPO++ijrUlBYOBh0wrDkWVEQyFkJ2dBY/HA0ookxX6RFKspx+BQAAAoCjORRLVhNfjRSwWR9WRo/B4nZAUqeuhgwd/fTrIcloJM2nSpMsaGhp7y7ICRXYgGomiS5fudr0yxMFnnn5my/r165ISPs3w+XwYMGAAcrNz/2SxWBOVBLKy/di9ew+cTiccDolYIn4fACxb9sBP/rzTlkCVmZmxLhwOFsqK/Za6riM3Nw+UStB1x+h//nPr/j/9aVNSwq2AiooK/POfX0Z79+mbJwS7UJZkNNQ3oGu3rpCojHAoWnTddcNeLy29v67dNczjjz+KW28d3SUYDPeWZRm67kAoFEZmZgZ0XQel0v4nnlj9flKsrY/rhg6bC1ComgqHrqOyvAq+VA8cuoaKivIHO8SWdPfdMxCJhH/NuelVFAWqqiEYDCE1LQUgHLJEn02KsvXxyCOPYMTIkWFVUd6CEHC7Pdi9Zye8Xh9cLicsSwy8d/68rFdffbX9CPPkk08CAOLx+B1CEKiaA8GmINxuF9xuD4RAhHHxYVKcrY+ZM2cCAGRF2UCoDJdLRygUwvFjtfB4PNA0KbUx0NhvxIgR7UeYadOm4bvvvneFw5HfqKoKh+ZAbW0dCgryQAjAGa8dNOg/diXF2Tb405/+BFmm3wGoByFIS0vFjh274HKmwOFwUYBcDQBbtmxpH8LYNswj44x4HJqmQpIpTMtCaloqZEmBJMnv3HjjdVZSlG2DYcOGYf26VyuIoD9KkgS324uqqipIsoCuO8C5uBEABg0a1H6Eqa+vG0klu+cJAeBLSYGiqOAccDqda5NibHvoTv2PBBQOhwrGOCyTwenUAWL5V616qKTdtqSVK5enhkKhElWlcDgciMUMOBwKPB4nCEFs1apV3yXF1/YoLi5+lRACRdVgWRaiMbv0WFNVlJdX3txuhNm2bVsnzoXLbsnlRiDQAK/XC84BSZK3AL+8PrYdAUuXLj0oSYjKkgRdd+BYTS1cuhMOhxumaQxvN8IYhtlJkmRdVXXouo6mpiB03QlCKKjE/w7gZ9Fq9EzCn//8BwCAJMn/4FzA6dRRUVEBh+6GrjsBsOLHH3/I3S6EIYT0oVSCw6FAUWTEojHoTicIBChRtiXF1/a49trhCcLQLwUYVFXDkSOV0BwUmqaAEEk7fLii8FQ1/08ijGma58kyhUPTEItFICDgcrnBBeKGZVQnxdd+UFVlG6UyFFVGY2MQjAkoCoWmaQ7DNPJPVfP/JMJwLnprmg5V1RCJRGzXmsqgRIo6VGdjUmztB8NglRBESFSBZVkINDRCVmSoqiZRqpxye66fRBiLxQtlBVBUGeFwFKqmgVABLnjU5XI2JcXWPkhUPwYBHieUgRCBhoY6KIoGWZYhUbQ9YdavX5fBGaDIDiiSA9FoDA7NYffIJTDcXmckKbr2wZAhQyDLUoRSGqOw+wKGQjFQIkOWJQjRDoTZu7esC+cCsiyBygKxWDTR51YAhFjnX/BvyVTMdkQ8bpmmyS0BAUmSEY2GEx3RJYCIojYnzPHjx0oIBRSFgBAKzk3IMoXggGWy2KCLByWPBNoRTrfDIoQxISxIMmCaFgAGSSKQKM1uc8IYplkoSxIIVSBRCZwn2AsLgGUmRda+SHF7GeOCcy4gOAVjFgTsqlTGWVabEyYWjfmpJEOiMjiHPTJGcAghQVGcSe3SzjAtBgjSMiQDoODMHu8DIfQ2J4yqqumUNP+5bcsIDnDBYFoxJSmy9nar4xLnjHLOIEkSKBVgLA5CKQglEEIobUoYyzJVQgB71gOHJMkQgkMIAs5E8jygncE5qGlZxDDiEMICpQpMywKEALFTuWmbEoZzLlFKIQAwZkGSJFiWBWZZYEw4hBA0Kbb2QzQWUikhiiRJEEKCQ1fAmAUu7B4969atlduYMMJhTyqj4IJBUSQIkbBluHA888xTelJs7YOvvvoKlsmdAHGYJgPnzO72ZVrgnIBAghBS22oYVVVDAAeIgGkg0eLdgmHGwWFo1UerXEnRtQ8uuOACECJSGLMcQjBIEoVEtQRZAEEsjBkzxmhrDdNkz1E0wbg9fMqyGDgT4IzrjYFGX1J07QfGWL5pGgREQNUUCBiwmAHLsiA4QAiJtylhGLNCRMjgTILgBJJEwbkdIBKcO03TSE+KrR3datM8TwgBZgEeVwpMQ4BZPDHgSzrlrLZTJozb7TrKhQnGTXBuQQhAkgi4MGBZpkwJSpJia3u8/fYfE4RhA0zTAoiAy+O05SQYGLNAJBEATi0b8pQJo6jKYS4AJMbxCiGgKDKYJWAxgZhhnZcUX9tjyJDrAADxeLQ/pYBpxqHriRFCwi5jFoxXAaeWDXnKhMnLyzvAOANjPOEdESiKBtMywZgBy7T+HQBeeOGFpBTbGPPmze0TjcZlRVFhGhYUWUkcDxi2hiGoOtX3lk/1D3v17Hn466++ghACpmUCYKCUIhKJwONxIRoP9xFCyISQ5DFBG2PPnt03M2ZCUXRwzqGoKriIgQsJnFOAkIo2t2GGD7+hXpJkYU91tc8oJInAMCxQKIjH4pgxfcZVSfG1PYKhpmsIoTAME4qigRIZQkgtI5CF4IfblDBHjx61/5hKhznnEBwtw8UNIwaTxQBB0RCoGZMUX9ti9OiRxUbczAOxZ3Hrug4BkQioApbFQQg51KaEyc620ykIRRnjDIzbZ0iESOBcIBqJgxAgFIr8+snVD7uTYmw7NDU19WaM+XSHjng8DpfbCaA5BE/BObM4Z1UfbfnPtt2SAEBVtB2MMXDGAQgQCCiqjFAomDhbEinffrOzd1KMbRl/MW40DIO43R5QKiWS8gkYtxKZBPG415tSPXjQpW1PGMbYDiE4BBKEoRQylREKR+D2uGCapmZZ5n8kxdg2EEJIwWBohKY5YDETsiJBkggEOAgoLGZAcMS7de1V2eZGLwAI8B85F6bgAgIcdv4oBYSAYZhQVQ3xePx2AFiwYEFSoq2M4cOvmx6JRKnfn4lwOAgpkftCCYWABcsyIctyzejRo4PtQpiM9Iwqy7CiggOCU1BCAUJACMGxmmPIzc1FUzBUNPOeKZcsWrQoKdFWQm1tLaqrj8r19bXTVU2GJCkIh+zBqxJVQIgMwRVwRuFwOP/2Uz7rJxHmjjvGVxJKo7bRK0CIgEQlEEJQV9cAQEDTVFRWVCUnULQiMjIyMHHinb+JxeN+TdUQDodACIEk2bIQQkAIDs450tLS3m43wpx77rkxXdd3WZYdmyNEAoiAJFNYzMKxY9Vwu3SEQrGzJ02a2HPAr36TlO5pxuzZswEAsVjsNtNgit+fg/r6RqiqBkppIvxPwDmHJEm49957P2o3wgBASkrKZsuKgws7K50QCoBAliRUVlYhy+9HPBbTGurrb/r8H39LSvg0Y+XKlXj55ZfTg8HgbW6PC4CA4CYkGSCU2ym0xALjJhSVfksIMdqVMJdccvFGSpVE/ZqARGXIkgJKCMKRMAwjhrR0HyLR8JRk2mbr4M0333zOMGIoKspDbV0NCKWgoJCobItYUAhO4HC41v/Uz/rJAhw9+rZjbrdzG+ccAEmMuCEg1D4ZLSs7gN5nn4NIJJ4+duzYe5PiPX2Yf+88jBo1uncgELjK4/GBMYH6ugbIsgIq2WQhRIALDofuMLJzUre2O2FsoyvtTdu4AkAEqGQXTFFCUV1VhUCgDpmZaTh2rHr+ipUrfXPnzk1K+ydiypQpeODBZaitrZlgGjHNn52GiopyyLLSYvBKkn3TUkrRqbgg4HZ693UIwqiq9tecnByLWRYIJBCi2F2oqARJovhu2zYUFxchGo05vv3m6wnLly9PtjL7Cfj+++/x1FNPYfHiJTnBYGiq2+ODpuoIBSO2dqEUmmZ3agCA3JxcgNAdEydOq+0QhEnxpe5XNa02PT3dJoIQoNQ2gAmRUV/XCCEkZGRkIhQKzX788ccdhBD84Q9vJKV/Cujbty8A4PPPP9tkmgZ69uyB8vJyEAmg1C5Z1jQNqqpCVlToThWKSk/LnOfTQphFCxcf58zclp6eBru4zX5elgkoFQAsbNv2DS7sfz5M00z/8ssvngOA4TfclJT+KWLI0GuGNwUbL/T7/QgEGtDQ0ABZkkEpRUqKJ3HDCkiUQlMdbOb0OW92GMIAQHp6zlOWZdn1SRCgdjkm7BleFOUVlThSWYWSkhLU1taNvnPiHf3Bk4L/V7B9+3YAwIoVy+VQMLTINBny8wtQVrYXsmwfMjbbLYwxRKIh+LMzoSjyywCwc+fOjkOYpUsXb5ZlOeBL9SUGnUvQNB2KooJSCaqi4YsvvkRBQSEYE6g5WrMUAGbNujvJhP8lJk2aBADYuvWrxY2NwV49evRCbW0t7PmaFIRK0BxqS6BOVR1IT0/nAFkHAGeffXbHIEyzAauq2hPZ/kwQIqAoCtxuDzweT0uI2jAMlJXtxoAB/RGOhAZPmXLnVQ8//HiSCf/L7/jzzz/HhAkT+lVXV89LS0uDLyUFBw4cBCEUkkxBKYEiK4kbVkFBfiGYxY94PO5dp8vJOC2Eac4+p5J4yzSteGFhIRizYFmGfXp90ut27doNSabwZ2Vj794f3hw69Nq+STr8/3HttXa26+HDhx42TQPFxYX4/vvvwbkJQgQgAFW1qwMMMwZCBNweHbIsfTRhwuT609Uv+bRGXs8759f7YjFrX3paOgiREYvF0BRshCyTFlJZloUtn3yKs3p0Q/XRamfN0ZrnJky4Q3E41CQr/h945533cOuto24OBht/W1CQh3A4gqamJlAqJ7YjAlWTYZomIChcbh2SRFFQkLf0dK7jtBLmlhE3xrxe70bTjCPF64YQgEPVIQRFoqoXlEpobArix8PluPTSwYhEIxcCom8sZuCBBx5IMuN/wF133dWlvLxyo8PhQlFRCfbt2w/Q5rM7QNNUO+9F2JkDRUUlUFXnX0eMGHPw+uv/vWMSBgBWrXpkBWMS8vILwbkA4/YkDU1X7WYPwk7l/P77HcjyZ6BHz56or2/8CLBnXyfxf2PBggVyWVnZE7FYjHbq1Am7du1ALBYFBUm4zwS6wwXLNEGohJycHKiqDIdDXQQAb731ccckzPPPPw9CiPD5fI8qioT09DSYpgnO7bxfAoBQCiEI4oaBz7Z8hh7duyIYbEy59bYRTwkh8NxzyYl/zbj77mkAgIMH990cDAWvyMrKhGHGcPRodaKrFAGlMjRNB0DAmF25kZ+fC8syDjl07dtEz97ThlbpFPW7383sHGwK7pQU4vju2x1gjNmlmon4QLPalCQJ/fr1g8vtxt49e3D++Rf0ffDBZdvtZKxkEysAeOihlUXvvvfOYUoJevbogW++2Y54PJ44L7I9I5/PB9OymzFkpGei+1nd4NS9j82dO3fG6V7Pad+S9uzZg4GDfvujAP8Swp6rTAhNuN4nXDtKKTjn2L17N1J9KUhNTcWevbvfSVRL/uKJMnXqVNx33730k08+fsmImyguKsb+A4cQiYSBxFZk2y72EUBzfVhRcSEoldC//4WtkhN72gnTo0cPXH3l1Zbfn7sqGjWRl5sDLizQxBUSAlAqJY4QCOLxOD777O/o0aMXopFo4c0337Dm5NjOLxGPPfYYVq9ejcrK6luagsFB/qxMRCIRHK2uSXhFdgSdSoDu0BAMhiEEkOX3w+nU4Xa5Hx406LeBM4IwzVi8eMm7TqerTHc6kZmZYZc6ENKSkXfyRzc1NeHgof3o2q0EgUDj6PHjx51LCMGSJUt+kYSZPn06Zs2a1bW8vPwVTZORk+fH4UPliRtOAKAgCQ8pFI6BcwZFUdGpUxE45xFNUx9rrbW1CmFeeeUVAIDH6xwbj8dQWFgIWbLbyv+X7SmhZQgBfij7AW5XCrKz89Ta2roPAOC+++77xZFlydIFWLDgfm3nzp0bYrEYSjp1xe7dZYgbpm3kSgClApQQ+0FtOyYjIw2EUMiy9NepU6cfef/9d84cwowaNQrPrHkSkiRt45zvpFRBZmYWAAlCsMT21BybsROvGGP48ssvkZeXA9M0M26++ab1vzTSXHzxQNxXughlZXsmRCKh/n5/FgKN9WioD9hbOLU1MyEyKJVBiAwkNHdBfjEgBHJyshcTQsQVV1zTKmtsdety5oy77w40Nj6mOXR88/VXiZIH2z6xU2fsk+3m9M6ioiIUFxfg++3beUlJl4ufXfPc56+88gpGjRr1iyDNrFmzzv3mm6++cblcyMnJwfbtO2BXZYhEFYAMSglkmSZOpgW6dOkKf3YWPG73X+699/4rWnN9rZ6U/cijjz8uy1KQgKO4uBgCwi5HAQBib002f+xIcOWRSnBOUFTYidYer9382msb3b8EsvTu3ROlpXNcu3fvfF0IIDs7B/v3H4BhGCDUPv23Dd4TwToAcLnd8PtzQInEsrPzprb2OluVMI899ggAICsre0I8biE9Ix0et+eEchPNFy4gBLO1Dge2bv0nMjJTYRhx36ZN72wSQpAXXlrzsyXLzJn3YMeO3ThwoLy0qampa3aOHzU1NQgGQ/ZJP6QTB7yUJrYj+6bLzcmDEAxra1UjAAAQCElEQVSyQt/PzMw49Ic/vNWqa231Lenhhx9GZWWlGg6HtgO8e1MwhP37TuQin3CfSYvrLUkUWVlZ6Na9C3bt2IucfP+NL76w7vczZt6FRx954mdJmsmTpw4sK9v1V01TkeXPxq6dO1u27xMhCZoI1lFQqsDt1tGvXz9wzlHSpeSSO8dP+rS119lmEbJ77pk5rbau5gldd2H3rj2IRCItX0hzdV5znAagkCSCvn37gBAJR49WmZf8dlDB9Ltm1vzciDJt2lRwzjIOHjz4XTgczu/WrZvtFcUjLW40oXbvHUqayWLbL3379oamaUhPz8DcufPbRJZtVliWl1f4umVKMA2B7t3Pwsk1TCeWQRIE4uAc2LZtBzweN6gklK3//Md/fv3tNnn06JE/K8I8+eRqHDt+fGE4HMrPzslGRWUFDDOa8IZIIpGeJoKdUsKWkZCVlQ1Nc8E0BXy+tE1ttd42I8yMGdOPu93O2lgsCkIocnJyT9IsiQ5JCXDerIIJtm/fgeLiYtTV1vVZ88zjEzds2Ijly5f9bAhzxx23j66vq5vi9fqgyArq6wIQvJkoJKFxT7b37Edubi4sy4IkScHa2roJAPDDDz/8PAjz2Wef2QZabu7I5lTNLH8mqHSiWByEQMBCc7WeEAKcczQ2NqG+rgFdu3ZDXW3Dk8uWPZg7d+68M5oke/fuTRi70/OPHKl6SgDIyEzD/v0HT4pT2eF/Qu2tqNnoFUKgpKSkJdmbEPLyDTfcUAsA3bp1+3kQ5uKLL8add96JYdcN+VBzaJ9Yln3a2rlz15ZTbIAkAnmAEBwAAxf2LKa9ZfvAhAlZIdixY9eHLzy/xrFw0Zkb0JsxYzoAoLKy6olQKOzJyvSjovwIGLe7YAiwxEDPhIY5KSKemupDaloKBDgYt2L9+p6zoHv37m128NZmW9Kzzz6L3mf3FZkZmQ9wLmJG3ITucCAjI+O/pTKIhDEMENhaRgiOst37kZdbhIaG4z2/+PKfkxcuWILzzjvzmo2/9957eP/9v+DOO8ePra+vG5aamgrGLASDwZYbxtYoooUkEqWJQ1t7K2KWgFN3ff34Y0+4Ro0e2fDii2vbbP1SW35ZZ53VFZs2vX3okksG/plz8wbGLafL7URtbS1OpD6QFk9JNO/bVIBxDkqA/Pwi1NfVXTps2HV/euONN844r6m+PoDLLr+kS2Vl5WbLMpX09HQcPnwInNshfgHbI7If9g1EiQQhBPLy8pCWlg5Kgcws/4QBAwb88Mc/voURI9ousNmm7Tf27rXjL4MHX7bD5fKuYoxBUWTk5uaAMYbmcyWbLKxF8xBhD/IqLy+HacYhywo5fPjwJ6+//qrzTCPM+++/i+PHGh4OBsN6Wno6yit+tEfSJGw2W8tYLRqFEgkAgcvtgt+fDcY4fL70T353z+/eBYDrrru+TdffLv1ahgy5FrfeNulxTdOqjLiBjMwMeFNSAPBEYpDd9fFEcM9uG0qIhB9+2I+MjAwEg8H0jz/5aAkAlJaeOV1Ebr/99rsDjcFrPV434rEoYtF4S3jBslji3EhKbM0k0TOQIy83D0IATqezoX///kMB4O9//7jN198uhPnoo7/ivHN7xHqe1fsKQikY48jNyYYkqYmRxiRxMita+rMh8dM0TVRXV6OwsBB1tfUz77+/tM/SpQ92aJK89tpriSDdXb2PHTv6kBAGvF43qqqqE3En+/ReUVQoitKyFdn1RgK+1FS43E5QSoXH41l0+eWXBwHgoov+/ZdBmMGDL8HKlSswY+bM7S6X+xnLNOFw6MjISAcXLOFW85babNGiaQDOOaqqqhAMNsHh0HHw4MGPH330iQ49/e3JJ58EABw9WrUqHAkrvpRU/PhjZUuJSHO02zZ0RYvBKwSBrjtRWFAEAPB4PPvnz5//9KZNm9rtWtqthdjs2XMAAGf36r2QUiViGCay/BnwetwgVCRa0SeSrQRaCCRgAuA4fPgwPF4XGpsCGbt3bV86bNh1LYlbHQnzS+fhiy++wIQJE6YEAo2XpnhTEY8biMejAHhLIE6A21l0FBDCrqyglCI3LxsQDLrDgT59ev+WEGIOHTr0l0eYZkyePPVYYWHhOEIkQEjIyysCBMWJYwJykgclwJmAAGBZBqqrjqIgvwiBxsCUbt26XTRq1Cjcv6Bj2TMPLF2GaXdN7VddXbWaUgJFVVBTcyzx1ZMWLUNgXz8EbbFpUlNT4XI5QSWKFK9n8U033Vy5YcO6dr0eqSN8qZ999tnOiy4a0DkaifRVVDuVMxQKtajpRESz5Qtu/ncsFoHL5QQIEI4Eb547d9Yzd02bFesoZJk7bzbqjsbg9KhvBAL1Rb5UH6qrjsBiVss90JwMj5acZ5s+uu5AcXERQAS8Hl/N8OFDb/j2u63W6tXtW7fVIbpazpgxHbk5maVUJk2WFYc/2w+329lyvGSPb+EtRjDnomUK3I8/lsPtcqGpKeTc8snfHgWAhQtL2/2acot1LF+2Er8eeM6MYDBwscvlRiQcscfP2LGCluuxDVzS8lOSCPLzc0Ephe50oFv34iv7ndM/unXr9na/rg5BmEWLHkHpfYvKSzp1nghIsEyO/PxCyLKS2JbQskWdODYwIQSDZTFUVdXA789BfcPx2xYuKh2wcOFSPNvOFZRVh6O4e/rEC4/WVDzMmYDD4UR9fcOJFFVBWzINT1RS2IZueno6XC4vqCTBl5I6f9ztU74dNfL6DqE1OwRhvF6K0aNHYeHCRa+lpqb+nnMORZGRmZma+HJPPjpIbE3CHnvMOUdDQx3CoSbouguHDh7+8OmnHku9c8Kd7XY9+fn5eGXDRunIkeOP6Q4nyS8oQHV1ZUvV5wmPiLTkMzcTx+FwIDc3HwIWXE7n/vMv6PPEiy+9gFc2vpUkzMlYs8bWCMXFxdMVRQ6YpoWMjHSkpPjAuUgcUtrL5VyAJ1S5AAeIQGVlJTIzM5CZmaZ//fXXTz3//Gr63HPPtfl1zJs3D5WVlfj753+bEY/Ff9W7T1+kp/lgGAZA+EkpqUBzq9rmbUmSgKKiIjBmwqnr6NWr1+VXX3lj6Paxd3QYI77DEMblcgEAZs2aVVVQkDeZUgLDNJGdkw1ZaR6ycMKOIYSA88SUMUbton/G0atnL8iqektZ2aELJ0yY0BIDaSssW7YM8+fPL6murnooPz8XbpcTwWAEWf6cxDaUCBnQ5tJhO+4iwOFLTYeqSVBUCZmZ2feNGTP2wLqXX+xQXl+HbOW+ZMmDr2VlZf0FApCojGx/HjhP9EIhAoQCzZ3HBQRMM478/HwQAtTW1aNbt+4IBALv2NHVaW2+/srKinsJJehU0gmHD/8IzjlysnPg8/lOeHyCJpxUO+bicnqQm5OT8JCcTS63tgEAbhtze5Iw/xuoGlkiKxJjzITP50Zaeqo9EZUTCJ7wnQSDEAw+nw8ZGRlgnKKi8hBcLie8Xk/GAw88eEVbr3v16tUaCHqd3asnGgONMAyzZdvJL8iFJEuJ7UiAUJ7YiiiKi4rAuYDD4YLL6Vl+9133/NgR5dIhCfPSS2uxfNkjX6R409bbvWTi8PszoGlqSwDvZBQX282LBDcgOHDkyBF06tQZAqxPW6/dEo00NdWt67oHgcZAwpszQSULkiTjrLN6glI7JABBAQH4/VmQZHsrcrkcLy1evKTD5qB2SMKMHTuu+W69PSUlZTuBBME5cnIygZOPDCDQ6+yekCTb/bYsEwIETU0BxIwQGDO7tfXamxqj3DRZuL6uHpbFbG1CqZ2nLACJKijqVAhC7G3V5dGR5c8ApUBqatrHyx5cMW7RooVIEuZf9prswrXf/nbwr1xu/SuLMTgcbvizM2CaBjhnKC4uASUUjJtg3AQXJNG8CKg7XofGQGPm7j2727TZjNuVxpiFqGGGW7whO9yPhIHL4fV40amkCAWFuSguLgKzOHy+tLrLL7tqKCFELFiQJMy/jIkTJwIAbrrphsi11141RNNUWMxEii8F3bp1R8+efeDxpIAxAsEFBOfgzPaYmMVhGIBhGKzHWT3aLN+1oaEBM6bPsAgVxyyLA4JAogoAAkoUe3QRLAguw6V74fOlg0CBrju435952cCBvwk1J8wnCXOqburyxRhy7Q3VuTl5QyghsEwLiipDkgg4NwDBwAWDAIUQJjhMcFgwrTgoUb5qy25WF1/8GwKAxKKxYosZCReaQSDx4AwEMkAsgHJwbjdayszMeW7WrNnfrF+/DhdffHGHlscZ0Rvs7c2bcO1VQ8j48be/GQgErydUQFHkE/OAiAIpUbIiSTIoBUwrDlXRNrmcKTeuevghs63WevXVVz7tcrkm6boLqiYDgttBRsEhINtVWEKAMTv+4vdn/7h8+fJinCE4I0bqDbl6KAghYvz4abd5PK5Ky7RgmhaYZR8bcMHAmJWY/m4gbkTg9/tx/Hjd0MamwD0AsGLFylZf59TJk0c1NjVNisVi+PWA/ojHYonqIprwijgYM8GYBS7icLm1YH6+fzAAtGdS1M+OMABw8OBB9O9/bqSoOP8STVMtZnFwZsJipp2+2ZIHbHfnLCgowv79+xEOhx58//3/TJ0zZ3arrW3r1q146OEVesWRH2c6HAp279mD7779FpRKMGIWeKIzhX3KLsA5gyzLyM7OXjF16oz9ANCeSVE/S8KUlJTgxZeew8IFDxxITU1fwTmDYVngjIMLbntHwkQoFMPx4/V4+qln0LVrN8TjMbz77qYZrbm2Cy+8EAf278syLbMnpRRdOpfgL3/5ENu370SgMQDLssAYBxe2FgQRyMrK/LB0/qIzrvX5GTXl9faxEwAAzzyzpjQtLW23ZVl2pr3JACEhEGjCtu++xY7tO5CV5Uc8HgfnQCQSO7e116Y7nB7BhcY5RyQaRVZWJqLRMD797FPs3bMXXJiJllsEbrenJjMj6wYAWLv2hSRhWhNvvfV7AMDZvXsO0lStnjG7P15TUxPK9u4D5wJpaWmIx6OIx2MwTQOEiEBrr6uxKVAvgHA8biIeM2CaFiRZQUF+AaLROIw4tjOLQFFUZGdnz541a05jRUUFxo27I0mY1sT119+AFSsewMwZs48VFhYtJ5RDlqVqj8dToygyNE2DZVkwDRPxuJ2tmZdX8ExrrkkIgSeeeLBalumHRjwGwzTs4jTOIcsyios7fZiZmXF+dk7O8IKCohH337doPQAUFBQgiTbGlo8/05v/feml/7H+3PPOEX379hHnnXeuuOSSgebt48bMB4Dhw4e3+lqEENLAgRe92rdf30jPnj3Fueee03TppYPXv735ef3k153J/YfP2En17777LgBg0L9fHG1+LjM9b0z37l3PzsjMWJmdnbPkrLN6dLrqsuEPAMCECRNadT0T7rwDhBA2YMCAUbk5Ofk9e/bsm5OTW3T99dePGXL1+OidE8e0vPaX2H+4Q2LaXZP+r+fmzWvbXjJLly5NCiKJJJJIIokkkkiig+H/ABIDiXN1ApuQAAAAAElFTkSuQmCC", + "strings": { + "initialNotificationDescription": "Tap to pair with this device", + "openCompanionAppDescription": "Tap to finish setup", + "updateCompanionAppDescription": "Tap to update device settings and finish setup", + "downloadCompanionAppDescription": "Tap to download device app on Google Play and see all features", + "unableToConnectTitle": "Unable to connect", + "unableToConnectDescription": "Try manually pairing to the device", + "initialPairingDescription": "%s will appear on devices linked with %s", + "connectSuccessCompanionAppInstalled": "Your device is ready to be set up", + "connectSuccessCompanionAppNotInstalled": "Download the device app on Google Play to see all available features", + "subsequentPairingDescription": "Connect %s to this phone", + "retroactivePairingDescription": "Save device to %s to connect more quickly to your other devices", + "waitLaunchCompanionAppDescription": "This will take a few moments", + "failConnectGoToSettingsDescription": "Try manually pairing to the device by going to Settings", + "assistantSetupHalfSheet": "Get hands-free help on the go from Google Assistant", + "assistantSetupNotification": "Tap to set up your Google Assistant", + "fastPairTvConnectDeviceNoAccountDescription": "Connect your %s with this device", + "subsequentPairingDescriptionOnTv": "Connect %s to TV" + } +} diff --git a/fastpair/rust/demo/local/706908.json b/fastpair/rust/demo/local/706908.json new file mode 100644 index 00000000..3a77259c --- /dev/null +++ b/fastpair/rust/demo/local/706908.json @@ -0,0 +1,40 @@ +{ + "device": { + "id": "706908", + "notificationType": "FAST_PAIR_ONE", + "imageUrl": "https://lh3.googleusercontent.com/9lYIq9GW5_tZ1WaTYsrU7NMc5MP8AgOcsHB5K75MlfeqhwIgm4jL_ilMtP9aLYEZR_6jx4rLI2-2-uYDjg", + "name": "Sony WH-1000XM3", + "intentUri": "intent:#Intent;action=com.google.android.gms.nearby.discovery%3AACTION_MAGIC_PAIR;package=com.google.android.gms;component=com.google.android.gms/.nearby.discovery.service.DiscoveryService;end", + "triggerDistance": 0.6, + "antiSpoofingKeyPair": {}, + "status": { + "statusType": "PUBLISHED" + }, + "lastUpdateTimestamp": "2020-05-19T17:58:19.881Z", + "deviceType": "HEADPHONES", + "trueWirelessImages": {}, + "companyName": "Sony", + "interactionType": "NOTIFICATION", + "companionDetail": {} + }, + "image": "iVBORw0KGgoAAAANSUhEUgAAAKAAAACgCAYAAACLz2ctAAAABGdBTUEAALGPC/xhBQAAM1xJREFUeAHtnQmQbVd1nvft27fn8U39RumNPEkPDQ4gxBBsSgzGxhRIFqkQpZxEGFJFnAomGMrBFckVQJghYEDBJgQsT2WJqRDEDjbWYM1CehoAlSae0Jvnnrtvd9/u/N9ae597+r5ux1U4Cbf77O5z9rT2Pufs9d+11h7OPiEUrmiBogWKFihaoGiBogWKFihaoGiBogWKFihaoGiB1dICpdXyoP8Yz3nNNdeUfzw93d47Ntam+lqnpqbK1NvZ2VmTNzfW2zuzs6OjeuuttxIv3D+gBQoALtNIl19++Y6FUuubagu17WF+fltYKA3Nh/nBsBB6wsJC50IIFRVticXn5c+WSmEqlErjCp8tlUrHS6F0sFwuPV9aWPjLBx988ECkLbxcC7TmwkUw1wJT1dl3t5YXPlCbrwlvC3YIfOYUy1HWg/5r1pl/oZFjfr4lzNZqHxPVB+uURSi1QAHA1BIN/uzMTM9867wDL+bV1UUKJSCWBMkUDovKtAiEtbm5nobqi2hsgQKAy0BB6ratUmoJ8p0CfLlw8wCpAhfS0YILCZRGZmmWgxRUXZZQnM5pgQKA5zRJTFgoVVChLZh5AE9hOyzbwZakHhhsaXEw5tU1+ZSR/Yi9WLglWqAA4BKNQlJHe3u5vbNd2HPgtbS0OJiUlw8DzqR95+ddZQPCfFhALNqZRl3CFQ2zRKOQ1NPTUyq3tpqK7enpNr8mgM3NzhoQW5W3yEnSzVRnQltbxQCK+p2emrZyrZVWG65ZRF9ErAUaWrFolXoLlCrlsuNmbm5OoEMZt4T29g4jMdWaiIU21G1HR4cBbn5eMUlByuPPzdWKdk5t1eAXDdPQICna0dFe7uzsCrNzs6ZO52u1MC8w5W28RGt+zk6k51uSyq5UKgFJqVghARc1Vj1SALDeFotCwyMjrdWZmbAgtSvxZ2rXuh50KuTyYWxAJCAOgKY44RZJzqnp6aKdrXXOPRUNc26bWEq5tSwTUDag1Cloy3rAEYBLFkNCkmEY5KResCRhy2xLIQGXbDDNZy6TvuqT1dMVBlvDfMt8HXwoUxd9S7RPHXwg0FS1qFDHZbrNhVuyBQoALtks+mWWW1uQgPMLAqCJQARhVL+LQGgyzyUfdWXSDwEoFazxQaTpMpdZ9ckFAJeBQLmlJB1cDqV5YIcOjgD0IDp5cckEPKVmdqAB0HrPhQRc3FpZrABg1hQNAalNBNe8OhFm/xneHH1pCCZB0GRgPOGZ+hX4kIYll4AFABuaN0ULAKaWaPArrZVyq4ZRluoFJwBmRXLgE/pMHScQYv6Vy0UnJGurhkABwIYGSVEBp6WCDahhGJeASD9Xx43aN5Ux0CniKtg7IvSCpcuTsEykhR9boADgMlDQ7FkpSUCTeIDPAKgCybeyYKveA3YQxl4wNqBo1ZkpVPAy7VwAcJmGURe4zExGJgFTR0SAwjWKNNfCdkYLRztwXr3gsoZhil7wMs1cjAMu2zBSm3kVDORcEp4LvlQHwEvSMG8DMpxTuKVboGiZpduFsTtbDVOqYQOide0UJR9gPLdgAh05KYzwU12FCj63uSylAOAyDaOVLBqGUSekVMvAhz1n8g8sZuUI5WxAwvSE40EHmLq8oHWQs5JFoJiKWw4DGoUWACsCYC2NAyap5+hzACYYJgDm/AhAtwE1mFi4JVugkIBLNot+mS3qBTMMU/JhGESeqWHRG+wadbAbgJJ8Lg/zElAdmmWuUiQXLbM0BkrSv7agFLAtsv9ywMuAiLRL9Zjkq4MQFawZFatGJBlZIl/tfgHAZRAg4Kj/4GsIAGAGNtHnw1nxHAiRfohCfMw/VZRswIy8CHgLFABcGglaga85DM1iACIDYJR8i9SwyiLSAKSJNkBHfdF3AJZ5R8QwS1bhFrdAAcDF7ZFigpuWw+QBSE5OEiZEGeDIIj8HPAMl4FUdpQVDbyoCZeFiCxQAXAYK6oP4auY4F2zgSwBMZfJxwEc8+gmM9n6ImYCpUOHnW6AAYL41cmF0sKleJFgCWs7PkWYq2KSeaAAfjjNlZQUW0s9a5NxTAcBz24QUaU6DoEm1c1QvIGtwKQUf4HFYzwMAZyPYDYWKaDEXvBwGSjLfAJ6BT34GsCXAZ3Uo3eSeTnkSyuWKL3e5VZtejNAvzXrUr+HIgBdVKikGsqXLuNgTRUYTkUg/WkUShpcrvSrTCwAuw3ZhTkJQmIrgg8zCufi5RevDMJYnWupQx6QA37mNZSkFAJduGADDIKA8l3qNQHRweuFGoJJqaVaak80FFyCkYRpc0QlpaJAYtVfZHEQuCm0oD0CiTfFj2F9cj2mxsJWLNIQjAIsfe2yfvFcAMN8a9XCL9G8rLyTZIdDlx/cyUQbIcPJjqB6PaSXGERdse7YCgN46i84FABc1R4ysWaNJ4FIrajepXgAGCJGACWwAMYWtJPkpLQKQJf1ytHPxcjot0eAKADY0CNGtXV2t2mKywn6ABiDrxDqh941joQg4U8skRdBZbi4sEFf6tm5tHT10KBYsvNQCBQBTS+R8vYxUATTaXNy2ZCMrU7sRjOdIv1z5TGoCQgPiQmWt6hzN0RRBb4ECgEsgobu7u02bTFbmtCdgtjsWdDlJuEQxS0rgQzcTZnMj6mpRncuVWc3pBQCX4H5bW2+7VG9lVtvxolYBns2FRDGYSUOTi3Ur0EIAz9Fn9mGpxrdC5isdbW3tS1xq1ScVAFwCAu3toVM7olbYDxpQAbjcvIgJQk93RWzAox7AKuqodmM8hJrq0qbnnZAUbnELFABc3B4W0wLS7tm5udYZ7ZCKA3wGwJz9Zxm5k4HQAAjufFjG1LEyZEtqb4SW7hx5EYwtUABwCSgslMt99H5n2BFf+Ql8WTiVAZAu9Ax0lpwDnwFRcUlAsnpTscKvt0ABwHpbZKGW+VI/9h8gBHzs8wzW8kC0hFRCIHSZF6UfIOSwYRwAOMcuqf2JvPDrLVAAsN4WWUhDx4MAkM8z8F6IrWoWAm15vWQiYMTWM/EooOE4u8pVzzeBTz4gti3eagtrjLA4LWqBAoCLmsMjCwvza5P9x3shAC8DoYtCw14qahCMUtAlnwOP7X0BIOisLSysTfSFX2+BAoD1tshCAtE6H4IRcHxFs6thraxHDbsAtLOXQeIpZOAz6YcUdMnHbApOduA6CxSnRS1QAHBRc3hEUmsI9YtrWZD00zd/GVCWbYghKABG9evkJuEMgkhBABglH19M4nvDEZ0bEnnh11ugAGC9LbKQZkA6pqenLM7eLmYHIv0y4CH9kHkJcPg245GBr6ZdteYFPrMBBcrqTLUYB7QWW3wqALi4PcK+ffva2tsqu1hDaj1g7D/UMJLPBJ9LwXwxl3raircFOYj9p7VcZQFQwEsAlCG5O+wO7eHZUM2XXe3hYo1aAwLWr1/fJz27eV4SjHlgDgNRCpuNp7zoe57HDXAm+bzzYd+X0xgg44Cq77ztc9sHGy636qMFABsgIElHb7UfSYaadR8iV7lZSAA0J89CnCwN9YzDT4cWA7aU+lo7OzdbVnHKWqAAYNYUHpiem9uqcbt2V6sNmTGaIGbAU8TihjWPZLaiZaiQgKmhnHJ7pbJ36RpXb2oBwAbeC3x7DFKGriA7TqtZFK7Zi22shlbcDpqOPNLy4VLQnqomDL2MS0gfvml5ecPlVn206IQ0QEC22qVspmEdDr0Ysq13imk02yHh1HRn6GufCb0VTdNpeOb4VEdY114Nk3PlMKOdVHsrMwbUttJsODHZGtZ1VMPzwxUNxSAE+W5cy5V0cn74wx/6KoeGa6/GaCEBc1y/5ppryhpNeYkNIiudXf129U+Foa5qGOqshjUdM2Fv/3g4PNETKsrbo3Bf21z4uXXDYXvfhMBZC6OzlXBeXzVctHYyVPWh9Hm9CsJcMk77DV40Xyr9vEWKk7VAAcAcEI4fP75T43n7kFZx1C+cqVbs6KnUQhvDLFLHXa210F6uhdn5sqnkHw0PhvUds6FSXgjjtfZwZKIrdFcWwolqd+BTD3z0ECnKB2u0LvV9umSyDnNXX53B4k2tHN83bdl2rYZS3gI62B2VTywIdlK/reFktSucmukOY3MdYW3nXJiabw9Hp3vUuSgr3BYOTfWFyRq0gLIlDM+0q6wsHBs/ZAxRtQq82nd117bt5z176ODBJ3KXXrXB4pcYWf+ud72rsv/RJ+7RuN7L2FGXz3TxpaRymcNnQ+xzH5JkbJoAntj2jw4J3ZC6YwxQ6fRclMs4IeOAdmh6j/dMBMaTF+3b99svueySb7773e8+VS+7+kIFACPPX/0LV755amL8W4rqC0kCX5sD0FWo1KhA2LgyxqQb5ZFysR5UtI0dKoAqZzHCIgDO1WyZ18DgQNi790UvDAz039zf2/uH73nPew7GKlaVl9ptVT1048P+xm/8RvuDDz9yx+zM7BV8I7hSaQttbW0mAQEin2sg3eaF2XQ8p1ZNtRoA1ZS51gR8GIz2brG6wSxK1TJ/Ax8LHXjfpL1D6nzN2rBu3dpjG4aGfn/DujWfu+6668Ya728lxwsbUNzt6u3/d9Wp6XeiVlG9bQKdHw7ENtQxgMykokCptHSgqpGUrZKcfNwGwHrcgWudECSoSVHvFTO/XJM0HBsbC4ePHOmZGJ+4UpD9xbf96tXPfvev/urASgZd/tlyv9l88uoJv+Utb7nk2PHTd87VZgfakHztbaFdYGtv75CEag+kJVChgpGCSD02vsf3wxcrmARE8mEVsjpG4XNsQEk/FrvOziINZ009QzcxMWEA3b1798z27ds/+qY3vv7DL33pS/Ve6Mp2qxqAH/jABy6+7/6H/nR8fPxipFS73sfk6BD4Ojp1KGySz4ZSZAcKfHRQbIW0wFgHoDcjZ+CH+uVgQUOy/+akgk31CoAsdp0FhFElQwNQASZA3LZtW7jggr1ff+k/+bl3XXXVVadXMgRX7UzIJz/5ybfc/8BDfygVOKRv0pjKtM4HKjhKQcBn6hd1G0HoawMj+EAGUjAiJA8+3gOxnJhJx8RAqXSAXMOmVJj6oGXdNHZmV1dXeOGFF1DNV01NTW36k6997e3XXn31oXiJFeetyoHoj9x447sfffwHtzz77HNDcBTGl82Gk+2GPQfgIugS8Mr6cuZi8AleqGQAiDQknDuQjiAT/BFMHRenR4XX6U2SOqWdkcKnT58ODz/8yCseuPPub952221bVhzy4gOtOgn44Y9+7H2PPfb47z35oyfBgqlYwOVA47tu3nEAIA4iIASI6qBBkrHUvjYb1/pJgpGGxMM2tG8Eo6512DScyjIuaDUpbHXFBa+xcvPyYe5jZGQkPLL/kZco/ZbHH3/8zZdccsnZOuHKCK0qAN748Y//5oMPPPSJp556yiRSWb1WgJbG+AwwUseILAOUfIAJGGbVYRgeGTZQjAyfDSOjo2FS9tr09LTZdthwAAt6JFhXd3fo6+0LAwMDob+/31QrQzvUzUJV0Ag9h7noEXagIjU1ozI8HPY/uv+VX/5K+Yu6p3eIfkUtZFg1APyvn/nMO++95/6PP/nkk8bvVvVuDXxIKcb2kHiSXkKeSa6uzk5LO3PmTDh65Eg4cuRwOHXqZFCHxQBHJQm8lOMvvYzkHQ+sugXZlpXQ09Mb1m3YELZs2RI2bdxk4LRpPnVCALo5eclOTEkGUp1OnjwpED569W9/6EMfFO3veoGVcc797lbGAy31FF/84pd/6fY7b//a/v37OwCHDTLHMTvCHEiu7q7uMLhm0MInjh8Pzz33bDh06KB6puOSksqXVOvp7ZXfEzo7Oq2zQjl7f0QXliJmHxjr5U5Xp8PU5KT1asfHxyzM8v5+ScTzz98RduzcGfr7+sKUJOiopCk9Y+5tTsMzSNvUYyY+MzujIZ1a2LVzd/XK1/78L77//e+/Y6nnbMa0FQ/Ab37zmxfd9u3/+bf3P/jAUFXMZpbDOhkCjvd65QuA69auDX19/eHEyRPhyR/9QMA7ZBKtv38gDCpvoH8w9AiAgJUOC9IPZ5Iv9nCJI9HsENiwEwEWanpMIByW6j575nSYHJ8wlbxz956wZ8+LTGUPnz0bJgVY5ooz8AnMAHpOA9Yzs1W7z30XXvTEdf/xN1/9S1dcsSL2u1zRMyHPnH6m78+/cuvXHnzowb1jY6MCnMBDj5cOgnxUZ2dnl6lGhkIefvj74eHvP2RgWb9hKGzfvits3XaewLnOpCPANeDJbkNNctC5SGFTpwbA+NKSAElPhx51d2e3bMEB2YSDobO7yyTfwRd+Yqq9TTbjBl0PZayhFx+cjh0bbEt7OUp51ZnpUK3ODB17/iczjz/26B1Kanq3YgEoMLR84sOf/vgDDz7wthMnjpm0K7dIcsnes0UFYt0azcNu3rI5AIS7775LttbxoDlZAW9n2ChbrUeqlg6IdRYSqwUoJYT+7pYw2FsOa/vKYaCnJXR3qEcti3pmDskHcQKmS0QWuYJUU/WqFzAy2D2qnu6BAz824G3atDl0aH6YwWjUcfZWHmXNzYeJqQk6MZf9ypt/+WsPPfTQmZjRtN6KBWBPf/+b77nn3k/8+MCzLa22pMrBZztdSfJt2bxZABwM35fEe+yxR00lbt+xMwwNbZJUVAfEgFbvqRoIJTnna9Vw6dBEeMPFnWHHYC1s7qmGrb2zYefaWrh4W2sYaNMy/JPaW1prAemU4DK1jHQ0iZk6Ot2ht68XqIbDsjVPSv0P6QdAz9k6O5o9SfRWh+g0ZagZk7kOScLO5w/8+LamRV688RVpA952++3r/ui/feE+jaHtZneCSmu7qdzUa92xfYckUTnce+/d4ezZM2HTlq1h/boNNgVnuJN9B+2ig3E7qe2OMB56Zw+Gv9l/3F5IEp5s3IQOtCjCL1y6PtS6t4az010Cnksx2yFB4LP3hKVSUauskkngYpruzNlT4YjsTnbyfdnlL7ee80HNiFQ1PQf4vIxsQlbVyK7U/U5uWLfx5d/97nd+0MwgXHHDMGJW6Z3v+rcfevqZp3djuLdX2k2FwiQ6DDvV+2QRwJ3f+1vrJOzctUe90QFTzahJwU5UdZeFFSgpf3qhM7R2nBfe8NrzVa9oIwE4xB6cnJ4PY9V2SVDFeWPOvjhXrw86DneunpGuawbX6UdRCYcPvhDuv+/ecPnLr5B5sCX85PnnJfVQ35SIJVX36NhIl3ri71XidV5Xc55XnAquzs+/ZP/DD3/+yNHDFXq52H0OlFLYvWuXDWncdecdtsKF4ZCe7l4HKAATELJDCCJsU2ek80dcUnB2oSNMzrbpbbi2MCHfj0qYmKmEmfmKKB1mrHJBehG1F51iPEk+VG/KV8CkX6fmgrELjx49YnYoQzXDikOb6qC+alW94kpl989ddvmtzz33VNPagitqLnjhllvKTzz62A2HjxzutMFhAQa5B8O3n3++DXH83V13mvG/bdt2GfydBgCYy787Ah6hdJZsmaRYjQIjOcx+MMUWD4X5xpcS6+UUdZARUBEAaS7Fidgd2H12qbe8RT1vhmIeeeT7ZjpouxBTwV6ByP02wvjEWO/IxPCvWXVNelpREvC59u7XPfPc0zeMjo6UUGf0duH3Vtl4PT3d4a677tDgcXvYunWbrfMznomZmdTLh1UW51LQ7UGWbNlC07RQQT1ketVIRwORLpaXesDK/qS6UzpgzB+AEprkk8dwDytyTqlTMjU1Hbbv2CF/MjC4bfXRkdEfy7c62to3v+H1r/sfmituyrWDK8YGvEXS7zOf+/wHz5w5LS2pMT5BAsN97Zo1Yf2G9eHOO/7Wxv02b96qoZWKASKz9kCpSbSoPBXFMehMj5gB6A75LE6VXreVLwDGcUfPlBmMWeswMI43rQMVWdOQTF3iWZUGNEujPNl2ckAZhRVZMNOAscijRw+HNRoIZ4hGEs+GZ6AD9Dzf+MT47hcOH36Nkv7SyjfZacVIwMnJmSsPHTn4O5IU6qz6qmUWBVyw94Kwf/8jQcDUQs/zDVTwCMkGgFxLw079KY7k7O3tCeuk9jas3xB4eQgQMlCNxJmUJGKIZEIHYGMqjTE7bEUWsjJ22KehFcpwDZvJUD5gyUs+wgDRcEgYZ/EIRoVZlQ2QmYPetGmL2a0MqEOR7EFmW9o7OiePHj7UlEMyCIqmd2Jm6eWvfNVthw698Ms8DKoSt+/CF8ugH9VY3wPhPHU4mMPFuVoFcJKBsbOB2uuTwY/EZCULYGAIBJABAlYwo0bNGVDALxIT+0+dE6lsgM+7JEhLFjNQJ6ueWdEyogN16ptW+rAKIMqAKbWaQJXvpKB2Dx38iUnACy/cF55+5indD/UwlOPLwYY2bHzuJZdddukf//EfT/gNNs95RUjARx554mVHjhz8iMAiDPBi+IKk11AYHFwT7rv/nrBWU2nM8yrZwAJgTNzh6Y9FCBu0WoX5YIA0NjqmcbmztkiA+WPmYt2pZuoAtPrjOjh+xQzBAAiTkprTRUoCXurr7unRQHe3yjqooTNpp+JWhwHaInaPnsq1NHOiXjw+UpDnQLKe1bIwrkk6y/41tTjQUmq77fnnnzvM/TSTWxG94BOnj/362MR4BWDgUKPnn7c9PPHEY5JKrVqBMmjMgtnZnwDDrIjey5V02SQQdtkav2NaBcO6PyRe5lStlQNvhGMnQInmogeRE4gItTwhIJ7QUqoTx09o8HhGttwa/TDW27smkFJn/I9+ujvLdIBJSvZKMvMuyqHDBzVm2W+vCQA+u57uZ7pabRmdGn0VV2821/QAvPbaazeNDI+8DQYjlZAuW9XRUE/YxtKY5Gdw2ZjlXDfGMhOyVoBYt269OhFz4ZSWwI/rFUlelXTnYAZxMNsOqyRmAwDFHQgKG3m8AOmJTGBlNcxprSvUfdq7wOtlWwJ4XI7SS8QqLF1h6mfxRK8Wt56WFMTmHBxYYyqYAjzzzEw16LXSptz6rekBeOCFQ2+ZmBxf5yoxmOE+NLQx/OiHPzC1y9SW2VbGarezGEqhZ4nNR6cCO9E+TAjzBSSwZIBD0hnQYHVMj9IvAcxhqjMgFU06Er1VRrpstonJCU39+ar6tbp+j1Qzzq5lAcr7HxXFkOVjl2L3HTt2RKbFoNmx6d6QtrJT911//fVN90nYpgbg9dcvtIyNDv8zOgmoX+Zat6i3yAs9vE+RVC/MNICIgaxGgYHYfahI1uAB0MwBpAx0FIwOQMQooHOQkhYhE69h17J8l5x5IPEjYYEp0hnQDMo0YJErLtXj96q4F7SLkocKpnNz4sQJsytZRpbuE19ScOsDDzzedJ+CaGoAPvjYVbvHxsevMAAJACwsXa/OxDPqKWI3JQMeZtKD5aVybCg6BFP6DMNMtW7nKduYbjgCEPZn2DAQ1FMMGspNLkk/T3Hg6CxQW52corPVMSJHko3HJVe8L8LqaqvQaP3Ki+/Hh3DogNADZgX1gMpZDzreiRYo9I1Mnt6WrtUsflMD8OyJE28QQzqRLDBjvey5yYlJG/LAZkrAREJAg8rjYIk7K0ocLGJVwkgOLDAQKefA01k01GGp0OswqCgjKw65nGWnROLQxLotTJruF/VPjZgCbPvhsyVOTy1eDvA5ANmhgbno06dP6TnYzF+l43Vkx5amJ6sFANWe/0+cmFMaHR//RYDEuB7HRtl+LC5FVdH7dWY7I9lmo0cDzGk5U2Kcc9C5aGeAQgDPgONhHgqo2V8OUIagVMaJKJhRW0Ux3ZItTL7XPz1dlVlQth8GnY38j4ZrZVdVYX4AbBvCfjKUYVaGe+QebKlXbW6zVdxEp6aVgO94xzvW6qWfl8EwmMCOAu3qcPBOB2+hMVSCQzIyNsgMBXPDJvkiEihXn6ONi0dVxiSOMZ8avB6YbMyOUQOHypMWkyCW8xhnAGOX8ohyFIj0KZ/7Y5+YTq2E7tQKaavB6vXrJeln11E6ZgY9fhYrdHZ0OWBViPWFGoNcbxU00alpAXjw6NHL1PnYgAqDiQynjGDcaxiGF48SsOAFNhYSEKbBeNxiMCXYkGHZdgI8RBPzSXS4ORH5yXl9MdcKeTnPV0KktTK5fEoglblflmKxhMx+VLZZh3LjTaR74MdEB4bOEz86+6GpPtqADZbS/TSL37QAnBibeAWvL2IHoX7XaNYD6cf8b2I6TKHX29nln2kj7ohKQFrMJmN2SsqjizQDgqMoy8qkoiPKSYBU41+8nhWPdaQboWodjD9yr7wnwvO45JN011/6MXF/5CGNAaB1Xrg3OQNobcG71J7UFOemBeDs3MzLkBxwj1UrrO1jyRIT+JIpYogGlLXCBUCSj41kAKGAHOrRHFHPiFFY7qAwQCrPVXIkIw5FLBNrsbL5k6WnimKG10wOGfEcadz2W7AFDYxTNqpeAxjXlKM3z7My18xjpPuZnZ9TQnO5pgTg9ddfzyDYRWnSnkUGqCW4wXgZzIKhGPUAcBHLxUMHQuR8FlNqBJXhgzDMjUw3tlJRdE5KGWioE98lrIHF6LiS15vq9pRUSfQprX/mk5GC2Hla3uCqOF7A6lSYP+aXGftEHbOgwosrBwnfZK4pAfj0889v0XzvZpgBSFBLzzzztBYAjNmAdAIAc8Ks4UsqLOMNjITn5iuQc9Tpf0pcnGVUDiS/LvnQOgJSyHur6R6yOrgglH5hvzalrROljBzY7eV3gct+YHE2xu4p3i8bILGqhkIsA7Mrc0sLC/6RYy7UJK4pF6ROjE3u1BSbjf+xoIA321if16ttM2A4TEYyoKJYsWyMJAP7yQjgDnHnknmKWjwChYhDKtJGjyog1UW8uCJ8xStWRY6DykIxHQLS9UcolbfElM4LTOSoXlQww0h2D7GXn6S9Pxtz3i7tzCa0CiVBS6WpVGez+E0JwLGRkT2oXFQQH5bW5uImBdmBwCSPmMiQC5tL2lCIs9yYC2PMyCcQwRb5Jw6SGUFTR4qVtgXTQCQHpoxY9UQ4Uik1Z4C0GNdRfXZvlnvuiTyjURbPhSrmPt02jGXtOgZTs2m5lj8LV0dpl0bOrflnO6UpAThTnd7BChNsP9bcwTyYZtIOJulIC0St+R0FDpIIhDxbwJoK6USm/ZNAqnkmOBX3FD9TxlIiaDN6K+TlyLe6icbqvFxK8NxUMxewzpEu6DsyuPSmSmjsL9LwfNRp1XJiKVopNN12vk0JQC0Q3ZYGYs/TMntUMJLQGCWu8GefVFAnxCSLs8nYiL4k31jvyPKxNEswdloezHV41MFjKSTaNexyOikhogAvKxOz/fpWSJm6NhWLKp1j0UhNVS7V7AclUBG3f65JWf4JSwX7rUCh57Uaysezipok0HSdEDV+SYPNQzABNcxsAEvV2VIj2UkwCQnBChljlpihJDuyc2SkCBw1kbkQQYvDX3QYDezOpzsAsjIK1MMe8hJKV/mU4uDhKnJEOKKDzlZdxx6uDUxTNndg41JXGttEFbeVWw+lOprFbzoJeIdMpFptflC8kPPhFl4GMluIRDECXtoL5S4jIsaM5SrhUsWpqMOBgZ8oIkpIimkW9JNdV5ROnPkJWlYmJ2XjbVpHxW6E61tZy/GkhuuQzfNw4PhheSCCWM+JjUgPmt4w19Ye1dX29nKxJN9b6v/e+dYbbujQZo1aySmm6B8WMf3GYc6RCQcVjbAwUg8bs5wSburfD6uOsvq3AxryEm30nUTpNjyimQp8qFI5grEePOowh697MmqFLSvWmYobLXmQ2h/VEs8divOs2IhIP94Jobw6XSe1sdHRVGWz+E0nAasHD7bJ/ukwJtPKYir2oA9EO8OSdDNGijkw0XuxUaIYNoEA5d2z+hyznhDPlLPyilsJThyxnEHKMrzAOVUYrU743BCe/vweFY9Srp5H1YnOiA2AVi6Wr2nxQqWPN+60pMweUhK/XD7w13/916NJakLfDK7pADg5WarUFuYrCYBJVcFUYyzqz9AGc2GBfP5j2ADi/HX+5MJ5kCbmUScuI7N6Uq7SDQC6pnxA5eo1lsiBy7CzqGys2TLq9aWQ1as8/Po9cBe+9pFFtYwEkI+9W2ktP6G2yG4z1fOz7jddJ6RcnmaOSvettqa58cSEiC9rb0WlnhLzIgsy2hxLSGtwzmwqVQYVRd+AkOq0dPIiNXFz6Zr4ZJPPX84pkv0IUkYqT5wy8inb2PlI94LPUn4WJOCYcixXKt+3SJOdmk4C0r55ttr8qzW6ixd4qCkpN84FGLidh0BivvlemUgUMzqrPJOWxvB4taTWDR2QRemWr8euQzo3kVxD2GiUliWnAKiLjjrNvsPGi/PLZBmF6Bii4Uub7KSKkwSc7W7raEoANp0E1PQa8501QUwM8Y0eUcM2MGssEovFJGxCmJiBL/IXz0BT57fRmLRKICDPwhZQBEdNXlsq6lJKMfuPeSqX/cUOShYHTFaTeY4ouwQVeD1Wl8J0NKyHm6sDGtJYN4hj7JNn1wzQcxs3bnwm1tpUXtNJQDGdXaBmYD4chCEwAakA81ySwUB1TJSnj24ZIM3YVxlI3MVuQJbgAacAorhYISFDbT3Nr+9xK5mhul7WSmcFSdfhl6GgOa5nRWMsefUvaXovl3QvWrK36ViOReeL59aCi/vvuOOOaSvbZKemk4CDg5dUxchJ44Y4AtCAEt97M/DAJR3sWMXye1sJA1MMsFH6GQngdeIEy1jU6iGNOJVZKAI+SzEwK0dERkE8hj3FiqbS0YcmdyjV64PWClsctWvfCtF6x2wM0Ah9E8tB7V/D7g1cl09GtHe2Ne02vU0HwE996r1VzRKM0Pg43qewcTEWZyYnkcICVN5+M0kFb7PDAWAJqgOAUpX+/WSBepjslJ/qcOJIIy9zCDgRcSDVMhfrSHG/dyVahZ7ql/Vz+thN2qXBilOvSGe1CwI/HF4/QPJrwcXJge6+m1PdzeY3HQDV6POa5TjpoMDW0/sUAhsvJKWOAj5ShC0r6kyss5h8Y2rGLQeNs1iJxuxEQarCVjyGLcXDdoY+HlRpJa1ITE/0Wb1+YUU9h0Asx7VnJLn58SDFPcPzeU6k+rHjR/ROsxakqvfb1t7xPX0B6qQTNt+56QBIE6vDcchtOqlgk3Sz9iJSvSMiIvGMt8dgZHKAxV3yY8yRYBEDFCGRGKicxIGSwjl6S6K6hiP1zqljUR4FrG68ep7TuVnAy+fc+6IVzhKpPCvSkeEXLkdnRHvM3EKVzeqaEoCyew6g4mAaPd2qJB1r/5gfTTyFIRjp7ICQDWXAtch842CKQ2wJeE5wDhBTunwvFiuyOCk491NZA5WlphKUMUI72TMowWskqWS233RVaxwl6XKkZgvOaicHdnPgU19sbqRdHg6sX7Pmb+o1Nl+oKQGo7348hf0Dg/ljDz9WENsLSQAF1sX86elJ3pc1zji156cwfnJeX8RIrCbLV5wks+1SXkyjfKKzeu0eIm2s3G9LufGeM7pYF8Anj94t73tgOti1svI+/sePjI2UAKh20L/lnnvuGYskTek1JQA7ezoFwJY4FKPvq0nKwTw2HIKxeQejtHuWScHEUJFGlNUprVRKj5E6SCxBZVLtHreYggYq5XmHJs3KxHj9EnZnXsYKWY5dw3K0zZrU7qQ+xcUPJl0JIqQ8H0vcvWdvWL9xYxhcxz6DG6Z2bn/RzbnqmzLYlAC8cNeun2j86zCMx6GCOZiewjB3DAoIUQoiVWzeVLQGFmMvICAhphm4vD4SU4j6nczTvLyXSSoUGsKpc5OXfQmc+Rq9PuqgpDvMhElt38Z9YjqkDhXlkHqbN2+x78hhWyLpB/oH/vKWW/7kyVS+Wf2mBODnP//5Cc2IPG5cFxPpHWq3ePWEO7JvfySGAELG1Nhh3hnrOXXwRBREVMBwS4nJqR7zE42GQQCMfW4rosizdOZfecQXOSfwpHymwoAN4CGpk7lgzyZqxgGRfrxeeubsaZOGXZ1d8+s2rP+cni1f06LLNUukKQFIwwtsf8cbcUkijY+P2iriPu2KlZc2MMIZPGWvbZqaVJpxTifDTyMbc5mZBMuAtqCPWg+EIX36Ya0+dshmQdBYRakc9Sstf3AfBu54QcvjLvRLQPWO6f7ZkJwxTX40SYryZh/bjrA7PlNvvHilfQ9v/7Vrr72LOpvdNSUAafT+3u47tQZuDkbCLl5O4mAzcvZXcYRF9kRVjIRhl1JzBoQYdGgoIohI4vCH87MFY9yv1auP3rAz1aA+4dCuD8p4mQiwJcpRONVJpfl6GVrRd9+s88HmlUn18kz8WNiYnHebz+i9F+ro6eqe37h+6Pfe/va3x0FCam9e17QAvPjiq57QJkRPJUmC5BgZHbZtOPp6+10qRb6YPBEIYfaYmA0IAYFBDSB6xDwrEpNSet533Grumd6obDWcgStXT6rDfCfwINehMvPlCeyjkmz8MOgs8Usy6Sef5+JTD+vXbjCA2hfT9cHtwTVrv/utb32jqYdevDH83LQA/Oxn/31VW5p9h8FnGIrkYOtbbCg+z8AkvfEZ9OHkQ2sSR3RsDpmA4AQ6WwFHBwDwBI9D41JswbYAHtaG46Nj46pn2js7WT4Bg3ZWPAHUy4My79mOjo/INh2195qpP4EvhTcObTZbc3jkrD2fzIvq5qEtN4jOl9VA2OSuaQFIu/f2939VkmjOBpoVR4oMD5+1XaP4IrnPRuQQKBq9vGN21qikJR0TB4WDy6VpAlqGH6Op0wXZaxO6zoi+3XFm0Ta/3BN0CbIeVoz/lCgaZjOYy8Wu46V6AAn40h/3geplp4fTZ07Zj4aer77wfvPXvv4XD3CdleKaGoD/4T3veUS7YokhzO2Kw2LiWUkLhmTWrVkv20lbtUXOGwxhtDjHG3OMrWH4o7b5TEPKz9CTOAxwFh0+vANg2KNFnudDn0CW0euuuD40dgEfMuIekXxIY6QynamUDz2fkN24YZMBlKEZaLQC5sS+C/feoGrSVbhi07um/lLSrbfeunD+9l3zU9OTb7V5U4AlpgJGhi7YT9k2LFI6gAEthgP5gBCnbd5MbZPPm2aAKjkDjyJeyvnOOdbiZFaPwd/qTvmkQJckG2DD9sQG1YdlBCPl27V0vfgj4Xr0erdtOc9U76nTJ7JnuWDP3j//oz/6yp+me1spflNLQJhw4Yt2fV1S8FkHi0unEa2VG9NOWRqs1ZeQ/CtJeYYliJkUk/Rh8SeS8OzIGZ87lnTEJTrqBlgOQfzcX8yDPuUTNsDLd+CNh7PDZ2Qz6gtMMhMAP1LNAAqxHDWStmkjHyWs6MM5J0xK06PfsX3HwUsu3ve7Trmyzk0tAWHFE088Ud2xcydjZG9CrcJ4gMCKkl7tFc1+0ZOaD2b+1KSeUJVJMNGahDIpBljmwvTMtElEr0sgSTSL4LIYBADVD4cUNilA47qo2glbvey2HluGQJt3AJzrbNq42b6IdOLkcZkRWuCstO3n76y9aO+F/+ZjH/3IirL90vM3PQB5kDe98Y1PHjt+4q2axF8P0/QvqaZv+ApQ/X0DNjuC+vPl+0gedzA9uQQ0MpFa9vkrgZhBYjoNpGn+w226JBHlA1RmRBiSgZZpP67F0EpVA8es6eMyma2XLhh9JB+w3bBho0nrU6f1OS7VQdqQPrh4wQV7P/3FL9z0mYZiKyZa50CTP9IVr3rN248dO/QXrCSxfVXEQBy9ScbSmOQ/euyogTLZf3kApscnzdW51CJAi2CjtgRSKyc60hINQHRaV8TkJjqr2+pRHv+xXiQldOvWrjeb9dSZk9YzJ43vnLz4ohd/7+qr3vorGnRuun3/Unv+n/ymtwHTA953951f7e8f/CYDxOaEDgDAh6rpdXZ1dpuKw8gHAMu5LI/y6iQgudhrEB/H7ATSEKmI1CMM+HAM8dg7ulKz0BtgyUjXy12W67CEjLE+howy8Ome2e96z649z+zeddG/Xsngo2lWDADF7PmtO7a/T3bfMSSI4OD/YuipUyesE8DMwhYZ+R16pzYDGq2wlAMsHFQVHYBKHQhTqRGYWVj5jS6HOctC5QJixvW4FxaWntT9TWgxBcMxvFqwe9fuk7v27vnnH/7whw421rfS4ivCBkxMeebJJ89e8uJLX9D6wKs1vCIB5r8vgGMzHyKkU5I2NcfOw5H/j+GWBHWUfo5nh2NfT7+2k9tolzyuDgcroLkHxi23bT3v6V17dv3aZz/1qfv+Me7pZ72OFQVAGvvAgR//6IKLLmrTSzuvQUUm1UkeC1d514KFq7361hoftGGOFTX604DQYJXULBeKLkk/gMkfn47FHuV7v3RUkMz0vLk2km/Tps0/vOiCF735CzfdtD/VsdL9FQdAGHbzV75y1733P7hdILw0MRgmczBLQi8TW5FhGqQhKpthk8yWE91P60ziAUod2J0DAt0GgY9thE9peo2pQECJiu9o7wR8j+x98b63/eFNNx34aa/dTOV/+pb+GX3a9773U533PvDVm0+dOvWrSL1MwvHE8F0gY8qLDgDLnVi0yuA1tpi9kRYlWlZumedsVLsu7Xy6D4nHN+pQ+ziWXdm3grVyJ61lRBqrI/K9Sy/Z9y8//elPN93+fss0yz84eUVKQJ7+/vv/19yvX3fdd44eO3b+zMzsJahjA1OUhNAgDRmvI49vcyAROeikMC2HdDJAoUIjIClnCrUhjbptmwyBrk/qfXBwrc3E8MkFgH1aQyz+OqUPOiN1Wbu4dcu2L/3TV73iX914441nqHu1uRUrARMjb7/99tbf+c83/BcN8P6WVK89b6NUA1zYimz129XVo69WdmYABJxIRHwO1LSvqgZIPkSDOgdo2JTUAw3jkYAbdZ+3MQEv4JZKHtPMx3/69re+8Xndz4pZXpXa/R/qr3gApoa48g1v+BcnTp78xMT42MY8IFI+fpJySDLAxHsYdA6w4RizQ2qlQW6n9SEV27FA4LTZE0lVpgG5BjSNYOcDg2vWrLt3y3lb33vrn/3Zg/nrr8bwqgEgzL366nfseeHwj28cHRm5immzBLilGJ/PA0RprA+pp6jZkUhC1hyaVLTBaBmX6O0GR12AWCu1hzUz87FXv/KK37/++ut9d8kG2tUWPbe1VngLCAwtr33dG68aPnv6gxoKeQkrYRYvXP37GyAPTLCGVMy7fD5hvlfX19enud6hOzdu3vRbN3/pS6te6uXba3Hr5XNWeJhe8vf3f+dqDYe8W3baK7VwoQVV+tO4BD4kJp0a9X7ntDD29s2bNt305S//928r3V8i+WkussLKrloAJj4KNOXXv/5Nrzg7NnxNdWryjXqnZI9Wt7SgVl0yJspGH3WLMzFowyrYiXqJfKS7s3v/xk2bHtm8ccstf/AHn3tIwFu1nQxvo+XPqx6A+aZ5l75D/PTdd18yOT71Cg3RXF6rzV6g5VSbJRn7BNQOM/ysgDVbTXbhpEB3WjvUP9/a1vZYd2fnfWsGBh74xmXfeKF0fQG6fNsuFy4AuFzLKJ0hnJtuumlwbGxsjYZVBmYXFjolHFsqpdJspVIab2vrO7Nx48CZL33pS+OSckkk/j01FllFCxQtULRA0QJFCxQtULRA0QJFCxQtULRA0QJFCxQtULRA0QJFC/x/aYH/DcZeQn52ItB2AAAAAElFTkSuQmCC", + "strings": { + "initialNotificationDescription": "Tap to pair with this device", + "openCompanionAppDescription": "Tap to finish setup", + "updateCompanionAppDescription": "Tap to update device settings and finish setup", + "downloadCompanionAppDescription": "Tap to download device app on Google Play and see all features", + "unableToConnectTitle": "Unable to connect", + "unableToConnectDescription": "Try manually pairing to the device", + "initialPairingDescription": "%s will appear on devices linked with %s", + "connectSuccessCompanionAppInstalled": "Your device is ready to be set up", + "connectSuccessCompanionAppNotInstalled": "Download the device app on Google Play to see all available features", + "subsequentPairingDescription": "Connect %s to this phone", + "retroactivePairingDescription": "Save device to %s to connect more quickly to your other devices", + "waitLaunchCompanionAppDescription": "This will take a few moments", + "failConnectGoToSettingsDescription": "Try manually pairing to the device by going to Settings", + "assistantSetupHalfSheet": "Get hands-free help on the go from Google Assistant", + "assistantSetupNotification": "Tap to set up your Google Assistant", + "fastPairTvConnectDeviceNoAccountDescription": "Connect your %s with this device", + "subsequentPairingDescriptionOnTv": "Connect %s to TV" + } +} diff --git a/fastpair/rust/demo/pubspec.lock b/fastpair/rust/demo/pubspec.lock new file mode 100644 index 00000000..a6087902 --- /dev/null +++ b/fastpair/rust/demo/pubspec.lock @@ -0,0 +1,644 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + url: "https://pub.dev" + source: hosted + version: "61.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + url: "https://pub.dev" + source: hosted + version: "5.13.0" + archive: + dependency: transitive + description: + name: archive + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" + url: "https://pub.dev" + source: hosted + version: "3.3.7" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_cli_annotations: + dependency: transitive + description: + name: build_cli_annotations + sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172 + url: "https://pub.dev" + source: hosted + version: "2.1.0" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" + url: "https://pub.dev" + source: hosted + version: "2.4.6" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41" + url: "https://pub.dev" + source: hosted + version: "7.2.10" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166" + url: "https://pub.dev" + source: hosted + version: "8.6.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + url: "https://pub.dev" + source: hosted + version: "0.4.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189" + url: "https://pub.dev" + source: hosted + version: "4.5.0" + collection: + dependency: transitive + description: + name: collection + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" + source: hosted + version: "1.17.1" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" + source: hosted + version: "1.0.5" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: "direct main" + description: + name: ffi + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + ffigen: + dependency: "direct dev" + description: + name: ffigen + sha256: d3e76c2ad48a4e7f93a29a162006f00eba46ce7c08194a77bb5c5e97d1b5ff0a + url: "https://pub.dev" + source: hosted + version: "8.0.2" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + flutter_rust_bridge: + dependency: "direct main" + description: + name: flutter_rust_bridge + sha256: dcb436ba4b466e19da1656ef14622b5ac2ed90efc8fcb0946942c6cd185578d1 + url: "https://pub.dev" + source: hosted + version: "1.79.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: "2df89855fe181baae3b6d714dc3c4317acf4fccd495a6f36e5e00f24144c6c3b" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + url: "https://pub.dev" + source: hosted + version: "2.4.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + http: + dependency: transitive + description: + name: http + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + url: "https://pub.dev" + source: hosted + version: "0.12.15" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" + source: hosted + version: "3.7.3" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + puppeteer: + dependency: transitive + description: + name: puppeteer + sha256: f00b54703dc22af04eaace8f23a33c56008870f990684c2ad8c4115ac51b0a38 + url: "https://pub.dev" + source: hosted + version: "3.1.1" + quiver: + dependency: transitive + description: + name: quiver + sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 + url: "https://pub.dev" + source: hosted + version: "3.2.1" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" + source: hosted + version: "0.5.1" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + uuid: + dependency: transitive + description: + name: uuid + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" + source: hosted + version: "3.0.7" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + yaml_edit: + dependency: transitive + description: + name: yaml_edit + sha256: "1579d4a0340a83cf9e4d580ea51a16329c916973bffd5bd4b45e911b25d46bfd" + url: "https://pub.dev" + source: hosted + version: "2.1.1" +sdks: + dart: ">=3.0.6 <4.0.0" diff --git a/fastpair/rust/demo/pubspec.yaml b/fastpair/rust/demo/pubspec.yaml new file mode 100644 index 00000000..3ae724d4 --- /dev/null +++ b/fastpair/rust/demo/pubspec.yaml @@ -0,0 +1,96 @@ +name: demo +description: FLutter UI demo for Fast Pair Windows written in Rust. +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: '>=3.0.6 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + ffi: ^2.0.2 + flutter_rust_bridge: ^1.79.0 + freezed_annotation: ^2.4.1 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + ffigen: ^8.0.2 + build_runner: ^2.4.6 + freezed: ^2.4.1 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/fastpair/rust/demo/rust/Cargo.toml b/fastpair/rust/demo/rust/Cargo.toml new file mode 100644 index 00000000..4d736a04 --- /dev/null +++ b/fastpair/rust/demo/rust/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["lib", "cdylib", "staticlib"] + +[dependencies] +bluetooth = { version = "0.1", path = "../../bluetooth" } +flutter_rust_bridge = "1" +futures = { version = "0.3", features = ["executor"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tracing = "0.1.37" +ttl_cache = "0.5.1" +thiserror = "1.0.43" diff --git a/fastpair/rust/demo/rust/src/advertisement.rs b/fastpair/rust/demo/rust/src/advertisement.rs new file mode 100644 index 00000000..da59517b --- /dev/null +++ b/fastpair/rust/demo/rust/src/advertisement.rs @@ -0,0 +1,230 @@ +// 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. + +use bluetooth::{BleAddress, BleAdvertisement, ServiceData}; + +use crate::{decoder::FpDecoder, error::FpError, fetcher::FpFetcher}; + +/// Represents a FP device model ID. +pub(crate) type ModelId = String; + +/// Holds information required to make decisions about an incoming Fast Pair +/// advertisement. +#[derive(Clone, Debug)] +pub(crate) struct FpPairingAdvertisement { + inner: BleAdvertisement, + /// Estimated distance in meters of device from BLE adapter. + distance: f64, + model_id: ModelId, + device_name: String, + image_url: String, +} + +impl FpPairingAdvertisement { + /// Create a new Fast Pair advertisement instance. + pub(crate) fn new( + adv: BleAdvertisement, + service_data: &ServiceData, + fetcher: &Box, + ) -> Result { + let rssi = adv.rssi().ok_or(FpError::ContractViolation(String::from( + "Windows advertisements should contain RSSI information.", + )))?; + let tx_power = adv + .tx_power() + .ok_or(FpError::ContractViolation(String::from( + "Windows advertisements should contain RSSI information.", + )))?; + + let distance = distance_from_rssi_and_tx_power(rssi, tx_power); + + // Extract model ID from service data. We don't need to store service + // data in the `FpPairingAdvertisement` since it's easily accessible from + // `FpPairingAdvertisement.inner`, but it's convenient to save the parsed + // model ID. + let mut model_id = FpDecoder::get_model_id_from_service_data(service_data)?; + + if model_id.len() != 3 { + // In this demo of Fast Pair Rust, only model ID's + // of length 3 bytes are supported. Therefore, if a + // larger model ID makes it this far, log an error. + // TODO b/294453912 + return Err(FpError::Internal(String::from( + "creating `model_id` should have already failed", + ))); + } + + // Pad with 0 at the beginning to successfully call `from_be_bytes`. + // Assumes `model_id.len() == 3` before the call to `insert`, otherwise + // this will panic. + model_id.insert(0, 0); + let model_id = format!("{}", u32::from_be_bytes(model_id.try_into().unwrap())); + + // Retrieve device info of the device corresponding to this model ID. + let device_info = fetcher.get_device_info_from_model_id(&model_id)?; + + Ok(FpPairingAdvertisement { + inner: adv, + distance, + model_id, + device_name: device_info.name().to_string(), + image_url: device_info.image_url().to_string(), + }) + } + + /// Retrieve estimated distance the BLE advertisement travelled between + /// the sending device and this receiver. + pub(crate) fn distance(&self) -> f64 { + self.distance + } + + /// Retrieve the BLE Address of the advertising device. + pub(crate) fn address(&self) -> BleAddress { + self.inner.address() + } + + /// Retrieve the Model ID advertised by this device, parsed from the + /// 16-bit UUID service data. + pub(crate) fn model_id(&self) -> &ModelId { + &self.model_id + } + + pub(crate) fn device_name(&self) -> &String { + &self.device_name + } + + pub(crate) fn image_url(&self) -> &String { + &self.image_url + } +} + +/// Convert RSSI and transmit power to distance using log-distance path loss +/// model, with reference path loss of 1m at 41dB in free space. +/// See: https://en.wikipedia.org/wiki/Log-distance_path_loss_model. +#[inline] +pub(crate) fn distance_from_rssi_and_tx_power(rssi: i16, tx_power: i16) -> f64 { + // Source: Android Nearby implementation, `RangingUtils.java`. + // + // PL = total path loss in db + // txPower = TxPower in dbm + // rssi = Received signal strength in dbm + // PL_0 = Path loss at reference distance d_0 {@link RSSI_DROP_OFF_AT_1_M} dbm + // d = length of path + // d_0 = reference distance (1 m) + // gamma = path loss exponent (2 in free space) + // + // Log-distance path loss (LDPL) formula: + // + // PL = txPower - rssi = PL_0 + 10 * gamma * log_10(d / d_0) + // txPower - rssi = RSSI_DROP_OFF_AT_1_M + 10 * gamma * log_10(d / d_0) + // txPower - rssi - RSSI_DROP_OFF_AT_1_M = 10 * 2 * log_10(distanceInMeters / 1) + // txPower - rssi - RSSI_DROP_OFF_AT_1_M = 20 * log_10(distanceInMeters / 1) + // (txPower - rssi - RSSI_DROP_OFF_AT_1_M) / 20 = log_10(distanceInMeters) + // 10 ^ ((txPower - rssi - RSSI_DROP_OFF_AT_1_M) / 20) = distanceInMeters + + const RSSI_DROPOFF_AT_1_M: i16 = 41; + const PATH_LOSS_EXPONENT: i16 = 2; + + f64::from(10.0).powf( + (f64::from(tx_power - rssi - RSSI_DROPOFF_AT_1_M)) / f64::from(10 * PATH_LOSS_EXPONENT), + ) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::fetcher::{mock::FpFetcherMock, DeviceInfo}; + + use bluetooth::BleAddressKind; + + #[test] + fn test_new_fp_pairing_advertisement() { + let addr = BleAddress::new(0x112233, BleAddressKind::Public); + let ble_adv = BleAdvertisement::new(addr, Some(-60), Some(10)); + + let raw_data = vec![3, 2, 1]; + let expected_model_id = "197121"; // (3 << 16) + (2 << 8) + 1. + let service_data = ServiceData::new(0x123 as u16, raw_data); + + let image_url = String::from("image_url"); + let device_name = String::from("name"); + let device_info = Ok(DeviceInfo::new(image_url.clone(), device_name.clone())); + let fetcher: Box = Box::new(FpFetcherMock::new(device_info)); + + let fp_adv = FpPairingAdvertisement::new(ble_adv, &service_data, &fetcher); + + assert!(fp_adv.is_ok()); + let fp_adv = fp_adv.unwrap(); + assert_eq!(fp_adv.address(), addr); + assert_eq!(fp_adv.image_url(), &image_url); + assert_eq!(fp_adv.device_name(), &device_name); + assert_eq!(fp_adv.model_id(), &expected_model_id); + } + + #[test] + fn test_new_fp_pairing_advertisement_bad_rssi() { + let addr = BleAddress::new(0x112233, BleAddressKind::Public); + let ble_adv = BleAdvertisement::new(addr, None, Some(10)); + + let raw_data = vec![3, 2, 1]; + let service_data = ServiceData::new(0x123 as u16, raw_data); + + let device_info = Ok(DeviceInfo::new( + String::from("image_url"), + String::from("name"), + )); + let fetcher: Box = Box::new(FpFetcherMock::new(device_info)); + + let fp_adv = FpPairingAdvertisement::new(ble_adv, &service_data, &fetcher); + + assert!(fp_adv.is_err()); + assert!(matches!(fp_adv.unwrap_err(), FpError::ContractViolation(_))); + } + + #[test] + fn test_new_fp_pairing_advertisement_bad_tx_power() { + let addr = BleAddress::new(0x112233, BleAddressKind::Public); + let ble_adv = BleAdvertisement::new(addr, Some(-60), None); + + let raw_data = vec![3, 2, 1]; + let service_data = ServiceData::new(0x123 as u16, raw_data); + + let device_info = Ok(DeviceInfo::new( + String::from("image_url"), + String::from("name"), + )); + let fetcher: Box = Box::new(FpFetcherMock::new(device_info)); + + let fp_adv = FpPairingAdvertisement::new(ble_adv, &service_data, &fetcher); + + assert!(fp_adv.is_err()); + assert!(matches!(fp_adv.unwrap_err(), FpError::ContractViolation(_))); + } + + #[test] + fn test_new_fp_pairing_advertisement_bad_fetcher() { + let addr = BleAddress::new(0x112233, BleAddressKind::Public); + let ble_adv = BleAdvertisement::new(addr, Some(-60), Some(10)); + + let raw_data = vec![3, 2, 1]; + let service_data = ServiceData::new(0x123 as u16, raw_data); + + let fetcher: Box = Box::new(FpFetcherMock::new(Err(FpError::Test))); + + let fp_adv = FpPairingAdvertisement::new(ble_adv, &service_data, &fetcher); + + assert!(fp_adv.is_err()); + assert!(matches!(fp_adv.unwrap_err(), FpError::Test)); + } +} diff --git a/fastpair/rust/demo/rust/src/api.rs b/fastpair/rust/demo/rust/src/api.rs new file mode 100644 index 00000000..40d69038 --- /dev/null +++ b/fastpair/rust/demo/rust/src/api.rs @@ -0,0 +1,249 @@ +// 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. + +use std::{collections::HashMap, sync::RwLock, time::Duration}; + +use bluetooth::{ + api::{BleAdapter, ClassicDevice}, + BleAdvertisement, BleDataTypeId, ClassicAddress, PairingResult, Platform, ServiceData, +}; +use flutter_rust_bridge::StreamSink; +use futures::executor; +use tracing::{info, warn}; +use ttl_cache::TtlCache; + +use crate::{ + advertisement::{FpPairingAdvertisement, ModelId}, + fetcher::{FpFetcher, FpFetcherFs}, +}; + +// Sends a device name to Flutter via `StreamSink` FFI layer. +static DEVICE_STREAM: RwLock>>> = RwLock::new(None); + +// Saves the currently displayed device's advertisement, to be used for pairing. +static CURR_DEVICE_ADV: RwLock> = RwLock::new(None); + +// Temporarily restricts which model IDs can be displayed. +static MODEL_ID_BLACKLIST: RwLock>> = RwLock::new(None); + +// Specifies how long entries should blacklisted for. +const TTL_BLACKLIST: Duration = Duration::from_secs(10); + +/// Updates the device name as displayed by Flutter. +#[inline] +async fn update_best_device(best_adv: FpPairingAdvertisement) { + match DEVICE_STREAM.read().unwrap().as_ref() { + Some(stream) => { + stream.add(Some([ + best_adv.device_name().to_string(), + best_adv.image_url().to_string(), + ])); + } + None => info!("Name stream is None"), + } + let mut curr_adv = CURR_DEVICE_ADV.write().unwrap(); + *curr_adv = Some(best_adv); +} + +/// Determines whether the device advertised by the provided service data is the +/// closest Fast Pair device. +/// If this device has been seen previously but has now moved further away, +/// decide which other seen device is now closer. +#[inline] +fn new_best_fp_advertisement( + advertisement: BleAdvertisement, + service_data: &ServiceData, + fetcher: &Box, + latest_advertisement_map: &mut HashMap, +) -> Option { + // Analyze service data sections. + let uuid = service_data.uuid(); + + // This is not a Fast Pair device. + if uuid != 0x2cfe { + return None; + } + + let fp_adv = match FpPairingAdvertisement::new(advertisement, service_data, fetcher) { + Ok(fp_adv) => fp_adv, + Err(err) => { + // If error during construction (e.g. non-discoverable + // Fast Pair device not advertising tx_power or + // with service data that isn't model ID) ignore + // this advertisement section. + warn!("Error creating FP Advertisement: {}", err); + return None; + } + }; + + // If blacklisted in TTL cache, skip this advertisement. + let blacklisted = match MODEL_ID_BLACKLIST.read().unwrap().as_ref() { + Some(cache) => cache.get(fp_adv.model_id()).is_some(), + None => false, + }; + if blacklisted { + latest_advertisement_map.remove(fp_adv.model_id()); + return None; + } + + // Else, this advertisement is now the most recent advertisement by the + // device with model ID `fp_adv.model_id()`. + latest_advertisement_map.insert(fp_adv.model_id().to_owned(), fp_adv.clone()); + + if let Some(best_adv) = CURR_DEVICE_ADV.read().unwrap().as_ref() { + if best_adv.distance() >= fp_adv.distance() { + // New advertised distance is closer. + Some(fp_adv) + } else if best_adv.model_id() == fp_adv.model_id() { + // New advertised distance by the previous best device has + // increased, so select new closest device. + let next_best_adv_ref = + latest_advertisement_map + .values() + .into_iter() + .min_by(|adv1, adv2| { + // We should never get NaN, so it's okay to unwrap. + adv1.distance().partial_cmp(&adv2.distance()).unwrap() + }); + + // If next closest device exists, it's now the closest! + if let Some(next_best_adv) = next_best_adv_ref { + Some(next_best_adv.to_owned()) + } else { + None + } + } else { + None + } + } else { + // First discovered device, must be closest. + Some(fp_adv) + } +} + +/// Sets up necessary constructs to maintain a TTL blacklist of model IDs. +#[inline] +fn init_cache() { + let mut cache = MODEL_ID_BLACKLIST.write().unwrap(); + *cache = Some(TtlCache::new(16)); +} + +/// Sets up initial constructs and infinitely polls for advertisements. +pub fn init() { + const JSON_PATH: &str = "./local"; + + let run = async { + info!("start making adapter"); + + let mut adapter = Platform::default_adapter().await.unwrap(); + adapter.start_scan().unwrap(); + + init_cache(); + + let mut latest_advertisement_map = HashMap::new(); + let datatype_selector = vec![BleDataTypeId::ServiceData16BitUuid]; + let fetcher: Box = Box::new(FpFetcherFs::new(String::from(JSON_PATH))); + + loop { + // Retrieve the next received advertisement. + let advertisement = adapter + .next_advertisement(Some(&datatype_selector)) + .await + .unwrap(); + + for service_data in advertisement.service_data_16bit_uuid().unwrap() { + if let Some(best_adv) = new_best_fp_advertisement( + advertisement.clone(), + service_data, + &fetcher, + &mut latest_advertisement_map, + ) { + update_best_device(best_adv).await; + } + } + } + }; + + executor::block_on(run) +} + +/// Sets up `StreamSink` for Dart-Rust FFI. +pub fn event_stream(s: StreamSink>) { + let mut stream = DEVICE_STREAM.write().unwrap(); + *stream = Some(s); +} + +/// Attempt classic pairing with currently displayed device. +pub fn pair() -> String { + let result = match CURR_DEVICE_ADV.read().unwrap().as_ref() { + Some(adv) => { + let run = async { + let classic_addr = ClassicAddress::try_from(adv.address()).unwrap(); + let classic_device = Platform::new_classic_device(classic_addr).await.unwrap(); + + match classic_device.pair().await { + Ok(result) => match result { + PairingResult::Success => String::from("Pairing success!"), + PairingResult::AlreadyPaired => { + String::from("This device is already paired.") + } + PairingResult::AlreadyInProgress => { + String::from("Pairing already in progress.") + } + _ => String::from("Unknown result."), + }, + Err(err) => { + format!("Error {}", err) + } + } + }; + + executor::block_on(run) + } + None => String::from("No device available to pair."), + }; + info!(result); + result +} + +/// Remove this device from display and add it to the TTL cache blacklist. +pub fn dismiss() { + let run = async { + let mut adv = CURR_DEVICE_ADV.write().unwrap(); + match MODEL_ID_BLACKLIST.write().unwrap().as_mut() { + Some(cache) => { + // Get rid of the best (i.e. currently displayed) device. + let adv = adv.take(); + match adv { + Some(adv) => { + // Add device to TTL blacklist. + cache.insert(adv.model_id().to_string(), (), TTL_BLACKLIST); + } + None => (), + } + + // Ensure the currently-displayed device is no longer displayed. + match DEVICE_STREAM.read().unwrap().as_ref() { + Some(stream) => { + stream.add(None); + } + None => (), + } + } + None => (), + } + }; + + executor::block_on(run); +} diff --git a/fastpair/rust/demo/rust/src/bridge_generated.io.rs b/fastpair/rust/demo/rust/src/bridge_generated.io.rs new file mode 100644 index 00000000..cb0a62f4 --- /dev/null +++ b/fastpair/rust/demo/rust/src/bridge_generated.io.rs @@ -0,0 +1,65 @@ +// 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. + +use super::*; +// Section: wire functions + +#[no_mangle] +pub extern "C" fn wire_init(port_: i64) { + wire_init_impl(port_) +} + +#[no_mangle] +pub extern "C" fn wire_event_stream(port_: i64) { + wire_event_stream_impl(port_) +} + +#[no_mangle] +pub extern "C" fn wire_pair(port_: i64) { + wire_pair_impl(port_) +} + +#[no_mangle] +pub extern "C" fn wire_dismiss(port_: i64) { + wire_dismiss_impl(port_) +} + +// Section: allocate functions + +// Section: related functions + +// Section: impl Wire2Api + +// Section: wire structs + +// Section: impl NewWithNullPtr + +pub trait NewWithNullPtr { + fn new_with_null_ptr() -> Self; +} + +impl NewWithNullPtr for *mut T { + fn new_with_null_ptr() -> Self { + std::ptr::null_mut() + } +} + +// Section: sync execution mode utility + +#[no_mangle] +pub extern "C" fn free_WireSyncReturn(ptr: support::WireSyncReturn) { + unsafe { + let _ = support::box_from_leak_ptr(ptr); + }; +} diff --git a/fastpair/rust/demo/rust/src/bridge_generated.rs b/fastpair/rust/demo/rust/src/bridge_generated.rs new file mode 100644 index 00000000..bf1f040f --- /dev/null +++ b/fastpair/rust/demo/rust/src/bridge_generated.rs @@ -0,0 +1,119 @@ +// 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. + +#![allow( + non_camel_case_types, + unused, + clippy::redundant_closure, + clippy::useless_conversion, + clippy::unit_arg, + clippy::double_parens, + non_snake_case, + clippy::too_many_arguments +)] +// AUTO GENERATED FILE, DO NOT EDIT. +// Generated by `flutter_rust_bridge`@ 1.79.0. + +use crate::api::*; +use core::panic::UnwindSafe; +use flutter_rust_bridge::rust2dart::IntoIntoDart; +use flutter_rust_bridge::*; +use std::ffi::c_void; +use std::sync::Arc; + +// Section: imports + +// Section: wire functions + +fn wire_init_impl(port_: MessagePort) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, ()>( + WrapInfo { + debug_name: "init", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || move |task_callback| Ok(init()), + ) +} +fn wire_event_stream_impl(port_: MessagePort) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, ()>( + WrapInfo { + debug_name: "event_stream", + port: Some(port_), + mode: FfiCallMode::Stream, + }, + move || { + move |task_callback| { + Ok(event_stream( + task_callback.stream_sink::<_, Option<[String; 2]>>(), + )) + } + }, + ) +} +fn wire_pair_impl(port_: MessagePort) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, String>( + WrapInfo { + debug_name: "pair", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || move |task_callback| Ok(pair()), + ) +} +fn wire_dismiss_impl(port_: MessagePort) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, ()>( + WrapInfo { + debug_name: "dismiss", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || move |task_callback| Ok(dismiss()), + ) +} +// Section: wrapper structs + +// Section: static checks + +// Section: allocate functions + +// Section: related functions + +// Section: impl Wire2Api + +pub trait Wire2Api { + fn wire2api(self) -> T; +} + +impl Wire2Api> for *mut S +where + *mut S: Wire2Api, +{ + fn wire2api(self) -> Option { + (!self.is_null()).then(|| self.wire2api()) + } +} +// Section: impl IntoDart + +// Section: executor + +support::lazy_static! { + pub static ref FLUTTER_RUST_BRIDGE_HANDLER: support::DefaultHandler = Default::default(); +} + +#[cfg(not(target_family = "wasm"))] +#[path = "bridge_generated.io.rs"] +mod io; +#[cfg(not(target_family = "wasm"))] +pub use io::*; diff --git a/fastpair/rust/demo/rust/src/decoder.rs b/fastpair/rust/demo/rust/src/decoder.rs new file mode 100644 index 00000000..fd190557 --- /dev/null +++ b/fastpair/rust/demo/rust/src/decoder.rs @@ -0,0 +1,90 @@ +// 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. + +use bluetooth::ServiceData; + +use crate::error::FpError; + +/// Unit struct providing parsing operations for Fast Pair advertisements. +pub(crate) struct FpDecoder; + +impl FpDecoder { + /// Retrieve the Fast Pair device model ID from a service data payload. + /// https://developers.google.com/nearby/fast-pair/specifications/service/provider. + /// * Length < 3: invalid payload + /// * Length == 3: entire payload is the model ID + /// * Length > 3: first byte specifies the length of the model ID, in bytes. + /// Currently unavailable in Fast Pair devices and not supported. + pub(crate) fn get_model_id_from_service_data( + service_data: &ServiceData, + ) -> Result, FpError> { + const MIN_MODEL_ID_LENGTH: usize = 3; + let data = service_data.data(); + + if data.len() < MIN_MODEL_ID_LENGTH { + // If service data too small, invalid payload. + Err(FpError::ContractViolation(format!( + "Invalid model ID for Fast Pair advertisement of length {}.", + data.len() + ))) + } else if data.len() == MIN_MODEL_ID_LENGTH { + // Else if service data length is exactly 3, all bytes are the ID. + Ok(data.clone()) + } else { + // Else, this Fast Pair advertisement is currently unsupported. + // b/294453912 + Err(FpError::NotImplemented(String::from( + "This Fast Pair device is currently unsupported.", + ))) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_get_model_id_valid() { + // Valid scenario: Length == 3 + let uuid: u16 = 0x1234; + let data = vec![0xAA, 0xBB, 0xCC]; + let service_data = ServiceData::new(uuid, data.clone()); + let result = FpDecoder::get_model_id_from_service_data(&service_data); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), data); + } + + #[test] + fn test_get_model_id_invalid() { + // Invalid scenario: Length < 3 + let uuid: u16 = 0x1234; + let data = vec![0xAA, 0xBB]; + let service_data = ServiceData::new(uuid, data); + let result = FpDecoder::get_model_id_from_service_data(&service_data); + assert!(result.is_err()); + assert!(matches!(result.unwrap_err(), FpError::ContractViolation(_))); + } + + #[test] + fn test_get_model_id_unsupported() { + // Unsupported scenario: Length > 3 + let uuid: u16 = 0x1234; + let data = vec![0xAA, 0xBB, 0xCC, 0xDD]; + let service_data = ServiceData::new(uuid, data); + let result = FpDecoder::get_model_id_from_service_data(&service_data); + assert!(result.is_err()); + assert!(matches!(result.unwrap_err(), FpError::NotImplemented(_))); + } +} diff --git a/fastpair/rust/demo/rust/src/error.rs b/fastpair/rust/demo/rust/src/error.rs new file mode 100644 index 00000000..81ecb400 --- /dev/null +++ b/fastpair/rust/demo/rust/src/error.rs @@ -0,0 +1,43 @@ +// 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. + +use thiserror::Error; + +/// Library error type. +#[non_exhaustive] +#[derive(Error, Debug, PartialEq, Clone)] +pub enum FpError { + /// Reported when a requested resource could not be accessed, either because + /// it's missing or because the user lacks access permissions. + #[error("not found: {0}")] + AccessDenied(String), + /// Reported when Fast Pair functionality does not behave according to the + /// specification. For example, advertisement packets with invalid lengths, + /// JSON data with bad formatting, etc. + #[error("contract violation: {0}")] + ContractViolation(String), + /// Reported when trying to invoke Fast Pair functionality that is currently + /// not implemented. + #[error("feature not implemented: {0}")] + NotImplemented(String), + /// Reported when a bug occurs inside the library. Whenever a seemingly + /// impossible error condition arises where you could call `expect()`, + /// return this error instead. + #[error("internal error: {0}")] + Internal(String), + /// Reported when an error was intentionally raised by test code. + #[error("intentional error")] + #[cfg(test)] + Test, +} diff --git a/fastpair/rust/demo/rust/src/fetcher/common.rs b/fastpair/rust/demo/rust/src/fetcher/common.rs new file mode 100644 index 00000000..d2bc13f4 --- /dev/null +++ b/fastpair/rust/demo/rust/src/fetcher/common.rs @@ -0,0 +1,63 @@ +// 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. + +use serde::Deserialize; + +use crate::{advertisement::ModelId, error::FpError}; + +/// Types that can fetch Fast Pair data from external storage (e.g. filesystem, +/// remote server). +pub(crate) trait FpFetcher { + fn get_device_info_from_model_id(&self, model_id: &ModelId) -> Result; +} + +/// Holds Fast Pair device information parsed from JSON. +#[derive(Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct DeviceInfo { + image_url: String, + name: String, +} + +/// Holds top-level Fast Pair information parsed from JSON. See `local` +/// directory for format. +#[derive(Deserialize)] +pub(super) struct JsonData { + device: DeviceInfo, +} + +impl DeviceInfo { + // `new()` is conceivably only used in tests, since this struct should be + // constructed by serde_json. Therefore, adding cfg to disable dead code + // warnings. Can be removed in the future. + #[cfg(test)] + pub(crate) fn new(image_url: String, name: String) -> Self { + DeviceInfo { image_url, name } + } + + pub(crate) fn name(&self) -> &String { + &self.name + } + + pub(crate) fn image_url(&self) -> &String { + &self.image_url + } +} + +impl JsonData { + // Returns the `DeviceInfo` associated with parsed self, consuming self. + pub(super) fn device(self) -> DeviceInfo { + self.device + } +} diff --git a/fastpair/rust/demo/rust/src/fetcher/fs.rs b/fastpair/rust/demo/rust/src/fetcher/fs.rs new file mode 100644 index 00000000..df2db495 --- /dev/null +++ b/fastpair/rust/demo/rust/src/fetcher/fs.rs @@ -0,0 +1,49 @@ +// 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. + +use std::fs; + +use crate::{ + advertisement::ModelId, + error::FpError, + fetcher::{DeviceInfo, FpFetcher, JsonData}, +}; + +/// A struct for retrieving Fast Pair information from the local filesystem. +pub(crate) struct FpFetcherFs { + path: String, +} + +impl FpFetcherFs { + pub(crate) fn new(path: String) -> Self { + FpFetcherFs { path } + } +} + +impl FpFetcher for FpFetcherFs { + /// Retrieve device information for the provided Model ID. Currently, + /// this information is saved locally. In the future, this should instead + /// be retrieved from a remote server and cached. + /// b/294456411 + fn get_device_info_from_model_id(&self, model_id: &ModelId) -> Result { + let file_path = format!("{}/{}.json", self.path, model_id); + let contents = fs::read_to_string(file_path) + .or_else(|err| Err(FpError::AccessDenied(err.to_string())))?; + + let model_info: JsonData = serde_json::from_str(&contents) + .or_else(|err| Err(FpError::ContractViolation(err.to_string())))?; + + Ok(model_info.device()) + } +} diff --git a/fastpair/rust/demo/rust/src/fetcher/mock.rs b/fastpair/rust/demo/rust/src/fetcher/mock.rs new file mode 100644 index 00000000..1d82efb5 --- /dev/null +++ b/fastpair/rust/demo/rust/src/fetcher/mock.rs @@ -0,0 +1,38 @@ +// 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. + +use crate::{ + advertisement::ModelId, + error::FpError, + fetcher::{DeviceInfo, FpFetcher}, +}; + +/// A struct for mocking retrieval of Fast Pair data. +pub(crate) struct FpFetcherMock { + device_info_from_model_id: Result, +} + +impl FpFetcherMock { + pub(crate) fn new(device_info_from_model_id: Result) -> Self { + FpFetcherMock { + device_info_from_model_id, + } + } +} + +impl FpFetcher for FpFetcherMock { + fn get_device_info_from_model_id(&self, _model_id: &ModelId) -> Result { + self.device_info_from_model_id.clone() + } +} diff --git a/fastpair/rust/tests/integration_test.rs b/fastpair/rust/demo/rust/src/fetcher/mod.rs similarity index 82% rename from fastpair/rust/tests/integration_test.rs rename to fastpair/rust/demo/rust/src/fetcher/mod.rs index 18021531..98772f6e 100644 --- a/fastpair/rust/tests/integration_test.rs +++ b/fastpair/rust/demo/rust/src/fetcher/mod.rs @@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use fastpair::*; +pub(crate) mod common; +pub(crate) mod fs; -mod tests { - use super::*; +#[cfg(test)] +pub(crate) mod mock; - // TODO b/288592509 write integration tests -} +pub(crate) use common::*; +pub(crate) use fs::*; diff --git a/fastpair/rust/demo/rust/src/lib.rs b/fastpair/rust/demo/rust/src/lib.rs new file mode 100644 index 00000000..3d3f5bfb --- /dev/null +++ b/fastpair/rust/demo/rust/src/lib.rs @@ -0,0 +1,20 @@ +// 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. + +mod advertisement; +mod api; +mod bridge_generated; /* AUTO INJECTED BY flutter_rust_bridge. This line may not be accurate, and you can change it according to your needs. */ +mod decoder; +mod error; +mod fetcher; diff --git a/fastpair/rust/demo/windows/.gitignore b/fastpair/rust/demo/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/fastpair/rust/demo/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/fastpair/rust/demo/windows/CMakeLists.txt b/fastpair/rust/demo/windows/CMakeLists.txt new file mode 100644 index 00000000..172a9862 --- /dev/null +++ b/fastpair/rust/demo/windows/CMakeLists.txt @@ -0,0 +1,103 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(demo LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "demo") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) +include(./rust.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/fastpair/rust/demo/windows/flutter/CMakeLists.txt b/fastpair/rust/demo/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..930d2071 --- /dev/null +++ b/fastpair/rust/demo/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/fastpair/rust/src/lib.rs b/fastpair/rust/demo/windows/flutter/generated_plugin_registrant.cc similarity index 78% rename from fastpair/rust/src/lib.rs rename to fastpair/rust/demo/windows/flutter/generated_plugin_registrant.cc index c9a294f5..5da9cfa4 100644 --- a/fastpair/rust/src/lib.rs +++ b/fastpair/rust/demo/windows/flutter/generated_plugin_registrant.cc @@ -12,5 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Library file, exports modules for use in integration tests and external crates. -pub mod bluetooth; +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "./generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/fastpair/rust/src/bluetooth/unsupported/device.rs b/fastpair/rust/demo/windows/flutter/generated_plugin_registrant.h similarity index 61% rename from fastpair/rust/src/bluetooth/unsupported/device.rs rename to fastpair/rust/demo/windows/flutter/generated_plugin_registrant.h index 6c8bc520..7e32ef7b 100644 --- a/fastpair/rust/src/bluetooth/unsupported/device.rs +++ b/fastpair/rust/demo/windows/flutter/generated_plugin_registrant.h @@ -12,20 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::bluetooth::common::Device; +// +// Generated file. Do not edit. +// -/// Concrete type implementing `Device`, used for unsupported devices. -/// Every method should panic. -pub struct BleDevice; +// clang-format off -impl Device for BleDevice { - fn name(&self) -> Result { - panic!("Unsupported target platform.") - } -} +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ -mod tests { - use super::*; +#include - // TODO b/288592509 unit tests -} +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/fastpair/rust/demo/windows/flutter/generated_plugins.cmake b/fastpair/rust/demo/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/fastpair/rust/demo/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/fastpair/rust/demo/windows/runner/CMakeLists.txt b/fastpair/rust/demo/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/fastpair/rust/demo/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/fastpair/rust/demo/windows/runner/Runner.rc b/fastpair/rust/demo/windows/runner/Runner.rc new file mode 100644 index 00000000..3c7cdc73 --- /dev/null +++ b/fastpair/rust/demo/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "demo" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "demo" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "demo.exe" "\0" + VALUE "ProductName", "demo" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/fastpair/rust/demo/windows/runner/flutter_window.cpp b/fastpair/rust/demo/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..0f6bf6e4 --- /dev/null +++ b/fastpair/rust/demo/windows/runner/flutter_window.cpp @@ -0,0 +1,80 @@ +// 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 "./flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/fastpair/rust/demo/windows/runner/flutter_window.h b/fastpair/rust/demo/windows/runner/flutter_window.h new file mode 100644 index 00000000..adb318a0 --- /dev/null +++ b/fastpair/rust/demo/windows/runner/flutter_window.h @@ -0,0 +1,47 @@ +// 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 RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "./win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/fastpair/rust/demo/windows/runner/main.cpp b/fastpair/rust/demo/windows/runner/main.cpp new file mode 100644 index 00000000..2827bb3a --- /dev/null +++ b/fastpair/rust/demo/windows/runner/main.cpp @@ -0,0 +1,57 @@ +// 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 +#include +#include + +#include "./flutter_window.h" +#include "./utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"demo", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/fastpair/rust/src/main.rs b/fastpair/rust/demo/windows/runner/resource.h similarity index 53% rename from fastpair/rust/src/main.rs rename to fastpair/rust/demo/windows/runner/resource.h index 5905e135..85a4c6eb 100644 --- a/fastpair/rust/src/main.rs +++ b/fastpair/rust/demo/windows/runner/resource.h @@ -12,23 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -use futures::executor; +// {{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#ifndef RUNNER_RESOURCE_H_ +#define RUNNER_RESOURCE_H_ +#define IDI_APP_ICON 101 -mod bluetooth; - -use bluetooth::{Adapter, Device}; - -fn main() -> Result<(), anyhow::Error> { - let run = async { - let mut adapter = bluetooth::default_adapter().await?; - adapter.start_scan_devices()?; - - while let Ok(device) = adapter.next_device().await { - println!("found {}", device.name()?) - } - - unreachable!("Done scanning"); - }; - - executor::block_on(run) -} +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif +#endif // RUNNER_RESOURCE_H_ diff --git a/fastpair/rust/demo/windows/runner/resources/app_icon.ico b/fastpair/rust/demo/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/fastpair/rust/demo/windows/runner/resources/app_icon.ico differ diff --git a/fastpair/rust/demo/windows/runner/runner.exe.manifest b/fastpair/rust/demo/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..a42ea768 --- /dev/null +++ b/fastpair/rust/demo/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/fastpair/rust/demo/windows/runner/utils.cpp b/fastpair/rust/demo/windows/runner/utils.cpp new file mode 100644 index 00000000..070097ec --- /dev/null +++ b/fastpair/rust/demo/windows/runner/utils.cpp @@ -0,0 +1,79 @@ +// 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 "./utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/fastpair/rust/demo/windows/runner/utils.h b/fastpair/rust/demo/windows/runner/utils.h new file mode 100644 index 00000000..b089ab5f --- /dev/null +++ b/fastpair/rust/demo/windows/runner/utils.h @@ -0,0 +1,33 @@ +// 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 RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/fastpair/rust/demo/windows/runner/win32_window.cpp b/fastpair/rust/demo/windows/runner/win32_window.cpp new file mode 100644 index 00000000..b3c2fa35 --- /dev/null +++ b/fastpair/rust/demo/windows/runner/win32_window.cpp @@ -0,0 +1,303 @@ +// 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 "./win32_window.h" + +#include +#include + +#include "./resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = + L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/fastpair/rust/demo/windows/runner/win32_window.h b/fastpair/rust/demo/windows/runner/win32_window.h new file mode 100644 index 00000000..0597809c --- /dev/null +++ b/fastpair/rust/demo/windows/runner/win32_window.h @@ -0,0 +1,116 @@ +// 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 RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/fastpair/rust/demo/windows/rust.cmake b/fastpair/rust/demo/windows/rust.cmake new file mode 100644 index 00000000..4931b359 --- /dev/null +++ b/fastpair/rust/demo/windows/rust.cmake @@ -0,0 +1,21 @@ +# We include Corrosion inline here, but ideally in a project with +# many dependencies we would need to install Corrosion on the system. +# See instructions on https://github.com/AndrewGaspar/corrosion#cmake-install +# Once done, uncomment this line: +# find_package(Corrosion REQUIRED) + +include(FetchContent) + +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/AndrewGaspar/corrosion.git + GIT_TAG origin/master # Optionally specify a version tag or branch here +) + +FetchContent_MakeAvailable(Corrosion) + +corrosion_import_crate(MANIFEST_PATH ../rust/Cargo.toml IMPORTED_CRATES imported_crates) +target_link_libraries(${BINARY_NAME} PRIVATE ${imported_crates}) +foreach(imported_crate ${imported_crates}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) +endforeach() \ No newline at end of file diff --git a/fastpair/rust/src/bluetooth/windows_ble/device.rs b/fastpair/rust/src/bluetooth/windows_ble/device.rs deleted file mode 100644 index 08c3d123..00000000 --- a/fastpair/rust/src/bluetooth/windows_ble/device.rs +++ /dev/null @@ -1,58 +0,0 @@ -// 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. - -use async_trait::async_trait; -use windows::Devices::Bluetooth::{ - // Enum describing the type of address (public, random, unspecified). - // https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothaddresstype?view=winrt-22621 - BluetoothAddressType, - - // Struct for interacting with and pairing to a discovered BLE device. - // https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothledevice?view=winrt-22621 - BluetoothLEDevice, -}; - -use crate::bluetooth::common::Device; - -/// Concrete type implementing `Device`, used for Windows BLE. -pub struct BleDevice { - inner: BluetoothLEDevice, -} - -impl BleDevice { - /// Create a `BleDevice` instance from the raw bluetooth address information. - pub(super) async fn from_addr( - addr: u64, - kind: BluetoothAddressType, - ) -> Result { - let inner = - BluetoothLEDevice::FromBluetoothAddressWithBluetoothAddressTypeAsync(addr, kind)? - .await?; - - Ok(BleDevice { inner }) - } -} - -#[async_trait] -impl Device for BleDevice { - fn name(&self) -> Result { - Ok(self.inner.Name()?.to_string_lossy()) - } -} - -mod tests { - use super::*; - - // TODO b/288592509 unit tests -} diff --git a/fastpair/scanning/BUILD b/fastpair/scanning/BUILD index 521dd002..c4b35887 100644 --- a/fastpair/scanning/BUILD +++ b/fastpair/scanning/BUILD @@ -33,7 +33,6 @@ cc_library( "//fastpair/repository:device_repository", "//fastpair/scanning/fastpair:scanning", "//internal/base", - "//internal/platform:logging", "//internal/platform:types", "@com_google_absl//absl/functional:bind_front", ], @@ -68,6 +67,7 @@ cc_test( "//fastpair/common", "//fastpair/internal/mediums", "//fastpair/proto:fastpair_cc_proto", + "//fastpair/repository:device_repository", "//fastpair/repository:test_support", "//fastpair/testing", "//internal/platform:base", diff --git a/fastpair/scanning/fastpair/BUILD b/fastpair/scanning/fastpair/BUILD index 3ece0245..f70cd686 100644 --- a/fastpair/scanning/fastpair/BUILD +++ b/fastpair/scanning/fastpair/BUILD @@ -41,7 +41,6 @@ cc_library( "//internal/base", "//internal/platform:base", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:types", "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/functional:bind_front", diff --git a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner.cc b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner.cc index e44f5172..5206bf93 100644 --- a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner.cc +++ b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner.cc @@ -203,20 +203,27 @@ void FastPairDiscoverableScanner::NotifyDeviceFound(FastPairDevice& device) { NEARBY_LOGS(VERBOSE) << "Notify Device found:" << "BluetoothAddress = " << device.GetBleAddress() << ", Model id = " << device.GetModelId(); + { + MutexLock lock(&mutex_); + notified_devices_[device.GetBleAddress()] = &device; + } found_callback_(device); } void FastPairDiscoverableScanner::OnDeviceLost( const BlePeripheral& peripheral) { NEARBY_LOGS(INFO) << __func__ << ": Running lost callback"; + { + MutexLock lock(&mutex_); + auto node = notified_devices_.extract(peripheral.GetName()); + // Don't invoke callback if we didn't notify this device. + if (node.empty()) return; + } executor_->Execute("device-lost", [this, address = peripheral.GetName()]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { auto opt_device = device_repository_->FindDevice(address); - - // Don't invoke callback if we didn't notify this - // device. if (!opt_device.has_value()) return; FastPairDevice* device = opt_device.value(); lost_callback_(*device); diff --git a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h index c53243e0..69606136 100644 --- a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h +++ b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h @@ -26,7 +26,7 @@ #include "fastpair/scanning/fastpair/fast_pair_scanner.h" #include "internal/base/observer_list.h" #include "internal/platform/bluetooth_adapter.h" -#include "internal/platform/logging.h" +#include "internal/platform/mutex.h" #include "internal/platform/single_thread_executor.h" namespace nearby { @@ -84,10 +84,13 @@ class FastPairDiscoverableScanner : public FastPairScanner::Observer { void NotifyDeviceFound(FastPairDevice& device) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); + Mutex mutex_; FastPairScanner& scanner_; DiscoverableScannerCallback found_callback_ ABSL_GUARDED_BY(*executor_); DiscoverableScannerCallback lost_callback_ ABSL_GUARDED_BY(*executor_); SingleThreadExecutor* executor_; + absl::flat_hash_map notified_devices_ + ABSL_GUARDED_BY(mutex_); FastPairDeviceRepository* device_repository_ ABSL_GUARDED_BY(*executor_); ObserverList observer_list_; }; diff --git a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_test.cc b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_test.cc index cc639a10..f487e463 100644 --- a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_test.cc +++ b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_test.cc @@ -309,8 +309,6 @@ TEST_F(FastPairDiscoverableScannerTest, std::make_unique(kTestBleDeviceAddress, kValidModelId); scanner_->NotifyDeviceLost(BlePeripheral(ble_peripheral.get())); EXPECT_FALSE(lost_notification.WaitForNotificationWithTimeout(kWaitTimeout)); - scanner_->NotifyDeviceLost(BlePeripheral(ble_peripheral.get())); - EXPECT_FALSE(lost_notification.WaitForNotificationWithTimeout(kWaitTimeout)); } } // namespace diff --git a/fastpair/scanning/fastpair/fast_pair_non_discoverable_scanner.cc b/fastpair/scanning/fastpair/fast_pair_non_discoverable_scanner.cc index 43148584..009ab87e 100644 --- a/fastpair/scanning/fastpair/fast_pair_non_discoverable_scanner.cc +++ b/fastpair/scanning/fastpair/fast_pair_non_discoverable_scanner.cc @@ -169,20 +169,27 @@ void FastPairNonDiscoverableScanner::NotifyDeviceFound(FastPairDevice& device) { NEARBY_LOGS(VERBOSE) << "Notify Device found:" << "BluetoothAddress = " << device.GetBleAddress() << ", Model id = " << device.GetModelId(); + { + MutexLock lock(&mutex_); + notified_devices_[device.GetBleAddress()] = &device; + } found_callback_(device); } void FastPairNonDiscoverableScanner::OnDeviceLost( const BlePeripheral& peripheral) { NEARBY_LOGS(INFO) << __func__ << ": Running lost callback"; + { + MutexLock lock(&mutex_); + auto node = notified_devices_.extract(peripheral.GetName()); + // Don't invoke callback if we didn't notify this device. + if (node.empty()) return; + } executor_->Execute("device-lost", [this, address = peripheral.GetName()]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { auto opt_device = device_repository_->FindDevice(address); - - // Don't invoke callback if we didn't notify this - // device. if (!opt_device.has_value()) return; FastPairDevice* device = opt_device.value(); lost_callback_(*device); diff --git a/fastpair/scanning/fastpair/fast_pair_non_discoverable_scanner.h b/fastpair/scanning/fastpair/fast_pair_non_discoverable_scanner.h index aa38e825..1db0c2cc 100644 --- a/fastpair/scanning/fastpair/fast_pair_non_discoverable_scanner.h +++ b/fastpair/scanning/fastpair/fast_pair_non_discoverable_scanner.h @@ -24,6 +24,7 @@ #include "fastpair/repository/fast_pair_device_repository.h" #include "fastpair/scanning/fastpair/fast_pair_scanner.h" #include "internal/base/observer_list.h" +#include "internal/platform/mutex.h" #include "internal/platform/single_thread_executor.h" namespace nearby { @@ -90,10 +91,13 @@ class FastPairNonDiscoverableScanner : public FastPairScanner::Observer { void NotifyDeviceFound(FastPairDevice& device) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); + Mutex mutex_; FastPairScanner& scanner_; NonDiscoverableScannerCallback found_callback_ ABSL_GUARDED_BY(*executor_); NonDiscoverableScannerCallback lost_callback_ ABSL_GUARDED_BY(*executor_); SingleThreadExecutor* executor_; + absl::flat_hash_map notified_devices_ + ABSL_GUARDED_BY(mutex_); FastPairDeviceRepository* device_repository_ ABSL_GUARDED_BY(*executor_); ObserverList observer_list_; }; diff --git a/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc b/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc index 80c9c254..184bd3aa 100644 --- a/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc +++ b/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc @@ -16,6 +16,7 @@ #include #include +#include #include "gtest/gtest.h" #include "absl/strings/escaping.h" @@ -26,6 +27,7 @@ #include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/medium_environment.h" +#include "internal/platform/single_thread_executor.h" namespace nearby { namespace fastpair { @@ -61,18 +63,16 @@ class FastPairScannerObserver : public FastPairScanner::Observer { }; class FastPairScannerImplTest : public testing::Test { - protected: - MediumEnvironment& env_{MediumEnvironment::Instance()}; - - SingleThreadExecutor executor_; + public: + void SetUp() override { MediumEnvironment::Instance().Start(); } + void TearDown() override { MediumEnvironment::Instance().Stop(); } }; TEST_F(FastPairScannerImplTest, StartScanning) { - env_.Start(); - // Create Fast Pair Scanner and add its observer Mediums mediums_1; - auto scanner = std::make_unique(mediums_1, &executor_); + SingleThreadExecutor executor; + auto scanner = std::make_unique(mediums_1, &executor); CountDownLatch accept_latch(1); CountDownLatch lost_latch(1); FastPairScannerObserver observer(scanner.get(), &accept_latch, &lost_latch); @@ -95,14 +95,14 @@ TEST_F(FastPairScannerImplTest, StartScanning) { // Notify device lost EXPECT_TRUE(lost_latch.Await(kTaskWaitTimeout).result()); scan_session.reset(); - env_.Stop(); + DestroyOnExecutor(std::move(scanner), &executor); } TEST_F(FastPairScannerImplTest, StopScanning) { - env_.Start(); // Create Fast Pair Scanner and add its observer Mediums mediums_1; - auto scanner = std::make_unique(mediums_1, &executor_); + SingleThreadExecutor executor; + auto scanner = std::make_unique(mediums_1, &executor); CountDownLatch accept_latch(1); CountDownLatch lost_latch(1); FastPairScannerObserver observer(scanner.get(), &accept_latch, &lost_latch); @@ -120,7 +120,7 @@ TEST_F(FastPairScannerImplTest, StopScanning) { mediums_2.GetBle().GetMedium().StopAdvertising(service_id); // Device lost event should not be delivered when scan session has terminated. EXPECT_FALSE(lost_latch.Await(kShortTimeout).result()); - env_.Stop(); + DestroyOnExecutor(std::move(scanner), &executor); } } // namespace diff --git a/fastpair/scanning/scanner_broker_impl_test.cc b/fastpair/scanning/scanner_broker_impl_test.cc index 58f3eb1c..6e00d9a4 100644 --- a/fastpair/scanning/scanner_broker_impl_test.cc +++ b/fastpair/scanning/scanner_broker_impl_test.cc @@ -26,16 +26,17 @@ #include "fastpair/internal/mediums/mediums.h" #include "fastpair/proto/fastpair_rpcs.proto.h" #include "fastpair/repository/fake_fast_pair_repository.h" +#include "fastpair/repository/fast_pair_device_repository.h" #include "fastpair/scanning/scanner_broker.h" #include "fastpair/testing/fast_pair_service_data_creator.h" #include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/medium_environment.h" +#include "internal/platform/single_thread_executor.h" namespace nearby { namespace fastpair { namespace { -constexpr absl::Duration kTaskWaitTimeout = absl::Milliseconds(1000); constexpr int kNotDiscoverableAdvHeader = 0b00000110; constexpr int kAccountKeyFilterHeader = 0b01100000; constexpr int kSaltHeader = 0b00010001; @@ -70,38 +71,62 @@ class ScannerBrokerObserver : public ScannerBroker::Observer { CountDownLatch* lost_latch_ = nullptr; }; +class MediumEnvironmentStarter { + public: + MediumEnvironmentStarter() { MediumEnvironment::Instance().Start(); } + ~MediumEnvironmentStarter() { MediumEnvironment::Instance().Stop(); } +}; + class ScannerBrokerImplTest : public testing::Test { protected: - MediumEnvironment& env_{MediumEnvironment::Instance()}; + void SetUp() override { + MediumEnvironment::Instance().Start(); + advertiser_ble_address_ = + mediums_advertiser_.GetBle().GetMedium().GetAdapter().GetMacAddress(); + } + + void TearDown() override { MediumEnvironment::Instance().Stop(); } + + // The medium environment must be initialized (started) + // before registering medium. + MediumEnvironmentStarter env_; + Mediums mediums_scanner_; + Mediums mediums_advertiser_; + std::string advertiser_ble_address_; }; TEST_F(ScannerBrokerImplTest, FoundDiscoverableAdvertisement) { - env_.Start(); + SingleThreadExecutor executor; + FastPairDeviceRepository devices{&executor}; + // Setup FakeFastPairRepository std::string decoded_key; absl::Base64Unescape(kPublicAntiSpoof, &decoded_key); - SingleThreadExecutor executor; - FastPairDeviceRepository devices(&executor); proto::Device metadata; auto repository_ = std::make_unique(); metadata.mutable_anti_spoofing_key_pair()->set_public_key(decoded_key); repository_->SetFakeMetadata(kModelId, metadata); - // Create Fast Pair Scanner and add its observer - Mediums mediums_1; - auto scanner_broker = - std::make_unique(mediums_1, &executor, &devices); + // Create Scanner and ScannerBrokerObserver + auto scanner_broker = std::make_unique( + mediums_scanner_, &executor, &devices); CountDownLatch accept_latch(1); CountDownLatch lost_latch(1); + CountDownLatch device_removed(1); + FastPairDeviceRepository::RemoveDeviceCallback callback = + [&](const FastPairDevice& device) { + EXPECT_EQ(device.GetBleAddress(), advertiser_ble_address_); + device_removed.CountDown(); + }; + devices.AddObserver(&callback); ScannerBrokerObserver observer(scanner_broker.get(), &accept_latch, &lost_latch); // Create Advertiser and startAdvertising - Mediums mediums_2; std::string service_id(kServiceID); ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; std::string fast_pair_service_uuid(kFastPairServiceUuid); - mediums_2.GetBle().GetMedium().StartAdvertising( + mediums_advertiser_.GetBle().GetMedium().StartAdvertising( service_id, advertisement_bytes, fast_pair_service_uuid); // Fast Pair scanner startScanning @@ -109,38 +134,44 @@ TEST_F(ScannerBrokerImplTest, FoundDiscoverableAdvertisement) { scanner_broker->StartScanning(Protocol::kFastPairInitialPairing); // Notify device found - EXPECT_TRUE(accept_latch.Await(kTaskWaitTimeout).result()); + accept_latch.Await(); // Advertiser stopAdvertising - mediums_2.GetBle().GetMedium().StopAdvertising(service_id); + mediums_advertiser_.GetBle().GetMedium().StopAdvertising(service_id); // Notify device lost - EXPECT_TRUE(lost_latch.Await(kTaskWaitTimeout).result()); + lost_latch.Await(); + device_removed.Await(); scanning_session.reset(); - env_.Stop(); } TEST_F(ScannerBrokerImplTest, FoundNonDiscoverableAdvertisement) { - env_.Start(); SingleThreadExecutor executor; - FastPairDeviceRepository devices(&executor); + FastPairDeviceRepository devices{&executor}; + + // Setup FakeFastPairRepository auto repository = std::make_unique(); proto::Device metadata; repository->SetFakeMetadata(kModelId, metadata); repository->SetResultOfCheckIfAssociatedWithCurrentAccount(AccountKey(), kModelId); - // Create Fast Pair Scanner and add its observer - Mediums mediums_1; - auto scanner_broker = - std::make_unique(mediums_1, &executor, &devices); + // Create Scanner and ScannerBrokerObserver + auto scanner_broker = std::make_unique( + mediums_scanner_, &executor, &devices); CountDownLatch accept_latch(1); CountDownLatch lost_latch(1); + CountDownLatch device_removed(1); + FastPairDeviceRepository::RemoveDeviceCallback callback = + [&](const FastPairDevice& device) { + EXPECT_EQ(device.GetBleAddress(), advertiser_ble_address_); + device_removed.CountDown(); + }; + devices.AddObserver(&callback); ScannerBrokerObserver observer(scanner_broker.get(), &accept_latch, &lost_latch); // Create Advertiser and startAdvertising - Mediums mediums_2; std::string service_id(kServiceID); std::vector service_data = FastPairServiceDataCreator::Builder() @@ -155,7 +186,7 @@ TEST_F(ScannerBrokerImplTest, FoundNonDiscoverableAdvertisement) { ByteArray advertisement_bytes( std::string(service_data.begin(), service_data.end())); std::string fast_pair_service_uuid(kFastPairServiceUuid); - mediums_2.GetBle().GetMedium().StartAdvertising( + mediums_advertiser_.GetBle().GetMedium().StartAdvertising( service_id, advertisement_bytes, fast_pair_service_uuid); // Fast Pair scanner startScanning @@ -163,16 +194,17 @@ TEST_F(ScannerBrokerImplTest, FoundNonDiscoverableAdvertisement) { scanner_broker->StartScanning(Protocol::kFastPairInitialPairing); // Notify device found - EXPECT_TRUE(accept_latch.Await(kTaskWaitTimeout).result()); + accept_latch.Await(); // Advertiser stopAdvertising - mediums_2.GetBle().GetMedium().StopAdvertising(service_id); + mediums_advertiser_.GetBle().GetMedium().StopAdvertising(service_id); // Notify device lost - EXPECT_TRUE(lost_latch.Await(kTaskWaitTimeout).result()); + lost_latch.Await(); + device_removed.Await(); scanning_session.reset(); - env_.Stop(); } + } // namespace } // namespace fastpair } // namespace nearby diff --git a/fastpair/server_access/BUILD b/fastpair/server_access/BUILD index 6aeffa98..89bfffa7 100644 --- a/fastpair/server_access/BUILD +++ b/fastpair/server_access/BUILD @@ -36,7 +36,6 @@ cc_library( "//internal/auth:types", "//internal/base", "//internal/network:types", - "//internal/platform:logging", "//internal/platform:types", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", diff --git a/fastpair/ui/BUILD b/fastpair/ui/BUILD index 52fef3f8..83ae1108 100644 --- a/fastpair/ui/BUILD +++ b/fastpair/ui/BUILD @@ -37,7 +37,7 @@ cc_library( "//fastpair/common", "//fastpair/repository", "//internal/base", - "//internal/platform:logging", + "//internal/platform:types", "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/strings", ], @@ -88,6 +88,7 @@ cc_test( ":fake_fast_pair_ui", ":fast_pair_ui", "//fastpair/common", + "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_googletest//:gtest_main", diff --git a/fastpair/ui/actions.h b/fastpair/ui/actions.h index 6228d4ee..d8b85a89 100644 --- a/fastpair/ui/actions.h +++ b/fastpair/ui/actions.h @@ -21,10 +21,12 @@ namespace fastpair { enum class DiscoveryAction { kUnknown = 0, kPairToDevice = 1, - kDismissedByUser = 2, - kDismissedByOs = 3, - kLearnMore = 4, - kDismissedByTimeout = 5, + kSaveDeviceToAccount = 2, + kDismissedByUser = 3, + kDismissedByOs = 4, + kLearnMore = 5, + kDone = 6, + kDismissedByTimeout = 7, }; } // namespace fastpair diff --git a/fastpair/ui/fast_pair/fake_fast_pair_notification_controller_observer.h b/fastpair/ui/fast_pair/fake_fast_pair_notification_controller_observer.h index 2c1a15d9..0416beda 100644 --- a/fastpair/ui/fast_pair/fake_fast_pair_notification_controller_observer.h +++ b/fastpair/ui/fast_pair/fake_fast_pair_notification_controller_observer.h @@ -21,8 +21,10 @@ #include #include "fastpair/common/device_metadata.h" +#include "fastpair/common/fast_pair_device.h" #include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" #include "internal/platform/count_down_latch.h" +#include "internal/platform/mutex_lock.h" namespace nearby { namespace fastpair { @@ -30,35 +32,45 @@ class FakeFastPairNotificationControllerObserver : public FastPairNotificationController::Observer { public: explicit FakeFastPairNotificationControllerObserver( - std::optional latch) { - latch_ = latch; + CountDownLatch* on_device_updated_latch, + CountDownLatch* on_pairing_result_latch) { + on_device_updated_latch_ = on_device_updated_latch; + on_pairing_result_latch_ = on_pairing_result_latch; } - void OnUpdateDevice(const DeviceMetadata& device) override { - device_metadata_name_list_.push_back(device.GetDetails().name()); - on_update_device_count_++; - if (latch_.has_value()) { - latch_->CountDown(); + void OnUpdateDevice(FastPairDevice& device) override { + MutexLock lock(&mutex_); + device_ = &const_cast(device); + if (on_device_updated_latch_) { + on_device_updated_latch_->CountDown(); } } - bool CheckDeviceMetadataListContainTestDevice( - const std::string& device_name) { - auto it = std::find(device_metadata_name_list_.begin(), - device_metadata_name_list_.end(), device_name); - return it != device_metadata_name_list_.end(); + void OnPairingResult(FastPairDevice& device, bool success) override { + MutexLock lock(&mutex_); + pairing_result_ = success; + device_ = &const_cast(device); + if (on_pairing_result_latch_) { + on_pairing_result_latch_->CountDown(); + } } - int on_update_device_count() { return on_update_device_count_; } + FastPairDevice* GetDevice() { + MutexLock lock(&mutex_); + return device_; + } - std::vector device_metadata_name_list() { - return device_metadata_name_list_; + std::optional GetPairingResult() { + MutexLock lock(&mutex_); + return pairing_result_; } private: - std::vector device_metadata_name_list_; - int on_update_device_count_ = 0; - std::optional latch_; + Mutex mutex_; + CountDownLatch* on_device_updated_latch_; + CountDownLatch* on_pairing_result_latch_; + FastPairDevice* device_ ABSL_GUARDED_BY(mutex_) = nullptr; + std::optional pairing_result_ ABSL_GUARDED_BY(mutex_); }; } // namespace fastpair } // namespace nearby diff --git a/fastpair/ui/fast_pair/fake_fast_pair_presenter.h b/fastpair/ui/fast_pair/fake_fast_pair_presenter.h index b5a1c89e..052fd955 100644 --- a/fastpair/ui/fast_pair/fake_fast_pair_presenter.h +++ b/fastpair/ui/fast_pair/fake_fast_pair_presenter.h @@ -35,13 +35,24 @@ class FakeFastPairPresenter : public FastPairPresenter { version_changed_ = true; callback(DiscoveryAction::kPairToDevice); } + + void ShowPairingResult( + FastPairDevice& device, + FastPairNotificationController& notification_controller, + bool success) override { + pairing_result_changed_ = true; + } + bool show_discovery() { return show_discovery_; } bool version_changed() { return version_changed_; } + bool pairing_result_changed() { return pairing_result_changed_; } + private: bool show_discovery_ = false; bool version_changed_ = false; + bool pairing_result_changed_ = false; }; class FakeFastPairPresenterFactory : public FastPairPresenterImpl::Factory { diff --git a/fastpair/ui/fast_pair/fast_pair_notification_controller.cc b/fastpair/ui/fast_pair/fast_pair_notification_controller.cc index e38e4405..60aa5b51 100644 --- a/fastpair/ui/fast_pair/fast_pair_notification_controller.cc +++ b/fastpair/ui/fast_pair/fast_pair_notification_controller.cc @@ -17,7 +17,7 @@ #include #include "absl/functional/any_invocable.h" -#include "fastpair/common/device_metadata.h" +#include "fastpair/common/fast_pair_device.h" #include "fastpair/ui/actions.h" #include "internal/platform/logging.h" @@ -32,20 +32,34 @@ void FastPairNotificationController::RemoveObserver(Observer* observer) { } void FastPairNotificationController::NotifyShowDiscovery( - const DeviceMetadata& device) { + FastPairDevice& device) { NEARBY_LOGS(INFO) << __func__; for (Observer* observer : observers_.GetObservers()) { observer->OnUpdateDevice(device); } } +void FastPairNotificationController::NotifyShowPairingResult( + FastPairDevice& device, bool success) { + NEARBY_LOGS(INFO) << __func__; + for (Observer* observer : observers_.GetObservers()) { + observer->OnPairingResult(device, success); + } +} + void FastPairNotificationController::ShowGuestDiscoveryNotification( - const DeviceMetadata& device, DiscoveryCallback callback) { + FastPairDevice& device, DiscoveryCallback callback) { callback_ = std::move(callback); NEARBY_LOGS(INFO) << __func__ << "Notify show guest discovery notification. "; NotifyShowDiscovery(device); } +void FastPairNotificationController::ShowPairingResultNotification( + FastPairDevice& device, bool success) { + NEARBY_LOGS(INFO) << __func__ << "Notify show pairing result notification. "; + NotifyShowPairingResult(device, success); +} + void FastPairNotificationController::OnDiscoveryClicked( DiscoveryAction action) { NEARBY_LOGS(INFO) << __func__ diff --git a/fastpair/ui/fast_pair/fast_pair_notification_controller.h b/fastpair/ui/fast_pair/fast_pair_notification_controller.h index 9f792225..617304ca 100644 --- a/fastpair/ui/fast_pair/fast_pair_notification_controller.h +++ b/fastpair/ui/fast_pair/fast_pair_notification_controller.h @@ -16,8 +16,8 @@ #define THIRD_PARTY_NEARBY_FASTPAIR_UI_FAST_PAIR_FAST_PAIR_NOTIFICATION_CONTROLLER_H_ #include "absl/functional/any_invocable.h" -#include "absl/strings/string_view.h" #include "fastpair/common/device_metadata.h" +#include "fastpair/common/fast_pair_device.h" #include "fastpair/ui/actions.h" #include "internal/base/observer_list.h" @@ -38,7 +38,8 @@ class FastPairNotificationController { class Observer { public: virtual ~Observer() = default; - virtual void OnUpdateDevice(const DeviceMetadata& device) = 0; + virtual void OnUpdateDevice(FastPairDevice& device) = 0; + virtual void OnPairingResult(FastPairDevice& device, bool success) = 0; }; FastPairNotificationController() = default; @@ -51,12 +52,15 @@ class FastPairNotificationController { // Observer process void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); - void NotifyShowDiscovery(const DeviceMetadata& device); + void NotifyShowDiscovery(FastPairDevice& device); + void NotifyShowPairingResult(FastPairDevice& device, bool success); // Creates and displays corresponding notification. - void ShowGuestDiscoveryNotification(const DeviceMetadata& device_metadata, + void ShowGuestDiscoveryNotification(FastPairDevice& device, DiscoveryCallback callback); + void ShowPairingResultNotification(FastPairDevice& device, bool success); + // Triggers callback when the related action is clicked. void OnDiscoveryClicked(DiscoveryAction action); diff --git a/fastpair/ui/fast_pair/fast_pair_notification_controller_test.cc b/fastpair/ui/fast_pair/fast_pair_notification_controller_test.cc index 871dd4a5..a4170969 100644 --- a/fastpair/ui/fast_pair/fast_pair_notification_controller_test.cc +++ b/fastpair/ui/fast_pair/fast_pair_notification_controller_test.cc @@ -14,66 +14,69 @@ #include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" -#include #include -#include -#include -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "fastpair/common/device_metadata.h" #include "fastpair/ui/actions.h" #include "fastpair/ui/fast_pair/fake_fast_pair_notification_controller_observer.h" +#include "internal/platform/count_down_latch.h" namespace nearby { namespace fastpair { namespace { const int64_t kDeviceId = 10148625; -const char kModelId[] = "9adb11"; const char kDeviceName[] = "Pixel Buds Pro"; +constexpr absl::string_view kModelId("9adb11"); +constexpr absl::string_view kBleAddress("AA:BB:CC:DD:EE:00"); -class FastPairNotificationControllerTest : public ::testing::Test { - protected: - FastPairNotificationControllerTest() { - notification_controller_obsesrver_ = - std::make_unique( - std::nullopt); - notification_controller_.AddObserver( - notification_controller_obsesrver_.get()); - } - - void TriggerOnUpdateDevice(DeviceMetadata& device, - DiscoveryCallback callback) { - notification_controller_.ShowGuestDiscoveryNotification( - device, std::move(callback)); - } - - void DiscoveryActionClicked(DiscoveryAction action) { - discovery_action_ = action; - } - - FastPairNotificationController notification_controller_; - std::unique_ptr - notification_controller_obsesrver_; - DiscoveryAction discovery_action_; -}; - -TEST_F(FastPairNotificationControllerTest, ShowGuestDiscoveryNotification) { +TEST(FastPairNotificationControllerTest, ShowGuestDiscoveryNotification) { + FastPairNotificationController notification_controller; proto::GetObservedDeviceResponse response; - response.mutable_device()->set_id(kDeviceId); - response.mutable_device()->set_name(kDeviceName); DeviceMetadata device_metadata(response); - TriggerOnUpdateDevice(device_metadata, [this](DiscoveryAction action) { - DiscoveryActionClicked(action); - }); - EXPECT_TRUE(notification_controller_obsesrver_ - ->CheckDeviceMetadataListContainTestDevice(kDeviceName)); - EXPECT_EQ(1, notification_controller_obsesrver_->on_update_device_count()); - notification_controller_.OnDiscoveryClicked(DiscoveryAction::kPairToDevice); - EXPECT_EQ(DiscoveryAction::kPairToDevice, discovery_action_); + FastPairDevice device(kModelId, kBleAddress, + Protocol::kFastPairInitialPairing); + device.SetMetadata(device_metadata); + CountDownLatch on_update_device_latch(1); + CountDownLatch on_click_latch(1); + FakeFastPairNotificationControllerObserver observer(&on_update_device_latch, + nullptr); + notification_controller.AddObserver(&observer); + EXPECT_EQ(observer.GetDevice(), nullptr); + DiscoveryAction discovery_action = DiscoveryAction::kUnknown; + notification_controller.ShowGuestDiscoveryNotification( + device, [&](DiscoveryAction action) { + on_click_latch.CountDown(); + discovery_action = action; + }); + on_update_device_latch.Await(); + EXPECT_EQ(observer.GetDevice(), &device); + notification_controller.OnDiscoveryClicked(DiscoveryAction::kPairToDevice); + on_click_latch.Await(); + EXPECT_EQ(discovery_action, DiscoveryAction::kPairToDevice); +} + +TEST(FastPairNotificationControllerTest, ShowPairingResultNotification) { + FastPairNotificationController notification_controller; + proto::GetObservedDeviceResponse response; + DeviceMetadata device_metadata(response); + FastPairDevice device(kModelId, kBleAddress, + Protocol::kFastPairInitialPairing); + device.SetMetadata(device_metadata); + + CountDownLatch on_pairing_result_latch(1); + FakeFastPairNotificationControllerObserver observer(nullptr, + &on_pairing_result_latch); + notification_controller.AddObserver(&observer); + EXPECT_FALSE(observer.GetPairingResult().has_value()); + EXPECT_EQ(observer.GetDevice(), nullptr); + notification_controller.ShowPairingResultNotification(device, true); + on_pairing_result_latch.Await(); + EXPECT_EQ(observer.GetDevice(), &device); + EXPECT_TRUE(observer.GetPairingResult().has_value()); + EXPECT_TRUE(observer.GetPairingResult().value()); } } // namespace diff --git a/fastpair/ui/fast_pair/fast_pair_presenter.h b/fastpair/ui/fast_pair/fast_pair_presenter.h index 6bd980b4..50da908a 100644 --- a/fastpair/ui/fast_pair/fast_pair_presenter.h +++ b/fastpair/ui/fast_pair/fast_pair_presenter.h @@ -24,11 +24,15 @@ namespace fastpair { // This Presenter creates and manages UI component with Notification Controller. class FastPairPresenter { public: - // observer_list of notification_controller is updated virtual void ShowDiscovery( FastPairDevice& device, FastPairNotificationController& notification_controller, DiscoveryCallback callback) = 0; + virtual void ShowPairingResult( + FastPairDevice& device, + FastPairNotificationController& notification_controller, + bool success) = 0; + virtual ~FastPairPresenter() = default; }; diff --git a/fastpair/ui/fast_pair/fast_pair_presenter_impl.cc b/fastpair/ui/fast_pair/fast_pair_presenter_impl.cc index d242096c..7a5d98e5 100644 --- a/fastpair/ui/fast_pair/fast_pair_presenter_impl.cc +++ b/fastpair/ui/fast_pair/fast_pair_presenter_impl.cc @@ -15,14 +15,10 @@ #include "fastpair/ui/fast_pair/fast_pair_presenter_impl.h" #include -#include #include -#include "fastpair/common/device_metadata.h" #include "fastpair/common/fast_pair_device.h" -#include "fastpair/repository/fast_pair_repository.h" #include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" -#include "internal/platform/logging.h" namespace nearby { namespace fastpair { @@ -51,8 +47,14 @@ void FastPairPresenterImpl::ShowDiscovery( FastPairDevice& device, FastPairNotificationController& notification_controller, DiscoveryCallback callback) { - notification_controller.ShowGuestDiscoveryNotification(*device.GetMetadata(), + notification_controller.ShowGuestDiscoveryNotification(device, std::move(callback)); } + +void FastPairPresenterImpl::ShowPairingResult( + FastPairDevice& device, + FastPairNotificationController& notification_controller, bool success) { + notification_controller.ShowPairingResultNotification(device, success); +} } // namespace fastpair } // namespace nearby diff --git a/fastpair/ui/fast_pair/fast_pair_presenter_impl.h b/fastpair/ui/fast_pair/fast_pair_presenter_impl.h index cc6595d2..f606658c 100644 --- a/fastpair/ui/fast_pair/fast_pair_presenter_impl.h +++ b/fastpair/ui/fast_pair/fast_pair_presenter_impl.h @@ -48,6 +48,10 @@ class FastPairPresenterImpl : public FastPairPresenter { void ShowDiscovery(FastPairDevice& device, FastPairNotificationController& notification_controller, DiscoveryCallback callback) override; + void ShowPairingResult( + FastPairDevice& device, + FastPairNotificationController& notification_controller, + bool success) override; }; } // namespace fastpair } // namespace nearby diff --git a/fastpair/ui/fast_pair/fast_pair_presenter_impl_test.cc b/fastpair/ui/fast_pair/fast_pair_presenter_impl_test.cc index cb699f4f..d3a00c5c 100644 --- a/fastpair/ui/fast_pair/fast_pair_presenter_impl_test.cc +++ b/fastpair/ui/fast_pair/fast_pair_presenter_impl_test.cc @@ -14,8 +14,8 @@ #include "fastpair/ui/fast_pair/fast_pair_presenter_impl.h" -#include - +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "fastpair/common/fast_pair_device.h" #include "fastpair/proto/fastpair_rpcs.proto.h" @@ -26,78 +26,88 @@ namespace nearby { namespace fastpair { +const int64_t kDeviceId = 10148625; constexpr absl::string_view kModelId = "000000"; constexpr absl::string_view kAddress = "00:00:00:00:00:00"; constexpr absl::string_view kPublicKey = "test public key"; +constexpr absl::string_view kInitialPairingdescription = + "InitialPairingdescription"; namespace { -TEST(FastPairPresenterImplTest, ShowDiscoveryForV1Version) { - // Setup repository with v1 version device metadata - FastPairDevice device(kModelId, kAddress, Protocol::kFastPairInitialPairing); - proto::GetObservedDeviceResponse response; - DeviceMetadata device_metadata(response); - device.SetMetadata(device_metadata); - - // Register FastPairNotificationControllerObserver - auto latch_1 = std::make_optional(1); - FastPairNotificationController controller; - FakeFastPairNotificationControllerObserver notification_controller_observer( - latch_1); - controller.AddObserver(¬ification_controller_observer); - EXPECT_EQ(notification_controller_observer.on_update_device_count(), 0); - - // FastPairPresenter ShowDiscovery - CountDownLatch latch_2(1); - FastPairPresenterImpl fast_pair_presenter; - DiscoveryAction discovery_action = DiscoveryAction::kUnknown; - fast_pair_presenter.ShowDiscovery(device, controller, - [&](DiscoveryAction action) { - discovery_action = action; - latch_2.CountDown(); - }); - latch_1->Await(); - EXPECT_EQ(notification_controller_observer.on_update_device_count(), 1); - EXPECT_EQ(device.GetVersion(), DeviceFastPairVersion::kV1); - controller.OnDiscoveryClicked(DiscoveryAction::kPairToDevice); - latch_2.Await(); - EXPECT_EQ(discovery_action, DiscoveryAction::kPairToDevice); +// A gMock matcher to match proto values. Use this matcher like: +// request/response proto, expected_proto; +// EXPECT_THAT(proto, MatchesProto(expected_proto)); +MATCHER_P( + MatchesProto, expected_proto, + absl::StrCat(negation ? "does not match" : "matches", + testing::PrintToString(expected_proto.SerializeAsString()))) { + return arg.SerializeAsString() == expected_proto.SerializeAsString(); } -TEST(FastPairPresenterImplTest, ShowDiscoveryForHigherThanV1Version) { - // Setup repository with HigherThanV1Version device metadata - FastPairDevice device(kModelId, kAddress, Protocol::kFastPairInitialPairing); - proto::GetObservedDeviceResponse response; - auto* higher_than_v1_version_device = response.mutable_device(); - higher_than_v1_version_device->mutable_anti_spoofing_key_pair() - ->set_public_key(kPublicKey); - DeviceMetadata device_metadata(response); - device.SetMetadata(device_metadata); +TEST(FastPairPresenterImplTest, ShowDiscovery) { + // Sets up proto::GetObservedDeviceResponse + proto::GetObservedDeviceResponse response_proto; + auto* device = response_proto.mutable_device(); + device->set_id(kDeviceId); + auto* observed_device_strings = response_proto.mutable_strings(); + observed_device_strings->set_initial_pairing_description( + kInitialPairingdescription); + DeviceMetadata device_metadata(response_proto); + FastPairDevice fast_pair_device(kModelId, kAddress, + Protocol::kFastPairInitialPairing); - // Register FastPairNotificationControllerObserver - auto latch_1 = std::make_optional(1); - FastPairNotificationController controller; - FakeFastPairNotificationControllerObserver notification_controller_observer( - latch_1); - controller.AddObserver(¬ification_controller_observer); - EXPECT_EQ(notification_controller_observer.on_update_device_count(), 0); + fast_pair_device.SetMetadata(device_metadata); - // FastPairPresenter ShowDiscovery - CountDownLatch latch_2(1); - FastPairPresenterImpl fast_pair_presenter; + FastPairNotificationController notification_controller; + CountDownLatch on_update_device_latch(1); + CountDownLatch on_click_latch(1); + FakeFastPairNotificationControllerObserver observer(&on_update_device_latch, + nullptr); + notification_controller.AddObserver(&observer); DiscoveryAction discovery_action = DiscoveryAction::kUnknown; - fast_pair_presenter.ShowDiscovery(device, controller, + FastPairPresenterImpl fast_pair_presenter; + fast_pair_presenter.ShowDiscovery(fast_pair_device, notification_controller, [&](DiscoveryAction action) { + on_click_latch.CountDown(); discovery_action = action; - latch_2.CountDown(); }); - latch_1->Await(); - EXPECT_EQ(notification_controller_observer.on_update_device_count(), 1); - EXPECT_EQ(device.GetVersion(), DeviceFastPairVersion::kHigherThanV1); - controller.OnDiscoveryClicked(DiscoveryAction::kDismissedByUser); - latch_2.Await(); - EXPECT_EQ(discovery_action, DiscoveryAction::kDismissedByUser); + on_update_device_latch.Await(); + EXPECT_EQ(observer.GetDevice()->GetMetadata()->GetFastPairVersion(), + DeviceFastPairVersion::kV1); + EXPECT_THAT(observer.GetDevice()->GetMetadata()->GetResponse(), + MatchesProto(response_proto)); } +TEST(FastPairPresenterImplTest, ShowPairingResult) { + // Sets up proto::GetObservedDeviceResponse + proto::GetObservedDeviceResponse response_proto; + auto* device = response_proto.mutable_device(); + device->set_id(kDeviceId); + auto* observed_device_strings = response_proto.mutable_strings(); + observed_device_strings->set_initial_pairing_description( + kInitialPairingdescription); + DeviceMetadata device_metadata(response_proto); + FastPairDevice fast_pair_device(kModelId, kAddress, + Protocol::kFastPairInitialPairing); + + fast_pair_device.SetMetadata(device_metadata); + + FastPairNotificationController notification_controller; + CountDownLatch on_pairing_result_latch(1); + FakeFastPairNotificationControllerObserver observer(nullptr, + &on_pairing_result_latch); + notification_controller.AddObserver(&observer); + FastPairPresenterImpl fast_pair_presenter; + fast_pair_presenter.ShowPairingResult(fast_pair_device, + notification_controller, true); + on_pairing_result_latch.Await(); + EXPECT_EQ(observer.GetDevice()->GetMetadata()->GetFastPairVersion(), + DeviceFastPairVersion::kV1); + EXPECT_THAT(observer.GetDevice()->GetMetadata()->GetResponse(), + MatchesProto(response_proto)); + EXPECT_TRUE(observer.GetPairingResult().has_value()); + EXPECT_TRUE(observer.GetPairingResult().value()); +} } // namespace } // namespace fastpair } // namespace nearby diff --git a/fastpair/ui/fast_pair/mock_fast_pair_notification_controller.h b/fastpair/ui/fast_pair/mock_fast_pair_notification_controller.h index 84b72603..e8427c57 100644 --- a/fastpair/ui/fast_pair/mock_fast_pair_notification_controller.h +++ b/fastpair/ui/fast_pair/mock_fast_pair_notification_controller.h @@ -26,12 +26,12 @@ class MockFastPairNotificationController : public FastPairNotificationController { public: MOCK_METHOD(void, ShowGuestDiscoveryNotification, - (const DeviceMetadata&, DiscoveryCallback)); + (FastPairDevice & device, DiscoveryCallback)); MOCK_METHOD(void, OnDiscoveryClicked, (DiscoveryAction)); MOCK_METHOD(void, AddObserver, (Observer*)); MOCK_METHOD(void, RemoveObserver, (Observer*)); - void NotifyShowDiscovery(const DeviceMetadata& device) { + void NotifyShowDiscovery(FastPairDevice& device) { for (Observer* observer : observers_.GetObservers()) { observer->OnUpdateDevice(device); } diff --git a/fastpair/ui/mock_ui_broker.h b/fastpair/ui/mock_ui_broker.h index f0467eae..70241c68 100644 --- a/fastpair/ui/mock_ui_broker.h +++ b/fastpair/ui/mock_ui_broker.h @@ -29,6 +29,10 @@ class MockUIBroker : public UIBroker { MOCK_METHOD(void, ShowDiscovery, (FastPairDevice&, FastPairNotificationController&), (override)); + MOCK_METHOD(void, ShowPairingResult, + (FastPairDevice&, FastPairNotificationController&, bool), + (override)); + void AddObserver(Observer* observer) override { observers_.AddObserver(observer); } diff --git a/fastpair/ui/ui_broker.h b/fastpair/ui/ui_broker.h index 6a414234..a6cfe1f2 100644 --- a/fastpair/ui/ui_broker.h +++ b/fastpair/ui/ui_broker.h @@ -43,6 +43,11 @@ class UIBroker { virtual void ShowDiscovery( FastPairDevice& device, FastPairNotificationController& notification_controller) = 0; + + virtual void ShowPairingResult( + FastPairDevice& device, + FastPairNotificationController& notification_controller, + bool success) = 0; }; } // namespace fastpair diff --git a/fastpair/ui/ui_broker_impl.cc b/fastpair/ui/ui_broker_impl.cc index 027e5db4..6b3c7b3c 100644 --- a/fastpair/ui/ui_broker_impl.cc +++ b/fastpair/ui/ui_broker_impl.cc @@ -60,6 +60,23 @@ void UIBrokerImpl::ShowDiscovery( } } +void UIBrokerImpl::ShowPairingResult( + FastPairDevice& device, + FastPairNotificationController& notification_controller, bool success) { + NEARBY_LOGS(VERBOSE) << __func__; + switch (device.GetProtocol()) { + case Protocol::kFastPairInitialPairing: + case Protocol::kFastPairSubsequentPairing: + fast_pair_presenter_->ShowPairingResult(device, notification_controller, + success); + break; + case Protocol::kFastPairRetroactivePairing: + // In this scenario, we don't show the error UI because it would be + // misleading, since a pair failure is a retroactive pair failure. + break; + } +} + void UIBrokerImpl::NotifyDiscoveryAction(FastPairDevice& device, DiscoveryAction action) { for (auto& observer : observers_.GetObservers()) diff --git a/fastpair/ui/ui_broker_impl.h b/fastpair/ui/ui_broker_impl.h index 3dae1743..039b448b 100644 --- a/fastpair/ui/ui_broker_impl.h +++ b/fastpair/ui/ui_broker_impl.h @@ -37,6 +37,10 @@ class UIBrokerImpl : public UIBroker { void ShowDiscovery( FastPairDevice &device, FastPairNotificationController ¬ification_controller) override; + void ShowPairingResult( + FastPairDevice &device, + FastPairNotificationController ¬ification_controller, + bool success) override; private: void NotifyDiscoveryAction(FastPairDevice &device, DiscoveryAction action); diff --git a/fastpair/ui/ui_broker_impl_test.cc b/fastpair/ui/ui_broker_impl_test.cc index 70600c86..8fe29107 100644 --- a/fastpair/ui/ui_broker_impl_test.cc +++ b/fastpair/ui/ui_broker_impl_test.cc @@ -31,7 +31,7 @@ constexpr absl::string_view kAddress = "74:74:46:01:6C:21"; class UIBrokerImplTest : public ::testing::Test, public UIBroker::Observer { protected: - UIBrokerImplTest() { + void SetUp() override { presenter_factory_ = std::make_unique(); FastPairPresenterImpl::Factory::SetFactoryForTesting( presenter_factory_.get()); @@ -68,6 +68,13 @@ TEST_F(UIBrokerImplTest, ShowDiscoveryWithoutObserver) { EXPECT_FALSE(on_discovery_action_notified_); } +TEST_F(UIBrokerImplTest, ShowPairingResult) { + FastPairDevice device(kModelId, kAddress, Protocol::kFastPairInitialPairing); + ui_broker_->ShowPairingResult(device, notification_controller_, true); + EXPECT_TRUE( + presenter_factory_->fake_fast_pair_presenter()->pairing_result_changed()); +} + } // namespace } // namespace fastpair } // namespace nearby diff --git a/internal/data/BUILD b/internal/data/BUILD index 562703c4..8628ea53 100644 --- a/internal/data/BUILD +++ b/internal/data/BUILD @@ -15,7 +15,7 @@ cc_library( "memory_data_set.h", ], deps = [ - "//internal/platform:logging", + "//internal/platform:types", "//third_party/leveldb:db", "//third_party/leveldb:table", "//third_party/leveldb:util", diff --git a/internal/network/BUILD b/internal/network/BUILD index 634db625..9a1b24f5 100644 --- a/internal/network/BUILD +++ b/internal/network/BUILD @@ -55,7 +55,6 @@ cc_library( ], deps = [ ":types", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform/implementation:platform", "@com_google_absl//absl/base:core_headers", diff --git a/internal/platform/BUILD b/internal/platform/BUILD index 8dc368fb..c1c1e3ef 100644 --- a/internal/platform/BUILD +++ b/internal/platform/BUILD @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Placeholder: load py_test + licenses(["notice"]) cc_library( @@ -47,7 +49,6 @@ cc_library( "//connections:__subpackages__", "//fastpair:__subpackages__", "//internal/auth:__subpackages__", - "//internal/interop:__pkg__", "//internal/platform:__subpackages__", "//internal/platform/implementation:__subpackages__", "//internal/preferences:__subpackages__", @@ -72,13 +73,11 @@ cc_library( name = "util", srcs = [ "base_input_stream.cc", - "base_pipe.cc", "byte_utils.cc", ], hdrs = [ "base_input_stream.h", "base_mutex_lock.h", - "base_pipe.h", "byte_utils.h", ], visibility = [ @@ -93,32 +92,6 @@ cc_library( ], ) -cc_library( - name = "logging", - hdrs = [ - "logging.h", - ], - copts = ["-DCORE_ADAPTER_DLL"], - visibility = [ - "//connections:__subpackages__", - "//fastpair:__subpackages__", - "//internal/auth:__subpackages__", - "//internal/auth/credential_store:__subpackages__", - "//internal/data:__subpackages__", - "//internal/interop:__pkg__", - "//internal/network:__subpackages__", - "//internal/platform:__subpackages__", - "//internal/proto/analytics:__subpackages__", - "//location/nearby/analytics/cpp:__subpackages__", - "//presence:__subpackages__", - ], - deps = [ - "//internal/platform/implementation:platform", - "//internal/platform/implementation:types", - "@com_google_glog//:glog", - ], -) - cc_library( name = "cancellation_flag", srcs = [ @@ -161,7 +134,7 @@ cc_library( "//presence:__subpackages__", ], deps = [ - ":logging", + ":types", "//proto:connections_enums_cc_proto", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", @@ -182,7 +155,7 @@ cc_library( ], visibility = ["//connections/implementation:__subpackages__"], deps = [ - ":logging", + ":types", "//proto:connections_enums_cc_proto", "//proto/errorcode:error_code_enums_cc_proto", "@com_google_absl//absl/functional:any_invocable", @@ -227,7 +200,6 @@ cc_library( ], deps = [ ":base", - ":logging", ":types", ":uuid", "//internal/base", @@ -355,16 +327,23 @@ cc_library( "//connections:__subpackages__", "//fastpair:__subpackages__", "//internal/account:__subpackages__", + "//internal/auth:__subpackages__", + "//internal/auth/credential_store:__subpackages__", "//internal/base:__subpackages__", + "//internal/data:__subpackages__", "//internal/flags:__subpackages__", "//internal/interop:__pkg__", "//internal/network:__subpackages__", + "//internal/platform:__subpackages__", "//internal/platform/implementation/g3:__pkg__", "//internal/platform/implementation/linux:__subpackages__", "//internal/platform/implementation/windows:__subpackages__", "//internal/preferences:__subpackages__", + "//internal/proto/analytics:__subpackages__", "//internal/test:__subpackages__", "//internal/weave:__subpackages__", + "//location/nearby/analytics/cpp:__subpackages__", + "//location/nearby/apps:__subpackages__", "//location/nearby/cpp:__subpackages__", "//location/nearby/testing/nearby_native:__subpackages__", "//presence:__subpackages__", @@ -372,7 +351,6 @@ cc_library( ], deps = [ ":base", - ":logging", ":util", "//internal/crypto_cros", "//internal/platform/implementation:platform", @@ -428,7 +406,6 @@ cc_library( deps = [ ":base", ":cancellation_flag", - ":logging", ":types", ":uuid", "//internal/base", @@ -487,9 +464,9 @@ cc_test( shard_count = 16, deps = [ ":base", + ":cancellation_flag", ":comm", ":connection_info", - ":logging", ":test_util", ":types", ":uuid", diff --git a/internal/platform/base_pipe.cc b/internal/platform/base_pipe.cc deleted file mode 100644 index 94c6b917..00000000 --- a/internal/platform/base_pipe.cc +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2020 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 "internal/platform/base_pipe.h" - -#include "internal/platform/base_mutex_lock.h" -#include "internal/platform/input_stream.h" -#include "internal/platform/output_stream.h" - -namespace nearby { - -ExceptionOr BasePipe::Read(size_t size) { - BaseMutexLock lock(mutex_.get()); - - // We're done reading all the chunks that were written before the OutputStream - // was closed, so there's nothing to do here other than return an empty chunk - // to serve as an EOF indication to callers. - if (read_all_chunks_) { - return ExceptionOr{ByteArray{}}; - } - - while (buffer_.empty() && !input_stream_closed_) { - Exception wait_exception = cond_->Wait(); - - if (wait_exception.Raised()) { - return ExceptionOr{wait_exception}; - } - } - - // If we received our sentinel chunk, mark the fact that there cannot - // possibly be any more chunks to read here on in, and return an empty chunk - // to serve as an EOF indication to callers. - if (buffer_.empty() || buffer_.front().Empty()) { - read_all_chunks_ = true; - return ExceptionOr{ByteArray{}}; - } - - ByteArray first_chunk{buffer_.front()}; - buffer_.pop_front(); - - // If first_chunk is small enough to not overshoot the requested 'size', just - // return that. - if (first_chunk.size() <= size) { - return ExceptionOr{first_chunk}; - } else { - // Break first_chunk into 2 parts -- the first one of which (next_chunk) - // will be 'size' bytes long, and will be returned, and the second one of - // which (overflow_chunk) will be re-inserted into buffer_, at the head of - // the queue, to be served up in the next call to read(). - ByteArray next_chunk(first_chunk.data(), size); - buffer_.push_front( - ByteArray(first_chunk.data() + size, first_chunk.size() - size)); - return ExceptionOr{next_chunk}; - } -} - -Exception BasePipe::Write(const ByteArray& data) { - BaseMutexLock lock(mutex_.get()); - - return WriteLocked(data); -} - -void BasePipe::MarkInputStreamClosed() { - BaseMutexLock lock(mutex_.get()); - - input_stream_closed_ = true; - // Trigger cond_ to unblock a potentially-blocked call to read(), and to let - // it know to return Exception::IO. - cond_->Notify(); -} - -void BasePipe::MarkOutputStreamClosed() { - BaseMutexLock lock(mutex_.get()); - - // Write a sentinel null chunk before marking output_stream_closed as true. - WriteLocked(ByteArray{}); - output_stream_closed_ = true; -} - -Exception BasePipe::WriteLocked(const ByteArray& data) { - if (input_stream_closed_ || output_stream_closed_) { - return {Exception::kIo}; - } - - buffer_.push_back(data); - // Trigger cond_ to unblock a potentially-blocked call to read(), now that - // there's more data for it to consume. - cond_->Notify(); - return {Exception::kSuccess}; -} - -} // namespace nearby diff --git a/internal/platform/base_pipe.h b/internal/platform/base_pipe.h deleted file mode 100644 index 3b8987de..00000000 --- a/internal/platform/base_pipe.h +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2020 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 PLATFORM_BASE_BASE_PIPE_H_ -#define PLATFORM_BASE_BASE_PIPE_H_ - -#include -#include -#include - -#include "absl/base/thread_annotations.h" -#include "internal/platform/implementation/condition_variable.h" -#include "internal/platform/implementation/mutex.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/exception.h" -#include "internal/platform/input_stream.h" -#include "internal/platform/output_stream.h" - -namespace nearby { - -// Common Pipe implementation. -// It does not depend on platform implementation, and this allows it to -// be used in the platform implementation itself. -// Concrete class must be derived from it, as follows: -// -// class DerivedPipe : public BasePipe { -// public: -// DerivedPipe() { -// auto mutex = /* construct platform-dependent mutex */; -// auto cond = /* construct platform-dependent condition variable */; -// Setup(std::move(mutex), std::move(cond)); -// } -// ~DerivedPipe() override = default; -// DerivedPipe(DerivedPipe&&) = default; -// DerivedPipe& operator=(DerivedPipe&&) = default; -// }; -class BasePipe { - public: - static constexpr const size_t kChunkSize = 64 * 1024; - virtual ~BasePipe() = default; - - // Pipe is not copyable or movable, because copy/move will invalidate - // references to input and output streams. - // If move is required, Pipe could be wrapped with std::unique_ptr<>. - BasePipe(BasePipe&&) = delete; - BasePipe& operator=(BasePipe&&) = delete; - - // Get...() methods return references to input and output steam facades. - // It is safe to call Get...() methods multiple times. - InputStream& GetInputStream() { return input_stream_; } - OutputStream& GetOutputStream() { return output_stream_; } - - protected: - BasePipe() = default; - - void Setup(std::unique_ptr mutex, - std::unique_ptr cond) { - mutex_ = std::move(mutex); - cond_ = std::move(cond); - } - - private: - class BasePipeInputStream : public InputStream { - public: - explicit BasePipeInputStream(BasePipe* pipe) : pipe_(pipe) {} - ~BasePipeInputStream() override { DoClose(); } - - ExceptionOr Read(std::int64_t size) override { - return pipe_->Read(size); - } - Exception Close() override { return DoClose(); } - - private: - Exception DoClose() { - pipe_->MarkInputStreamClosed(); - return {Exception::kSuccess}; - } - BasePipe* pipe_; - }; - class BasePipeOutputStream : public OutputStream { - public: - explicit BasePipeOutputStream(BasePipe* pipe) : pipe_(pipe) {} - ~BasePipeOutputStream() override { DoClose(); } - - Exception Write(const ByteArray& data) override { - return pipe_->Write(data); - } - Exception Flush() override { return {Exception::kSuccess}; } - Exception Close() override { return DoClose(); } - - private: - Exception DoClose() { - pipe_->MarkOutputStreamClosed(); - return {Exception::kSuccess}; - } - BasePipe* pipe_; - }; - - ExceptionOr Read(size_t size) ABSL_LOCKS_EXCLUDED(mutex_); - Exception Write(const ByteArray& data) ABSL_LOCKS_EXCLUDED(mutex_); - - void MarkInputStreamClosed() ABSL_LOCKS_EXCLUDED(mutex_); - void MarkOutputStreamClosed() ABSL_LOCKS_EXCLUDED(mutex_); - - Exception WriteLocked(const ByteArray& data) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Order of declaration matters: - // - mutex must be defined before condvar; - // - input & output streams must be after both mutex and condvar. - bool input_stream_closed_ ABSL_GUARDED_BY(mutex_) = false; - bool output_stream_closed_ ABSL_GUARDED_BY(mutex_) = false; - bool read_all_chunks_ ABSL_GUARDED_BY(mutex_) = false; - - std::deque ABSL_GUARDED_BY(mutex_) buffer_; - std::unique_ptr mutex_; - std::unique_ptr cond_; - - BasePipeInputStream input_stream_{this}; - BasePipeOutputStream output_stream_{this}; -}; - -} // namespace nearby - -#endif // PLATFORM_BASE_BASE_PIPE_H_ diff --git a/internal/platform/ble.cc b/internal/platform/ble.cc index a47f1852..d6792c22 100644 --- a/internal/platform/ble.cc +++ b/internal/platform/ble.cc @@ -90,31 +90,29 @@ bool BleMedium::StartAcceptingConnections(const std::string& service_id, } return impl_->StartAcceptingConnections( service_id, - { - .accepted_cb = - [this](api::BleSocket& socket, const std::string& service_id) { - MutexLock lock(&mutex_); - auto pair = sockets_.emplace( - &socket, absl::make_unique()); - auto& context = *pair.first->second; - if (!pair.second) { - NEARBY_LOG(INFO, "Accepting (again) socket=%p, impl=%p", - &context.socket, &socket); - } else { - context.socket = BleSocket(&socket); - NEARBY_LOG(INFO, "Accepting socket=%p, impl=%p", - &context.socket, &socket); - } - accepted_connection_callback_.accepted_cb(context.socket, - service_id); - }, + [this](api::BleSocket& socket, const std::string& service_id) { + MutexLock lock(&mutex_); + auto pair = sockets_.emplace( + &socket, std::make_unique()); + auto& context = *pair.first->second; + if (!pair.second) { + NEARBY_LOG(INFO, "Accepting (again) socket=%p, impl=%p", + &context.socket, &socket); + } else { + context.socket = BleSocket(&socket); + NEARBY_LOG(INFO, "Accepting socket=%p, impl=%p", &context.socket, + &socket); + } + if (accepted_connection_callback_) { + accepted_connection_callback_(context.socket, service_id); + } }); } bool BleMedium::StopAcceptingConnections(const std::string& service_id) { { MutexLock lock(&mutex_); - accepted_connection_callback_ = {}; + accepted_connection_callback_ = nullptr; sockets_.clear(); NEARBY_LOG(INFO, "Ble accepted connection disabled: impl=%p", &GetImpl()); } diff --git a/internal/platform/ble.h b/internal/platform/ble.h index df28b38f..cf1f4fab 100644 --- a/internal/platform/ble.h +++ b/internal/platform/ble.h @@ -100,10 +100,8 @@ class BleMedium final { BlePeripheral peripheral; }; - struct AcceptedConnectionCallback { - absl::AnyInvocable - accepted_cb = DefaultCallback(); - }; + using AcceptedConnectionCallback = absl::AnyInvocable; struct AcceptedConnectionInfo { BleSocket socket; }; diff --git a/internal/platform/ble_test.cc b/internal/platform/ble_test.cc index d526e3df..8f48b908 100644 --- a/internal/platform/ble_test.cc +++ b/internal/platform/ble_test.cc @@ -86,14 +86,11 @@ TEST_P(BleMediumTest, CanStartAcceptingConnectionsAndConnect) { ble_b.StartAdvertising(service_id, advertisement_bytes, fast_advertisement_service_uuid); ble_b.StartAcceptingConnections( - service_id, - AcceptedConnectionCallback{ - .accepted_cb = [&accepted_latch](BleSocket socket, - const std::string& service_id) { - NEARBY_LOG(INFO, "Connection accepted: socket=%p, service_id=%s", - &socket, service_id.c_str()); - accepted_latch.CountDown(); - }}); + service_id, [&](BleSocket socket, const std::string& service_id) { + NEARBY_LOG(INFO, "Connection accepted: socket=%p, service_id=%s", + &socket, service_id.c_str()); + accepted_latch.CountDown(); + }); EXPECT_TRUE(found_latch.Await(kWaitDuration).result()); BleSocket socket_a; @@ -148,14 +145,11 @@ TEST_P(BleMediumTest, CanCancelConnect) { ble_b.StartAdvertising(service_id, advertisement_bytes, fast_advertisement_service_uuid); ble_b.StartAcceptingConnections( - service_id, - AcceptedConnectionCallback{ - .accepted_cb = [&accepted_latch](BleSocket socket, - const std::string& service_id) { - NEARBY_LOG(INFO, "Connection accepted: socket=%p, service_id=%s", - &socket, service_id.c_str()); - accepted_latch.CountDown(); - }}); + service_id, [&](BleSocket socket, const std::string& service_id) { + NEARBY_LOG(INFO, "Connection accepted: socket=%p, service_id=%s", + &socket, service_id.c_str()); + accepted_latch.CountDown(); + }); EXPECT_TRUE(found_latch.Await(kWaitDuration).result()); BleSocket socket_a; diff --git a/internal/platform/ble_v2.cc b/internal/platform/ble_v2.cc index 780d34c0..fbe765d4 100644 --- a/internal/platform/ble_v2.cc +++ b/internal/platform/ble_v2.cc @@ -89,7 +89,7 @@ bool BleV2Medium::StartScanning(const Uuid& service_uuid, MutexLock lock(&mutex_); if (!peripherals_.contains(&peripheral)) { NEARBY_LOGS(INFO) << "Peripheral impl=" << &peripheral - << " is not existed; adds it to the map."; + << " does not exist; add it to the map."; peripherals_.insert(&peripheral); } @@ -134,25 +134,24 @@ std::unique_ptr BleV2Medium::StartScanningTmp( const Uuid& service_uuid, api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::BleMedium::ScanningCallback callback) { - // auto scan_callback = std::move(callback.advertisement_found_cb); MutexLock lock(&mutex_); if (impl_->StartScanning( service_uuid, tx_power_level, api::ble_v2::BleMedium::ScanCallback{ .advertisement_found_cb = - [this, &callback](api::ble_v2::BlePeripheral& peripheral, - BleAdvertisementData advertisement_data) { + [this, + found_callback = std::move(callback.advertisement_found_cb)]( + api::ble_v2::BlePeripheral& peripheral, + BleAdvertisementData advertisement_data) mutable { MutexLock lock(&mutex_); if (!peripherals_.contains(&peripheral)) { NEARBY_LOGS(INFO) - << "There is no need to callback due to peripheral " - "impl=" - << &peripheral << ", which already exists."; + << "Peripheral impl=" << &peripheral + << " does not exist; add it to the map."; peripherals_.insert(&peripheral); } - callback.advertisement_found_cb(peripheral, - advertisement_data); + found_callback(peripheral, advertisement_data); }, })) { callback.start_scanning_result(absl::OkStatus()); diff --git a/internal/platform/bluetooth_classic_test.cc b/internal/platform/bluetooth_classic_test.cc index 12d97989..3eabdb03 100644 --- a/internal/platform/bluetooth_classic_test.cc +++ b/internal/platform/bluetooth_classic_test.cc @@ -18,12 +18,16 @@ #include #include -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/strings/string_view.h" #include "absl/time/time.h" #include "internal/platform/bluetooth_adapter.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/count_down_latch.h" +#include "internal/platform/exception.h" +#include "internal/platform/feature_flags.h" +#include "internal/platform/implementation/bluetooth_adapter.h" #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" @@ -270,7 +274,7 @@ TEST_F(BluetoothClassicMediumTest, SendData) { server_socket.Close(); } -TEST_F(BluetoothClassicMediumTest, IoOnClosedSocketReturnsError) { +TEST_F(BluetoothClassicMediumTest, IoOnClosedSocketReturnsEmpty) { adapter_a_->SetScanMode(BluetoothAdapter::ScanMode::kConnectable); CountDownLatch found_latch(1); BluetoothDevice* discovered_device = nullptr; @@ -308,7 +312,7 @@ TEST_F(BluetoothClassicMediumTest, IoOnClosedSocketReturnsError) { BluetoothSocket socket_b = server_socket.Accept(); ASSERT_TRUE(socket_b.IsValid()); socket_b.Close(); - EXPECT_FALSE(socket_b.GetInputStream().Read(data.size()).ok()); + EXPECT_TRUE(socket_b.GetInputStream().Read(data.size()).result().Empty()); }); } server_socket.Close(); diff --git a/internal/platform/device_info.h b/internal/platform/device_info.h index 88254734..c95f592d 100644 --- a/internal/platform/device_info.h +++ b/internal/platform/device_info.h @@ -52,6 +52,9 @@ class DeviceInfo { virtual void UnregisterScreenLockedListener( absl::string_view listener_name) = 0; + virtual bool PreventSleep() = 0; + virtual bool AllowSleep() = 0; + // Returns localized device name depends on device type. std::u16string GetDeviceTypeName() const { // TODO(b/230132370): return localized device name. diff --git a/internal/platform/device_info_impl.cc b/internal/platform/device_info_impl.cc index 702c83a0..6ac551d5 100644 --- a/internal/platform/device_info_impl.cc +++ b/internal/platform/device_info_impl.cc @@ -108,4 +108,10 @@ void DeviceInfoImpl::UnregisterScreenLockedListener( device_info_impl_->UnregisterScreenLockedListener(listener_name); } +bool DeviceInfoImpl::PreventSleep() { + return device_info_impl_->PreventSleep(); +} + +bool DeviceInfoImpl::AllowSleep() { return device_info_impl_->AllowSleep(); } + } // namespace nearby diff --git a/internal/platform/device_info_impl.h b/internal/platform/device_info_impl.h index 1c44d961..98e6032f 100644 --- a/internal/platform/device_info_impl.h +++ b/internal/platform/device_info_impl.h @@ -53,6 +53,9 @@ class DeviceInfoImpl : public DeviceInfo { std::function callback) override; void UnregisterScreenLockedListener(absl::string_view listener_name) override; + bool PreventSleep() override; + bool AllowSleep() override; + private: std::unique_ptr device_info_impl_; }; diff --git a/internal/platform/feature_flags.h b/internal/platform/feature_flags.h index 92d0e532..d4202188 100644 --- a/internal/platform/feature_flags.h +++ b/internal/platform/feature_flags.h @@ -15,6 +15,8 @@ #ifndef PLATFORM_BASE_FEATURE_FLAGS_H_ #define PLATFORM_BASE_FEATURE_FLAGS_H_ +#include + #include "absl/synchronization/mutex.h" #include "absl/time/time.h" @@ -56,6 +58,22 @@ class FeatureFlags { // Controls enable or disable BLE scan advertisement for fast pair // service uuid 0x2cfe bool enable_scan_for_fast_pair_advertisement = false; + // Skip Service Discovery Protocol check if the remote party supports the + // requested service id before attempting to connect over rfcomm. SDP fails + // on Windows when connecting to FP service id but the rfcomm is successful. + bool skip_service_discovery_before_connecting_to_rfcomm = false; + std::int32_t min_nc_version_supports_safe_to_disconnect = 1; + // Android code won't be able to launch "payload_received_ack" feature for + // in near future, so change "payload_received_ack" version from "2" to "5" + // after auto-reconnect and auto-resume. + std::int32_t min_nc_version_supports_payload_received_ack = 5; + // If the other part doesn't ack the safe_to_disconnect request, the + // initiator will end the connection in 30s. + absl::Duration safe_to_disconnect_ack_delay_millis = + absl::Milliseconds(30000); + // If the receiver doesn't ack with payload_received_ack frame in 1s, the + // sender will timeout the waiting. + absl::Duration wait_payload_received_ack_millis = absl::Milliseconds(1000); }; static const FeatureFlags& GetInstance() { diff --git a/internal/platform/flags/nearby_platform_feature_flags.h b/internal/platform/flags/nearby_platform_feature_flags.h index 0283353b..934574e8 100644 --- a/internal/platform/flags/nearby_platform_feature_flags.h +++ b/internal/platform/flags/nearby_platform_feature_flags.h @@ -15,6 +15,8 @@ #ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_FLAGS_NEARBY_PLATFORM_FEATURE_FLAGS_H_ #define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_FLAGS_NEARBY_PLATFORM_FEATURE_FLAGS_H_ +#include + #include "absl/strings/string_view.h" #include "internal/flags/flag.h" @@ -57,7 +59,7 @@ constexpr auto kWifiHotspotConnectionMaxRetries = // The interval between 2 connectin attempts. constexpr auto kWifiHotspotConnectionIntervalMillis = - flags::Flag(kConfigPackage, "45415887", 500); + flags::Flag(kConfigPackage, "45415887", 2000); // The connection timeout to remote Wi-Fi hotspot. constexpr auto kWifiHotspotConnectionTimeoutMillis = diff --git a/internal/platform/implementation/BUILD b/internal/platform/implementation/BUILD index a9203745..1eeb0b58 100644 --- a/internal/platform/implementation/BUILD +++ b/internal/platform/implementation/BUILD @@ -101,7 +101,6 @@ cc_library( # TODO: Support WebRTC "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/functional:any_invocable", - "@com_google_absl//absl/log:check", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", diff --git a/internal/platform/implementation/apple/BUILD b/internal/platform/implementation/apple/BUILD index 7563076c..0e2b044e 100644 --- a/internal/platform/implementation/apple/BUILD +++ b/internal/platform/implementation/apple/BUILD @@ -23,9 +23,6 @@ package(default_visibility = [ objc_library( name = "apple", srcs = [ - "ble.mm", - "ble_utils.mm", - "bluetooth_adapter.mm", "crypto.mm", "device_info.mm", "log_message.mm", @@ -34,13 +31,9 @@ objc_library( "preferences_manager.mm", "scheduled_executor.mm", "timer.mm", - "utils.mm", "wifi_lan.mm", ], hdrs = [ - "ble.h", - "ble_utils.h", - "bluetooth_adapter.h", "device_info.h", "log_message.h", "multi_thread_executor.h", @@ -48,7 +41,6 @@ objc_library( "scheduled_executor.h", "single_thread_executor.h", "timer.h", - "utils.h", "wifi_lan.h", ], # Prevent Objective-C++ headers from being pulled into swift. @@ -57,8 +49,8 @@ objc_library( deps = [ ":Platform_cc", ":Shared", + ":ble_v2", "//internal/platform:base", - "//internal/platform:cancellation_flag", "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", "//internal/platform/implementation:types", @@ -73,7 +65,6 @@ objc_library( "@com_google_absl//absl/strings", "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", - "@com_google_absl//absl/types:optional", "@com_google_absl//absl/types:span", "@nlohmann_json//:json", ] + select({ @@ -84,6 +75,50 @@ objc_library( }), ) +objc_library( + name = "ble_v2", + srcs = [ + "ble_gatt_client.h", + "ble_gatt_client.mm", + "ble_gatt_server.h", + "ble_gatt_server.mm", + "ble_medium.h", + "ble_medium.mm", + "ble_peripheral.h", + "ble_peripheral.mm", + "ble_server_socket.h", + "ble_server_socket.mm", + "ble_socket.h", + "ble_socket.mm", + "ble_utils.mm", + "bluetooth_adapter_v2.h", + "bluetooth_adapter_v2.mm", + "utils.mm", + ], + hdrs = [ + "ble.h", + "ble_utils.h", + "utils.h", + ], + # Prevent Objective-C++ headers from being pulled into swift. + aspect_hints = ["//tools/build_defs/swift:no_module"], + deps = [ + "//internal/platform:base", + "//internal/platform:cancellation_flag", + "//internal/platform:uuid", + "//internal/platform/implementation:comm", + "//internal/platform/implementation/apple/Mediums", + "//internal/platform/implementation/apple/Mediums/Ble/Sockets:Central", + "//internal/platform/implementation/apple/Mediums/Ble/Sockets:Peripheral", + "//third_party/apple_frameworks:CoreBluetooth", + "//third_party/apple_frameworks:Foundation", + "//third_party/objective_c/google_toolbox_for_mac:GTM_Logger", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/strings", + ], +) + objc_library( name = "Shared", srcs = [ diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEError.h b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEError.h new file mode 100644 index 00000000..0db6d168 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEError.h @@ -0,0 +1,30 @@ +// 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. + +#import + +/** The domain for @c NSErrors raised by the BLE medium. */ +extern NSErrorDomain const GNCBLEErrorDomain; + +/** BLE medium error codes. */ +typedef NS_ERROR_ENUM(GNCBLEErrorDomain, GNCBLEError){ + GNCBLEErrorUnknown, + GNCBLEErrorDuplicateCharacteristic, + GNCBLEErrorInvalidServiceData, + GNCBLEErrorAlreadyAdvertising, + GNCBLEErrorInvalidCharacteristic, + GNCBLEErrorAlreadyDiscoveringSpecifiedCharacteristics, + GNCBLEErrorAlreadyReadingCharacteristic, + GNCBLEErrorAlreadyScanning, +}; diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEError.m b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEError.m new file mode 100644 index 00000000..53d2b15a --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEError.m @@ -0,0 +1,19 @@ +// 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. + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEError.h" + +#import + +NSErrorDomain const GNCBLEErrorDomain = @"com.google.nearby.ble.error"; diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h index a0e56440..de21587b 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h @@ -15,20 +15,24 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + /** A container for GATT characteristic information. */ @interface GNCBLEGATTCharacteristic : NSObject /** @remark init is not an available initializer. */ -- (nonnull instancetype)init NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; /** - * Creates a container for GATT characteristic information. + * Creates a container for GATT characteristic information with properties. * * @param characteristicUUID The UUID of the characteristic. * @param serviceUUID The UUID of the service. + * @param properties The properties of the characteristic. */ -- (instancetype)initWithUUID:(nonnull CBUUID *)characteristicUUID - serviceUUID:(nonnull CBUUID *)serviceUUID; +- (instancetype)initWithUUID:(CBUUID *)characteristicUUID + serviceUUID:(CBUUID *)serviceUUID + properties:(CBCharacteristicProperties)properties; /** * Creates a container for GATT characteristic information with permissions and properties. @@ -38,17 +42,16 @@ * @param permissions The permissions of the characteristic value. * @param properties The properties of the characteristic. */ -- (nonnull instancetype)initWithUUID:(nonnull CBUUID *)characteristicUUID - serviceUUID:(nonnull CBUUID *)serviceUUID - permissions:(CBAttributePermissions)permissions - properties:(CBCharacteristicProperties)properties - NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithUUID:(CBUUID *)characteristicUUID + serviceUUID:(CBUUID *)serviceUUID + permissions:(CBAttributePermissions)permissions + properties:(CBCharacteristicProperties)properties NS_DESIGNATED_INITIALIZER; /** The 128-bit UUID that identifies the characteristic. */ -@property(nonatomic, readonly, nonnull) CBUUID *characteristicUUID; +@property(nonatomic, readonly) CBUUID *characteristicUUID; /** The 128-bit UUID that identifies the service that the characteristic belongs to. */ -@property(nonatomic, readonly, nonnull) CBUUID *serviceUUID; +@property(nonatomic, readonly) CBUUID *serviceUUID; /** * The permissions of the characteristic value. @@ -67,3 +70,5 @@ @property(nonatomic, readonly) CBCharacteristicProperties properties; @end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.m b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.m index de8dea86..6759b417 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.m +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.m @@ -17,10 +17,17 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + @implementation GNCBLEGATTCharacteristic -- (instancetype)initWithUUID:(CBUUID *)characteristicUUID serviceUUID:(CBUUID *)serviceUUID { - return [self initWithUUID:characteristicUUID serviceUUID:serviceUUID permissions:0 properties:0]; +- (instancetype)initWithUUID:(CBUUID *)characteristicUUID + serviceUUID:(CBUUID *)serviceUUID + properties:(CBCharacteristicProperties)properties { + return [self initWithUUID:characteristicUUID + serviceUUID:serviceUUID + permissions:0 + properties:properties]; } - (instancetype)initWithUUID:(CBUUID *)characteristicUUID @@ -38,3 +45,5 @@ } @end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h new file mode 100644 index 00000000..f41f8f00 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h @@ -0,0 +1,117 @@ +// 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. + +#import +#import + +@class GNCBLEGATTCharacteristic; + +@protocol GNCPeripheral; + +NS_ASSUME_NONNULL_BEGIN + +/** + * A block to be invoked when a call to + * @c discoverCharacteristicsWithUUIDs:serviceUUID:completionHandler: has completed. + * + * @param error On success, error will be @c nil. Otherwise, the error that occurred. + */ +typedef void (^GNCDiscoverCharacteristicsCompletionHandler)(NSError *_Nullable error); + +/** + * A block to be invoked when a call to @c characteristicWithUUID:serviceUUID:completionHandler: has + * completed. + * + * @param characteristic The characteristic or @c nil if an error occurred. + * @param error On success, error will be @c nil. Otherwise, the error that occurred. + */ +typedef void (^GNCGetCharacteristicCompletionHandler)( + GNCBLEGATTCharacteristic *_Nullable characteristic, NSError *_Nullable error); + +/** + * A block to be invoked when a call to @c readValueForCharacteristic:completionHandler: has + * completed. + * + * @param value The characteristic's value or @c nil if an error occurred. + * @param error On success, error will be @c nil. Otherwise, the error that occurred. + */ +typedef void (^GNCReadCharacteristicValueCompletionHandler)(NSData *_Nullable value, + NSError *_Nullable error); + +/** + * An object that can be used to discover, explore, and interact with GATT services and + * characteristics available on a remote peripheral. + * + * @note The public APIs of this class are thread safe. + */ +@interface GNCBLEGATTClient : NSObject + +/** @remark init is not an available initializer. */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Initializes the GATT client with a specified peripheral. + * + * @param peripheral The peripheral instance. + */ +- (instancetype)initWithPeripheral:(id)peripheral; + +/** + * Discovers the specified characteristics of a service. + * + * A successful call to this method means the characteristics can be retreived with + * @c characteristicWithUUID:serviceUUID:completionHandler:. + * + * @param characteristics An array of 128-bit UUID objects of the characteristics that you are + * interested in. + * @param serviceUUID A 128-bit UUID that identifies the service that the characteristics belongs + * to. + * @param completionHandler Called on a private queue with @c nil if all characteristics have + * successfully been discovered or else an error. + */ +- (void)discoverCharacteristicsWithUUIDs:(NSArray *)characteristicUUIDs + serviceUUID:(CBUUID *)serviceUUID + completionHandler: + (nullable GNCDiscoverCharacteristicsCompletionHandler)completionHandler; + +/** + * Retrieves a GATT characteristic. + * + * If you haven’t yet called the @c discoverCharacteristicsWithUUIDs:serviceUUID:completionHandler: + * method to discover the characteristic, or if there was an error in doing so, this method will + * complete with an error. + * + * @param characteristicUUID A 128-bit UUID that identifies the characteristic. + * @param serviceUUID A 128-bit UUID that identifies the service that the characteristic belongs to. + * @param completionHandler Called on a private queue with the characteristic if successful or an + * error if one has occured. + */ +- (void)characteristicWithUUID:(CBUUID *)characteristicUUID + serviceUUID:(CBUUID *)serviceUUID + completionHandler:(nullable GNCGetCharacteristicCompletionHandler)completionHandler; + +/** + * Reads the requested characteristic from the associated remote device. + * + * @param characteristic The characteristic whose value you want to read. + * @param completionHandler Called on a private queue with the characteristics value if successful + * or an error if one has occured. + */ +- (void)readValueForCharacteristic:(GNCBLEGATTCharacteristic *)characteristic + completionHandler: + (nullable GNCReadCharacteristicValueCompletionHandler)completionHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.m b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.m new file mode 100644 index 00000000..8b91c879 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.m @@ -0,0 +1,299 @@ +// 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. + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h" + +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEError.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h" + +NS_ASSUME_NONNULL_BEGIN + +static char *const kGNCBLEGATTClientQueueLabel = "com.nearby.GNCBLEGATTClient"; + +static NSError *InvalidCharacteristicError() { + return [NSError errorWithDomain:GNCBLEErrorDomain + code:GNCBLEErrorInvalidCharacteristic + userInfo:nil]; +} + +static NSError *AlreadyDiscoveringSpecifiedCharacteristicsError() { + return [NSError errorWithDomain:GNCBLEErrorDomain + code:GNCBLEErrorAlreadyDiscoveringSpecifiedCharacteristics + userInfo:nil]; +} + +static NSError *AlreadyReadingCharacteristicError() { + return [NSError errorWithDomain:GNCBLEErrorDomain + code:GNCBLEErrorAlreadyReadingCharacteristic + userInfo:nil]; +} + +@interface GNCBLEGATTClient () +@end + +@implementation GNCBLEGATTClient { + dispatch_queue_t _queue; + id _peripheral; + + /** + * A map of service UUIDs with each service holding a map of a list of characterisitcs to a + * completion handler. This is used to track the groupings of characteristic discovery requests. + * When all characteristics of a request are discovered, the completion handler is called and + * removed from the map. + */ + NSMutableDictionary *, + GNCDiscoverCharacteristicsCompletionHandler> *> + *_discoverCharacteristicsCompletionHandlers; + + /** + * A service to characteristic to completion handler map. Used to track pending read requests. + * When a characteristic's value has been updated, the completion handler is called and removed + * from the map. + */ + NSMutableDictionary *> + *_readCharacteristicValueCompletionHandlers; +} + +- (instancetype)initWithPeripheral:(id)peripheral { + return [self + initWithPeripheral:peripheral + queue:dispatch_queue_create(kGNCBLEGATTClientQueueLabel, DISPATCH_QUEUE_SERIAL)]; +}; + +// Private. +- (instancetype)initWithPeripheral:(id)peripheral + queue:(nullable dispatch_queue_t)queue { + self = [super init]; + if (self) { + _queue = queue ?: dispatch_get_main_queue(); + _peripheral = peripheral; + _peripheral.peripheralDelegate = self; + _discoverCharacteristicsCompletionHandlers = [[NSMutableDictionary alloc] init]; + _readCharacteristicValueCompletionHandlers = [[NSMutableDictionary alloc] init]; + } + return self; +}; + +- (void)discoverCharacteristicsWithUUIDs:(NSArray *)characteristicUUIDs + serviceUUID:(CBUUID *)serviceUUID + completionHandler: + (nullable GNCDiscoverCharacteristicsCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + if (!_discoverCharacteristicsCompletionHandlers[serviceUUID]) { + _discoverCharacteristicsCompletionHandlers[serviceUUID] = [[NSMutableDictionary alloc] init]; + } + // Return an error if we are already discovering the provided characteristics. + if (_discoverCharacteristicsCompletionHandlers[serviceUUID][characteristicUUIDs]) { + if (completionHandler) { + completionHandler(AlreadyDiscoveringSpecifiedCharacteristicsError()); + } + return; + } + // Use the list of characteristic UUIDs as the key. This makes it easy to associate the + // completion handler with the list of characteristics we are waiting for, as well as retrieving + // the complete list of characteristics we need to query for a single service. + _discoverCharacteristicsCompletionHandlers[serviceUUID][characteristicUUIDs] = + completionHandler; + + // Note: A call to @c discoverServices: will always be paired with a delegate call even if the + // service has already been discovered. + [_peripheral discoverServices:@[ serviceUUID ]]; + }); +} + +- (void)characteristicWithUUID:(CBUUID *)characteristicUUID + serviceUUID:(CBUUID *)serviceUUID + completionHandler:(nullable GNCGetCharacteristicCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + CBCharacteristic *characteristic = [self synchronousCharacteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID]; + if (!characteristic) { + if (completionHandler) { + completionHandler(nil, InvalidCharacteristicError()); + } + return; + } + if (completionHandler) { + completionHandler([[GNCBLEGATTCharacteristic alloc] initWithUUID:characteristic.UUID + serviceUUID:characteristic.service.UUID + properties:characteristic.properties], + nil); + } + }); +} + +- (void)readValueForCharacteristic:(GNCBLEGATTCharacteristic *)characteristic + completionHandler: + (nullable GNCReadCharacteristicValueCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + CBCharacteristic *cbCharacteristic = + [self synchronousCharacteristicWithUUID:characteristic.characteristicUUID + serviceUUID:characteristic.serviceUUID]; + + if (!cbCharacteristic) { + if (completionHandler) { + completionHandler(nil, InvalidCharacteristicError()); + } + return; + } + + if (!_readCharacteristicValueCompletionHandlers[characteristic.serviceUUID]) { + _readCharacteristicValueCompletionHandlers[characteristic.serviceUUID] = + [[NSMutableDictionary alloc] init]; + } + // Return an error if we are already discovering the provided characteristics. + if (_readCharacteristicValueCompletionHandlers[characteristic.serviceUUID] + [characteristic.characteristicUUID]) { + if (completionHandler) { + completionHandler(nil, AlreadyReadingCharacteristicError()); + } + return; + } + _readCharacteristicValueCompletionHandlers[characteristic.serviceUUID] + [characteristic.characteristicUUID] = + completionHandler; + + [_peripheral readValueForCharacteristic:cbCharacteristic]; + }); +} + +#pragma mark - Internal + +- (CBCharacteristic *)synchronousCharacteristicWithUUID:(CBUUID *)characteristicUUID + serviceUUID:(CBUUID *)serviceUUID { + dispatch_assert_queue(_queue); + for (CBService *service in _peripheral.services) { + if ([service.UUID isEqual:serviceUUID]) { + for (CBCharacteristic *characteristic in service.characteristics) { + if ([characteristic.UUID isEqual:characteristicUUID]) { + return characteristic; + } + } + } + } + return nil; +} + +#pragma mark - GNCPeripheralDelegate + +- (void)gnc_peripheral:(id)peripheral didDiscoverServices:(nullable NSError *)error { + dispatch_assert_queue(_queue); + // TODO(b/295911088): Queue incoming requests by service would allow us to not attempt + // characteristc discovery on all services and to short circuit and call the completion handler if + // there was an error. + for (CBService *service in peripheral.services) { + // Flatten lists of characteristics for a given service into a single list for discovery. + NSArray *> *groupedCharacteristics = + _discoverCharacteristicsCompletionHandlers[service.UUID].allKeys; + if (!groupedCharacteristics) { + continue; + } + NSMutableSet *flattenedCharacteristics = [[NSMutableSet alloc] init]; + for (NSArray *characteristics in groupedCharacteristics) { + [flattenedCharacteristics addObjectsFromArray:characteristics]; + } + + // Note: Since we don't clear @c _discoverCharacteristicsCompletionHandlers until the + // characterististics have been discovered, multiple calls to + // @c discoverService:characteristics:completionHandler: will cause duplicate characteristic + // discovery calls on the same service. We CANNOT clear the pending list until after we actually + // discover the characteristics, because there can be more than 1 service with the same UUID. + // This is a common occurence for Nearby services, so it should not be treated as an edge case. + [_peripheral discoverCharacteristics:[flattenedCharacteristics allObjects] forService:service]; + } +} + +- (void)gnc_peripheral:(id)peripheral + didDiscoverCharacteristicsForService:(CBService *)service + error:(nullable NSError *)error { + dispatch_assert_queue(_queue); + + // Check if each group of characteristics is a subset of the discovered characteristics. If all + // characteristics of the group have been discovered, call the completion handler with success, + // otherwise continue waiting. If the characteristic discovery returns an error, call all pending + // discovery request completion handlers with the error. + NSMutableSet *characteristics = [[NSMutableSet alloc] init]; + for (CBCharacteristic *characteristic in service.characteristics) { + [characteristics addObject:characteristic.UUID]; + } + [_discoverCharacteristicsCompletionHandlers[service.UUID].copy + enumerateKeysAndObjectsUsingBlock:^(NSArray *pendingCharacteristics, + GNCDiscoverCharacteristicsCompletionHandler handler, + BOOL *stop) { + if ([[NSSet setWithArray:pendingCharacteristics] isSubsetOfSet:characteristics]) { + _discoverCharacteristicsCompletionHandlers[service.UUID][pendingCharacteristics] = nil; + handler(nil); + return; + } + + // TODO(b/295911088): Queue incoming requests by service to avoid this issue. + // This could be a race, where @c discoverService:characteristics:completionHandler: is + // called multiple times quickly for the same service. If a request fails, all pending + // requests for the same service are also failed. + if (error) { + _discoverCharacteristicsCompletionHandlers[service.UUID][pendingCharacteristics] = nil; + handler(error); + return; + } + }]; +} + +- (void)gnc_peripheral:(id)peripheral + didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic + error:(nullable NSError *)error { + dispatch_assert_queue(_queue); + NSMutableDictionary *handlers = + _readCharacteristicValueCompletionHandlers[characteristic.service.UUID]; + if (!handlers) { + return; + } + GNCReadCharacteristicValueCompletionHandler handler = handlers[characteristic.UUID]; + handlers[characteristic.UUID] = nil; + if (handler) { + handler(characteristic.value, error); + } +} + +#pragma mark - CBPeripheralDelegate + +- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error { + dispatch_async(_queue, ^{ + [self gnc_peripheral:peripheral didDiscoverServices:error]; + }); +} + +- (void)peripheral:(CBPeripheral *)peripheral + didDiscoverCharacteristicsForService:(CBService *)service + error:(nullable NSError *)error { + dispatch_async(_queue, ^{ + [self gnc_peripheral:peripheral didDiscoverCharacteristicsForService:service error:error]; + }); +} + +- (void)peripheral:(CBPeripheral *)peripheral + didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic + error:(nullable NSError *)error { + dispatch_async(_queue, ^{ + [self gnc_peripheral:peripheral didUpdateValueForCharacteristic:characteristic error:error]; + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h index 9131555d..1b94731a 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h @@ -19,11 +19,43 @@ NS_ASSUME_NONNULL_BEGIN +/** + * A block to be invoked when a call to + * @c createCharacteristicWithServiceID:characteristicUUID:permissions:properties:completionHandler: + * has completed. + * + * @param characteristic The created characteristic, or @c nil if an error occurred. + * @param error The cause of the failure, or @c nil if no error occurred. + */ +typedef void (^GNCCreateCharacteristicCompletionHandler)( + GNCBLEGATTCharacteristic *_Nullable characteristic, NSError *_Nullable error); + +/** + * A block to be invoked when a call to @c updateCharacteristic:value:completionHandler: has + * completed. + * + * @param error The cause of the failure, or @c nil if no error occurred. + */ +typedef void (^GNCUpdateCharacteristicCompletionHandler)(NSError *_Nullable error); + +/** + * A block to be invoked when a call to @c startAdvertisingData:completionHandler: has completed. + * + * @param error The cause of the failure, or @c nil if no error occurred. + */ +typedef void (^GNCStartAdvertisingCompletionHandler)(NSError *_Nullable error); + +/** + * A block to be invoked when a call to @c stopAdvertisingWithcompletionHandler: has completed. + * + * @param error The cause of the failure, or @c nil if no error occurred. + */ +typedef void (^GNCStopAdvertisingCompletionHandler)(NSError *_Nullable error); + /** * An object that manages and advertises GATT characteritics. * - * @note The public APIs of this class are NOT thread safe. All methods in this class should be - * invoked from the same thread or serially. + * @note The public APIs of this class are thread safe. */ @interface GNCBLEGATTServer : NSObject @@ -33,30 +65,31 @@ NS_ASSUME_NONNULL_BEGIN * Characteristics of the same service UUID will cause the service to be unpublished and republished * with the new characteristic appended. * - * This method blocks until the characteristic has successfully been added to the GATT server or an - * error occurs. - * * @param serviceUUID A 128-bit UUID that identifies the service that the characteristic belongs to. * @param characteristicUUID A 128-bit UUID that identifies the characteristic. * @param permissions The permissions of the characteristic value. * @param properties The properties of the characteristic. - * @return Returns the characteristic or nil if an error has occured. + * @param completionHandler Called on a private queue with the characteristic if successfully + * created or an error if one has occured. */ -- (nullable GNCBLEGATTCharacteristic *) - createCharacteristicWithServiceID:(CBUUID *)serviceUUID - characteristicUUID:(CBUUID *)characteristicUUID - permissions:(CBAttributePermissions)permissions - properties:(CBCharacteristicProperties)properties; +- (void)createCharacteristicWithServiceID:(CBUUID *)serviceUUID + characteristicUUID:(CBUUID *)characteristicUUID + permissions:(CBAttributePermissions)permissions + properties:(CBCharacteristicProperties)properties + completionHandler: + (nullable GNCCreateCharacteristicCompletionHandler)completionHandler; /** * Updates a local characteristic with the provided value. * * @param characteristic The characteristic to update. * @param value The new value for the characteristic. - * @return Returns @c YES if successfully updated or @c NO if an error has occured. + * @param completionHandler Called on a private queue with @c nil if successfully updated or an + * error if one has occured. */ -- (BOOL)updateCharacteristic:(GNCBLEGATTCharacteristic *)characteristic - value:(nullable NSData *)value; +- (void)updateCharacteristic:(GNCBLEGATTCharacteristic *)characteristic + value:(nullable NSData *)value + completionHandler:(nullable GNCUpdateCharacteristicCompletionHandler)completionHandler; /** Removes all published services from the local GATT database. */ - (void)stop; @@ -68,14 +101,23 @@ NS_ASSUME_NONNULL_BEGIN * service list is advertised using @c CBAdvertisementDataServiceUUIDsKey and the associated data is * advertised using @c CBAdvertisementDataLocalNameKey. Since @c CBAdvertisementDataLocalNameKey * does not support binary data, the value is base64 encoded and truncated if the resulting value is - * longer than 22 bytes. - * - * This method blocks until the service data is being advertised or an error occurs. + * longer than 22 bytes. This also means we can only support advertising a single service. * * @param serviceData A dictionary that contains service-specific advertisement data. - * @return Returns @c YES if successfully updated or @c NO if an error has occured. + * @param completionHandler Called on a private queue with @c nil if successfully started + * advertising or an error if one has occured. */ -- (BOOL)startAdvertisingData:(NSDictionary *)serviceData; +- (void)startAdvertisingData:(NSDictionary *)serviceData + completionHandler:(nullable GNCStartAdvertisingCompletionHandler)completionHandler; + +/** + * Stops advertising all service data. + * + * @param completionHandler Called on a private queue with @c nil if successfully stopped + * advertising or an error if one has occured. + */ +- (void)stopAdvertisingWithCompletionHandler: + (nullable GNCStopAdvertisingCompletionHandler)completionHandler; @end diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.m b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.m index e80fec94..703f6edd 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.m +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.m @@ -17,174 +17,193 @@ #import #import +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEError.h" #import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h" #import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheralManager.h" #import "internal/platform/implementation/apple/Mediums/BLEv2/NSData+GNCWebSafeBase64.h" +#import "GoogleToolboxForMac/GTMLogger.h" NS_ASSUME_NONNULL_BEGIN -// An arbitrary timeout that should be pretty lenient. -static NSTimeInterval const GNCBLEGATTServerTimeoutInSeconds = 2; +static char *const kGNCBLEGATTServerQueueLabel = "com.nearby.GNCBLEGATTServer"; -@interface GNCBLEGATTServer () +@interface GNCBLEGATTServer () @end @implementation GNCBLEGATTServer { + dispatch_queue_t _queue; id _peripheralManager; // A map of service UUIDs to the service. This is used to keep track of all services and - // characteristics that should be in the GATT database. This also keeps track of a characteristics - // dynamic read value. This is the value returned when a remote device attempts to read the - // characteristic. + // characteristics that have been requested to be added to the GATT database. This may not match + // the "real" services that remote devices can see. NSMutableDictionary *_services; - // A list of services that have been requested to be added to the GATT database, but have not yet - // completed. This is used by the create characteristic method to block until the characteristic - // has been added to the database. - NSMutableArray *_pendingServiceAdditions; + // A list of characteristics that will be added to the GATT database once the peripheral + // transitions into a valid state. If a characteristic is in this list it means that a + // CoreBluetooth request to add to the characteristic to the GATT database has not yet been made. + NSMutableDictionary *> + *_pendingCharacteristics; - // A map of service UUIDs to its associated error if the service had failed to be added to the - // GATT database. This is used by the create characteristic method to determine if the service was - // successfully added. - NSMutableDictionary *_serviceErrors; + // This keeps track of a characteristic's dynamic read value. This is the value returned when a + // remote device attempts to read the characteristic. + NSMutableDictionary *> *_characteristicValues; - // Guards access to @c _services, @c _pendingServiceAdditions and @c _serviceErrors. The condition - // is also used to block method execution until its async action completes. - NSCondition *_condition; + // The data that should be advertised. This value is cached until the caller explicitly stops + // advertising, because we will do our best to restart the advertisement if BT turns off then back + // on. + NSDictionary *_advertisementData; } - (instancetype)init { - dispatch_queue_t queue = - dispatch_queue_create("com.nearby.GNCBLEGATTServer", DISPATCH_QUEUE_SERIAL); - return [self initWithPeripheralManager:[[CBPeripheralManager alloc] initWithDelegate:nil - queue:queue]]; -} - -- (instancetype)initWithPeripheralManager:(id)peripheralManager { self = [super init]; if (self) { + _queue = dispatch_queue_create(kGNCBLEGATTServerQueueLabel, DISPATCH_QUEUE_SERIAL); + _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:nil queue:_queue]; + // Set for @c GNCPeripheralManager to be able to forward callbacks. + _peripheralManager.peripheralDelegate = self; + _services = [[NSMutableDictionary alloc] init]; + _pendingCharacteristics = [[NSMutableDictionary alloc] init]; + _characteristicValues = [[NSMutableDictionary alloc] init]; + _advertisementData = nil; + } + return self; +} + +// This is private and should only be used for tests. The provided peripheral manager must call +// delegate methods on the main queue. +- (instancetype)initWithPeripheralManager:(nullable id)peripheralManager { + self = [super init]; + if (self) { + _queue = dispatch_get_main_queue(); _peripheralManager = peripheralManager; // Set for @c GNCPeripheralManager to be able to forward callbacks. _peripheralManager.peripheralDelegate = self; _services = [[NSMutableDictionary alloc] init]; - _pendingServiceAdditions = [[NSMutableArray alloc] init]; - _serviceErrors = [[NSMutableDictionary alloc] init]; - _condition = [[NSCondition alloc] init]; + _pendingCharacteristics = [[NSMutableDictionary alloc] init]; + _characteristicValues = [[NSMutableDictionary alloc] init]; + _advertisementData = nil; } return self; -}; - -- (nullable GNCBLEGATTCharacteristic *) - createCharacteristicWithServiceID:(CBUUID *)serviceUUID - characteristicUUID:(CBUUID *)characteristicUUID - permissions:(CBAttributePermissions)permissions - properties:(CBCharacteristicProperties)properties { - // Ensure we are in a powered on state. - if (![self waitUntilPoweredOn]) { - return nil; - } - - NSDate *timeLimit = [NSDate dateWithTimeIntervalSinceNow:GNCBLEGATTServerTimeoutInSeconds]; - BOOL wasSignaled = YES; - [_condition lock]; - - // If a service with the specified UUID exists, we are modifying it, which requires us to remove - // the service and then re-add it after the new characteristic has been added. Otherwise, create - // the service for the specified UUID and keep track of it. - CBMutableService *service = _services[serviceUUID]; - if (service != nil) { - [_peripheralManager removeService:service]; - } else { - service = [[CBMutableService alloc] initWithType:serviceUUID primary:YES]; - _services[serviceUUID] = service; - } - - // Create a characteristic with the specified permissions and properties. - CBMutableCharacteristic *characteristic = - [[CBMutableCharacteristic alloc] initWithType:characteristicUUID - properties:properties - value:nil - permissions:permissions]; - - // Add the characteristic to the service's list of characteristics - NSMutableArray *characteristics = - [service.characteristics mutableCopy]; - if (characteristics == nil) { - characteristics = [[NSMutableArray alloc] init]; - } - [characteristics addObject:characteristic]; - service.characteristics = characteristics; - - // Publish the service and wait until complete. - [_pendingServiceAdditions addObject:service.UUID]; - [_peripheralManager addService:service]; - while ([_pendingServiceAdditions containsObject:service.UUID] && wasSignaled) { - wasSignaled = [_condition waitUntilDate:timeLimit]; - } - NSError *serviceError = [_serviceErrors objectForKey:service.UUID]; - [_serviceErrors removeObjectForKey:service.UUID]; - [_condition unlock]; - if (serviceError) { - return nil; - } - return [[GNCBLEGATTCharacteristic alloc] initWithUUID:characteristicUUID - serviceUUID:serviceUUID - permissions:permissions - properties:properties]; } -- (BOOL)updateCharacteristic:(GNCBLEGATTCharacteristic *)characteristic - value:(nullable NSData *)value { - // Ensure we are in a powered on state. - if (![self waitUntilPoweredOn]) { - return NO; - } - - [_condition lock]; - // Find and update the specified characteristic's value. - CBMutableService *service = _services[characteristic.serviceUUID]; - if (!service) { - [_condition unlock]; - return NO; - } - for (CBMutableCharacteristic *c in service.characteristics) { - if ([c.UUID isEqual:characteristic.characteristicUUID]) { - c.value = value; - [_condition unlock]; - return YES; +- (void)createCharacteristicWithServiceID:(CBUUID *)serviceUUID + characteristicUUID:(CBUUID *)characteristicUUID + permissions:(CBAttributePermissions)permissions + properties:(CBCharacteristicProperties)properties + completionHandler: + (nullable GNCCreateCharacteristicCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + // Check if the characteristic exists in the pending additions or existing services. + for (CBCharacteristic *c in _pendingCharacteristics[serviceUUID]) { + if ([c.UUID isEqual:characteristicUUID]) { + if (completionHandler) { + completionHandler(nil, [NSError errorWithDomain:GNCBLEErrorDomain + code:GNCBLEErrorDuplicateCharacteristic + userInfo:nil]); + } + return; + } } - } - [_condition unlock]; - return NO; + for (CBCharacteristic *c in _services[serviceUUID].characteristics) { + if ([c.UUID isEqual:characteristicUUID]) { + if (completionHandler) { + completionHandler(nil, [NSError errorWithDomain:GNCBLEErrorDomain + code:GNCBLEErrorDuplicateCharacteristic + userInfo:nil]); + } + return; + } + } + + // Create a characteristic with the specified permissions and properties. + CBMutableCharacteristic *characteristic = + [[CBMutableCharacteristic alloc] initWithType:characteristicUUID + properties:properties + value:nil + permissions:permissions]; + // Track characteristics that need to be added to the GATT database. These will either be added + // immediately or as soon as the peripheral manager is in a valid state. + if (!_pendingCharacteristics[serviceUUID]) { + _pendingCharacteristics[serviceUUID] = [[NSMutableArray alloc] init]; + } + [_pendingCharacteristics[serviceUUID] addObject:characteristic]; + + GNCBLEGATTCharacteristic *gncCharacteristic = + [[GNCBLEGATTCharacteristic alloc] initWithUUID:characteristicUUID + serviceUUID:serviceUUID + permissions:permissions + properties:properties]; + [self internalAddPendingServicesIfPoweredOn]; + if (completionHandler) { + completionHandler(gncCharacteristic, nil); + } + }); +} + +- (void)updateCharacteristic:(GNCBLEGATTCharacteristic *)characteristic + value:(nullable NSData *)value + completionHandler:(nullable GNCUpdateCharacteristicCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + // Keep track of the characteristics value, because we will need to retreive it during a read + // request. + if (_characteristicValues[characteristic.serviceUUID] == nil) { + _characteristicValues[characteristic.serviceUUID] = [[NSMutableDictionary alloc] init]; + } + _characteristicValues[characteristic.serviceUUID][characteristic.characteristicUUID] = value; + if (completionHandler) { + completionHandler(nil); + } + }); } - (void)stop { - [_condition lock]; - [_services removeAllObjects]; - [_condition unlock]; - [_peripheralManager removeAllServices]; + dispatch_async(_queue, ^{ + // Note: Do not clear/stop advertisements here, since there is a separate method for that. + [_peripheralManager removeAllServices]; + [_services removeAllObjects]; + [_pendingCharacteristics removeAllObjects]; + [_characteristicValues removeAllObjects]; + }); } -- (BOOL)startAdvertisingData:(NSDictionary *)serviceData { - // We can only handle advertising a single service data item, so return early if there is more - // than one service incuded. - if (serviceData.count > 1) { - return NO; - } +- (void)startAdvertisingData:(NSDictionary *)serviceData + completionHandler:(nullable GNCStartAdvertisingCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + // We can only handle advertising a single service data item, so return early if there is more + // than one service incuded. + if (serviceData.count != 1) { + if (completionHandler) { + completionHandler([NSError + errorWithDomain:GNCBLEErrorDomain + code:GNCBLEErrorInvalidServiceData + userInfo:@{ + NSLocalizedDescriptionKey : + @"Failed to start advertising, because Nearby for Apple platforms only " + @"supports a single service data item." + }]); + } + return; + } - // Ensure we are in a powered on state. - if (![self waitUntilPoweredOn]) { - return NO; - } + // If we have advertisement data set, that means we are already advertising and should return + // early. Advertising must be stopped before being started again. + if (_advertisementData) { + if (completionHandler) { + completionHandler([NSError errorWithDomain:GNCBLEErrorDomain + code:GNCBLEErrorAlreadyAdvertising + userInfo:nil]); + } + return; + } - if (serviceData.count == 1) { // Apple doesn't support setting service data, so we must convert it to a "local name". We do // this by assuming there will only ever be one service and then base64 encoding its associated // data. Other platforms are aware of this behavior and always check the local name if service // data is unavailable. CBUUID *serviceUUID = [serviceData.allKeys objectAtIndex:0]; NSData *value = [serviceData objectForKey:serviceUUID]; - NSString *encoded = [value webSafebase64EncodedString]; + NSString *encoded = [value webSafeBase64EncodedString]; // Base64 encoding increases the size of the data so we must truncate it to 22 bytes to ensure // it fits in the advertisement alongside an assumed 16-bit serviceUUID. @@ -192,107 +211,151 @@ static NSTimeInterval const GNCBLEGATTServerTimeoutInSeconds = 2; encoded = [encoded substringToIndex:22]; } - [_peripheralManager startAdvertising:@{ + _advertisementData = @{ CBAdvertisementDataLocalNameKey : encoded, CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ] - }]; - } else { - [_peripheralManager startAdvertising:nil]; - } + }; - // Wait until advertisement has started. - NSDate *timeLimit = [NSDate dateWithTimeIntervalSinceNow:GNCBLEGATTServerTimeoutInSeconds]; - BOOL wasSignaled = YES; - [_condition lock]; - while (!_peripheralManager.isAdvertising && wasSignaled) { - wasSignaled = [_condition waitUntilDate:timeLimit]; - } - [_condition unlock]; - return _peripheralManager.isAdvertising; + [self internalStartAdvertisingIfPoweredOn]; + if (completionHandler) { + completionHandler(nil); + } + }); } -#pragma mark - Helpers +- (void)stopAdvertisingWithCompletionHandler: + (nullable GNCStopAdvertisingCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + _advertisementData = nil; + [_peripheralManager stopAdvertising]; + if (completionHandler) { + completionHandler(nil); + } + }); +} -- (BOOL)waitUntilPoweredOn { - NSDate *timeLimit = [NSDate dateWithTimeIntervalSinceNow:GNCBLEGATTServerTimeoutInSeconds]; - BOOL timedOut = NO; - [_condition lock]; - while (_peripheralManager.state != CBManagerStatePoweredOn && !timedOut) { - timedOut = ![_condition waitUntilDate:timeLimit]; +#pragma mark - Internal + +- (void)internalAddPendingServicesIfPoweredOn { + dispatch_assert_queue(_queue); + // Services can only be added while bluetooth is on or off. Since this method will be called + // anytime the peripheral manager's state changes and turning bluetooth on/off does not reset + // the GATT database, we can add all pending services when we transition to the on or off state. + // However, other state transitions may behave differently, so we may need to modify this + // functionality in this future to re-add services if they disapear. + if (_peripheralManager.state == CBManagerStatePoweredOn || + _peripheralManager.state == CBManagerStatePoweredOff) { + for (CBUUID *serviceUUID in _pendingCharacteristics.allKeys) { + // If a service with the specified UUID exists, we are modifying it, which requires us to + // remove the service and then re-add it after the new characteristic has been added. + // Otherwise, create the service for the specified UUID and keep track of it. + CBMutableService *service = _services[serviceUUID]; + if (service != nil) { + [_peripheralManager removeService:service]; + } else { + service = [[CBMutableService alloc] initWithType:serviceUUID primary:YES]; + _services[serviceUUID] = service; + } + + // Add the pending characteristics to the current service's list of characteristics. + NSMutableArray *characteristics = + [service.characteristics mutableCopy]; + if (characteristics == nil) { + characteristics = [[NSMutableArray alloc] init]; + } + // This makes the assumption that _pendingCharacteristics does not contain any duplicate + // characteristics within itself or the current service characteristics. This is only + // enforced on characteristic creation. + [characteristics addObjectsFromArray:_pendingCharacteristics[serviceUUID]]; + service.characteristics = characteristics; + + // Publish the service. + [_peripheralManager addService:service]; + } + // Clean up pending characteristics so we don't try to re-add them any time the power state + // changes. + [_pendingCharacteristics removeAllObjects]; + } +} + +- (void)internalStartAdvertisingIfPoweredOn { + dispatch_assert_queue(_queue); + // Advertising can only be done when powered on and must be restarted if bluetooth is turned off + // then back on. This will be called anytime the peripheral manager's state changes, so + // @c startAdvertising: will be called anytime state transitions back to powered on. + if (_peripheralManager.state == CBManagerStatePoweredOn && _advertisementData != nil) { + // Stop advertising just in case something outside of this class is advertising (like weave). + [_peripheralManager stopAdvertising]; + [_peripheralManager startAdvertising:_advertisementData]; } - [_condition unlock]; - return _peripheralManager.state == CBManagerStatePoweredOn; } #pragma mark - GNCPeripheralManagerDelegate - (void)gnc_peripheralManagerDidUpdateState:(id)peripheral { - [_condition lock]; - [_condition signal]; - [_condition unlock]; + dispatch_assert_queue(_queue); + [self internalAddPendingServicesIfPoweredOn]; + [self internalStartAdvertisingIfPoweredOn]; } - (void)gnc_peripheralManagerDidStartAdvertising:(id)peripheral error:(nullable NSError *)error { - [_condition lock]; - [_condition signal]; - [_condition unlock]; + dispatch_assert_queue(_queue); + if (error) { + GTMLoggerError(@"Failed to start advertising: %@", error); + } } - (void)gnc_peripheralManager:(id)peripheral didAddService:(CBService *)service error:(nullable NSError *)error { - [_condition lock]; - [_pendingServiceAdditions removeObject:service.UUID]; + dispatch_assert_queue(_queue); if (error) { - [_serviceErrors setObject:error forKey:service.UUID]; + GTMLoggerError(@"Failed to add service %@: %@", service, error); } - [_condition signal]; - [_condition unlock]; } - (void)gnc_peripheralManager:(id)peripheral didReceiveReadRequest:(CBATTRequest *)request { - [_condition lock]; - // Find the requested charactertic and respond with its value if it exists. - CBMutableService *service = _services[request.characteristic.service.UUID]; - if (!service) { - [_condition unlock]; + dispatch_assert_queue(_queue); + NSData *value = + _characteristicValues[request.characteristic.service.UUID][request.characteristic.UUID]; + if (!value) { [_peripheralManager respondToRequest:request withResult:CBATTErrorAttributeNotFound]; return; } - for (CBMutableCharacteristic *c in service.characteristics) { - if ([c.UUID isEqual:request.characteristic.UUID]) { - request.value = c.value; - [_condition unlock]; - [_peripheralManager respondToRequest:request withResult:CBATTErrorSuccess]; - return; - } - } - [_condition unlock]; - [_peripheralManager respondToRequest:request withResult:CBATTErrorAttributeNotFound]; + request.value = value; + [_peripheralManager respondToRequest:request withResult:CBATTErrorSuccess]; } #pragma mark - CBPeripheralManagerDelegate - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral { - [self gnc_peripheralManagerDidUpdateState:peripheral]; + dispatch_async(_queue, ^{ + [self gnc_peripheralManagerDidUpdateState:peripheral]; + }); } - (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(nullable NSError *)error { - [self gnc_peripheralManagerDidStartAdvertising:peripheral error:error]; + dispatch_async(_queue, ^{ + [self gnc_peripheralManagerDidStartAdvertising:peripheral error:error]; + }); } - (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(nullable NSError *)error { - [self gnc_peripheralManager:peripheral didAddService:service error:error]; + dispatch_async(_queue, ^{ + [self gnc_peripheralManager:peripheral didAddService:service error:error]; + }); } - (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request { - [self gnc_peripheralManager:peripheral didReceiveReadRequest:request]; + dispatch_async(_queue, ^{ + [self gnc_peripheralManager:peripheral didReceiveReadRequest:request]; + }); } @end diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h new file mode 100644 index 00000000..51574091 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h @@ -0,0 +1,171 @@ +// 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. + +#import +#import + +@class GNCBLEGATTServer; +@class GNCBLEGATTClient; +@class GNCBLEGATTCharacteristic; + +@protocol GNCPeripheral; + +NS_ASSUME_NONNULL_BEGIN + +/** + * A block to be invoked when a call to @c startAdvertisingData:completionHandler: has completed. + * + * @param error The cause of the failure, or @c nil if no error occurred. + */ +typedef void (^GNCStartAdvertisingCompletionHandler)(NSError *_Nullable error); + +/** + * A block to be invoked when a call to @c stopAdvertisingWithcompletionHandler: has completed. + * + * @param error The cause of the failure, or @c nil if no error occurred. + */ +typedef void (^GNCStopAdvertisingCompletionHandler)(NSError *_Nullable error); + +/** + * A block to be invoked when a peripheral’s advertisement has been discovered. + * + * @note This block can be called numerous times. + * + * @param peripheral The discovered peripheral. + * @param serviceData A dictionary that contains service-specific advertisement data. The keys + * represent services and the values represent the service-specific data. + */ +typedef void (^GNCAdvertisementFoundHandler)(id peripheral, + NSDictionary *serviceData); + +/** + * A block to be invoked when a call to + * @c startScanningForService:advertisementFoundHandler:completionHandler: has completed. + * + * @param error The cause of the failure, or @c nil if no error occurred. + */ +typedef void (^GNCStartScanningCompletionHandler)(NSError *_Nullable error); + +/** + * A block to be invoked when a call to @c stopScanningWithCompletionHandler: has completed. + * + * @param error The cause of the failure, or @c nil if no error occurred. + */ +typedef void (^GNCStopScanningCompletionHandler)(NSError *_Nullable error); + +/** + * A block to be invoked when a call to @c startGATTServerWithCompletionHandler: has completed. + * + * @param server The successfully started GATT server, or @c nil if an error occurred. + * @param error The cause of the failure, or @c nil if no error occurred. + */ +typedef void (^GNCGATTServerCompletionHandler)(GNCBLEGATTServer *_Nullable server, + NSError *_Nullable error); + +/** A block to be invoked when a peripheral has disconnected. */ +typedef void (^GNCGATTDisconnectionHandler)(); + +/** + * A block to be invoked when a call to + * @c connectToGATTServerForPeripheral:disconnectionHandler:completionHandler: has completed. + * + * @param client The interface to the remote peripheral’s GATT server, or @c nil if an error + * occurred. + * @param error The cause of the failure, or @c nil if no error occurred. + */ +typedef void (^GNCGATTConnectionCompletionHandler)(GNCBLEGATTClient *_Nullable client, + NSError *_Nullable error); + +/** + * The main BLE medium used inside of Nearby. This serves as the entry point for all BLE and GATT + * related operations. + * + * @note The public APIs of this class are thread safe. + */ +@interface GNCBLEMedium : NSObject + +/** The hardware supports BOTH advertising extensions and extended scans. */ +@property(nonatomic, readonly) BOOL supportsExtendedAdvertisements; + +/** + * Starts advertising service data in a way that is supported by CoreBluetooth. + * + * Since CoreBluetooth doesn't support setting the @c CBAdvertisementDataServiceDataKey key, the + * service list is advertised using @c CBAdvertisementDataServiceUUIDsKey and the associated data is + * advertised using @c CBAdvertisementDataLocalNameKey. Since @c CBAdvertisementDataLocalNameKey + * does not support binary data, the value is base64 encoded and truncated if the resulting value is + * longer than 22 bytes. This also means we can only support advertising a single service. + * + * @param serviceData A dictionary that contains service-specific advertisement data. + * @param completionHandler Called on a private queue with @c nil if successfully started + * advertising or an error if one has occured. + */ +- (void)startAdvertisingData:(NSDictionary *)serviceData + completionHandler:(nullable GNCStartAdvertisingCompletionHandler)completionHandler; + +/** + * Stops advertising all service data. + * + * @param completionHandler Called on a private queue with @c nil if successfully stopped + * advertising or an error if one has occured. + */ +- (void)stopAdvertisingWithCompletionHandler: + (nullable GNCStopAdvertisingCompletionHandler)completionHandler; + +/** + * Scans for peripherals that are advertising the specified service. + * + * @param serviceUUID The service UUID to scan for. + * @param advertisementFoundHandler Called on a private queue when a peripheral has been discovered. + * @param completionHandler Called on a private queue with @c nil if successfully started scanning + * or an error if one has occured. + */ +- (void)startScanningForService:(CBUUID *)serviceUUID + advertisementFoundHandler:(GNCAdvertisementFoundHandler)advertisementFoundHandler + completionHandler:(nullable GNCStartScanningCompletionHandler)completionHandler; + +/** + * Stops scanning for peripherals. + * + * @param completionHandler Called on a private queue with @c nil if successfully stopped + * scanning or an error if one has occured. + */ +- (void)stopScanningWithCompletionHandler: + (nullable GNCStopScanningCompletionHandler)completionHandler; + +/** + * Starts a GATT server. + * + * @param completionHandler Called on a private queue with the GATT server if successfully started + * or an error if one has occured. + */ +- (void)startGATTServerWithCompletionHandler: + (nullable GNCGATTServerCompletionHandler)completionHandler; + +/** + * Connects to a peripheral’s GATT server. + * + * @param remotePeripheral The peripheral to which the central is attempting to connect. + * @param disconnectionHandler Called on a private queue when the peripheral has been disconnected. + * @param completionHandler Called on a private queue with a GATT client if successfully connected + * or an error if one has occured. + */ +- (void)connectToGATTServerForPeripheral:(id)remotePeripheral + disconnectionHandler:(nullable GNCGATTDisconnectionHandler)disconnectionHandler + completionHandler: + (nullable GNCGATTConnectionCompletionHandler)completionHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.m b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.m new file mode 100644 index 00000000..139b5169 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.m @@ -0,0 +1,319 @@ +// 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. + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h" + +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEError.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCCentralManager.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/NSData+GNCWebSafeBase64.h" + +NS_ASSUME_NONNULL_BEGIN + +static char *const kBLEMediumQueueLabel = "com.nearby.GNCBLEMedium"; + +static NSError *AlreadyScanningError() { + return [NSError errorWithDomain:GNCBLEErrorDomain code:GNCBLEErrorAlreadyScanning userInfo:nil]; +} + +@interface GNCBLEMedium () +@end + +@implementation GNCBLEMedium { + dispatch_queue_t _queue; + id _centralManager; + + // The active GATT server, or @nil if one hasn't been started yet. + GNCBLEGATTServer *_server; + + // The service that is being actively scanned for, or @c nil if not currently scanning. + CBUUID *_serviceUUID; + + // The handler called when an advertisement for the service represented by @c _serviceUUID has + // been discovered. This will be called continuously, until the peripheral disappears. + GNCAdvertisementFoundHandler _advertisementFoundHandler; + + // A peripheral to connection completion handler map. Used to track connection attempts. When a + // connection attempt has succeeded or failed, the completion handler is called and removed from + // the map. + NSMutableDictionary *_connectionCompletionHandlers; + + // A peripheral to disconnection handler map. Used to track when a peripheral becomes + // disconnected. Once disconnected, the completion handler is called and removed from the map. + NSMutableDictionary *_disconnectionHandlers; +} + +- (instancetype)init { + CBCentralManager *centralManager = + [[CBCentralManager alloc] initWithDelegate:self + queue:_queue + options:@{CBCentralManagerOptionShowPowerAlertKey : @NO}]; + dispatch_queue_t queue = dispatch_queue_create(kBLEMediumQueueLabel, DISPATCH_QUEUE_SERIAL); + return [self initWithCentralManager:centralManager queue:queue]; +} + +// This is private and should only be used for tests. The provided central manager must call +// delegate methods on the main queue. +- (instancetype)initWithCentralManager:(id)centralManager + queue:(nullable dispatch_queue_t)queue { + self = [super init]; + if (self) { + _queue = queue ?: dispatch_get_main_queue(); + _centralManager = centralManager; + _centralManager.centralDelegate = self; + _connectionCompletionHandlers = [NSMutableDictionary dictionary]; + _disconnectionHandlers = [NSMutableDictionary dictionary]; + } + return self; +} + +- (BOOL)supportsExtendedAdvertisements { + // TODO(b/294736083): CoreBluetooth doesn't support actually advertising any extensions, however + // some devices can scan for them if the feature is available. If we return @c YES from this + // method, we would be enabling advertising extensions (which won't work), so we must return @c NO + // until we add support for a new method to check only if extended scans are supported. + return NO; +} + +- (void)startAdvertisingData:(NSDictionary *)serviceData + completionHandler:(nullable GNCStartAdvertisingCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + if (!_server) { + _server = [[GNCBLEGATTServer alloc] init]; + } + [_server startAdvertisingData:serviceData completionHandler:completionHandler]; + }); +} + +- (void)stopAdvertisingWithCompletionHandler: + (nullable GNCStopAdvertisingCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + if (!_server) { + if (completionHandler) { + completionHandler(nil); + } + return; + } + [_server stopAdvertisingWithCompletionHandler:completionHandler]; + }); +} + +- (void)startScanningForService:(CBUUID *)serviceUUID + advertisementFoundHandler:(GNCAdvertisementFoundHandler)advertisementFoundHandler + completionHandler:(nullable GNCStartScanningCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + if (_serviceUUID) { + if (completionHandler) { + completionHandler(AlreadyScanningError()); + } + return; + } + + _serviceUUID = serviceUUID; + _advertisementFoundHandler = advertisementFoundHandler; + + [self internalStartScanningIfPoweredOn]; + if (completionHandler) { + completionHandler(nil); + } + }); +} + +- (void)stopScanningWithCompletionHandler: + (nullable GNCStopScanningCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + _serviceUUID = nil; + _advertisementFoundHandler = nil; + [_centralManager stopScan]; + if (completionHandler) { + completionHandler(nil); + } + }); +} + +- (void)startGATTServerWithCompletionHandler: + (nullable GNCGATTServerCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + if (!_server) { + _server = [[GNCBLEGATTServer alloc] init]; + } + if (completionHandler) { + completionHandler(_server, nil); + } + }); +} + +- (void)connectToGATTServerForPeripheral:(id)remotePeripheral + disconnectionHandler:(nullable GNCGATTDisconnectionHandler)disconnectionHandler + completionHandler: + (nullable GNCGATTConnectionCompletionHandler)completionHandler { + dispatch_async(_queue, ^{ + _disconnectionHandlers[remotePeripheral.identifier] = disconnectionHandler; + _connectionCompletionHandlers[remotePeripheral.identifier] = completionHandler; + [_centralManager connectPeripheral:remotePeripheral options:@{}]; + }); +} + +#pragma mark - Internal + +- (void)internalStartScanningIfPoweredOn { + dispatch_assert_queue(_queue); + // Scanning can only be done when powered on and must be restarted if bluetooth is turned off + // then back on. This will be called anytime the central manager's state changes, so + // @c scanForPeripheralsWithServices:options: will be called anytime state transitions back to + // powered on. + if (_centralManager.state == CBManagerStatePoweredOn && _serviceUUID != nil) { + // Stop scanning just in case something outside of this class is already scanning. + [_centralManager stopScan]; + [_centralManager + scanForPeripheralsWithServices:@[ _serviceUUID ] + // Nearby relies on the existence of an advertisement for endpoint + // discovery/lost events, so we must set this key to keep the stream + // of duplicate delegate events flowing. This has adverse effect on + // battery life, but currently necessary. + options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @YES}]; + } +} + +- (NSDictionary *)decodeAdvertisementData: + (NSDictionary *)advertisementData { + dispatch_assert_queue(_queue); + // If service data is available, return it directly. + NSDictionary *serviceData = + advertisementData[CBAdvertisementDataServiceDataKey]; + if (serviceData) { + return serviceData; + } + + // Apple devices don't support advertising service data, so Apple devices advertise a base64 + // encoded local name, while other devices advertise service data. Here we attempt to reconstruct + // service data by decoding the local name. If successful, this is possibly a Nearby advertisement + // on an Apple device. + NSString *localName = advertisementData[CBAdvertisementDataLocalNameKey]; + if (!localName) { + return @{}; + } + NSData *data = [[NSData alloc] initWithWebSafeBase64EncodedString:localName]; + + // A Nearby Apple advertisement should only have a single service, so simply grab the first one if + // it exists. + NSArray *serviceUUIDs = advertisementData[CBAdvertisementDataServiceUUIDsKey]; + CBUUID *serviceUUID = serviceUUIDs.firstObject; + if (data && serviceUUID) { + return @{serviceUUID : data}; + } + + return @{}; +} + +#pragma mark - GNCCentralManagerDelegate + +- (void)gnc_centralManagerDidUpdateState:(id)central { + dispatch_assert_queue(_queue); + [self internalStartScanningIfPoweredOn]; +} + +- (void)gnc_centralManager:(id)central + didDiscoverPeripheral:(id)peripheral + advertisementData:(NSDictionary *)advertisementData + RSSI:(NSNumber *)RSSI { + dispatch_assert_queue(_queue); + if (_advertisementFoundHandler) { + _advertisementFoundHandler(peripheral, [self decodeAdvertisementData:advertisementData]); + } +} + +- (void)gnc_centralManager:(id)central + didConnectPeripheral:(id)peripheral { + dispatch_assert_queue(_queue); + GNCGATTConnectionCompletionHandler handler = _connectionCompletionHandlers[peripheral.identifier]; + _connectionCompletionHandlers[peripheral.identifier] = nil; + if (handler) { + GNCBLEGATTClient *client = [[GNCBLEGATTClient alloc] initWithPeripheral:peripheral]; + handler(client, nil); + } +} + +- (void)gnc_centralManager:(id)central + didFailToConnectPeripheral:(id)peripheral + error:(nullable NSError *)error { + dispatch_assert_queue(_queue); + GNCGATTConnectionCompletionHandler handler = _connectionCompletionHandlers[peripheral.identifier]; + _connectionCompletionHandlers[peripheral.identifier] = nil; + if (handler) { + handler(nil, error); + } +} + +- (void)gnc_centralManager:(id)central + didDisconnectPeripheral:(id)peripheral + error:(nullable NSError *)error { + dispatch_assert_queue(_queue); + GNCGATTDisconnectionHandler handler = _disconnectionHandlers[peripheral.identifier]; + _disconnectionHandlers[peripheral.identifier] = nil; + if (handler) { + handler(); + } +} + +#pragma mark - CBCentralManagerDelegate + +- (void)centralManagerDidUpdateState:(CBCentralManager *)central { + dispatch_async(_queue, ^{ + [self gnc_centralManagerDidUpdateState:central]; + }); +} + +- (void)centralManager:(CBCentralManager *)central + didDiscoverPeripheral:(CBPeripheral *)peripheral + advertisementData:(NSDictionary *)advertisementData + RSSI:(NSNumber *)RSSI { + dispatch_async(_queue, ^{ + [self gnc_centralManager:central + didDiscoverPeripheral:peripheral + advertisementData:advertisementData + RSSI:RSSI]; + }); +} + +- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { + dispatch_async(_queue, ^{ + [self gnc_centralManager:central didConnectPeripheral:peripheral]; + }); +} + +- (void)centralManager:(CBCentralManager *)central + didFailToConnectPeripheral:(CBPeripheral *)peripheral + error:(nullable NSError *)error { + dispatch_async(_queue, ^{ + [self gnc_centralManager:central didFailToConnectPeripheral:peripheral error:error]; + }); +} + +- (void)centralManager:(CBCentralManager *)central + didDisconnectPeripheral:(CBPeripheral *)peripheral + error:(nullable NSError *)error { + dispatch_async(_queue, ^{ + [self gnc_centralManager:central didDisconnectPeripheral:peripheral error:error]; + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCCentralManager.h b/internal/platform/implementation/apple/Mediums/BLEv2/GNCCentralManager.h new file mode 100644 index 00000000..770377ea --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCCentralManager.h @@ -0,0 +1,181 @@ +// 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. + +#import +#import + +@protocol GNCCentralManagerDelegate; +@protocol GNCPeripheral; + +NS_ASSUME_NONNULL_BEGIN + +/** Protocol which helps create a fake of a @c CBCentralManager to inject for testing. */ +@protocol GNCCentralManager + +/** Shadow property of a @c CBCentralManagerDelegate. */ +@property(weak, nonatomic, nullable) id centralDelegate; + +/** + * The current state of the manager. + * + * This state is initially set to @c CBManagerStateUnknown. When the state updates, the manager + * calls its delegate’s @c gnc_centralManagerDidUpdateState: method. + */ +@property(nonatomic, assign, readonly) CBManagerState state; + +/** + * Scans for peripherals that are advertising services. + * + * You can provide an array of @c CBUUID objects, representing service UUIDs, in the @c serviceUUIDs + * parameter. When you do, the central manager returns only peripherals that advertise the services + * you specify. If the @c serviceUUIDs parameter is @c nil, this method returns all discovered + * peripherals, regardless of their supported services. + * + * @note The recommended practice is to populate the @c serviceUUIDs parameter rather than leaving + * it @c nil. + * + * If the central manager is actively scanning with one set of parameters and it receives another + * set to scan, the new parameters override the previous set. When the central manager discovers a + * peripheral, it calls the @c gnc_centralManager:didDiscoverPeripheral:advertisementData:RSSI: + * method of its delegate object. + * + * Your app can scan for Bluetooth devices in the background by specifying the @c bluetooth-central + * background mode. To do this, your app must explicitly scan for one or more services by specifying + * them in the @c serviceUUIDs parameter. The CBCentralManager scan option has no effect while + * scanning in the background. + * + * @param serviceUUIDs An array of @c CBUUID objects that the app is interested in. Each @c CBUUID + * object represents the UUID of a service that a peripheral advertises. + * @param options A dictionary of options for customizing the scan. + */ +- (void)scanForPeripheralsWithServices:(nullable NSArray *)serviceUUIDs + options:(nullable NSDictionary *)options; + +/** + * Establishes a local connection to a peripheral. + * + * After successfully establishing a local connection to a peripheral, the central manager object + * calls the @c gnc_centralManager:didConnectPeripheral: method of its delegate object. If the + * connection attempt fails, the central manager object calls the + * @c gnc_centralManager:didFailToConnectPeripheral:error: method of its delegate object instead. + * Attempts to connect to a peripheral don’t time out. To explicitly cancel a pending connection to + * a peripheral, call the @c cancelPeripheralConnection: method. Deallocating @c peripheral also + * implicitly calls @c cancelPeripheralConnection:. + * + * @param peripheral The peripheral to which the central is attempting to connect. + * @param options A dictionary to customize the behavior of the connection. + */ +- (void)connectPeripheral:(id)peripheral + options:(nullable NSDictionary *)options; + +/** Asks the central manager to stop scanning for peripherals. */ +- (void)stopScan; + +@end + +/** + * Protocol which helps the @c GNCCentralManager wrap a @c CBCentralManagerDelegate for + * testing. + */ +@protocol GNCCentralManagerDelegate + +/** + * Tells the delegate the central manager’s state updated. + * + * You implement this required method to ensure that the central device supports Bluetooth low + * energy and that it’s available to use. You should issue commands to the central manager only when + * the central manager’s @c state indicates it’s powered on. A state with a value lower than + * @c CBManagerStatePoweredOn implies that scanning has stopped, which in turn disconnects any + * previously-connected peripherals. If the state moves below @c CBManagerStatePoweredOff, all + * @c CBPeripheral objects obtained from this central manager become invalid; you must retrieve or + * discover these peripherals again. + * + * @param central The central manager whose state has changed. + */ +- (void)gnc_centralManagerDidUpdateState:(id)central; + +/** + * Tells the delegate the central manager discovered a peripheral while scanning for devices. + * + * You must retain a local copy of the peripheral if you want to perform commands on it. Use the + * RSSI data to determine the proximity of a discoverable peripheral device, and whether you want to + * connect to it automatically. + * + * @param central The central manager that provides the update. + * @param peripheral The discovered peripheral. + * @param advertisementData A dictionary containing any advertisement data. + * @param RSSI The current received signal strength indicator (RSSI) of the peripheral, in decibels. + */ +- (void)gnc_centralManager:(id)central + didDiscoverPeripheral:(id)peripheral + advertisementData:(NSDictionary *)advertisementData + RSSI:(NSNumber *)RSSI; + +/** + * Tells the delegate that the central manager connected to a peripheral. + * + * The manager invokes this method when a call to @c connectPeripheral:options: succeeds. You + * typically implement this method to set the peripheral’s delegate and discover its services. + * + * @param central The central manager that provides this information. + * @param peripheral The now-connected peripheral. + */ +- (void)gnc_centralManager:(id)central + didConnectPeripheral:(id)peripheral; + +/** + * Tells the delegate the central manager failed to create a connection with a peripheral. + * + * The manager invokes this method when a connection initiated with the + * @c connectPeripheral:options: method fails to complete. Because connection attempts don’t time + * out, a failed connection usually indicates a transient issue, in which case you may attempt + * connecting to the peripheral again. + * + * @param central The central manager that provides this information. + * @param peripheral The peripheral that failed to connect. + * @param error The cause of the failure, or @c nil if no error occurred. + */ +- (void)gnc_centralManager:(id)central + didFailToConnectPeripheral:(id)peripheral + error:(nullable NSError *)error; + +/** + * Tells the delegate that the central manager disconnected from a peripheral. + * + * The manager invokes this method when disconnecting a peripheral previously connected with the + * @c connectPeripheral:options: method. The error parameter contains the reason for the + * disconnection, unless the disconnect resulted from a call to @c cancelPeripheralConnection:. + * + * All services, characteristics, and characteristic descriptors of a peripheral become invalidated + * after it disconnects. + * + * @param central The central manager that provides this information. + * @param peripheral The now-disconnected peripheral. + * @param error The cause of the failure, or @c nil if no error occurred. + */ +- (void)gnc_centralManager:(id)central + didDisconnectPeripheral:(id)peripheral + error:(nullable NSError *)error; + +@end + +/** + * Declares that @c CBCentralManager implements the @c GNCCentralManager protocol. + * + * This allows us to directly use a @c CBCentralManager as a @c GNCCentralManager. + */ +@interface CBCentralManager () +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCCentralManager.m b/internal/platform/implementation/apple/Mediums/BLEv2/GNCCentralManager.m new file mode 100644 index 00000000..921e8d92 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCCentralManager.m @@ -0,0 +1,36 @@ +// 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. + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCCentralManager.h" + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@implementation CBCentralManager (GNCCentralManagerAdditions) + +- (void)setCentralDelegate:(nullable id)centralDelegate { + NSAssert([centralDelegate conformsToProtocol:@protocol(CBCentralManagerDelegate)], + @"centralDelegate must conform to protocol CBCentralManagerDelegate"); + self.delegate = (id)centralDelegate; +} + +- (nullable id)centralDelegate { + return (id)self.delegate; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h b/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h new file mode 100644 index 00000000..c43b7b6b --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h @@ -0,0 +1,177 @@ +// 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. + +#import +#import + +@protocol GNCPeripheralDelegate; + +NS_ASSUME_NONNULL_BEGIN + +/** Protocol which helps create a fake of a @c CBPeripheral to inject for testing. */ +@protocol GNCPeripheral + +// This can't be @c delegate, because it would shadow @c CBPeripheral's delegate. +/** + * The peripheral's delegate. + * + * This delegate is only sent CBPeripheralDelegate messages, and the delegate is responsible for + * forwarding those messages to its GNCPeripheralDelegate method implementations. + * + * See: https://developer.apple.com/videos/play/wwdc2018/417/ + */ +@property(weak, nonatomic, nullable) id peripheralDelegate; + +/** + * A list of a peripheral’s discovered services. + * + * Returns an array of services (represented by CBService objects) that successful a call to the + * @c discoverServices: method discovered. If you haven’t yet called the @c discoverServices: method + * to discover the services of the peripheral, or if there was an error in doing so, the value of + * this property is @c nil. + */ +@property(retain, readonly, nullable) NSArray *services; + +/** + * The UUID associated with the peer. + * + * The value of this property represents the unique identifier of the peer. The first time a local + * manager encounters a peer, the system assigns the peer a UUID, represented by a new @c NSUUID + * object. Peers use @c NSUUID instances to identify themselves, instead of by the @c CBUUID objects + * that identify a peripheral’s services, characteristics, and descriptors. + */ +@property(readonly, nonatomic) NSUUID *identifier; + +/** + * Discovers the specified services of the peripheral. + * + * You can provide an array of CBUUID objects, representing service UUIDs, in the @c serviceUUIDs + * parameter. When you do, the peripheral returns only the services of the peripheral that match the + * provided UUIDs. + * + * @note If the @c serviceUUIDs parameter is @c nil, this method returns all of the peripheral’s + * available services. This is much slower than providing an array of service UUIDs to search for. + * + * When the peripheral discovers one or more services, it calls the + * @c peripheral:didDiscoverServices: method of its delegate object. After a peripheral discovers + * services, you can access them through the peripheral’s @c services property. + * + * @param serviceUUIDs An array of CBUUID objects that you are interested in. Each CBUUID object + * represents a UUID that identifies the type of service you want to discover. + */ +- (void)discoverServices:(nullable NSArray *)serviceUUIDs; + +/** + * Discovers the specified characteristics of a service. + * + * You can provide an array of CBUUID objects, representing characteristic UUIDs, in the + * @c characteristicUUIDs parameter. When you do, the peripheral returns only the characteristics of + * the service that match the provided UUIDs. If the @c characteristicUUIDs parameter is @c nil, + * this method returns all characteristics of the service. + * + * @note If the @c characteristicUUIDs parameter is @c nil, this method returns all of the service’s + * characteristics. This is much slower than providing an array of characteristic UUIDs to search + * for. + * + * When the peripheral discovers one or more characteristics of the specified service, it calls the + * @c peripheral:didDiscoverCharacteristicsForService:error: method of its delegate object. After + * the peripheral discovers the service’s characteristics, you can access them through the service’s + * @c characteristics property. + * + * @param characteristicUUIDs An array of CBUUID objects that you are interested in. Each CBUUID + * object represents a UUID that identifies the type of a characteristic + * you want to discover. + * @param service The service whose characteristics you want to discover. + */ +- (void)discoverCharacteristics:(nullable NSArray *)characteristicUUIDs + forService:(CBService *)service; + +/** + * Retrieves the value of a specified characteristic. + * + * When you call this method to read the value of a characteristic, the peripheral calls the + * @c peripheral:didUpdateValueForCharacteristic:error: method of its delegate object. If the + * peripheral successfully reads the value of the characteristic, you can access it through the + * characteristic’s @c value property. + * + * Not all characteristics have a readable value. You can determine whether a characteristic’s value + * is readable by accessing the relevant properties of the CBCharacteristicProperties enumeration. + * + * @param characteristic The characteristic whose value you want to read. + */ +- (void)readValueForCharacteristic:(CBCharacteristic *)characteristic; + +@end + +/** + * Protocol which helps the @c GNCPeripheral wrap a @c CBPeripheralDelegate for + * testing. + */ +@protocol GNCPeripheralDelegate + +/** + * Tells the delegate that peripheral service discovery succeeded. + * + * Called when your app calls the @c discoverServices: method. If the peripheral successfully + * discovers services, you can access them through the peripheral’s @c services property. If + * successful, the @c error parameter is @c nil. If unsuccessful, the @c error parameter returns the + * cause of the failure. + * + * @param peripheral The peripheral to which the services belong. + * @param error The reason the call failed, or @c nil if no error occurred. + */ +- (void)gnc_peripheral:(id)peripheral didDiscoverServices:(nullable NSError *)error; + +/** + * Tells the delegate that the peripheral found characteristics for a service. + * + * Called when your app calls the @c discoverCharacteristics:forService: method. If the peripheral + * successfully discovers the characteristics of the specified service, you can access them through + * the service’s @c characteristics property. If successful, the @c error parameter is @c nil. If + * unsuccessful, the @c error parameter returns the cause of the failure. + * + * @param peripheral The peripheral providing this information. + * @param service The service to which the characteristics belong. + * @param error The reason the call failed, or @c nil if no error occurred. + */ +- (void)gnc_peripheral:(id)peripheral + didDiscoverCharacteristicsForService:(CBService *)service + error:(nullable NSError *)error; + +/** + * Tells the delegate that retrieving the specified characteristic’s value succeeded, or that the + * characteristic’s value changed. + * + * Called when your app calls the @c readValueForCharacteristic: method. If successful, the @c error + * parameter is @c nil. If unsuccessful, the @c error parameter returns the cause of the failure. + * + * @param peripheral The peripheral providing this information. + * @param characteristic The characteristic containing the value. + * @param error The reason the call failed, or @c nil if no error occurred. + */ +- (void)gnc_peripheral:(id)peripheral + didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic + error:(nullable NSError *)error; + +@end + +/** + * Declares that @c CBPeripheral implements the @c GNCPeripheral protocol. + * + * This allows us to directly use a @c CBPeripheral as a @c GNCPeripheral. + */ +@interface CBPeripheral () +@end + +NS_ASSUME_NONNULL_END diff --git a/fastpair/rust/src/bluetooth/mod.rs b/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.m similarity index 54% rename from fastpair/rust/src/bluetooth/mod.rs rename to internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.m index 2faa2576..69923133 100644 --- a/fastpair/rust/src/bluetooth/mod.rs +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.m @@ -12,24 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Split into separate crate once demo is finished, providing custom error types -// instead of using anyhow. -// b/290070686 +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h" -pub mod common; +#import +#import -pub use common::{Adapter, Device}; +NS_ASSUME_NONNULL_BEGIN -cfg_if::cfg_if! { - if #[cfg(windows)] { - mod windows_ble; - use windows_ble::BleAdapter; - } else { - mod unsupported; - use unsupported::BleAdapter; - } +@implementation CBPeripheral (GNCPeripheralAdditions) + +- (void)setPeripheralDelegate:(nullable id)peripheralDelegate { + self.delegate = peripheralDelegate; } -pub async fn default_adapter() -> Result { - BleAdapter::default().await +- (nullable id)peripheralDelegate { + return (id)self.delegate; } + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheralManager.h b/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheralManager.h index 9ea367e8..ecbeb887 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheralManager.h +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheralManager.h @@ -23,7 +23,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol GNCPeripheralManager /** Shadow property of a @c CBPeripheralManagerDelegate. */ -@property(nonatomic, nullable) id peripheralDelegate; +@property(weak, nonatomic, nullable) id peripheralDelegate; @property(nonatomic, assign, readonly) CBManagerState state; @@ -111,13 +111,20 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)respondToRequest:(CBATTRequest *)request withResult:(CBATTError)result; +/** + * Stops advertising peripheral manager data. + * + * Call this method when you no longer want to advertise peripheral manager data. + */ +- (void)stopAdvertising; + @end /** * Protocol which helps the @c GNCPeripheralManager wrap a @c CBPeripheralManagerDelegate for * testing. */ -@protocol GNCPeripheralManagerDelegate +@protocol GNCPeripheralManagerDelegate /** * Tells the delegate the peripheral manager’s state updated. diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheralManager.m b/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheralManager.m index cf7eecbd..784b6b76 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheralManager.m +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheralManager.m @@ -23,9 +23,7 @@ NS_ASSUME_NONNULL_BEGIN @implementation CBPeripheralManager (GNCPeripheralManagerAdditions) - (void)setPeripheralDelegate:(nullable id)peripheralDelegate { - NSAssert([peripheralDelegate conformsToProtocol:@protocol(CBPeripheralManagerDelegate)], - @"peripheralDelegate must conform to protocol CBPeripheralManagerDelegate"); - self.delegate = (id)peripheralDelegate; + self.delegate = peripheralDelegate; } - (nullable id)peripheralDelegate { diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/NSData+GNCWebSafeBase64.h b/internal/platform/implementation/apple/Mediums/BLEv2/NSData+GNCWebSafeBase64.h index c4d03b74..1143cef2 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/NSData+GNCWebSafeBase64.h +++ b/internal/platform/implementation/apple/Mediums/BLEv2/NSData+GNCWebSafeBase64.h @@ -19,7 +19,16 @@ NS_ASSUME_NONNULL_BEGIN @interface NSData (GNCWebSafeBase64) /** Creates a Base64 encoded string from the data using websafe characters and no padding. */ -- (NSString *)webSafebase64EncodedString; +- (NSString *)webSafeBase64EncodedString; + +/** + * Initializes a data object with the given Base64 encoded string. + * + * @param base64String A Base64 encoded string. + * @return A data object built by Base64 decoding the provided string. Returns @c nil if the data + * object could not be decoded. + */ +- (nullable instancetype)initWithWebSafeBase64EncodedString:(NSString *)base64String; @end diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/NSData+GNCWebSafeBase64.m b/internal/platform/implementation/apple/Mediums/BLEv2/NSData+GNCWebSafeBase64.m index 1f0b3014..e2dd69cb 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/NSData+GNCWebSafeBase64.m +++ b/internal/platform/implementation/apple/Mediums/BLEv2/NSData+GNCWebSafeBase64.m @@ -14,11 +14,13 @@ #import "internal/platform/implementation/apple/Mediums/BLEv2/NSData+GNCWebSafeBase64.h" +#import + NS_ASSUME_NONNULL_BEGIN @implementation NSData (GNCWebSafeBase64) -- (NSString *)webSafebase64EncodedString { +- (NSString *)webSafeBase64EncodedString { NSString *encoded = [self base64EncodedStringWithOptions:0]; // Convert the standard base64 characters to URL safe variants. @@ -29,6 +31,20 @@ NS_ASSUME_NONNULL_BEGIN return encoded; } +- (nullable instancetype)initWithWebSafeBase64EncodedString:(NSString *)base64String { + // Convert the URL safe base64 characters to the standard variants. + base64String = [base64String stringByReplacingOccurrencesOfString:@"-" withString:@"+"]; + base64String = [base64String stringByReplacingOccurrencesOfString:@"_" withString:@"/"]; + + // @c initWithBase64EncodedString:options: requires a padded base64 string. Append enough "=" + // characters to make the string a multiple of 4. + NSUInteger paddedLength = base64String.length + ((4 - (base64String.length % 4)) % 4); + base64String = [base64String stringByPaddingToLength:paddedLength + withString:@"=" + startingAtIndex:0]; + return [self initWithBase64EncodedString:base64String options:0]; +} + @end NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BUILD b/internal/platform/implementation/apple/Mediums/BUILD index d1a70ace..21f1c10d 100644 --- a/internal/platform/implementation/apple/Mediums/BUILD +++ b/internal/platform/implementation/apple/Mediums/BUILD @@ -18,13 +18,16 @@ package(default_visibility = ["//internal/platform/implementation/apple:__subpac objc_library( name = "Mediums", srcs = [ + "BLEv2/GNCBLEError.m", "BLEv2/GNCBLEGATTCharacteristic.m", + "BLEv2/GNCBLEGATTClient.m", "BLEv2/GNCBLEGATTServer.m", + "BLEv2/GNCBLEMedium.m", + "BLEv2/GNCCentralManager.m", + "BLEv2/GNCPeripheral.m", "BLEv2/GNCPeripheralManager.m", "BLEv2/NSData+GNCWebSafeBase64.m", - "Ble/GNCMBleCentral.m", "Ble/GNCMBleConnection.m", - "Ble/GNCMBlePeripheral.m", "Ble/GNCMBleUtils.mm", "GNCLeaks.h", "GNCLeaks.m", @@ -37,13 +40,16 @@ objc_library( "WiFiLAN/GNCWiFiLANSocket.m", ], hdrs = [ + "BLEv2/GNCBLEError.h", "BLEv2/GNCBLEGATTCharacteristic.h", + "BLEv2/GNCBLEGATTClient.h", "BLEv2/GNCBLEGATTServer.h", + "BLEv2/GNCBLEMedium.h", + "BLEv2/GNCCentralManager.h", + "BLEv2/GNCPeripheral.h", "BLEv2/GNCPeripheralManager.h", "BLEv2/NSData+GNCWebSafeBase64.h", - "Ble/GNCMBleCentral.h", "Ble/GNCMBleConnection.h", - "Ble/GNCMBlePeripheral.h", "Ble/GNCMBleUtils.h", "GNCMConnection.h", "WiFiLAN/GNCIPv4Address.h", @@ -54,8 +60,6 @@ objc_library( ], deps = [ "//internal/platform/implementation/apple:Shared", - "//internal/platform/implementation/apple/Mediums/Ble/Sockets:Central", - "//internal/platform/implementation/apple/Mediums/Ble/Sockets:Peripheral", "//internal/platform/implementation/apple/Mediums/Ble/Sockets:Shared", "//proto/mediums:ble_frames_cc_proto", "//third_party/apple_frameworks:CoreBluetooth", diff --git a/internal/platform/implementation/apple/Mediums/Ble/GNCMBleCentral.h b/internal/platform/implementation/apple/Mediums/Ble/GNCMBleCentral.h deleted file mode 100644 index d617113f..00000000 --- a/internal/platform/implementation/apple/Mediums/Ble/GNCMBleCentral.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2022 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. - -#import - -#import "internal/platform/implementation/apple/Mediums/GNCMConnection.h" - -@class CBUUID; - -NS_ASSUME_NONNULL_BEGIN - -/** - * This handler is called on a discover when a nearby advertising endpoint is discovered. - */ -typedef void (^GNCMScanResultHandler)(NSString *peripheralID, NSData *serviceData); - -/** - * This handler is called on a discovery when a nearby advertising endpoint is connected. - */ -typedef void (^GNCMGATTConnectionResultHandler)(NSError *_Nullable error); - -/** - * This handler is called on a discovery when a nearby advertising endpoint is connected. The input - * is a discovered set of characteristics. - */ -typedef void (^GNCMGATTDiscoverResultHandler)( - NSOrderedSet *_Nullable characteristicValues); - -/** - * This handler is called by a discovering endpoint to request a connection with an an advertising - * endpoint. - */ -typedef void (^GNCMBleConnectionRequester)(NSString *serviceID, - GNCMConnectionHandler connectionHandler); - -/** - * This handler is called on a discoverer when a nearby advertising endpoint is discovered. - * Call |requestConnection| to request a connection with the advertiser. - */ -typedef void (^GNCMBleRequestConnectionHandler)(GNCMBleConnectionRequester requestConnection); - -/** - * GNCMBleCentral discovers devices advertising the specified service UUID via BLE (using the - * GNCMBlePeripheral class) and calls the specififed scanning result handler when one is found. - * - * This class is thread-safe. Any calls made to it (and to the objects/closures it passes back via - * callbacks) can be made from any thread/queue. Callbacks made from this class are called on the - * specified queue. - */ -@interface GNCMBleCentral : NSObject - -- (instancetype)init NS_DESIGNATED_INITIALIZER; - -/** - * Starts scanning with service UUID. - * - * @param serviceUUID A string that uniquely identifies the scanning services to search for. - * @param scanResultHandler The handler that is called when an endpoint advertising the service - * UUID is discovered. - * @param requestConnectionHandler The handler that is called when an endpoint is discovered. - * @param callbackQueue The queue on which all callbacks are made. - */ -- (BOOL)startScanningWithServiceUUID:(NSString *)serviceUUID - scanResultHandler:(GNCMScanResultHandler)scanResultHandler - requestConnectionHandler:(GNCMBleRequestConnectionHandler)requestConnectionHandler - callbackQueue:(nullable dispatch_queue_t)callbackQueue; - -/** - * Sets up a GATT connection. - * - * @param peripheralID A string that uniquely identifies the peripheral. - * @param gattConnectionResultHandler The handler that is called when an endpoint is - * connected. - */ -- (void)connectGattServerWithPeripheralID:(NSString *)peripheralID - gattConnectionResultHandler: - (GNCMGATTConnectionResultHandler)gattConnectionResultHandler; - -/** - * Discovers GATT service and its associated characteristics with values. - * - * @param serviceUUID A CBUUID for service to discover. - * @param gattCharacteristics Array of CBUUID for characteristic to discover. - * @param peripheralID A string that uniquely identifies the peripheral. - * @param gattDiscoverResultHandler This handler is called on a discovery for a discovered map of - * characteristic values when a nearby advertising endpoint is - * connected. - */ -- (void)discoverGattService:(CBUUID *)serviceUUID - gattCharacteristics:(NSArray *)characteristicUUIDs - peripheralID:(NSString *)peripheralID - gattDiscoverResultHandler:(GNCMGATTDiscoverResultHandler)gattDiscoverResultHandler; - -/** - * Disconnects GATT connection. - * - * @param peripheralID A string that uniquely identifies the peripheral. - */ -- (void)disconnectGattServiceWithPeripheralID:(NSString *)peripheralID; - -@end - -NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/Ble/GNCMBleCentral.m b/internal/platform/implementation/apple/Mediums/Ble/GNCMBleCentral.m deleted file mode 100644 index bc5ea3aa..00000000 --- a/internal/platform/implementation/apple/Mediums/Ble/GNCMBleCentral.m +++ /dev/null @@ -1,510 +0,0 @@ -// Copyright 2022 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. - -#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleCentral.h" - -#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleConnection.h" -#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleUtils.h" -#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Central/GNSCentralManager.h" -#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Central/GNSCentralPeerManager.h" -#import "internal/platform/implementation/apple/Mediums/GNCMConnection.h" - -NS_ASSUME_NONNULL_BEGIN - -typedef NS_ENUM(NSUInteger, GNCMCentralState) { - GNCMCentralStateStopped, - GNCMCentralStateScanning, -}; - -typedef void (^GNCMBleCharacteristicsHandler)(NSArray *characteristics, - NSError *error); -typedef void (^GNCMBleCharacteristicValueHandler)(CBCharacteristic *characteristic, NSError *error); -typedef void (^GNCIntHandler)(int); - -/** This lets a GNCIntHandler call itself. */ -GNCIntHandler GNCRecursiveIntHandler(void (^block)(GNCIntHandler blockSelf, int i)) { - return ^(int i) { - return block(GNCRecursiveIntHandler(block), i); - }; -} - -/** This represents a discovered peripheral. */ -@interface GNCMPeripheralInfo : NSObject -@property(nonatomic) CBPeripheral *peripheral; -@property(nonatomic, copy) NSDictionary *advertisementData; - -/** Called when characteristics are discovered. */ -@property(nonatomic, nullable) GNCMBleCharacteristicsHandler charsHandler; - -/** Called when a characteristic value is read. */ -@property(nonatomic, nullable) GNCMBleCharacteristicValueHandler charValueHandler; - -@end - -@implementation GNCMPeripheralInfo - -- (instancetype)initWithPeripheral:(CBPeripheral *)peripheral - advertisementData:(NSDictionary *)advertisementData { - self = [super init]; - if (self) { - _peripheral = peripheral; - _advertisementData = [advertisementData copy]; - } - return self; -} - -- (BOOL)isEqual:(id)object { - // There is always exactly one info object per peripheral, so compare by identity. This is needed - // for maintenance of the peripherals stored in multiple maps. - return self == object; -} - -- (NSUInteger)hash { - return (NSUInteger)self; -} - -@end - -@interface GNCMBleCentral () -@end - -@implementation GNCMBleCentral { - /** Service UUID the central is scanning for. */ - CBUUID *_serviceUUID; - /** The scan result callback handler. */ - GNCMScanResultHandler _scanResultHandler; - /** Central manager used to scan or connect to peripherals. */ - CBCentralManager *_centralManager; - /** Serial background queue for |centralManager|. */ - dispatch_queue_t _selfQueue; - /** Central state for stop or scanning. */ - GNCMCentralState _centralState; - /** The dictionary keyed by CBPeripheral identifier to value GNCMPeripheralInfo. */ - NSMutableDictionary *_nearbyPeripheralsByID; - /** Array of characteristic UUID used for discovering. */ - NSArray *_characteristicUUIDs; - /** GATT connection result handler. */ - GNCMGATTConnectionResultHandler _gattConnectionResultHandler; - /** GATT service and characteristic discovery result hanadler. */ - GNCMGATTDiscoverResultHandler _gattDiscoverResultHandler; - /** The discovered characteristic values map used to callback for `_gattDiscoverResultHandler`. */ - NSMutableOrderedSet *_gattCharacteristicValues; - /** Central manager used for socket connection based on weave protocol. */ - GNSCentralManager *_socketCentralManager; - /** A callback handler to reuqest connection on the discovered advertiser. */ - GNCMBleRequestConnectionHandler _requestConnectionHandler; - /** Client callback queue. If client doesn't assign it, then use main queue. */ - dispatch_queue_t _clientCallbackQueue; - /** Internal async priority queue. */ - dispatch_queue_t _internalCallbackQueue; - /** Flag to disable callback for dealloc. */ - BOOL _callbacksEnabled; -} - -- (instancetype)init { - if (self = [super init]) { - // To make this class thread-safe, use a serial queue for all state changes, and have Core - // Bluetooth also use this queue. - _selfQueue = dispatch_queue_create("GNCCentralManagerQueue", DISPATCH_QUEUE_SERIAL); - - _nearbyPeripheralsByID = [NSMutableDictionary dictionary]; - _gattCharacteristicValues = [[NSMutableOrderedSet alloc] init]; - - _centralState = GNCMCentralStateStopped; - } - return self; -} - -- (void)dealloc { - // These calls must be made on |selfQueue|. Can't capture |self| in an async block, so must use - // dispatch_sync. This means dealloc must be called from an external queue, which means |self| - // must never be captured by any escaping block used in this class. - dispatch_sync(_selfQueue, ^{ - [self stopScanningInternal]; - [_socketCentralManager stopNoScanMode]; - - _callbacksEnabled = NO; - }); -} - -- (BOOL)startScanningWithServiceUUID:(NSString *)serviceUUID - scanResultHandler:(GNCMScanResultHandler)scanResultHandler - requestConnectionHandler:(GNCMBleRequestConnectionHandler)requestConnectionHandler - callbackQueue:(nullable dispatch_queue_t)callbackQueue { - NSLog(@"[NEARBY] Client rquests startScanning"); - _serviceUUID = [CBUUID UUIDWithString:serviceUUID]; - _scanResultHandler = scanResultHandler; - _requestConnectionHandler = requestConnectionHandler; - - // The client may be using the callback queue for other purposes, so wrap it with a private - // queue to know with certainty when all callbacks are done. - _clientCallbackQueue = callbackQueue ?: dispatch_get_main_queue(); - _internalCallbackQueue = - dispatch_queue_create("GNCMBleCentralCallbackQueue", DISPATCH_QUEUE_PRIORITY_DEFAULT); - _callbacksEnabled = YES; - - // Set up the central manager for scanning. - _centralManager = - [[CBCentralManager alloc] initWithDelegate:self - queue:_selfQueue - options:@{CBCentralManagerOptionShowPowerAlertKey : @NO}]; - - // Set up the central manager for the socket. - _socketCentralManager = [[GNSCentralManager alloc] initWithSocketServiceUUID:_serviceUUID - queue:_selfQueue]; - _socketCentralManager.delegate = self; - [_socketCentralManager startNoScanModeWithAdvertisedServiceUUIDs:@[ _serviceUUID ]]; - - _centralState = GNCMCentralStateScanning; - return YES; -} - -- (void)connectGattServerWithPeripheralID:(NSString *)peripheralID - gattConnectionResultHandler: - (GNCMGATTConnectionResultHandler)gattConnectionResultHandler { - _gattConnectionResultHandler = gattConnectionResultHandler; - dispatch_sync(_selfQueue, ^{ - GNCMPeripheralInfo *peripheralInfo = - _nearbyPeripheralsByID[[[NSUUID alloc] initWithUUIDString:peripheralID]]; - if (!peripheralInfo) return; - [_centralManager connectPeripheral:peripheralInfo.peripheral options:nil]; - }); -} - -- (void)discoverGattService:(CBUUID *)serviceUUID - gattCharacteristics:(NSArray *)characteristicUUIDs - peripheralID:(NSString *)peripheralID - gattDiscoverResultHandler:(GNCMGATTDiscoverResultHandler)gattDiscoverResultHandler { - _gattDiscoverResultHandler = gattDiscoverResultHandler; - [_gattCharacteristicValues removeAllObjects]; - dispatch_sync(_selfQueue, ^{ - GNCMPeripheralInfo *peripheralInfo = - _nearbyPeripheralsByID[[[NSUUID alloc] initWithUUIDString:peripheralID]]; - if (!peripheralInfo) return; - _characteristicUUIDs = [characteristicUUIDs copy]; - - // Start to discover service and the delegate will get its characteristics and read their values - // recursively - [peripheralInfo.peripheral discoverServices:@[ serviceUUID ]]; - }); -} - -- (void)disconnectGattServiceWithPeripheralID:(NSString *)peripheralID { - dispatch_sync(_selfQueue, ^{ - GNCMPeripheralInfo *peripheralInfo = - _nearbyPeripheralsByID[[[NSUUID alloc] initWithUUIDString:peripheralID]]; - if (!peripheralInfo) return; - _gattConnectionResultHandler = nil; - _gattDiscoverResultHandler = nil; - [_centralManager cancelPeripheralConnection:peripheralInfo.peripheral]; - }); -} - -#pragma mark CBCentralManagerDelegate - -- (void)centralManagerDidUpdateState:(CBCentralManager *)central { - if (central.state == CBManagerStatePoweredOn && !central.isScanning && - _centralState == GNCMCentralStateScanning) { - NSLog(@"[NEARBY] CBCentralManager powered on; starting scan"); - [self startScanningInternal]; - } else { - NSLog(@"[NEARBY] CBCentralManager not powered on; stopping scan"); - [self stopScanningInternal]; - } -} - -- (void)centralManager:(CBCentralManager *)central - didDiscoverPeripheral:(CBPeripheral *)peripheral - advertisementData:(NSDictionary *)advertisementData - RSSI:(NSNumber *)RSSI { - NSNumber *connectable = advertisementData[CBAdvertisementDataIsConnectable]; - if (![connectable boolValue]) return; - - // Look for the NC advertisement header in either the service data (from non-iOS) or the - // advertised name (from iOS). - NSData *serviceData = advertisementData[CBAdvertisementDataServiceDataKey][_serviceUUID] - ?: advertisementData[CBAdvertisementDataLocalNameKey]; - - // Try to look up the peripheral by ID. - GNCMPeripheralInfo *info = _nearbyPeripheralsByID[peripheral.identifier]; - if (!info) { - NSLog(@"[NEARBY] New peripheral: %@", peripheral); - // This is a new peripheral, so create a new peripheral info object. - info = [[GNCMPeripheralInfo alloc] initWithPeripheral:peripheral - advertisementData:advertisementData]; - } else { - info.peripheral = peripheral; - } - - _nearbyPeripheralsByID[peripheral.identifier] = info; - _scanResultHandler(peripheral.identifier.UUIDString, serviceData); -} - -- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { - NSLog(@"[NEARBY] Connected to peripheral: %@", peripheral); - peripheral.delegate = self; - // Tell the caller the connection is done. - _gattConnectionResultHandler(nil); -} - -- (void)centralManager:(CBCentralManager *)central - didFailToConnectPeripheral:(CBPeripheral *)peripheral - error:(nullable NSError *)error { - NSLog(@"[NEARBY] Failed to connect to peripheral: %@, error: %@", peripheral, error); - // Tell the caller the connection failed. - _gattConnectionResultHandler(error); -} - -- (void)centralManager:(CBCentralManager *)central - didDisconnectPeripheral:(CBPeripheral *)peripheral - error:(nullable NSError *)error { - NSLog(@"[NEARBY] Disconnected to peripheral: %@, error: %@", peripheral, error); -} - -#pragma mark CBPeripheralDelegate - -- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error { - GNCMPeripheralInfo *peripheralInfo = _nearbyPeripheralsByID[peripheral.identifier]; - if (!peripheralInfo) return; - if (error || (peripheral.services.count == 0)) { - NSLog(@"[NEARBY] Error reading advertisement: unable to discover services."); - _gattDiscoverResultHandler(nil); - } else { - NSLog(@"[NEARBY] Discovered services for %@: %@", peripheral.name, peripheral.services); - - // Helper functions for discovering characteristics and reading their values. - void (^discoverChars)(CBService *, GNCMBleCharacteristicsHandler) = - ^(CBService *service, GNCMBleCharacteristicsHandler handler) { - NSAssert(!peripheralInfo.charsHandler, @"Unexpected characteristic handler"); - peripheralInfo.charsHandler = handler; - - // Discover all characteristics that may contain the advertisement. - [peripheral discoverCharacteristics:_characteristicUUIDs forService:service]; - }; - void (^readCharValue)(CBCharacteristic *, GNCMBleCharacteristicValueHandler) = - ^(CBCharacteristic *characteristic, GNCMBleCharacteristicValueHandler handler) { - NSAssert(!peripheralInfo.charValueHandler, @"Unexpected characteristic value handler"); - peripheralInfo.charValueHandler = handler; - [peripheral readValueForCharacteristic:characteristic]; - }; - - // Multiple services may have the same UUID, so find the right service by searching for the - // characteristic containing the advertisement with a matching service ID hash. - __weak __typeof__(self) weakSelf = self; - void (^tryService)(int) = GNCRecursiveIntHandler(^(GNCIntHandler tryService, int serviceIndex) { - __strong __typeof__(self) strongSelf = weakSelf; - if (!strongSelf) return; - - // We've tried all the services, report the discovered characteristics and their values. - if (serviceIndex == peripheral.services.count) { - NSLog(@"[NEARBY] Done traversing all services or no services to traverse."); - _gattDiscoverResultHandler(_gattCharacteristicValues); - if (_gattCharacteristicValues.count > 0) { - CBCharacteristic *characteristic = [_gattCharacteristicValues objectAtIndex:0]; - [strongSelf completeGATTReadWithData:characteristic.value - forPeripheralInfo:peripheralInfo]; - } - return; - } - - NSLog(@"[NEARBY] Trying service: %@", peripheral.services[serviceIndex]); - discoverChars( - peripheral.services[serviceIndex], ^(NSArray *chars, NSError *error) { - void (^tryNextService)() = ^{ - tryService(serviceIndex + 1); - }; - - // If there was an error or there are no characteristics on this service, try next one. - if (error || (chars.count == 0)) { - tryNextService(); - return; - } - - // Read each characteristic. - void (^tryChar)(int) = GNCRecursiveIntHandler(^(GNCIntHandler tryChar, int charIndex) { - // We've tried all characteristics on this service without error, try next service. - if (charIndex == chars.count) { - NSLog(@"[NEARBY] No matching advertisement found"); - tryNextService(); - return; - } - - NSLog(@"[NEARBY] Trying characteristic: %@", chars[charIndex]); - readCharValue(chars[charIndex], ^(CBCharacteristic *characteristic, NSError *error) { - if (error) { - tryNextService(); - } else { - // We've found the characteristic and its non-nil value. Store it. - if (characteristic.value.length != 0) { - [_gattCharacteristicValues addObject:characteristic]; - } - tryChar(charIndex + 1); - } - }); - }); - - // Start searching the characteristics for the current service. - tryChar(0); - }); - }); - - // Start searching the services. - tryService(0); - } -} - -- (void)peripheral:(CBPeripheral *)peripheral - didDiscoverCharacteristicsForService:(CBService *)service - error:(nullable NSError *)error { - NSLog(@"[NEARBY] Discovered characteristics: %@ error: %@", service.characteristics, error); - GNCMPeripheralInfo *peripheralInfo = _nearbyPeripheralsByID[peripheral.identifier]; - if (!peripheralInfo) return; - GNCMBleCharacteristicsHandler charsHandler = peripheralInfo.charsHandler; - peripheralInfo.charsHandler = nil; - charsHandler(service.characteristics, error); -} - -- (void)peripheral:(CBPeripheral *)peripheral - didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic - error:(nullable NSError *)error { - NSLog(@"[NEARBY] Read characteristic value: %@ error: %@", characteristic, error); - GNCMPeripheralInfo *peripheralInfo = _nearbyPeripheralsByID[peripheral.identifier]; - if (!peripheralInfo) return; - GNCMBleCharacteristicValueHandler valueHandler = peripheralInfo.charValueHandler; - peripheralInfo.charValueHandler = nil; - valueHandler(characteristic, error); -} - -#pragma mark GNSCentralManagerDelegate - -- (void)centralManager:(GNSCentralManager *)centralManager - didDiscoverPeer:(GNSCentralPeerManager *)centralPeerManager - advertisementData:(nullable NSDictionary *)advertisementData { - if (!_callbacksEnabled) return; - - // Retrieve the cached peripheral info. - NSUUID *peerId = centralPeerManager.identifier; - GNCMPeripheralInfo *peripheralInfo = _nearbyPeripheralsByID[peerId]; - if (!peripheralInfo) return; - - __weak __typeof__(self) weakSelf = self; - [self callbackAsync:^{ - _requestConnectionHandler(^(NSString *serviceID, GNCMConnectionHandler connectionHandler) { - __strong __typeof__(self) strongSelf = weakSelf; - if (!strongSelf) return; - - void (^callConnectionHandler)(GNSSocket *__nullable) = ^(GNSSocket *__nullable socket) { - __strong __typeof__(self) strongSelf = weakSelf; - if (!strongSelf->_callbacksEnabled) return; - [strongSelf callbackAsync:^{ - if (!socket) { - NSLog(@"[NEARBY] Central failed to create BLE socket"); - connectionHandler(nil); - } else { - GNCMBleConnection *connection = - [GNCMBleConnection connectionWithSocket:socket - serviceID:serviceID - expectedIntroPacket:NO - callbackQueue:strongSelf->_clientCallbackQueue]; - connection.connectionHandlers = connectionHandler(connection); - } - }]; - }; - - dispatch_async(strongSelf->_selfQueue, ^{ - // A connection is being requested, so establish a BLE socket. Make sure to use the most - // up-to-date GNSCentralPeerManager in case the MAC address rotated. The cached - // peripheral info should be the single source of truth for which MAC address to use. - GNSCentralPeerManager *updatedCentralPeerManager = - [centralManager retrieveCentralPeerWithIdentifier:peripheralInfo.peripheral.identifier]; - if (!updatedCentralPeerManager) { - callConnectionHandler(nil); - } - - // Make a socket connection. - [updatedCentralPeerManager - socketWithPairingCharacteristic:NO - completion:^(GNSSocket *socket, NSError *error) { - __strong __typeof__(self) strongSelf = weakSelf; - if (!strongSelf) return; - dispatch_async(strongSelf->_selfQueue, ^{ - if (!error) { - // Call the connection handler when the socket has - // connected or fails to connect. - GNCMWaitForConnection(socket, ^(BOOL didConnect) { - callConnectionHandler(didConnect ? socket : nil); - }); - } else { - callConnectionHandler(nil); - } - }); - }]; - }); - }); - }]; -} - -- (void)centralManagerDidUpdateBleState:(GNSCentralManager *)centralManager { - // No op. -} - -#pragma mark Private - -/** This method assumes it's being called on selfQueue. */ -- (void)completeGATTReadWithData:(NSData *)advertisement - forPeripheralInfo:(GNCMPeripheralInfo *)peripheralInfo { - NSAssert(peripheralInfo, @"Nil peripheralInfo"); - if (peripheralInfo) { - CBPeripheral *peripheral = peripheralInfo.peripheral; - NSUUID *peripheralID = peripheral.identifier; - // Store the data for the socket callback, and report the peripheral to the socket library. - [_socketCentralManager retrievePeripheralWithIdentifier:peripheralID - advertisementData:peripheralInfo.advertisementData]; - } -} - -/** Signals the central manager to start scanning. Must be called on _selfQueue. */ -- (void)startScanningInternal { - if (![_centralManager isScanning]) { - NSLog(@"[NEARBY] startScanningInternal"); - - [_centralManager - scanForPeripheralsWithServices:@[ _serviceUUID ] - options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @YES}]; - } -} - -/** Signals the central manager to stop scanning. Must be called on _selfQueue */ -- (void)stopScanningInternal { - if ([_centralManager isScanning]) { - NSLog(@"[NEARBY] stopScanningInternal"); - _centralState = GNCMCentralStateStopped; - - [_centralManager stopScan]; - } -} - -/** Calls the specified block on the callback queue. */ -- (void)callbackAsync:(dispatch_block_t)block { - dispatch_queue_t clientCallbackQueue = _clientCallbackQueue; // don't capture |self| - dispatch_async(_internalCallbackQueue, ^{ - dispatch_sync(clientCallbackQueue, block); - }); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/Ble/GNCMBlePeripheral.h b/internal/platform/implementation/apple/Mediums/Ble/GNCMBlePeripheral.h deleted file mode 100644 index 8511da36..00000000 --- a/internal/platform/implementation/apple/Mediums/Ble/GNCMBlePeripheral.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2022 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. - -#import - -#import "internal/platform/implementation/apple/Mediums/GNCMConnection.h" - -@class CBCharacteristic; -@class CBUUID; - -NS_ASSUME_NONNULL_BEGIN - -/** - * GNCMBlePeripheral advertises the specified service UUID via Ble for the purpose of being - * discovered by a central using the GNCMBleCentral class. - * - * This class is thread-safe. Any calls made to it (and to the objects/closures it passes back via - * callbacks) can be made from any thread/queue. Callbacks made from this class are called on the - * specified queue. - */ -@interface GNCMBlePeripheral : NSObject - -- (instancetype)init NS_DESIGNATED_INITIALIZER; - -/** - * Adds GATT CBService. - * - * @param serviceUUID A GATT service ID to advertise for. - */ -- (void)addCBServiceWithUUID:(CBUUID *)serviceUUID; - -/** - * Adds GATT CBCharacteristic. - * - * @param characteristic A characteristic CBUUID. - */ -- (void)addCharacteristic:(CBCharacteristic *)characteristic; - -/** - * Updates GATT CBCharacteristic with value. - * - * @param value The NSData to advertise. - * @param characteristicUUID A characteristic CBUUID. - */ -- (void)updateValue:(NSData *)value forCharacteristic:(CBUUID *)characteristicUUID; - -/** - * Stops GATT server service. - */ -- (void)stopGATTService; - -/** - * Starts advertising with service UUID and advertisement data. - * - * @param serviceUUID A string that uniquely identifies the advertised service to search for. - * @param advertisementData The data to advertise. - * @param endpointconnectedHandler The handler that is called when a discoverer connects. - * @param callbackQueue The queue on which all callbacks are made. If |callbackQueue| is not - * provided, then the main queue is used in the function. - */ -- (BOOL)startAdvertisingWithServiceUUID:(NSString *)serviceUUID - advertisementData:(NSData *)advertisementData - endpointConnectedHandler:(GNCMConnectionHandler)endpointConnectedHandler - callbackQueue:(nullable dispatch_queue_t)callbackQueue; - -@end - -NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/Ble/GNCMBlePeripheral.m b/internal/platform/implementation/apple/Mediums/Ble/GNCMBlePeripheral.m deleted file mode 100644 index d915a3c3..00000000 --- a/internal/platform/implementation/apple/Mediums/Ble/GNCMBlePeripheral.m +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2022 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. - -#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBlePeripheral.h" - -#import - -#import "internal/platform/implementation/apple/GNCUtils.h" -#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleConnection.h" -#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleUtils.h" -#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Peripheral/GNSPeripheralManager.h" -#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Peripheral/GNSPeripheralServiceManager.h" -#import "internal/platform/implementation/apple/Mediums/GNCMConnection.h" - -NS_ASSUME_NONNULL_BEGIN - -typedef NS_ENUM(NSUInteger, GNCMPeripheralState) { - GNCMPeripheralStateStopped, - GNCMPeripheralStateAdvertising, -}; - -@interface GNCMBlePeripheral () -@end - -@implementation GNCMBlePeripheral { - /** Service UUID for advertisement. */ - CBMutableService *_advertisementService; - /** GATT service for GATT connection. */ - CBMutableService *_GATTService; - /** GATT characteristics for GATT connection. */ - NSMutableArray *_gattCharacteristics; - /** CBUUID characteristic to NSData value dictionary for GATT connection. */ - NSMutableDictionary *_gattCharacteristicValues; - /** Data to be advertised. */ - NSData *_advertisementData; - /** Peripheral manager used to advertise or connect to peripherals. */ - CBPeripheralManager *_peripheralManager; - /** Serial background queue for |peripheralManager|. */ - dispatch_queue_t _selfQueue; - /** Peripheral state for stop or advertising. */ - GNCMPeripheralState _state; - /** Peripheral manager used for socket connection based on weave protocol. */ - GNSPeripheralManager *_socketPeripheralManager; - /** Peripheral service manager used to manage one BLE service. */ - GNSPeripheralServiceManager *_socketPeripheralServiceManager; - /** Client callback queue. If client doesn't assign it, then use main queue. */ - dispatch_queue_t _clientCallbackQueue; - /** Internal async priority queue. */ - dispatch_queue_t _internalCallbackQueue; - /** Flag to disable callback for dealloc. */ - BOOL _callbacksEnabled; -} - -- (instancetype)init { - if (self = [super init]) { - // To make this class thread-safe, use a serial queue for all state changes, and have Core - // Bluetooth also use this queue. - _selfQueue = dispatch_queue_create("GNCPeripheralManagerQueue", DISPATCH_QUEUE_SERIAL); - - _state = GNCMPeripheralStateStopped; - } - return self; -} - -- (void)dealloc { - // These calls must be made on |selfQueue|. Can't capture |self| in an async block, so must use - // dispatch_sync. This means delloc must be called from an external queue, which means |self| - // must never be captured by any escaping block used in this class. - dispatch_sync(_selfQueue, ^{ - [self stopAdvertisingInternal]; - - _callbacksEnabled = NO; - }); -} - -- (void)addCBServiceWithUUID:(CBUUID *)serviceUUID { - if (!_GATTService) { - // If it has been called, then don't do it again. Initialize one time. - _GATTService = [[CBMutableService alloc] initWithType:serviceUUID primary:YES]; - _gattCharacteristics = [[NSMutableArray alloc] init]; - _gattCharacteristicValues = [[NSMutableDictionary alloc] init]; - } -} - -- (void)addCharacteristic:(CBCharacteristic *)characteristic { - if (_gattCharacteristics) { - [_gattCharacteristics addObject:characteristic]; - } - if (_gattCharacteristicValues) { - [_gattCharacteristicValues setObject:[[NSData alloc] init] forKey:characteristic.UUID]; - } -} - -- (void)updateValue:(NSData *)value forCharacteristic:(CBUUID *)characteristicUUID { - if ([_gattCharacteristicValues objectForKey:characteristicUUID]) { - [_gattCharacteristicValues setObject:value forKey:characteristicUUID]; - } -} - -- (void)stopGATTService { - if (!_GATTService) return; - dispatch_sync(_selfQueue, ^{ - [_peripheralManager removeService:_GATTService]; - }); -} - -- (BOOL)startAdvertisingWithServiceUUID:(NSString *)serviceUUID - advertisementData:(NSData *)advertisementData - endpointConnectedHandler:(GNCMConnectionHandler)endpointConnectedHandler - callbackQueue:(nullable dispatch_queue_t)callbackQueue { - NSLog(@"[NEARBY] Client rquests startAdvertising"); - // The client may be using the callback queue for other purposes, so wrap it with a private - // queue to know with certainty when all callbacks are done. - _clientCallbackQueue = callbackQueue ?: dispatch_get_main_queue(); - _internalCallbackQueue = - dispatch_queue_create("GNCMBlePeripheralCallbackQueue", DISPATCH_QUEUE_PRIORITY_DEFAULT); - _callbacksEnabled = YES; - - _advertisementService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:serviceUUID] - primary:YES]; - _advertisementData = [advertisementData copy]; - - // To make this class thread-safe, use a serial queue for all state changes, and have Core - // Bluetooth also use this queue. - _selfQueue = dispatch_queue_create("GNCPeripheralManagerQueue", DISPATCH_QUEUE_SERIAL); - __weak __typeof__(self) weakSelf = self; - // Set up the peripheral manager for the socket. This must be done before creating the - // peripheral manager for the advertisement data because it's started/stopped in the - // -peripheralManagerDidUpdateState: callback. - _socketPeripheralServiceManager = [[GNSPeripheralServiceManager alloc] - initWithBleServiceUUID:_advertisementService.UUID - addPairingCharacteristic:NO - shouldAcceptSocketHandler:^BOOL(GNSSocket *socket) { - // Call the connection handler when the socket has connected or fails to connect. - GNCMWaitForConnection(socket, ^(BOOL didConnect) { - [weakSelf establishConnectionWithSocket:socket - didConnect:didConnect - endpointConnectedHandler:endpointConnectedHandler]; - }); - return YES; - } - queue:_selfQueue]; - _socketPeripheralManager = [[GNSPeripheralManager alloc] initWithAdvertisedName:nil - restoreIdentifier:nil - queue:_selfQueue]; - [_socketPeripheralManager addPeripheralServiceManager:_socketPeripheralServiceManager - bleServiceAddedCompletion:^(NSError *error) { - NSLog(@"Failed to add service"); - }]; - - // Set up the peripheral manager for the advertisement data. - _peripheralManager = [[CBPeripheralManager alloc] - initWithDelegate:self - queue:_selfQueue - options:@{CBPeripheralManagerOptionShowPowerAlertKey : @NO}]; - - if (_GATTService) { - if (_gattCharacteristics && _gattCharacteristics.count > 0) { - _GATTService.characteristics = _gattCharacteristics; - } - } - _state = GNCMPeripheralStateAdvertising; - return YES; -} - -#pragma mark CBPeripheralManagerDelegate - -- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral { - NSLog(@"[NEARBY] peripheralManagerDidUpdateState %li", (long)peripheral.state); - if (peripheral.state == CBManagerStatePoweredOn && !peripheral.isAdvertising && - _state == GNCMPeripheralStateAdvertising) { - NSLog(@"[NEARBY] CBPeripheralManager powered on; starting advertising"); - [_socketPeripheralManager start]; - [self startAdvertisingInternal]; - } else { - NSLog(@"[NEARBY] CBPeripheralManager not powered on; stopping advertising"); - [self stopAdvertisingInternal]; - } -} - -- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral - error:(nullable NSError *)error { - if (error) { - NSLog(@"[NEARBY] Error starting advertising: %@,", [error localizedDescription]); - return; - } - if (_peripheralManager.state != CBManagerStatePoweredOn) { - NSLog(@"[NEARBY] Error starting advertising: peripheral manager not on!"); - return; - } - - NSLog(@"[NEARBY] Peripheral manager started advertising"); -} - -- (void)peripheralManager:(CBPeripheralManager *)peripheral - didReceiveReadRequest:(CBATTRequest *)request { - NSLog(@"[NEARBY] peripheralManager:didReceiveReadRequest"); - // This is called when a central asks to read a characteristic's value. - CBATTError error = CBATTErrorAttributeNotFound; - NSData *value = _gattCharacteristicValues[request.characteristic.UUID]; - if (value != nil && value.length > 0) { - if (request.offset > value.length) { - error = CBATTErrorInvalidOffset; - } else { - // Reply with the advertisement data. - NSRange rangeFromOffset = NSMakeRange(request.offset, value.length - request.offset); - request.value = [value subdataWithRange:rangeFromOffset]; - error = CBATTErrorSuccess; - } - } - [_peripheralManager respondToRequest:request withResult:error]; -} - -#pragma mark Private - -/** Signals the peripheral manager to start advertising. Must be called on _selfQueue */ -- (void)startAdvertisingInternal { - if (![_peripheralManager isAdvertising]) { - NSLog(@"[NEARBY] startAdvertisingInternal"); - - if (_GATTService) { - [_peripheralManager addService:_GATTService]; - } - [_peripheralManager startAdvertising:@{ - CBAdvertisementDataServiceUUIDsKey : @[ _advertisementService.UUID ], - CBAdvertisementDataLocalNameKey : _advertisementData - }]; - } -} - -/** Signals the peripheral manager to stop advertising. Must be called on _selfQueue */ -- (void)stopAdvertisingInternal { - if ([_peripheralManager isAdvertising]) { - NSLog(@"[NEARBY] stopAdvertisingInternal"); - _state = GNCMPeripheralStateStopped; - - if (_GATTService) { - [_peripheralManager removeService:_GATTService]; - } - [_peripheralManager stopAdvertising]; - } -} - -/** - * Connects with socket and callback the |GNCMBleConnection| is established or nil if it is not. - */ -- (void)establishConnectionWithSocket:(GNSSocket *)socket - didConnect:(BOOL)didConnect - endpointConnectedHandler:(GNCMConnectionHandler)endpointConnectedHandler { - if (!_callbacksEnabled) { - return; - } - - [self callbackAsync:^{ - if (!didConnect) { - NSLog(@"[NEARBY] Peripheral failed to create BLE socket"); - endpointConnectedHandler(nil); - } else { - GNCMBleConnection *connection = [GNCMBleConnection connectionWithSocket:socket - serviceID:nil - expectedIntroPacket:YES - callbackQueue:_clientCallbackQueue]; - connection.connectionHandlers = endpointConnectedHandler(connection); - } - }]; -} - -/** - * Calls the specified block on the callback queue, preventing it from being dispatched to the - * client callback queue when callbacks are disabled. And without capturing |self|, since - * callbacks are disabled in dealloc. - */ -- (void)callbackAsync:(dispatch_block_t)block { - dispatch_queue_t clientCallbackQueue = _clientCallbackQueue; // don't capture |self| - dispatch_async(_internalCallbackQueue, ^{ - dispatch_sync(clientCallbackQueue, block); - }); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Tests/BUILD b/internal/platform/implementation/apple/Tests/BUILD index 8f4ee847..d10e8cc3 100644 --- a/internal/platform/implementation/apple/Tests/BUILD +++ b/internal/platform/implementation/apple/Tests/BUILD @@ -24,16 +24,23 @@ objc_library( testonly = True, srcs = [ "GNCBLEGATTCharacteristicTest.mm", + "GNCBLEGATTClient+Testing.h", + "GNCBLEGATTClientTest.m", "GNCBLEGATTServer+Testing.h", "GNCBLEGATTServerTest.m", + "GNCBLEMedium+Testing.h", + "GNCBLEMediumTest.m", "GNCBLEUtilsTest.mm", - "GNCBleTest.mm", - "GNCBluetoothAdapterTest.mm", "GNCCryptoTest.mm", + "GNCFakeCentralManager.h", + "GNCFakeCentralManager.m", + "GNCFakePeripheral.h", + "GNCFakePeripheral.m", "GNCFakePeripheralManager.h", "GNCFakePeripheralManager.m", "GNCIPAddressTest.mm", "GNCMultiThreadExecutorTest.mm", + "GNCPlatformTest.mm", "GNCScheduledExecutorTest.mm", "GNCSingleThreadExecutorTest.mm", "GNCUtilsTest.mm", @@ -44,7 +51,8 @@ objc_library( "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", "//internal/platform/implementation:types", - "//internal/platform/implementation/apple", + "//internal/platform/implementation/apple", # buildcleaner: keep + "//internal/platform/implementation/apple:ble_v2", "//internal/platform/implementation/apple/Mediums", "//third_party/apple_frameworks:CoreBluetooth", "//third_party/apple_frameworks:Foundation", diff --git a/internal/platform/implementation/apple/Tests/GNCBLEGATTCharacteristicTest.mm b/internal/platform/implementation/apple/Tests/GNCBLEGATTCharacteristicTest.mm index c7b99b88..4aa8c827 100644 --- a/internal/platform/implementation/apple/Tests/GNCBLEGATTCharacteristicTest.mm +++ b/internal/platform/implementation/apple/Tests/GNCBLEGATTCharacteristicTest.mm @@ -26,12 +26,15 @@ - (void)testConvenienceInit { CBUUID *characteristicUUID = [CBUUID UUIDWithString:@"00000000-0000-3000-8000-000000000000"]; CBUUID *serviceUUID = [CBUUID UUIDWithString:@"0000FEF3-0000-1000-8000-00805F9B34FB"]; + CBCharacteristicProperties properties = CBCharacteristicPropertyRead; GNCBLEGATTCharacteristic *characteristic = - [[GNCBLEGATTCharacteristic alloc] initWithUUID:characteristicUUID serviceUUID:serviceUUID]; + [[GNCBLEGATTCharacteristic alloc] initWithUUID:characteristicUUID + serviceUUID:serviceUUID + properties:properties]; XCTAssertEqualObjects(characteristic.characteristicUUID, characteristicUUID); XCTAssertEqualObjects(characteristic.serviceUUID, serviceUUID); XCTAssertEqual(characteristic.permissions, 0); - XCTAssertEqual(characteristic.properties, 0); + XCTAssertEqual(characteristic.properties, properties); } - (void)testInit { diff --git a/internal/platform/implementation/apple/Tests/GNCBLEGATTClient+Testing.h b/internal/platform/implementation/apple/Tests/GNCBLEGATTClient+Testing.h new file mode 100644 index 00000000..a3a52f65 --- /dev/null +++ b/internal/platform/implementation/apple/Tests/GNCBLEGATTClient+Testing.h @@ -0,0 +1,40 @@ +// THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_APPLE_TESTS_GNCBLEGATTCLIENT_TESTING_H_ +// 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. + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h" + +#import + +@protocol GNCPeripheral; + +NS_ASSUME_NONNULL_BEGIN + +@interface GNCBLEGATTClient (Testing) + +/** + * Creates a GATT client with a provided peripheral. + * + * This is only exposed for testing and can be used to inject a fake peripheral. + * + * @param peripheral The peripheral instance. + * @param queue The queue to run on, this must match the queue that the peripheral's delegate is + * running on. Defaults to the main queue when @c nil. + */ +- (instancetype)initWithPeripheral:(id)peripheral + queue:(nullable dispatch_queue_t)queue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Tests/GNCBLEGATTClientTest.m b/internal/platform/implementation/apple/Tests/GNCBLEGATTClientTest.m new file mode 100644 index 00000000..b53cdef7 --- /dev/null +++ b/internal/platform/implementation/apple/Tests/GNCBLEGATTClientTest.m @@ -0,0 +1,748 @@ +// 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. + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h" + +#import +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h" +#import "internal/platform/implementation/apple/Tests/GNCBLEGATTClient+Testing.h" +#import "internal/platform/implementation/apple/Tests/GNCFakePeripheral.h" + +static NSString *const kServiceUUID1 = @"0000FEF3-0000-1000-8000-00805F9B34FB"; +static NSString *const kServiceUUID2 = @"0000FEF4-0000-1000-8000-00805F9B34FB"; +static NSString *const kCharacteristicUUID1 = @"00000000-0000-3000-8000-000000000000"; +static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-000000000001"; + +@interface GNCBLEGATTClientTest : XCTestCase +@end + +@implementation GNCBLEGATTClientTest + +#pragma mark - Discover Characteristics + +- (void)testDiscoverCharacteristics { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *discoverCharacteristicsExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Discover characteristics."]; + + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [discoverCharacteristicsExpectation fulfill]; + }]; + + [self waitForExpectations:@[ discoverCharacteristicsExpectation ] timeout:3]; + + XCTAssertEqualObjects(fakePeripheral.services[0].UUID, serviceUUID); + XCTAssertEqualObjects(fakePeripheral.services[0].characteristics[0].UUID, characteristicUUID); +} + +- (void)testDiscoverCharacteristicsWithServiceDiscoveryError { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + fakePeripheral.discoverServicesError = [NSError errorWithDomain:@"fake" code:0 userInfo:nil]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *discoverCharacteristicsExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Discover characteristics."]; + + // TODO(b/295911088): Failed discovery of services won't trigger the completionHandler until we + // implement a service queue. + discoverCharacteristicsExpectation.inverted = YES; + + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + // TODO(b/295911088): Make assertions when service queue is + // implemented. + [discoverCharacteristicsExpectation fulfill]; + }]; + + [self waitForExpectations:@[ discoverCharacteristicsExpectation ] timeout:3]; + + XCTAssertEqual(fakePeripheral.services.count, 0); +} + +- (void)testDiscoverCharacteristicsWithCharacteristicDiscoveryError { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + fakePeripheral.discoverCharacteristicsForServiceError = [NSError errorWithDomain:@"fake" + code:0 + userInfo:nil]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *discoverCharacteristicsExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Discover characteristics."]; + + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + XCTAssertNotNil(error); + [discoverCharacteristicsExpectation fulfill]; + }]; + + [self waitForExpectations:@[ discoverCharacteristicsExpectation ] timeout:3]; + + XCTAssertEqualObjects(fakePeripheral.services[0].UUID, serviceUUID); + XCTAssertEqual(fakePeripheral.services[0].characteristics.count, 0); +} + +// TODO(b/295911088): When service queue is implemented, this is expected to not be an error. +- (void)testDuplicateDiscoverCharacteristics { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *discoverCharacteristics1Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Discover characteristics 1."]; + XCTestExpectation *discoverCharacteristics2Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Discover characteristics 2."]; + + fakePeripheral.delegateDelay = 1; + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [discoverCharacteristics1Expectation fulfill]; + }]; + + // Queue the delay change so it doesn't immediately overwrite the delay set for the previous + // operation. + dispatch_async(dispatch_get_main_queue(), ^{ + fakePeripheral.delegateDelay = 0; + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + XCTAssertNotNil(error); + [discoverCharacteristics2Expectation fulfill]; + }]; + }); + + [self waitForExpectations:@[ + discoverCharacteristics1Expectation, discoverCharacteristics2Expectation + ] + timeout:3]; +} + +- (void)testDiscoverCharacteristicsMultipleCallsWithDifferentServices { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID1 = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *serviceUUID2 = [CBUUID UUIDWithString:kServiceUUID2]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *discoverCharacteristics1Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Discover characteristics 1."]; + XCTestExpectation *discoverCharacteristics2Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Discover characteristics 2."]; + + fakePeripheral.delegateDelay = 1; + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID1 + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [discoverCharacteristics1Expectation fulfill]; + }]; + + // Queue the delay change so it doesn't immediately overwrite the delay set for the previous + // operation. + dispatch_async(dispatch_get_main_queue(), ^{ + fakePeripheral.delegateDelay = 0; + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID2 + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [discoverCharacteristics2Expectation fulfill]; + }]; + }); + + [self waitForExpectations:@[ + discoverCharacteristics1Expectation, discoverCharacteristics2Expectation + ] + timeout:3]; + + XCTAssertEqualObjects(fakePeripheral.services[0].UUID, serviceUUID2); + XCTAssertEqualObjects(fakePeripheral.services[0].characteristics[0].UUID, characteristicUUID); + XCTAssertEqualObjects(fakePeripheral.services[1].UUID, serviceUUID1); + XCTAssertEqualObjects(fakePeripheral.services[1].characteristics[0].UUID, characteristicUUID); +} + +- (void)testDiscoverCharacteristicsMultipleCallsWithDifferentCharacteristics { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID1 = [CBUUID UUIDWithString:kCharacteristicUUID1]; + CBUUID *characteristicUUID2 = [CBUUID UUIDWithString:kCharacteristicUUID2]; + + XCTestExpectation *discoverCharacteristics1Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Discover characteristics 1."]; + XCTestExpectation *discoverCharacteristics2Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Discover characteristics 2."]; + + fakePeripheral.delegateDelay = 1; + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID1 ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [discoverCharacteristics1Expectation fulfill]; + }]; + + // Queue the delay change so it doesn't immediately overwrite the delay set for the previous + // operation. + dispatch_async(dispatch_get_main_queue(), ^{ + fakePeripheral.delegateDelay = 0; + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID2 ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [discoverCharacteristics2Expectation fulfill]; + }]; + }); + + [self waitForExpectations:@[ + discoverCharacteristics1Expectation, discoverCharacteristics2Expectation + ] + timeout:3]; + + XCTAssertEqualObjects(fakePeripheral.services[0].UUID, serviceUUID); + XCTAssertEqualObjects(fakePeripheral.services[0].characteristics[0].UUID, characteristicUUID2); + XCTAssertEqualObjects(fakePeripheral.services[0].characteristics[1].UUID, characteristicUUID1); +} + +#pragma mark - Get Characteristic + +- (void)testGetCharacteristic { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *characteristicExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Get characteristic."]; + + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + [gattClient characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^( + GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + XCTAssertNil(error); + XCTAssertNotNil(characteristic); + [characteristicExpectation fulfill]; + }]; + }]; + + [self waitForExpectations:@[ characteristicExpectation ] timeout:3]; +} + +- (void)testGetCharacteristicWithServiceDiscoveryError { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + fakePeripheral.discoverServicesError = [NSError errorWithDomain:@"fake" code:0 userInfo:nil]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *characteristicExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Get characteristic."]; + + // TODO(b/295911088): Failed discovery of services won't trigger the completionHandler until we + // implement a service queue. + characteristicExpectation.inverted = YES; + + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + [gattClient characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^( + GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + // TODO(b/295911088): Make assertions when service + // queue is implemented. + [characteristicExpectation fulfill]; + }]; + }]; + + [self waitForExpectations:@[ characteristicExpectation ] timeout:3]; +} + +- (void)testGetCharacteristicWithCharacteristicDiscoveryError { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + fakePeripheral.discoverCharacteristicsForServiceError = [NSError errorWithDomain:@"fake" + code:0 + userInfo:nil]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *characteristicExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Get characteristic."]; + + [gattClient discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + [gattClient characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^( + GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + XCTAssertNotNil(error); + XCTAssertNil(characteristic); + [characteristicExpectation fulfill]; + }]; + }]; + + [self waitForExpectations:@[ characteristicExpectation ] timeout:3]; +} + +- (void)testDuplicateGetCharacteristic { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *characteristic1Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Get characteristic 1."]; + XCTestExpectation *characteristic2Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Get characteristic 2."]; + + [gattClient + discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + fakePeripheral.delegateDelay = 1; + [gattClient + characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + XCTAssertNil(error); + XCTAssertNotNil(characteristic); + [characteristic1Expectation fulfill]; + }]; + // Queue the delay change so it doesn't immediately overwrite the delay set + // for the previous operation. + dispatch_async(dispatch_get_main_queue(), ^{ + fakePeripheral.delegateDelay = 0; + [gattClient + characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + XCTAssertNil(error); + XCTAssertNotNil(characteristic); + [characteristic2Expectation fulfill]; + }]; + }); + }]; + + [self waitForExpectations:@[ characteristic1Expectation, characteristic2Expectation ] timeout:3]; +} + +- (void)testGetNonExistentCharacteristic { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *characteristicExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Get characteristic."]; + + [gattClient characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, NSError *error) { + XCTAssertNotNil(error); + XCTAssertNil(characteristic); + [characteristicExpectation fulfill]; + }]; + + [self waitForExpectations:@[ characteristicExpectation ] timeout:3]; +} + +#pragma mark - Read Value for Characteristic + +- (void)testReadValueForCharacteristic { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *readValueForCharacteristicExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Read value for characteristic."]; + + [gattClient + discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + [gattClient + characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + [gattClient + readValueForCharacteristic:characteristic + completionHandler:^(NSData *value, NSError *error) { + XCTAssertNil(error); + XCTAssertNotNil(value); + [readValueForCharacteristicExpectation fulfill]; + }]; + }]; + }]; + + [self waitForExpectations:@[ readValueForCharacteristicExpectation ] timeout:3]; +} + +- (void)testReadValueForCharacteristicWithServiceDiscoveryError { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + fakePeripheral.discoverServicesError = [NSError errorWithDomain:@"fake" code:0 userInfo:nil]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *readValueForCharacteristicExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Read value for characteristic."]; + + // TODO(b/295911088): Failed discovery of services won't trigger the completionHandler until we + // implement a service queue. + readValueForCharacteristicExpectation.inverted = YES; + + [gattClient + discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + [gattClient + characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + [gattClient + readValueForCharacteristic:characteristic + completionHandler:^(NSData *value, NSError *error) { + // TODO(b/295911088): Make assertions when service + // queue is implemented. + [readValueForCharacteristicExpectation fulfill]; + }]; + }]; + }]; + + [self waitForExpectations:@[ readValueForCharacteristicExpectation ] timeout:3]; +} + +- (void)testReadValueForCharacteristicWithCharacteristicDiscoveryError { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + fakePeripheral.discoverCharacteristicsForServiceError = [NSError errorWithDomain:@"fake" + code:0 + userInfo:nil]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *readValueForCharacteristicExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Read value for characteristic."]; + + [gattClient + discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + [gattClient + characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + [gattClient + readValueForCharacteristic:characteristic + completionHandler:^(NSData *value, NSError *error) { + XCTAssertNotNil(error); + XCTAssertNil(value); + [readValueForCharacteristicExpectation fulfill]; + }]; + }]; + }]; + + [self waitForExpectations:@[ readValueForCharacteristicExpectation ] timeout:3]; +} + +- (void)testReadValueForCharacteristicWithReadValueForCharacteristicError { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + fakePeripheral.readValueForCharacteristicError = [NSError errorWithDomain:@"fake" + code:0 + userInfo:nil]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *readValueForCharacteristicExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Read value for characteristic."]; + + [gattClient + discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + [gattClient + characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + [gattClient + readValueForCharacteristic:characteristic + completionHandler:^(NSData *value, NSError *error) { + XCTAssertNotNil(error); + XCTAssertNil(value); + [readValueForCharacteristicExpectation fulfill]; + }]; + }]; + }]; + + [self waitForExpectations:@[ readValueForCharacteristicExpectation ] timeout:3]; +} + +// TODO(b/295911088): When service queue is implemented, this is expected to not be an error. +- (void)testDuplicateReadValueForCharacteristic { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + XCTestExpectation *readValueForCharacteristic1Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Read value for characteristic 1."]; + XCTestExpectation *readValueForCharacteristic2Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Read value for characteristic 2."]; + + [gattClient + discoverCharacteristicsWithUUIDs:@[ characteristicUUID ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + [gattClient + characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + fakePeripheral.delegateDelay = 1; + [gattClient + readValueForCharacteristic:characteristic + completionHandler:^(NSData *value, NSError *error) { + XCTAssertNil(error); + XCTAssertNotNil(value); + [readValueForCharacteristic1Expectation fulfill]; + }]; + + // Queue the delay change so it doesn't immediately overwrite the + // delay set for the previous operation. + dispatch_async(dispatch_get_main_queue(), ^{ + fakePeripheral.delegateDelay = 0; + [gattClient + readValueForCharacteristic:characteristic + completionHandler:^(NSData *value, + NSError *error) { + XCTAssertNotNil(error); + XCTAssertNil(value); + [readValueForCharacteristic2Expectation fulfill]; + }]; + }); + }]; + }]; + + [self waitForExpectations:@[ + readValueForCharacteristic1Expectation, readValueForCharacteristic2Expectation + ] + timeout:3]; +} + +- (void)testReadValueForMultipleCharacteristics { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID1 = [CBUUID UUIDWithString:kCharacteristicUUID1]; + CBUUID *characteristicUUID2 = [CBUUID UUIDWithString:kCharacteristicUUID2]; + + XCTestExpectation *readValueForCharacteristic1Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Read value for characteristic 1."]; + XCTestExpectation *readValueForCharacteristic2Expectation = + [[XCTestExpectation alloc] initWithDescription:@"Read value for characteristic 2."]; + + [gattClient + discoverCharacteristicsWithUUIDs:@[ characteristicUUID1, characteristicUUID2 ] + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + [gattClient + characteristicWithUUID:characteristicUUID1 + serviceUUID:serviceUUID + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + fakePeripheral.delegateDelay = 1; + [gattClient + readValueForCharacteristic:characteristic + completionHandler:^(NSData *value, NSError *error) { + XCTAssertNil(error); + XCTAssertNotNil(value); + [readValueForCharacteristic1Expectation fulfill]; + }]; + }]; + + [gattClient + characteristicWithUUID:characteristicUUID2 + serviceUUID:serviceUUID + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + // Queue the delay change so it doesn't immediately overwrite the + // delay set for the previous operation. + dispatch_async(dispatch_get_main_queue(), ^{ + fakePeripheral.delegateDelay = 0; + [gattClient + readValueForCharacteristic:characteristic + completionHandler:^(NSData *value, + NSError *error) { + XCTAssertNil(error); + XCTAssertNotNil(value); + [readValueForCharacteristic2Expectation fulfill]; + }]; + }); + }]; + }]; + + [self waitForExpectations:@[ + readValueForCharacteristic1Expectation, readValueForCharacteristic2Expectation + ] + timeout:3]; +} + +- (void)testReadValueForUndiscoveredCharacteristic { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + GNCBLEGATTCharacteristic *characteristic = + [[GNCBLEGATTCharacteristic alloc] initWithUUID:characteristicUUID + serviceUUID:serviceUUID + properties:CBCharacteristicPropertyRead]; + + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Read value for characteristic."]; + + [gattClient readValueForCharacteristic:characteristic + completionHandler:^(NSData *value, NSError *error) { + XCTAssertNotNil(error); + XCTAssertNil(value); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; +} + +#pragma mark - Delegate Calls + +- (void)testUnexpectedDelegateCalls { + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + + GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral + queue:nil]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + + [fakePeripheral.peripheralDelegate gnc_peripheral:fakePeripheral didDiscoverServices:nil]; + + [fakePeripheral.peripheralDelegate + gnc_peripheral:fakePeripheral + didDiscoverCharacteristicsForService:[[CBMutableService alloc] initWithType:serviceUUID + primary:YES] + error:nil]; + + [fakePeripheral.peripheralDelegate gnc_peripheral:fakePeripheral + didUpdateValueForCharacteristic:[[CBMutableCharacteristic alloc] + initWithType:characteristicUUID + properties:0 + value:nil + permissions:0] + error:nil]; + + // Test to make sure unexpected delegate calls don't cause any issues from missing handlers. + XCTAssertNotNil(gattClient); +} + +@end diff --git a/internal/platform/implementation/apple/Tests/GNCBLEGATTServerTest.m b/internal/platform/implementation/apple/Tests/GNCBLEGATTServerTest.m index f0531320..ada28625 100644 --- a/internal/platform/implementation/apple/Tests/GNCBLEGATTServerTest.m +++ b/internal/platform/implementation/apple/Tests/GNCBLEGATTServerTest.m @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h" #import #import #import -#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h" #import "internal/platform/implementation/apple/Tests/GNCBLEGATTServer+Testing.h" #import "internal/platform/implementation/apple/Tests/GNCFakePeripheralManager.h" @@ -42,17 +42,26 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Create characteristic."]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; - GNCBLEGATTCharacteristic *characteristic = - [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead]; + [gattServer + createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + XCTAssertNotNil(characteristic); + XCTAssertNil(error); + XCTAssertEqual(fakePeripheralManager.services.count, 1); + XCTAssertEqual(fakePeripheralManager.services[0].characteristics.count, 1); + [expectation fulfill]; + }]; - XCTAssertNotNil(characteristic); - XCTAssertEqual(fakePeripheralManager.services.count, 1); - XCTAssertEqual(fakePeripheralManager.services[0].characteristics.count, 1); + [self waitForExpectations:@[ expectation ] timeout:3]; } - (void)testCreateMultipleCharacteristicsForOneService { @@ -63,41 +72,132 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + XCTestExpectation *expectation1 = + [[XCTestExpectation alloc] initWithDescription:@"Create characteristic 1."]; + XCTestExpectation *expectation2 = + [[XCTestExpectation alloc] initWithDescription:@"Create characteristic 2."]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; CBUUID *characteristicUUID1 = [CBUUID UUIDWithString:kCharacteristicUUID1]; CBUUID *characteristicUUID2 = [CBUUID UUIDWithString:kCharacteristicUUID2]; - GNCBLEGATTCharacteristic *characteristic1 = - [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID1 - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead]; - GNCBLEGATTCharacteristic *characteristic2 = - [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID2 - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead]; + [gattServer createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID1 + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + XCTAssertNotNil(characteristic); + XCTAssertNil(error); + [expectation1 fulfill]; + }]; - XCTAssertNotNil(characteristic1); - XCTAssertNotNil(characteristic2); + [gattServer createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID2 + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + XCTAssertNotNil(characteristic); + XCTAssertNil(error); + [expectation2 fulfill]; + }]; + + [self waitForExpectations:@[ expectation1, expectation2 ] timeout:3]; XCTAssertEqual(fakePeripheralManager.services.count, 1); XCTAssertEqual(fakePeripheralManager.services[0].characteristics.count, 2); } +- (void)testCreateDuplicateCharacteristics { + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Create characteristic."]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID1 = [CBUUID UUIDWithString:kCharacteristicUUID1]; + [gattServer createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID1 + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:nil]; + + [gattServer createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID1 + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + XCTAssertNil(characteristic); + XCTAssertNotNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; + XCTAssertEqual(fakePeripheralManager.services.count, 1); + XCTAssertEqual(fakePeripheralManager.services[0].characteristics.count, 1); +} + +- (void)testCreateDuplicatePendingCharacteristics { + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Create characteristic."]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID1 = [CBUUID UUIDWithString:kCharacteristicUUID1]; + [gattServer createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID1 + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:nil]; + + [gattServer createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID1 + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + XCTAssertNil(characteristic); + XCTAssertNotNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; +} + - (void)testCreateCharacteristicNotPoweredOn { GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; GNCBLEGATTServer *gattServer = [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Create characteristic."]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; - GNCBLEGATTCharacteristic *characteristic = - [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead]; + [gattServer createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + // The error occurs after completion, so its expected to fail + // silently. + XCTAssertNotNil(characteristic); + XCTAssertNil(error); + [expectation fulfill]; + }]; - XCTAssertNil(characteristic); + [self waitForExpectations:@[ expectation ] timeout:3]; } - (void)testCreateCharacteristicServiceFailure { @@ -109,101 +209,25 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 fakePeripheralManager.didAddServiceError = [NSError errorWithDomain:@"fake" code:0 userInfo:nil]; [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; - CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; - GNCBLEGATTCharacteristic *characteristic = - [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead]; - - XCTAssertNil(characteristic); -} - -#pragma mark - Update Characteristic - -- (void)testUpdateCharacteristic { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; - - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Create characteristic."]; CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; - GNCBLEGATTCharacteristic *characteristic = - [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead]; - - BOOL success = [gattServer updateCharacteristic:characteristic value:[NSData data]]; - - XCTAssertTrue(success); - XCTAssertEqual(fakePeripheralManager.services.count, 1); - XCTAssertEqual(fakePeripheralManager.services[0].characteristics.count, 1); -} - -- (void)testUpdateCharacteristicInvalidService { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; - - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - - CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; - CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; - GNCBLEGATTCharacteristic *characteristic = - [[GNCBLEGATTCharacteristic alloc] initWithUUID:characteristicUUID serviceUUID:serviceUUID]; - - BOOL success = [gattServer updateCharacteristic:characteristic value:[NSData data]]; - - XCTAssertFalse(success); -} - -- (void)testUpdateCharacteristicInvalidCharacteristic { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; - - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - - CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; - CBUUID *characteristicUUID1 = [CBUUID UUIDWithString:kCharacteristicUUID1]; - CBUUID *characteristicUUID2 = [CBUUID UUIDWithString:kCharacteristicUUID2]; [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID1 + characteristicUUID:characteristicUUID permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead]; + properties:CBCharacteristicPropertyRead + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + // The error occurs after completion, so its expected to fail + // silently. + XCTAssertNotNil(characteristic); + XCTAssertNil(error); + [expectation fulfill]; + }]; - GNCBLEGATTCharacteristic *characteristic2 = - [[GNCBLEGATTCharacteristic alloc] initWithUUID:characteristicUUID2 serviceUUID:serviceUUID]; - - BOOL success = [gattServer updateCharacteristic:characteristic2 value:[NSData data]]; - - XCTAssertFalse(success); -} - -- (void)testUpdateCharacteristicNotPoweredOn { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; - - CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; - CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; - GNCBLEGATTCharacteristic *characteristic = - [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead]; - - BOOL success = [gattServer updateCharacteristic:characteristic value:[NSData data]]; - - XCTAssertFalse(success); + [self waitForExpectations:@[ expectation ] timeout:3]; } #pragma mark - Read Request @@ -216,15 +240,25 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Create and update characteristic."]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; - GNCBLEGATTCharacteristic *characteristic = - [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead]; + [gattServer createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + [gattServer updateCharacteristic:characteristic + value:[NSData data] + completionHandler:^(NSError *error) { + [expectation fulfill]; + }]; + }]; - [gattServer updateCharacteristic:characteristic value:[NSData data]]; + [self waitForExpectations:@[ expectation ] timeout:3]; [fakePeripheralManager simulatePeripheralManagerDidReceiveReadRequestForService:serviceUUID @@ -242,15 +276,25 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Create and update characteristic."]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; - GNCBLEGATTCharacteristic *characteristic = - [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead]; + [gattServer createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + [gattServer updateCharacteristic:characteristic + value:[NSData data] + completionHandler:^(NSError *error) { + [expectation fulfill]; + }]; + }]; - [gattServer updateCharacteristic:characteristic value:[NSData data]]; + [self waitForExpectations:@[ expectation ] timeout:3]; CBUUID *invalidServiceUUID = [CBUUID UUIDWithString:kServiceUUID2]; @@ -269,15 +313,25 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Create and update characteristic."]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; - GNCBLEGATTCharacteristic *characteristic = - [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead]; + [gattServer createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + [gattServer updateCharacteristic:characteristic + value:[NSData data] + completionHandler:^(NSError *error) { + [expectation fulfill]; + }]; + }]; - [gattServer updateCharacteristic:characteristic value:[NSData data]]; + [self waitForExpectations:@[ expectation ] timeout:3]; CBUUID *invalidCharacteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID2]; @@ -311,12 +365,18 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - BOOL success = [gattServer startAdvertisingData:@{}]; - XCTAssertTrue(success); - XCTAssertTrue(fakePeripheralManager.isAdvertising); - NSDictionary *data = fakePeripheralManager.advertisementData; - XCTAssertEqual(data, nil); + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + [gattServer startAdvertisingData:@{} + completionHandler:^(NSError *error) { + XCTAssertNotNil(error); + XCTAssertFalse(fakePeripheralManager.isAdvertising); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; } - (void)testStartAdvertisingEmptyServiceData { @@ -326,16 +386,22 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - BOOL success = [gattServer startAdvertisingData:@{ - [CBUUID UUIDWithString:@"FEF3"] : [NSData data], - }]; - XCTAssertTrue(success); - XCTAssertTrue(fakePeripheralManager.isAdvertising); - NSDictionary *data = fakePeripheralManager.advertisementData; - XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], @""); - XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], - [CBUUID UUIDWithString:@"FEF3"]); + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + [gattServer startAdvertisingData:@{[CBUUID UUIDWithString:@"FEF3"] : [NSData data]} + completionHandler:^(NSError *error) { + XCTAssertNil(error); + XCTAssertTrue(fakePeripheralManager.isAdvertising); + NSDictionary *data = fakePeripheralManager.advertisementData; + XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], @""); + XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], + [CBUUID UUIDWithString:@"FEF3"]); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; } - (void)testStartAdvertisingShortServiceData { @@ -345,16 +411,24 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - BOOL success = [gattServer startAdvertisingData:@{ - [CBUUID UUIDWithString:@"FEF3"] : [@"0123" dataUsingEncoding:NSUTF8StringEncoding], - }]; - XCTAssertTrue(success); - XCTAssertTrue(fakePeripheralManager.isAdvertising); - NSDictionary *data = fakePeripheralManager.advertisementData; - XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], @"MDEyMw"); - XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], - [CBUUID UUIDWithString:@"FEF3"]); + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + [gattServer startAdvertisingData:@{ + [CBUUID UUIDWithString:@"FEF3"] : [@"0123" dataUsingEncoding:NSUTF8StringEncoding], + } + completionHandler:^(NSError *error) { + XCTAssertNil(error); + XCTAssertTrue(fakePeripheralManager.isAdvertising); + NSDictionary *data = fakePeripheralManager.advertisementData; + XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], @"MDEyMw"); + XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], + [CBUUID UUIDWithString:@"FEF3"]); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; } - (void)testStartAdvertising22ByteServiceData { @@ -364,16 +438,25 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - BOOL success = [gattServer startAdvertisingData:@{ - [CBUUID UUIDWithString:@"FEF3"] : [@"0123456789012345" dataUsingEncoding:NSUTF8StringEncoding], - }]; - XCTAssertTrue(success); - XCTAssertTrue(fakePeripheralManager.isAdvertising); - NSDictionary *data = fakePeripheralManager.advertisementData; - XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], @"MDEyMzQ1Njc4OTAxMjM0NQ"); - XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], - [CBUUID UUIDWithString:@"FEF3"]); + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + [gattServer startAdvertisingData:@{ + [CBUUID UUIDWithString:@"FEF3"] : [@"0123456789012345" dataUsingEncoding:NSUTF8StringEncoding], + } + completionHandler:^(NSError *error) { + XCTAssertNil(error); + XCTAssertTrue(fakePeripheralManager.isAdvertising); + NSDictionary *data = fakePeripheralManager.advertisementData; + XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], + @"MDEyMzQ1Njc4OTAxMjM0NQ"); + XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], + [CBUUID UUIDWithString:@"FEF3"]); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; } - (void)testStartAdvertisingLongServiceData { @@ -383,17 +466,26 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - BOOL success = [gattServer startAdvertisingData:@{ - [CBUUID UUIDWithString:@"FEF3"] : - [@"012345678901234567890123456789" dataUsingEncoding:NSUTF8StringEncoding], - }]; - XCTAssertTrue(success); - XCTAssertTrue(fakePeripheralManager.isAdvertising); - NSDictionary *data = fakePeripheralManager.advertisementData; - XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], @"MDEyMzQ1Njc4OTAxMjM0NT"); - XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], - [CBUUID UUIDWithString:@"FEF3"]); + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + [gattServer + startAdvertisingData:@{ + [CBUUID UUIDWithString:@"FEF3"] : + [@"012345678901234567890123456789" dataUsingEncoding:NSUTF8StringEncoding], + } + completionHandler:^(NSError *error) { + XCTAssertNil(error); + XCTAssertTrue(fakePeripheralManager.isAdvertising); + NSDictionary *data = fakePeripheralManager.advertisementData; + XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], @"MDEyMzQ1Njc4OTAxMjM0NT"); + XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], + [CBUUID UUIDWithString:@"FEF3"]); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; } - (void)testStartAdvertisingWithEmojiServiceData { @@ -403,16 +495,25 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - BOOL success = [gattServer startAdvertisingData:@{ - [CBUUID UUIDWithString:@"FEF3"] : [@"😁❤️🤡" dataUsingEncoding:NSUTF8StringEncoding], - }]; - XCTAssertTrue(success); - XCTAssertTrue(fakePeripheralManager.isAdvertising); - NSDictionary *data = fakePeripheralManager.advertisementData; - XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], @"8J-YgeKdpO-4j_CfpKE"); - XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], - [CBUUID UUIDWithString:@"FEF3"]); + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + [gattServer + startAdvertisingData:@{ + [CBUUID UUIDWithString:@"FEF3"] : [@"😁❤️🤡" dataUsingEncoding:NSUTF8StringEncoding], + } + completionHandler:^(NSError *error) { + XCTAssertNil(error); + XCTAssertTrue(fakePeripheralManager.isAdvertising); + NSDictionary *data = fakePeripheralManager.advertisementData; + XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], @"8J-YgeKdpO-4j_CfpKE"); + XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], + [CBUUID UUIDWithString:@"FEF3"]); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; } - (void)testStartAdvertisingMultipleServices { @@ -422,15 +523,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - BOOL success = [gattServer startAdvertisingData:@{ + + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + [gattServer startAdvertisingData:@{ [CBUUID UUIDWithString:@"FEF3"] : [@"012345678901234567890123456789" dataUsingEncoding:NSUTF8StringEncoding], [CBUUID UUIDWithString:@"FEF4"] : [@"012345678901234567890123456789" dataUsingEncoding:NSUTF8StringEncoding], - }]; + } + completionHandler:^(NSError *error) { + XCTAssertNotNil(error); + XCTAssertFalse(fakePeripheralManager.isAdvertising); + [expectation fulfill]; + }]; - XCTAssertFalse(success); - XCTAssertFalse(fakePeripheralManager.isAdvertising); + [self waitForExpectations:@[ expectation ] timeout:3]; } - (void)testStartAdvertisingNotPoweredOn { @@ -439,10 +548,18 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 GNCBLEGATTServer *gattServer = [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; - BOOL success = [gattServer startAdvertisingData:@{}]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; - XCTAssertFalse(success); - XCTAssertFalse(fakePeripheralManager.isAdvertising); + [gattServer startAdvertisingData:@{[CBUUID UUIDWithString:@"FEF3"] : [NSData data]} + completionHandler:^(NSError *error) { + // The error occurs after completion, so its expected to fail silently. + XCTAssertNil(error); + XCTAssertFalse(fakePeripheralManager.isAdvertising); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; } - (void)testStartAdvertisingStartFailure { @@ -455,10 +572,86 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 code:0 userInfo:nil]; [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - BOOL success = [gattServer startAdvertisingData:@{}]; - XCTAssertFalse(success); - XCTAssertFalse(fakePeripheralManager.isAdvertising); + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + [gattServer startAdvertisingData:@{[CBUUID UUIDWithString:@"FEF3"] : [NSData data]} + completionHandler:^(NSError *error) { + // The error occurs after completion, so its expected to fail silently. + XCTAssertNil(error); + XCTAssertFalse(fakePeripheralManager.isAdvertising); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; +} + +- (void)testStartAdvertisingAlreadyAdvertising { + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + + fakePeripheralManager.didStartAdvertisingError = [NSError errorWithDomain:@"fake" + code:0 + userInfo:nil]; + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + [gattServer startAdvertisingData:@{[CBUUID UUIDWithString:@"FEF3"] : [NSData data]} + completionHandler:nil]; + + [gattServer startAdvertisingData:@{[CBUUID UUIDWithString:@"FEF4"] : [NSData data]} + completionHandler:^(NSError *error) { + XCTAssertNotNil(error); + XCTAssertFalse(fakePeripheralManager.isAdvertising); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; +} + +- (void)testStartStopStartAdvertising { + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + [gattServer startAdvertisingData:@{[CBUUID UUIDWithString:@"FEF3"] : [NSData data]} + completionHandler:^(NSError *error) { + XCTAssertNil(error); + XCTAssertTrue(fakePeripheralManager.isAdvertising); + NSDictionary *data = fakePeripheralManager.advertisementData; + XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], @""); + XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], + [CBUUID UUIDWithString:@"FEF3"]); + [gattServer stopAdvertisingWithCompletionHandler:^(NSError *error) { + XCTAssertNil(error); + XCTAssertFalse(fakePeripheralManager.isAdvertising); + [gattServer + startAdvertisingData:@{[CBUUID UUIDWithString:@"FEF4"] : [NSData data]} + completionHandler:^(NSError *error) { + XCTAssertNil(error); + XCTAssertTrue(fakePeripheralManager.isAdvertising); + NSDictionary *data = + fakePeripheralManager.advertisementData; + XCTAssertEqualObjects(data[CBAdvertisementDataLocalNameKey], @""); + XCTAssertEqualObjects(data[CBAdvertisementDataServiceUUIDsKey][0], + [CBUUID UUIDWithString:@"FEF4"]); + [expectation fulfill]; + }]; + }]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; } @end diff --git a/internal/platform/implementation/apple/Tests/GNCBLEMedium+Testing.h b/internal/platform/implementation/apple/Tests/GNCBLEMedium+Testing.h new file mode 100644 index 00000000..3431613a --- /dev/null +++ b/internal/platform/implementation/apple/Tests/GNCBLEMedium+Testing.h @@ -0,0 +1,42 @@ +// 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. + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h" + +#import + +@protocol GNCCentralManager; + +NS_ASSUME_NONNULL_BEGIN + +@interface GNCBLEMedium (Testing) + +/** + * Creates a BLE Medium with a provided central manager. + * + * This is only exposed for testing and can be used to inject a fake central manager. + * + * @param centralManager The central manager instance. + * @param queue The queue to run on, this must match the queue that the central manager's delegate + * is running on. Defaults to the main queue when @c nil. + */ +- (instancetype)initWithCentralManager:(id)centralManager + queue:(nullable dispatch_queue_t)queue; + +- (NSDictionary *)decodeAdvertisementData: + (NSDictionary *)advertisementData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Tests/GNCBLEMediumTest.m b/internal/platform/implementation/apple/Tests/GNCBLEMediumTest.m new file mode 100644 index 00000000..47121133 --- /dev/null +++ b/internal/platform/implementation/apple/Tests/GNCBLEMediumTest.m @@ -0,0 +1,340 @@ +// 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. + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h" + +#import +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h" +#import "internal/platform/implementation/apple/Tests/GNCBLEMedium+Testing.h" +#import "internal/platform/implementation/apple/Tests/GNCFakeCentralManager.h" +#import "internal/platform/implementation/apple/Tests/GNCFakePeripheral.h" + +static NSString *const kServiceUUID = @"0000FEF3-0000-1000-8000-00805F9B34FB"; + +@interface GNCBLEMediumTest : XCTestCase +@end + +@implementation GNCBLEMediumTest + +#pragma mark - Supports Extended Advertisements + +- (void)testSupportsExtendedAdvertisements { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + + XCTAssertFalse([medium supportsExtendedAdvertisements]); +} + +#pragma mark - Start Scanning + +- (void)testStartScanning { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + XCTestExpectation *startScanningExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Start scanning."]; + XCTestExpectation *advertisementFoundExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Advertisement found."]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + [fakeCentralManager simulateCentralManagerDidUpdateState:CBManagerStatePoweredOn]; + + [medium startScanningForService:serviceUUID + advertisementFoundHandler:^(id peripheral, + NSDictionary *data) { + NSDictionary *expected = @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }; + XCTAssertEqualObjects(expected, data); + [advertisementFoundExpectation fulfill]; + } + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [startScanningExpectation fulfill]; + }]; + + [self waitForExpectations:@[ startScanningExpectation ] timeout:3]; + + XCTAssertEqualObjects(@[ serviceUUID ], fakeCentralManager.serviceUUIDs); + + [fakeCentralManager + simulateCentralManagerDidDiscoverPeripheral:[[GNCFakePeripheral alloc] init] + advertisementData:@{ + CBAdvertisementDataLocalNameKey : @"dGVzdA", + CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], + }]; + + [self waitForExpectations:@[ advertisementFoundExpectation ] timeout:3]; +} + +- (void)testAlreadyScanning { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start scanning."]; + + [medium startScanningForService:[CBUUID UUIDWithString:kServiceUUID] + advertisementFoundHandler:^(id peripheral, + NSDictionary *data) { + } + completionHandler:nil]; + + [medium startScanningForService:[CBUUID UUIDWithString:kServiceUUID] + advertisementFoundHandler:^(id peripheral, + NSDictionary *data) { + } + completionHandler:^(NSError *error) { + XCTAssertNotNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; +} + +- (void)testStartStopStartScanning { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start scanning."]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + [medium startScanningForService:serviceUUID + advertisementFoundHandler:^(id peripheral, + NSDictionary *data) { + } + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [medium stopScanningWithCompletionHandler:^(NSError *error) { + XCTAssertNil(error); + [medium startScanningForService:serviceUUID + advertisementFoundHandler:^(id peripheral, + NSDictionary *data) { + } + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [expectation fulfill]; + }]; + }]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; +} + +#pragma mark - Decode Advertisement Data + +- (void)testDecodeAndroidStyleAdvertisementData { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + NSDictionary *expected = @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }; + + NSDictionary *data = @{ + CBAdvertisementDataServiceDataKey : @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }, + }; + NSDictionary *actual = [medium decodeAdvertisementData:data]; + + XCTAssertEqualObjects(expected, actual); +} + +- (void)testDecodeAndroidStyleAdvertisementDataWithLocalName { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + NSDictionary *expected = @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }; + + NSDictionary *data = @{ + CBAdvertisementDataLocalNameKey : @"Nearby", // Just happens to be base64 decodable. + CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], + CBAdvertisementDataServiceDataKey : @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }, + }; + NSDictionary *actual = [medium decodeAdvertisementData:data]; + + XCTAssertEqualObjects(expected, actual); +} + +- (void)testDecodeAppleStyleAdvertisementData { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + NSDictionary *expected = @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }; + + NSDictionary *data = @{ + CBAdvertisementDataLocalNameKey : @"dGVzdA", + CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], + }; + NSDictionary *actual = [medium decodeAdvertisementData:data]; + + XCTAssertEqualObjects(expected, actual); +} + +- (void)testDecodeInvalidAdvertisementData { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + NSDictionary *data = @{ + CBAdvertisementDataLocalNameKey : @"!@#$", + CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], + }; + NSDictionary *actual = [medium decodeAdvertisementData:data]; + + XCTAssertEqualObjects(@{}, actual); +} + +- (void)testDecodeEmptyAdvertisementData { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + + NSDictionary *actual = [medium decodeAdvertisementData:@{}]; + + XCTAssertEqualObjects(@{}, actual); +} + +#pragma mark - Start GATT Server + +- (void)testStartGATTServer { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start GATT server."]; + + [medium startGATTServerWithCompletionHandler:^(GNCBLEGATTServer *server, NSError *error) { + XCTAssertNotNil(server); + XCTAssertNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; +} + +#pragma mark - Start Advertising + +- (void)testStartAdvertising { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + // Start advertising is fully covered with @c GNCBLEGATTServer tests. We are passing invalid + // advertising data here so we can test code paths relevant to @c GNCBLEMedium, but bail early + // enough to avoid making actual CoreBluetooth calls. + [medium startAdvertisingData:@{} + completionHandler:^(NSError *error) { + XCTAssertNotNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; +} + +- (void)testStopAdvertising { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Stop advertising."]; + + // Stop advertising is fully covered with @c GNCBLEGATTServer tests. We are only testing stopping + // without having started which tests the code paths relevant to @c GNCBLEMedium. + [medium stopAdvertisingWithCompletionHandler:^(NSError *error) { + XCTAssertNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; +} + +#pragma mark - Connect + +- (void)testSuccessfulConnect { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"Connect."]; + + [medium connectToGATTServerForPeripheral:[[GNCFakePeripheral alloc] init] + disconnectionHandler:nil + completionHandler:^(GNCBLEGATTClient *client, NSError *error) { + XCTAssertNotNil(client); + XCTAssertNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; +} + +- (void)testFailedConnect { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"Connect."]; + + fakeCentralManager.didFailToConnectPeripheralError = [NSError errorWithDomain:@"fake" + code:0 + userInfo:nil]; + + [medium connectToGATTServerForPeripheral:[[GNCFakePeripheral alloc] init] + disconnectionHandler:nil + completionHandler:^(GNCBLEGATTClient *client, NSError *error) { + XCTAssertNil(client); + XCTAssertNotNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; +} + +- (void)testDisconnect { + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; + XCTestExpectation *connectExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Connect."]; + XCTestExpectation *disconnectExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Disconnect."]; + + GNCFakePeripheral *peripheral = [[GNCFakePeripheral alloc] init]; + + [medium connectToGATTServerForPeripheral:peripheral + disconnectionHandler:^() { + [disconnectExpectation fulfill]; + } + completionHandler:^(GNCBLEGATTClient *client, NSError *error) { + XCTAssertNotNil(client); + XCTAssertNil(error); + [connectExpectation fulfill]; + }]; + + [self waitForExpectations:@[ connectExpectation ] timeout:3]; + + [fakeCentralManager simulateCentralManagerDidDisconnectPeripheral:peripheral]; + + [self waitForExpectations:@[ disconnectExpectation ] timeout:3]; +} + +@end diff --git a/internal/platform/implementation/apple/Tests/GNCBLEUtilsTest.mm b/internal/platform/implementation/apple/Tests/GNCBLEUtilsTest.mm index 4434a2b2..1cc73ecb 100644 --- a/internal/platform/implementation/apple/Tests/GNCBLEUtilsTest.mm +++ b/internal/platform/implementation/apple/Tests/GNCBLEUtilsTest.mm @@ -13,6 +13,7 @@ // limitations under the License. #import +#import #import #import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h" @@ -25,6 +26,7 @@ using Property = ::nearby::api::ble_v2::GattCharacteristic::Property; using Permission = ::nearby::api::ble_v2::GattCharacteristic::Permission; using WriteType = ::nearby::api::ble_v2::GattClient::WriteType; using Uuid = ::nearby::Uuid; +using ByteArray = ::nearby::ByteArray; @interface GNCBLEUtilsTest : XCTestCase @end @@ -120,6 +122,22 @@ using Uuid = ::nearby::Uuid; XCTAssertEqual(actual.properties, properties); } +- (void)testObjCServiceDataFromCpp { + CBUUID *serviceUUID1 = [CBUUID UUIDWithString:@"0000FEF3-0000-1000-8000-00805F9B34FB"]; + CBUUID *serviceUUID2 = [CBUUID UUIDWithString:@"0000FEF4-0000-1000-8000-00805F9B34FB"]; + NSData *data1 = [@"one" dataUsingEncoding:NSUTF8StringEncoding]; + NSData *data2 = [@"two" dataUsingEncoding:NSUTF8StringEncoding]; + + absl::flat_hash_map service_data; + service_data[Uuid(0x0000FEF300001000, 0x800000805F9B34FB)] = ByteArray("one"); + service_data[Uuid(0x0000FEF400001000, 0x800000805F9B34FB)] = ByteArray("two"); + + NSMutableDictionary *actual = + ::nearby::apple::ObjCServiceDataFromCPP(service_data); + XCTAssertEqualObjects(actual[serviceUUID1], data1); + XCTAssertEqualObjects(actual[serviceUUID2], data2); +} + #pragma mark - Objective-C to C++ - (void)testCPPUUIDFromObjC16Bit { diff --git a/internal/platform/implementation/apple/Tests/GNCBleTest.mm b/internal/platform/implementation/apple/Tests/GNCBleTest.mm deleted file mode 100644 index d8679575..00000000 --- a/internal/platform/implementation/apple/Tests/GNCBleTest.mm +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2022 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. - -#import -#include "internal/platform/implementation/apple/bluetooth_adapter.h" - -#include -#include -#include - -#include "internal/platform/byte_array.h" -#include "internal/platform/implementation/ble_v2.h" -#include "internal/platform/implementation/bluetooth_adapter.h" -#include "internal/platform/implementation/platform.h" - -using ::nearby::ByteArray; -using ::nearby::Uuid; -using ::nearby::api::BluetoothAdapter; -using ::nearby::api::ImplementationPlatform; -using ::nearby::api::ble_v2::BleAdvertisementData; -using ::nearby::api::ble_v2::BleMedium; -using ::nearby::api::ble_v2::GattCharacteristic; -using ::nearby::api::ble_v2::TxPowerLevel; -using IOSBluetoothAdapter = ::nearby::apple::BluetoothAdapter; - -static const char *const kAdvertisementString = "\x0a\x0b\x0c\x0d"; -static const TxPowerLevel kTxPowerLevel = TxPowerLevel::kHigh; - -@interface GNCBleTest : XCTestCase -@end - -// TODO(b/222392304): More tests on GNCBleTest. -@implementation GNCBleTest { - std::unique_ptr _adapter; - std::unique_ptr _ble; -} - -- (void)setUp { - [super setUp]; - _adapter = ImplementationPlatform::CreateBluetoothAdapter(); - _ble = ImplementationPlatform::CreateBleV2Medium(*_adapter); -} - -- (void)testStartandStopAdvertising { - Uuid service_uuid(1234, 5678); - ByteArray advertisement_bytes{std::string(kAdvertisementString)}; - - // Assemble regular advertisement data. - BleAdvertisementData advertising_data; - advertising_data.is_extended_advertisement = false; - advertising_data.service_data = {{service_uuid, advertisement_bytes}}; - - XCTAssertTrue(_ble->StartAdvertising(advertising_data, - {.tx_power_level = kTxPowerLevel, .is_connectable = true})); - - [NSThread sleepForTimeInterval:0.1]; - - XCTAssertTrue(_ble->StopAdvertising()); -} - -- (void)testStartandStopScanning { - Uuid service_uuid(1234, 5678); - - XCTAssertTrue(_ble->StartScanning(service_uuid, kTxPowerLevel, BleMedium::ScanCallback{})); - - [NSThread sleepForTimeInterval:0.1]; - - XCTAssertTrue(_ble->StopScanning()); -} - -- (void)testGattServerWorking { - // Test creating gatt_server. - auto gatt_server = _ble->StartGattServer(/*ServerGattConnectionCallback=*/{}); - XCTAssert(gatt_server != nullptr); - - // Test creating characteristic. - Uuid service_uuid(1234, 5678); - Uuid characteristic_uuid(5678, 1234); - GattCharacteristic::Permission permission = GattCharacteristic::Permission::kRead; - GattCharacteristic::Property property = GattCharacteristic::Property::kRead; - - // NOLINTNEXTLINE - absl::optional gatt_characteristic = - gatt_server->CreateCharacteristic(service_uuid, characteristic_uuid, permission, property); - XCTAssertTrue(gatt_characteristic.has_value()); - - // Test updating characteristic. - ByteArray any_byte("any"); - XCTAssertTrue(gatt_server->UpdateCharacteristic(gatt_characteristic.value(), any_byte)); - - gatt_server->Stop(); -} - -- (void)testCreateGattClient { - IOSBluetoothAdapter *adapter = static_cast(_adapter.get()); - auto gatt_client = _ble->ConnectToGattServer(adapter->GetPeripheral(), kTxPowerLevel, {}); - - XCTAssert(gatt_client != nullptr); -} - -@end diff --git a/internal/platform/implementation/apple/Tests/GNCBluetoothAdapterTest.mm b/internal/platform/implementation/apple/Tests/GNCBluetoothAdapterTest.mm deleted file mode 100644 index bb4955c8..00000000 --- a/internal/platform/implementation/apple/Tests/GNCBluetoothAdapterTest.mm +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2022 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. - -#import - -#include - -#include "internal/platform/implementation/apple/bluetooth_adapter.h" -#include "internal/platform/implementation/ble_v2.h" -#include "internal/platform/implementation/bluetooth_adapter.h" - -using ::nearby::apple::BlePeripheral; -using ::nearby::apple::BluetoothAdapter; -using ScanMode = ::nearby::api::BluetoothAdapter::ScanMode; -using Status = ::nearby::api::BluetoothAdapter::Status; - -static const char kAdapterName[] = "MyBtAdapter"; -static const char kMacAddress[] = "4C:8B:1D:CE:BA:D1"; - -@interface GNCBluetoothAdapterTest : XCTestCase -@end - -@implementation GNCBluetoothAdapterTest - -- (void)testName { - BluetoothAdapter adapter; - - XCTAssertTrue(adapter.SetName(kAdapterName)); - - XCTAssertEqual(adapter.GetName(), std::string(kAdapterName)); -} - -- (void)testGetScanMode { - BluetoothAdapter adapter; - - // Always return kNone as ScanMode is not supported . - XCTAssertEqual(adapter.GetScanMode(), ScanMode::kNone); -} - -- (void)testSetScanMode_DefaultUnsupported { - BluetoothAdapter adapter; - - XCTAssertFalse(adapter.SetScanMode(ScanMode::kNone)); - XCTAssertFalse(adapter.SetScanMode(ScanMode::kConnectable)); - XCTAssertFalse(adapter.SetScanMode(ScanMode::kConnectableDiscoverable)); -} - -- (void)testSetStatus { - BluetoothAdapter adapter; - - XCTAssertTrue(adapter.SetStatus(Status::kDisabled)); - XCTAssertFalse(adapter.IsEnabled()); - - XCTAssertTrue(adapter.SetStatus(Status::kEnabled)); - XCTAssertTrue(adapter.IsEnabled()); -} - -- (void)testMacAddress { - BluetoothAdapter adapter; - - adapter.SetMacAddress(kMacAddress); - - XCTAssertEqual(adapter.GetMacAddress(), std::string(kMacAddress)); -} - -- (void)testGetPeripheral { - BluetoothAdapter adapter; - - adapter.SetMacAddress(kMacAddress); - - // The peripheral from adapter, the MAC address is the same. - BlePeripheral& peripheral = adapter.GetPeripheral(); - XCTAssertEqual(adapter.GetMacAddress(), peripheral.GetAddress()); -} - -@end diff --git a/internal/platform/implementation/apple/Tests/GNCFakeCentralManager.h b/internal/platform/implementation/apple/Tests/GNCFakeCentralManager.h new file mode 100644 index 00000000..2e2c15e5 --- /dev/null +++ b/internal/platform/implementation/apple/Tests/GNCFakeCentralManager.h @@ -0,0 +1,70 @@ +// 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. + +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCCentralManager.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A fake implementation of @c GNCCentralManager to inject for testing. */ +@interface GNCFakeCentralManager : NSObject + +/** The list of services being scanned for. */ +@property(nonatomic, nullable, readonly) NSArray *serviceUUIDs; + +/** + * Similates a @c connectPeripheral:options: error. + * + * Setting this error to a value other than @c nil will simulate a failure when calling + * @c connectPeripheral:options: and will call the + * @c gnc_centralManager:didFailToConnectPeripheral:error: delegate method with the provided error. + */ +@property(nonatomic, nullable, readwrite) NSError *didFailToConnectPeripheralError; + +/** + * Simulates a state update event. + * + * Updates the central manager state to the provided value and calls the + * @c gnc_centralManagerDidUpdateState: delegate method. + * + * @param fakeState The new state to transition to. + */ +- (void)simulateCentralManagerDidUpdateState:(CBManagerState)fakeState; + +/** + * Simulates a peripheral discovery event. + * + * Calls the @c gnc_centralManager:didDiscoverPeripheral:advertisementData:RSSI: delegate method. + * + * @param peripheral The discovered peripheral. + * @param peripheral A dictionary containing any advertisement data. + */ +- (void)simulateCentralManagerDidDiscoverPeripheral:(id)peripheral + advertisementData: + (NSDictionary *)advertisementData; + +/** + * Simulates a peripheral disconnection event. + * + * Calls the @c gnc_centralManager:didDisconnectPeripheral:error: delegate method. + * + * @param peripheral The now-disconnected peripheral. + */ +- (void)simulateCentralManagerDidDisconnectPeripheral:(id)peripheral; + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Tests/GNCFakeCentralManager.m b/internal/platform/implementation/apple/Tests/GNCFakeCentralManager.m new file mode 100644 index 00000000..dc080f7e --- /dev/null +++ b/internal/platform/implementation/apple/Tests/GNCFakeCentralManager.m @@ -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. + +#import "internal/platform/implementation/apple/Tests/GNCFakeCentralManager.h" + +#import +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCCentralManager.h" +#import "internal/platform/implementation/apple/Tests/GNCFakePeripheral.h" + +@implementation GNCFakeCentralManager { + CBManagerState _state; + NSArray *_serviceUUIDs; +} + +@synthesize centralDelegate; + +- (instancetype)init { + self = [super init]; + if (self) { + _state = CBManagerStateUnknown; + } + return self; +} + +- (CBManagerState)state { + return _state; +} + +- (void)scanForPeripheralsWithServices:(nullable NSArray *)serviceUUIDs + options:(nullable NSDictionary *)options { + _serviceUUIDs = serviceUUIDs; +} + +- (void)connectPeripheral:(id)peripheral + options:(nullable NSDictionary *)options { + if (_didFailToConnectPeripheralError) { + [centralDelegate gnc_centralManager:self + didFailToConnectPeripheral:peripheral + error:_didFailToConnectPeripheralError]; + return; + } + [centralDelegate gnc_centralManager:self didConnectPeripheral:peripheral]; +} + +- (void)stopScan { +} + +#pragma mark - Testing Helpers + +- (NSArray *)serviceUUIDs { + return _serviceUUIDs; +} + +- (void)simulateCentralManagerDidUpdateState:(CBManagerState)fakeState { + _state = fakeState; + [centralDelegate gnc_centralManagerDidUpdateState:self]; +} + +- (void)simulateCentralManagerDidDiscoverPeripheral:(id)peripheral + advertisementData: + (NSDictionary *)advertisementData { + [centralDelegate gnc_centralManager:self + didDiscoverPeripheral:peripheral + advertisementData:advertisementData + RSSI:[NSNumber numberWithInt:0]]; +} + +- (void)simulateCentralManagerDidDisconnectPeripheral:(id)peripheral { + [centralDelegate gnc_centralManager:self didDisconnectPeripheral:peripheral error:nil]; +} + +@end diff --git a/internal/platform/implementation/apple/Tests/GNCFakePeripheral.h b/internal/platform/implementation/apple/Tests/GNCFakePeripheral.h new file mode 100644 index 00000000..0d62478d --- /dev/null +++ b/internal/platform/implementation/apple/Tests/GNCFakePeripheral.h @@ -0,0 +1,60 @@ +// 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. + +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A fake implementation of @c GNCPeripheral to inject for testing. */ +@interface GNCFakePeripheral : NSObject + +/** + * Similates a @c discoverServices: error. + * + * Setting this error to a value other than @c nil will simulate a failure when calling + * @c discoverServices: and will call the + * @c gnc_peripheral:didDiscoverServices: delegate method with the provided + * error. + */ +@property(nonatomic, nullable, readwrite) NSError *discoverServicesError; + +/** + * Similates a @c discoverCharacteristics:forService: error. + * + * Setting this error to a value other than @c nil will simulate a failure when calling + * @c discoverCharacteristics:forService: and will call the + * @c gnc_peripheral:didDiscoverCharacteristicsForService:error: delegate method with the provided + * error. + */ +@property(nonatomic, nullable, readwrite) NSError *discoverCharacteristicsForServiceError; + +/** + * Similates a @c readValueForCharacteristic: error. + * + * Setting this error to a value other than @c nil will simulate a failure when calling + * @c discoverCharacteristics:forService: and will call the + * @c gnc_peripheral:didUpdateValueForCharacteristic:error: delegate method with the provided + * error. + */ +@property(nonatomic, nullable, readwrite) NSError *readValueForCharacteristicError; + +/** Similates a delay in all delegate calls by the specified amount. */ +@property(nonatomic, readwrite) NSTimeInterval delegateDelay; + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Tests/GNCFakePeripheral.m b/internal/platform/implementation/apple/Tests/GNCFakePeripheral.m new file mode 100644 index 00000000..ebed3f24 --- /dev/null +++ b/internal/platform/implementation/apple/Tests/GNCFakePeripheral.m @@ -0,0 +1,124 @@ +// 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. + +#import "internal/platform/implementation/apple/Tests/GNCFakePeripheral.h" + +#import +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface CBService () + +// Change property to readwrite for tests. +@property(retain, readwrite, nullable) NSArray *characteristics; + +@end + +@interface CBCharacteristic () + +// Change property to readwrite for tests. +@property(retain, readwrite, nullable) NSData *value; + +@end + +@implementation GNCFakePeripheral { + NSMutableArray *_services; + NSUUID *_identifier; +} + +@synthesize peripheralDelegate; + +- (instancetype)init { + self = [super init]; + if (self) { + _services = [[NSMutableArray alloc] init]; + _identifier = [[NSUUID alloc] init]; + } + return self; +} + +- (NSUUID *)identifier { + return _identifier; +} + +- (nullable NSArray *)services { + return _services; +} + +- (void)discoverServices:(nullable NSArray *)serviceUUIDs { + [self delayDelegateUsingBlock:^() { + if (!_discoverServicesError) { + for (CBUUID *serviceUUID in serviceUUIDs) { + [_services addObject:[[CBMutableService alloc] initWithType:serviceUUID primary:YES]]; + } + } + + [peripheralDelegate gnc_peripheral:self didDiscoverServices:_discoverServicesError]; + }]; +} + +- (void)discoverCharacteristics:(nullable NSArray *)characteristicUUIDs + forService:(CBService *)service { + [self delayDelegateUsingBlock:^() { + if (!_discoverCharacteristicsForServiceError) { + NSMutableArray *characteristics = service.characteristics.mutableCopy; + if (!characteristics) { + characteristics = [NSMutableArray array]; + } + for (CBUUID *characteristicUUID in characteristicUUIDs) { + [characteristics addObject:[[CBMutableCharacteristic alloc] + initWithType:characteristicUUID + properties:CBCharacteristicPropertyRead + value:nil + permissions:CBAttributePermissionsReadable]]; + } + service.characteristics = characteristics; + } + + [peripheralDelegate gnc_peripheral:self + didDiscoverCharacteristicsForService:service + error:_discoverCharacteristicsForServiceError]; + }]; +} + +- (void)readValueForCharacteristic:(CBCharacteristic *)characteristic { + [self delayDelegateUsingBlock:^() { + if (!_readValueForCharacteristicError) { + characteristic.value = [NSData data]; + } + + [peripheralDelegate gnc_peripheral:self + didUpdateValueForCharacteristic:characteristic + error:_readValueForCharacteristicError]; + }]; +} + +- (void)delayDelegateUsingBlock:(void (^)())block { + if (_delegateDelay <= 0) { + block(); + } else { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, _delegateDelay * NSEC_PER_SEC), + dispatch_get_main_queue(), ^{ + block(); + }); + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Tests/GNCFakePeripheralManager.m b/internal/platform/implementation/apple/Tests/GNCFakePeripheralManager.m index 96cbd8ea..297730fa 100644 --- a/internal/platform/implementation/apple/Tests/GNCFakePeripheralManager.m +++ b/internal/platform/implementation/apple/Tests/GNCFakePeripheralManager.m @@ -61,9 +61,6 @@ BOOL _isAdvertising; NSDictionary *_advertisementData; NSMutableArray *_services; - - // Used to deliver delegate callbacks. - dispatch_queue_t _queue; } @synthesize peripheralDelegate; @@ -79,7 +76,6 @@ _state = CBManagerStateUnknown; _advertisementData = nil; _services = [[NSMutableArray alloc] init]; - _queue = dispatch_queue_create("com.nearby.GNCFakePeripheralManager", DISPATCH_QUEUE_SERIAL); } return self; } @@ -96,9 +92,7 @@ if (!_didAddServiceError) { [_services addObject:service]; } - dispatch_async(_queue, ^{ - [peripheralDelegate gnc_peripheralManager:self didAddService:service error:_didAddServiceError]; - }); + [peripheralDelegate gnc_peripheralManager:self didAddService:service error:_didAddServiceError]; } - (void)removeService:(CBMutableService *)service { @@ -112,10 +106,8 @@ - (void)startAdvertising:(NSDictionary *)advertisementData { _isAdvertising = _didStartAdvertisingError == nil; _advertisementData = advertisementData; - dispatch_async(_queue, ^{ - [peripheralDelegate gnc_peripheralManagerDidStartAdvertising:self - error:_didStartAdvertisingError]; - }); + [peripheralDelegate gnc_peripheralManagerDidStartAdvertising:self + error:_didStartAdvertisingError]; } - (void)respondToRequest:(CBATTRequest *)request withResult:(CBATTError)result { @@ -126,6 +118,10 @@ [_respondToRequestErrorExpectation fulfill]; } +- (void)stopAdvertising { + _isAdvertising = false; +} + #pragma mark - Testing Helpers - (NSArray *)services { @@ -138,18 +134,14 @@ - (void)simulatePeripheralManagerDidUpdateState:(CBManagerState)fakeState { _state = fakeState; - dispatch_async(_queue, ^{ - [peripheralDelegate gnc_peripheralManagerDidUpdateState:self]; - }); + [peripheralDelegate gnc_peripheralManagerDidUpdateState:self]; } - (void)simulatePeripheralManagerDidReceiveReadRequestForService:(CBUUID *)service characteristic:(CBUUID *)characteristic { CBATTRequest *request = [[CBATTRequest alloc] initWithService:service characteristic:characteristic]; - dispatch_async(_queue, ^{ - [peripheralDelegate gnc_peripheralManager:self didReceiveReadRequest:request]; - }); + [peripheralDelegate gnc_peripheralManager:self didReceiveReadRequest:request]; } @end diff --git a/internal/platform/implementation/apple/Tests/GNCPlatformTest.mm b/internal/platform/implementation/apple/Tests/GNCPlatformTest.mm new file mode 100644 index 00000000..322d0725 --- /dev/null +++ b/internal/platform/implementation/apple/Tests/GNCPlatformTest.mm @@ -0,0 +1,83 @@ +// 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 "internal/platform/implementation/platform.h" + +#import +#import + +void GNCEnsureFileAtPath(std::string path) { + [NSFileManager.defaultManager + createDirectoryAtPath:[@(path.c_str()) stringByDeletingLastPathComponent] + withIntermediateDirectories:YES + attributes:nil + error:nil]; + [[NSData data] writeToFile:@(path.c_str()) options:0 error:nil]; +} + +@interface GNCPlatformTest : XCTestCase +@end + +@implementation GNCPlatformTest + +- (void)testGetCustomSavePath { + NSString *expected = [NSURL fileURLWithPath:@"a/b/c.d"].path; + std::string actual = nearby::api::ImplementationPlatform::GetCustomSavePath("a/b", "c.d"); + XCTAssertEqualObjects(@(actual.c_str()), expected); +} + +- (void)testGetCustomSavePathWithIllegalCharacters { + NSString *expected = [NSURL fileURLWithPath:@"a/b/Fi?le*: Name.ext"].path; + std::string actual = + nearby::api::ImplementationPlatform::GetCustomSavePath("a/b", "Fi?le*/ Name.ext"); + XCTAssertEqualObjects(@(actual.c_str()), expected); +} + +- (void)testGetCustomSavePathWithPathEscapingCharacters { + NSString *expected = [NSURL fileURLWithPath:@"a/b/..:c:..:d.e"].path; + std::string actual = + nearby::api::ImplementationPlatform::GetCustomSavePath("a/../../b", "../c/../d.e"); + XCTAssertEqualObjects(@(actual.c_str()), expected); +} + +- (void)testGetCustomSavePathDuplicateNames { + NSString *expected1 = [NSURL fileURLWithPath:@"a/b/cat.jpg"].path; + NSString *expected2 = [NSURL fileURLWithPath:@"a/b/cat 2.jpg"].path; + NSString *expected3 = [NSURL fileURLWithPath:@"a/b/cat 3.jpg"].path; + + std::string actual1 = nearby::api::ImplementationPlatform::GetCustomSavePath("a/b", "cat.jpg"); + GNCEnsureFileAtPath(actual1); + + std::string actual2 = nearby::api::ImplementationPlatform::GetCustomSavePath("a/b", "cat.jpg"); + GNCEnsureFileAtPath(actual2); + + std::string actual3 = nearby::api::ImplementationPlatform::GetCustomSavePath("a/b", "cat.jpg"); + + // Cleanup created files. + [NSFileManager.defaultManager removeItemAtPath:@(actual1.c_str()) error:nil]; + [NSFileManager.defaultManager removeItemAtPath:@(actual2.c_str()) error:nil]; + + XCTAssertEqualObjects(@(actual1.c_str()), expected1); + XCTAssertEqualObjects(@(actual2.c_str()), expected2); + XCTAssertEqualObjects(@(actual3.c_str()), expected3); +} + +- (void)testGetDownloadPath { + NSString *expected = + [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:@"a/b/c.d"].path; + std::string actual = nearby::api::ImplementationPlatform::GetDownloadPath("a/b", "c.d"); + XCTAssertEqualObjects(@(actual.c_str()), expected); +} + +@end diff --git a/internal/platform/implementation/apple/Tests/NSData+GNCWebSafeBase64Test.m b/internal/platform/implementation/apple/Tests/NSData+GNCWebSafeBase64Test.m index ec1c14b6..8310962c 100644 --- a/internal/platform/implementation/apple/Tests/NSData+GNCWebSafeBase64Test.m +++ b/internal/platform/implementation/apple/Tests/NSData+GNCWebSafeBase64Test.m @@ -25,7 +25,7 @@ - (void)testEncodingWithPadding { NSString *expected = @"AQ"; NSData *data = [[NSData alloc] initWithBase64EncodedString:@"AQ==" options:0]; - NSString *actual = [data webSafebase64EncodedString]; + NSString *actual = [data webSafeBase64EncodedString]; XCTAssertEqualObjects(expected, actual); } @@ -35,8 +35,58 @@ [[NSData alloc] initWithBase64EncodedString: @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" options:0]; - NSString *actual = [data webSafebase64EncodedString]; + NSString *actual = [data webSafeBase64EncodedString]; XCTAssertEqualObjects(expected, actual); } +- (void)testDecodingWithoutPadding { + NSData *expected = [[NSData alloc] initWithBase64EncodedString:@"AQ==" options:0]; + NSData *actual = [[NSData alloc] initWithWebSafeBase64EncodedString:@"AQ"]; + XCTAssertNotNil(actual); + XCTAssertEqualObjects(expected, actual); +} + +- (void)testDecodingNoPad { + NSData *expected = [[NSData alloc] initWithBase64EncodedString:@"aaaa" options:0]; + NSData *actual = [[NSData alloc] initWithWebSafeBase64EncodedString:@"aaaa"]; + XCTAssertNotNil(actual); + XCTAssertEqualObjects(expected, actual); +} + +- (void)testDecoding1Pad { + NSData *expected = [[NSData alloc] initWithBase64EncodedString:@"aaa=" options:0]; + NSData *actual = [[NSData alloc] initWithWebSafeBase64EncodedString:@"aaa"]; + XCTAssertNotNil(actual); + XCTAssertEqualObjects(expected, actual); +} + +- (void)testDecoding2Pad { + NSData *expected = [[NSData alloc] initWithBase64EncodedString:@"aa==" options:0]; + NSData *actual = [[NSData alloc] initWithWebSafeBase64EncodedString:@"aa"]; + XCTAssertNotNil(actual); + XCTAssertEqualObjects(expected, actual); +} + +- (void)testDecodingSingleCharacterInLastQuadruple { + NSData *actual = [[NSData alloc] initWithWebSafeBase64EncodedString:@"aaaab"]; + XCTAssertNil(actual); +} + +- (void)testDecodingWithAllValidCharacters { + NSData *expected = + [[NSData alloc] initWithBase64EncodedString: + @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + options:0]; + NSData *actual = + [[NSData alloc] initWithWebSafeBase64EncodedString: + @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"]; + XCTAssertNotNil(actual); + XCTAssertEqualObjects(expected, actual); +} + +- (void)testDecodingWithIllegalCharacters { + NSData *actual = [[NSData alloc] initWithWebSafeBase64EncodedString:@"@#$^&*()"]; + XCTAssertNil(actual); +} + @end diff --git a/internal/platform/implementation/apple/ble.h b/internal/platform/implementation/apple/ble.h index 6d41a16d..fd540fe7 100644 --- a/internal/platform/implementation/apple/ble.h +++ b/internal/platform/implementation/apple/ble.h @@ -12,218 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_APPLE_BLE_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_APPLE_BLE_H_ +// Note: File language is detected using heuristics. Many Objective-C++ headers are incorrectly +// classified as C++ resulting in invalid linter errors. The use of "NSArray" and other Foundation +// classes like "NSData", "NSDictionary" and "NSUUID" are highly weighted for Objective-C and +// Objective-C++ scores. Oddly, "#import " does not contribute any points. +// This comment alone should be enough to trick the IDE in to believing this is actually some sort +// of Objective-C file. See: cs/google3/devtools/search/lang/recognize_language_classifiers_data -#import #import -#include -#include -#include - -#include "absl/types/optional.h" -#include "internal/platform/cancellation_flag.h" -#include "internal/platform/implementation/apple/bluetooth_adapter.h" -#include "internal/platform/implementation/ble_v2.h" -#include "internal/platform/implementation/bluetooth_adapter.h" - -#import "internal/platform/implementation/apple/Mediums/GNCMConnection.h" - -@class GNCMBlePeripheral, GNCMBleCentral; - -namespace nearby { -namespace apple { - -/** InputStream that reads from GNCMConnection. */ -class BleInputStream : public InputStream { - public: - BleInputStream(); - ~BleInputStream() override; - - ExceptionOr Read(std::int64_t size) override; - Exception Close() override; - - GNCMConnectionHandlers *GetConnectionHandlers() { return connectionHandlers_; } - - private: - GNCMConnectionHandlers *connectionHandlers_; - NSMutableArray *newDataPackets_; - NSMutableData *accumulatedData_; - NSCondition *condition_; -}; - -/** OutputStream that writes to GNCMConnection. */ -class BleOutputStream : public OutputStream { - public: - explicit BleOutputStream(id connection) - : connection_(connection), condition_([[NSCondition alloc] init]) {} - ~BleOutputStream() override; - - Exception Write(const ByteArray &data) override; - Exception Flush() override; - Exception Close() override; - - private: - id connection_; - NSCondition *condition_; -}; - -/** Concrete BleSocket implementation. */ -class BleSocket : public api::ble_v2::BleSocket { - public: - BleSocket(id connection, BlePeripheral *peripheral); - ~BleSocket() override; - - InputStream &GetInputStream() override { return *input_stream_; } - OutputStream &GetOutputStream() override { return *output_stream_; } - Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); - BlePeripheral *GetRemotePeripheral() override { return peripheral_; } - - bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_); - - private: - void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - mutable absl::Mutex mutex_; - bool closed_ ABSL_GUARDED_BY(mutex_) = false; - std::unique_ptr input_stream_; - std::unique_ptr output_stream_; - BlePeripheral *peripheral_; -}; - -/** Concrete BleServerSocket implementation. */ -class BleServerSocket : public api::ble_v2::BleServerSocket { - public: - ~BleServerSocket() override; - - std::unique_ptr Accept() override ABSL_LOCKS_EXCLUDED(mutex_); - Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); - - bool Connect(std::unique_ptr socket) ABSL_LOCKS_EXCLUDED(mutex_); - void SetCloseNotifier(absl::AnyInvocable notifier) ABSL_LOCKS_EXCLUDED(mutex_); - - private: - Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - mutable absl::Mutex mutex_; - absl::CondVar cond_; - absl::flat_hash_set> pending_sockets_ ABSL_GUARDED_BY(mutex_); - absl::AnyInvocable close_notifier_ ABSL_GUARDED_BY(mutex_); - bool closed_ ABSL_GUARDED_BY(mutex_) = false; -}; - -/** Concrete BleMedium implementation. */ -class BleMedium : public api::ble_v2::BleMedium { - public: - explicit BleMedium(api::BluetoothAdapter &adapter); - - // api::BleMedium: - bool StartAdvertising(const api::ble_v2::BleAdvertisementData &advertising_data, - api::ble_v2::AdvertiseParameters advertise_set_parameters) override; - bool StopAdvertising() override; - std::unique_ptr StartAdvertising( - const api::ble_v2::BleAdvertisementData &advertising_data, - api::ble_v2::AdvertiseParameters advertise_parameters, AdvertisingCallback callback) override; - - bool StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, - api::ble_v2::BleMedium::ScanCallback scan_callback) override; - bool StopScanning() override; - std::unique_ptr StartScanning(const Uuid &service_uuid, - api::ble_v2::TxPowerLevel tx_power_level, - ScanningCallback callback) override; - std::unique_ptr StartGattServer( - api::ble_v2::ServerGattConnectionCallback callback) override; - std::unique_ptr ConnectToGattServer( - api::ble_v2::BlePeripheral &peripheral, api::ble_v2::TxPowerLevel tx_power_level, - api::ble_v2::ClientGattConnectionCallback callback) override; - std::unique_ptr OpenServerSocket( - const std::string &service_id) override; - std::unique_ptr Connect(const std::string &service_id, - api::ble_v2::TxPowerLevel tx_power_level, - api::ble_v2::BlePeripheral &peripheral, - CancellationFlag *cancellation_flag) override; - bool IsExtendedAdvertisementsAvailable() override; - - bool GetRemotePeripheral(const std::string& mac_address, - GetRemotePeripheralCallback callback) override { - return false; - } - - bool GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id, - GetRemotePeripheralCallback callback) override { - return false; - } - - private: - // A concrete implemenation for GattServer. - class GattServer : public api::ble_v2::GattServer { - public: - GattServer() = default; - GattServer(BluetoothAdapter *adapter, GNCMBlePeripheral *peripheral) - : adapter_(adapter), peripheral_(peripheral) {} - - absl::optional CreateCharacteristic( - const Uuid &service_uuid, const Uuid &characteristic_uuid, - api::ble_v2::GattCharacteristic::Permission permission, - api::ble_v2::GattCharacteristic::Property property) override; - - bool UpdateCharacteristic(const api::ble_v2::GattCharacteristic &characteristic, - const nearby::ByteArray &value) override; - absl::Status NotifyCharacteristicChanged(const api::ble_v2::GattCharacteristic &characteristic, - bool confirm, const ByteArray &new_value) override; - void Stop() override; - BlePeripheral &GetBlePeripheral() override { return adapter_->GetPeripheral(); } - - private: - BluetoothAdapter *adapter_ = nullptr; - GNCMBlePeripheral *peripheral_; - }; - - // A concrete implemenation for GattClient. - class GattClient : public api::ble_v2::GattClient { - public: - GattClient() = default; - explicit GattClient(GNCMBleCentral *central, const std::string &peripheral_id) - : central_(central), peripheral_id_(peripheral_id) {} - - bool DiscoverServiceAndCharacteristics(const Uuid &service_uuid, - const std::vector &characteristic_uuids) override; - - // NOLINTNEXTLINE - absl::optional GetCharacteristic( - const Uuid &service_uuid, const Uuid &characteristic_uuid) override; - - // NOLINTNEXTLINE - absl::optional ReadCharacteristic( - const api::ble_v2::GattCharacteristic &characteristic) override; - - bool WriteCharacteristic(const api::ble_v2::GattCharacteristic &characteristic, - absl::string_view value, - api::ble_v2::GattClient::WriteType write_type) override; - - bool SetCharacteristicSubscription( - const api::ble_v2::GattCharacteristic &characteristic, bool enable, - absl::AnyInvocable on_characteristic_changed_cb) override; - - void Disconnect() override; - - private: - GNCMBleCentral *central_; - std::string peripheral_id_; - absl::flat_hash_map - gatt_characteristic_values_; - }; - - absl::Mutex mutex_; - BluetoothAdapter *adapter_; - GNCMBlePeripheral *peripheral_; - GNCMBleCentral *central_; - absl::flat_hash_map server_sockets_ ABSL_GUARDED_BY(mutex_); - dispatch_queue_t callback_queue_; -}; - -} // namespace apple -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_APPLE_BLE_H_ +#import "internal/platform/implementation/apple/ble_medium.h" diff --git a/internal/platform/implementation/apple/ble.mm b/internal/platform/implementation/apple/ble.mm deleted file mode 100644 index a6fdfd77..00000000 --- a/internal/platform/implementation/apple/ble.mm +++ /dev/null @@ -1,600 +0,0 @@ -// Copyright 2022 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. - -#import "internal/platform/implementation/apple/ble.h" - -#include - -#include -#include -#include -#include - -#include "internal/platform/implementation/apple/bluetooth_adapter.h" -#include "internal/platform/implementation/apple/utils.h" -#include "internal/platform/implementation/ble_v2.h" - -#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleCentral.h" -#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBlePeripheral.h" - -namespace nearby { -namespace apple { - -using Permission = api::ble_v2::GattCharacteristic::Permission; -using Property = api::ble_v2::GattCharacteristic::Property; - -namespace { - -CBAttributePermissions PermissionToCBPermissions(Permission permission) { - CBAttributePermissions characteristPermissions = 0; - if ((permission & Permission::kRead) != Permission::kNone) { - characteristPermissions |= CBAttributePermissionsReadable; - } - if ((permission & Permission::kWrite) != Permission::kNone) { - characteristPermissions |= CBAttributePermissionsWriteable; - } - return characteristPermissions; -} - -CBCharacteristicProperties PropertiesToCBProperties(Property property) { - CBCharacteristicProperties characteristicProperties = 0; - if ((property & Property::kRead) != Property::kNone) { - characteristicProperties |= CBCharacteristicPropertyRead; - } - if ((property & Property::kWrite) != Property::kNone) { - characteristicProperties |= CBCharacteristicPropertyWrite; - } - if ((property & Property::kIndicate) != Property::kNone) { - characteristicProperties |= CBCharacteristicPropertyIndicate; - } - if ((property & Property::kNotify) != Property::kNone) { - characteristicProperties |= CBCharacteristicPropertyNotify; - } - return characteristicProperties; -} - -} // namespace - -using ::nearby::api::ble_v2::BleAdvertisementData; -using ::nearby::api::ble_v2::TxPowerLevel; -using ScanCallback = ::nearby::api::ble_v2::BleMedium::ScanCallback; - -/** InputStream that reads from GNCMConnection. */ -BleInputStream::BleInputStream() - : newDataPackets_([NSMutableArray array]), - accumulatedData_([NSMutableData data]), - condition_([[NSCondition alloc] init]) { - // Create the handlers of incoming data from the remote endpoint. - connectionHandlers_ = [GNCMConnectionHandlers - payloadHandler:^(NSData* data) { - [condition_ lock]; - // Add the incoming data to the data packet array to be processed in read() below. - [newDataPackets_ addObject:data]; - [condition_ signal]; - [condition_ unlock]; - } - disconnectedHandler:^{ - [condition_ lock]; - // Release the data packet array, meaning the stream has been closed or severed. - newDataPackets_ = nil; - [condition_ signal]; - [condition_ unlock]; - }]; -} - -BleInputStream::~BleInputStream() { - NSCAssert(!newDataPackets_, @"BleInputStream not closed before destruction"); -} - -ExceptionOr BleInputStream::Read(std::int64_t size) { - // Block until either (a) the connection has been closed, (b) we have enough data to return. - NSData* dataToReturn; - [condition_ lock]; - while (true) { - // Check if the stream has been closed or severed. - if (!newDataPackets_) break; - - if (newDataPackets_.count > 0) { - // Add the packet data to the accumulated data. - for (NSData* data in newDataPackets_) { - if (data.length > 0) { - [accumulatedData_ appendData:data]; - } - } - [newDataPackets_ removeAllObjects]; - } - - if ((size == -1) && (accumulatedData_.length > 0)) { - // Return all of the data. - dataToReturn = accumulatedData_; - accumulatedData_ = [NSMutableData data]; - break; - } else if (accumulatedData_.length > 0) { - // Return up to |size| bytes of the data. - std::int64_t sizeToReturn = (accumulatedData_.length < size) ? accumulatedData_.length : size; - NSRange range = NSMakeRange(0, (NSUInteger)sizeToReturn); - dataToReturn = [accumulatedData_ subdataWithRange:range]; - [accumulatedData_ replaceBytesInRange:range withBytes:nil length:0]; - break; - } - - [condition_ wait]; - } - [condition_ unlock]; - - if (dataToReturn) { - NSLog(@"[NEARBY] Input stream: Received data of size: %lu", (unsigned long)dataToReturn.length); - return ExceptionOr(ByteArrayFromNSData(dataToReturn)); - } else { - return ExceptionOr{Exception::kIo}; - } -} - -Exception BleInputStream::Close() { - // Unblock pending read operation. - [condition_ lock]; - newDataPackets_ = nil; - [condition_ signal]; - [condition_ unlock]; - return {Exception::kSuccess}; -} - -/** OutputStream that writes to GNCMConnection. */ -BleOutputStream::~BleOutputStream() { - NSCAssert(!connection_, @"BleOutputStream not closed before destruction"); -} - -Exception BleOutputStream::Write(const ByteArray& data) { - [condition_ lock]; - NSLog(@"[NEARBY] Sending data of size: %lu", (unsigned long)NSDataFromByteArray(data).length); - - NSMutableData* packet = [NSMutableData dataWithData:NSDataFromByteArray(data)]; - - // Send the data, blocking until the completion handler is called. - __block GNCMPayloadResult sendResult = GNCMPayloadResultFailure; - __block bool isComplete = NO; - NSCondition* condition = condition_; // don't capture |this| in completion - - // Check if connection_ is nil, then just don't wait and return as failure. - if (connection_ != nil) { - [connection_ sendData:packet - progressHandler:^(size_t count) { - } - completion:^(GNCMPayloadResult result) { - // Make sure we haven't already reported completion before. This prevents a crash - // where we try leaving a dispatch group more times than we entered it. - // b/79095653. - if (isComplete) { - return; - } - isComplete = YES; - sendResult = result; - [condition lock]; - [condition signal]; - [condition unlock]; - }]; - [condition_ wait]; - [condition_ unlock]; - } else { - sendResult = GNCMPayloadResultFailure; - [condition_ unlock]; - } - - if (sendResult == GNCMPayloadResultSuccess) { - return {Exception::kSuccess}; - } else { - return {Exception::kIo}; - } -} - -Exception BleOutputStream::Flush() { - // The write() function blocks until the data is received by the remote endpoint, so there's - // nothing to do here. - return {Exception::kSuccess}; -} - -Exception BleOutputStream::Close() { - // Unblock pending write operation. - [condition_ lock]; - connection_ = nil; - [condition_ signal]; - [condition_ unlock]; - return {Exception::kSuccess}; -} - -/** BleSocket implementation.*/ -BleSocket::BleSocket(id connection, BlePeripheral* peripheral) - : input_stream_(new BleInputStream()), - output_stream_(new BleOutputStream(connection)), - peripheral_(peripheral) {} - -BleSocket::~BleSocket() { - absl::MutexLock lock(&mutex_); - DoClose(); -} - -bool BleSocket::IsClosed() const { - absl::MutexLock lock(&mutex_); - return closed_; -} - -Exception BleSocket::Close() { - absl::MutexLock lock(&mutex_); - DoClose(); - return {Exception::kSuccess}; -} - -void BleSocket::DoClose() { - if (!closed_) { - input_stream_->Close(); - output_stream_->Close(); - closed_ = true; - } -} - -/** WifiLanServerSocket implementation. */ -BleServerSocket::~BleServerSocket() { - absl::MutexLock lock(&mutex_); - DoClose(); -} - -std::unique_ptr BleServerSocket::Accept() { - absl::MutexLock lock(&mutex_); - while (!closed_ && pending_sockets_.empty()) { - cond_.Wait(&mutex_); - } - // Return early if closed. - if (closed_) return {}; - - auto remote_socket = std::move(pending_sockets_.extract(pending_sockets_.begin()).value()); - return std::move(remote_socket); -} - -bool BleServerSocket::Connect(std::unique_ptr socket) { - absl::MutexLock lock(&mutex_); - if (closed_) { - return false; - } - // add client socket to the pending list - pending_sockets_.insert(std::move(socket)); - cond_.SignalAll(); - if (closed_) { - return false; - } - return true; -} - -void BleServerSocket::SetCloseNotifier(absl::AnyInvocable notifier) { - absl::MutexLock lock(&mutex_); - close_notifier_ = std::move(notifier); -} - -Exception BleServerSocket::Close() { - absl::MutexLock lock(&mutex_); - return DoClose(); -} - -Exception BleServerSocket::DoClose() { - bool should_notify = !closed_; - closed_ = true; - if (should_notify) { - cond_.SignalAll(); - if (close_notifier_) { - auto notifier = std::move(close_notifier_); - mutex_.Unlock(); - // Notifier may contain calls to public API, and may cause deadlock, if - // mutex_ is held during the call. - notifier(); - mutex_.Lock(); - } - } - return {Exception::kSuccess}; -} - -/** BleMedium implementation. */ -BleMedium::BleMedium(::nearby::api::BluetoothAdapter& adapter) - : adapter_(static_cast(&adapter)) {} - -bool BleMedium::StartAdvertising( - const BleAdvertisementData& advertising_data, - ::nearby::api::ble_v2::AdvertiseParameters advertise_set_parameters) { - if (advertising_data.service_data.empty()) { - return false; - } - const auto& service_uuid = advertising_data.service_data.begin()->first.Get16BitAsString(); - const ByteArray& service_data_bytes = advertising_data.service_data.begin()->second; - - if (!peripheral_) { - peripheral_ = [[GNCMBlePeripheral alloc] init]; - } - - auto& peripheral = adapter_->GetPeripheral(); - [peripheral_ - startAdvertisingWithServiceUUID:ObjCStringFromCppString(service_uuid) - advertisementData:NSDataFromByteArray(service_data_bytes) - endpointConnectedHandler:^GNCMConnectionHandlers*(id connection) { - // TODO(edwinwu): This server_socket is supposed to be gotten from the map by key of - // servcie_id. We now always get the first iteration since we don't know the key now. - // Try the way to move the Ble socket frame verification up to one layer. - std::string service_id; - BleServerSocket* server_socket; - if (!server_sockets_.empty()) { - service_id = server_sockets_.begin()->first; - server_socket = server_sockets_.begin()->second; - } else { - return nil; - } - auto socket = std::make_unique(connection, &peripheral); - GNCMConnectionHandlers* connectionHandlers = - static_cast(socket->GetInputStream()).GetConnectionHandlers(); - server_socket->Connect(std::move(socket)); - return connectionHandlers; - } - callbackQueue:callback_queue_]; - return true; -} - -bool BleMedium::StopAdvertising() { - peripheral_ = nil; - return true; -} -std::unique_ptr BleMedium::StartAdvertising( - const api::ble_v2::BleAdvertisementData& advertising_data, - api::ble_v2::AdvertiseParameters advertise_parameters, - BleMedium::AdvertisingCallback callback) { - // TODO(hais): add real impl for iOs StartAdvertising - return std::make_unique(AdvertisingSession{}); -} -bool BleMedium::StartScanning(const Uuid& service_uuid, TxPowerLevel tx_power_level, - ScanCallback scan_callback) { - if (!central_) { - central_ = [[GNCMBleCentral alloc] init]; - } - - __block ScanCallback callback = std::move(scan_callback); - [central_ startScanningWithServiceUUID:ObjCStringFromCppString(service_uuid.Get16BitAsString()) - scanResultHandler:^(NSString* peripheralID, NSData* serviceData) { - BleAdvertisementData advertisement_data; - advertisement_data.service_data = {{service_uuid, ByteArrayFromNSData(serviceData)}}; - BlePeripheral& peripheral = adapter_->GetPeripheral(); - peripheral.SetPeripheralId(CppStringFromObjCString(peripheralID)); - callback.advertisement_found_cb(peripheral, advertisement_data); - } - requestConnectionHandler:^(GNCMBleConnectionRequester connectionRequester) { - BlePeripheral& peripheral = adapter_->GetPeripheral(); - peripheral.SetConnectionRequester(connectionRequester); - } - callbackQueue:callback_queue_]; - - return true; -} - -bool BleMedium::StopScanning() { - central_ = nil; - return true; -} - -std::unique_ptr BleMedium::StartScanning( - const Uuid& service_uuid, TxPowerLevel tx_power_level, BleMedium::ScanningCallback callback) { - // TODO(hais): add real impl for windows StartScanning. - return std::make_unique(ScanningSession{}); -} - -std::unique_ptr BleMedium::StartGattServer( - api::ble_v2::ServerGattConnectionCallback callback) { - if (!peripheral_) { - peripheral_ = [[GNCMBlePeripheral alloc] init]; - } - return std::make_unique(adapter_, peripheral_); -} - -std::unique_ptr BleMedium::ConnectToGattServer( - api::ble_v2::BlePeripheral& peripheral, TxPowerLevel tx_power_level, - api::ble_v2::ClientGattConnectionCallback callback) { - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - __block NSError* connectedError; - BlePeripheral iosPeripheral = static_cast(peripheral); - std::string peripheral_id = iosPeripheral.GetPeripheralId(); - [central_ connectGattServerWithPeripheralID:ObjCStringFromCppString(peripheral_id) - gattConnectionResultHandler:^(NSError* _Nullable error) { - connectedError = error; - dispatch_semaphore_signal(semaphore); - }]; - dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC)); - - if (connectedError) { - return nullptr; - } - return std::make_unique(central_, peripheral_id); -} - -std::unique_ptr BleMedium::OpenServerSocket( - const std::string& service_id) { - auto server_socket = std::make_unique(); - server_socket->SetCloseNotifier([this, service_id]() { - absl::MutexLock lock(&mutex_); - server_sockets_.erase(service_id); - }); - absl::MutexLock lock(&mutex_); - server_sockets_.insert({service_id, server_socket.get()}); - return server_socket; -} - -std::unique_ptr BleMedium::Connect(const std::string& service_id, - TxPowerLevel tx_power_level, - api::ble_v2::BlePeripheral& peripheral, - CancellationFlag* cancellation_flag) { - NSString* serviceID = ObjCStringFromCppString(service_id); - __block std::unique_ptr socket; - __block BlePeripheral ios_peripheral = static_cast(peripheral); - GNCMBleConnectionRequester connection_requester = ios_peripheral.GetConnectionRequester(); - if (!connection_requester) return {}; - - dispatch_group_t group = dispatch_group_create(); - dispatch_group_enter(group); - if (cancellation_flag->Cancelled()) { - NSLog(@"[NEARBY] BLE Connect: Has been cancelled: service_id=%@", serviceID); - dispatch_group_leave(group); // unblock - return {}; - } - - connection_requester(serviceID, ^(id connection) { - // If the connection wasn't successfully established, return a NULL socket. - if (connection) { - socket = std::make_unique(connection, &ios_peripheral); - } - - dispatch_group_leave(group); // unblock - return socket != nullptr - ? static_cast(socket->GetInputStream()).GetConnectionHandlers() - : nullptr; - }); - dispatch_group_wait(group, DISPATCH_TIME_FOREVER); - - // Send the (empty) intro packet, which the BLE advertiser is expecting. - if (socket != nullptr) { - socket->GetOutputStream().Write(ByteArray()); - } - - return std::move(socket); -} - -bool BleMedium::IsExtendedAdvertisementsAvailable() { return false; } - -// NOLINTNEXTLINE -absl::optional BleMedium::GattServer::CreateCharacteristic( - const Uuid& service_uuid, const Uuid& characteristic_uuid, - api::ble_v2::GattCharacteristic::Permission permission, - api::ble_v2::GattCharacteristic::Property property) { - api::ble_v2::GattCharacteristic characteristic = {.uuid = characteristic_uuid, - .service_uuid = service_uuid, - .permission = permission, - .property = property}; - [peripheral_ - addCBServiceWithUUID:[CBUUID - UUIDWithString:ObjCStringFromCppString( - characteristic.service_uuid.Get16BitAsString())]]; - [peripheral_ - addCharacteristic:[[CBMutableCharacteristic alloc] - initWithType:[CBUUID UUIDWithString:ObjCStringFromCppString(std::string( - characteristic.uuid))] - properties:PropertiesToCBProperties(characteristic.property) - value:nil - permissions:PermissionToCBPermissions(characteristic.permission)]]; - return characteristic; -} - -bool BleMedium::GattServer::UpdateCharacteristic( - const api::ble_v2::GattCharacteristic& characteristic, const nearby::ByteArray& value) { - [peripheral_ updateValue:NSDataFromByteArray(value) - forCharacteristic:[CBUUID UUIDWithString:ObjCStringFromCppString( - std::string(characteristic.uuid))]]; - return true; -} - -absl::Status BleMedium::GattServer::NotifyCharacteristicChanged( - const api::ble_v2::GattCharacteristic& characteristic, bool confirm, - const ByteArray& new_value) { - // no-op because client cannot request notifications. - return absl::UnimplementedError("Unimplemented!"); -} - -void BleMedium::GattServer::Stop() { [peripheral_ stopGATTService]; } - -bool BleMedium::GattClient::DiscoverServiceAndCharacteristics( - const Uuid& service_uuid, const std::vector& characteristic_uuids) { - // Discover all characteristics that may contain the advertisement. - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - gatt_characteristic_values_.clear(); - CBUUID* serviceUUID = [CBUUID UUIDWithString:ObjCStringFromCppString(std::string(service_uuid))]; - - absl::flat_hash_map gatt_characteristics; - NSMutableArray* characteristicUUIDs = - [NSMutableArray arrayWithCapacity:characteristic_uuids.size()]; - for (const auto& characteristic_uuid : characteristic_uuids) { - [characteristicUUIDs addObject:[CBUUID UUIDWithString:ObjCStringFromCppString( - std::string(characteristic_uuid))]]; - gatt_characteristics.insert({std::string(characteristic_uuid), characteristic_uuid}); - } - - [central_ discoverGattService:serviceUUID - gattCharacteristics:characteristicUUIDs - peripheralID:ObjCStringFromCppString(peripheral_id_) - gattDiscoverResultHandler:^(NSOrderedSet* _Nullable cb_characteristics) { - if (cb_characteristics != nil) { - for (CBCharacteristic* cb_characteristic in cb_characteristics) { - auto const& it = gatt_characteristics.find( - CppStringFromObjCString(cb_characteristic.UUID.UUIDString)); - if (it == gatt_characteristics.end()) continue; - - api::ble_v2::GattCharacteristic characteristic = {.uuid = it->second, - .service_uuid = service_uuid}; - gatt_characteristic_values_.insert( - {characteristic, ByteArrayFromNSData(cb_characteristic.value).string_data()}); - } - } - - dispatch_semaphore_signal(semaphore); - }]; - - dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC)); - - if (gatt_characteristic_values_.empty()) { - return false; - } - return true; -} - -// NOLINTNEXTLINE -absl::optional BleMedium::GattClient::GetCharacteristic( - const Uuid& service_uuid, const Uuid& characteristic_uuid) { - api::ble_v2::GattCharacteristic characteristic = {.uuid = characteristic_uuid, - .service_uuid = service_uuid}; - auto const it = gatt_characteristic_values_.find(characteristic); - if (it == gatt_characteristic_values_.end()) { - return absl::nullopt; // NOLINT - } - return it->first; -} - -// NOLINTNEXTLINE -absl::optional BleMedium::GattClient::ReadCharacteristic( - const api::ble_v2::GattCharacteristic& characteristic) { - auto const it = gatt_characteristic_values_.find(characteristic); - if (it == gatt_characteristic_values_.end()) { - return absl::nullopt; // NOLINT - } - return it->second; -} - -bool BleMedium::GattClient::WriteCharacteristic( - const api::ble_v2::GattCharacteristic& characteristic, absl::string_view value, - api::ble_v2::GattClient::WriteType write_type) { - // No op. - return false; -} - -bool BleMedium::GattClient::SetCharacteristicSubscription( - const api::ble_v2::GattCharacteristic& characteristic, bool enable, - absl::AnyInvocable on_characteristic_changed_cb) { - // No op since we can't write characteristics. - return false; -} - -void BleMedium::GattClient::Disconnect() { - [central_ disconnectGattServiceWithPeripheralID:ObjCStringFromCppString(peripheral_id_)]; -} - -} // namespace apple -} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_gatt_client.h b/internal/platform/implementation/apple/ble_gatt_client.h new file mode 100644 index 00000000..b9bf9ce7 --- /dev/null +++ b/internal/platform/implementation/apple/ble_gatt_client.h @@ -0,0 +1,88 @@ +// 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. + +// Note: File language is detected using heuristics. Many Objective-C++ headers are incorrectly +// classified as C++ resulting in invalid linter errors. The use of "NSArray" and other Foundation +// classes like "NSData", "NSDictionary" and "NSUUID" are highly weighted for Objective-C and +// Objective-C++ scores. Oddly, "#import " does not contribute any points. +// This comment alone should be enough to trick the IDE in to believing this is actually some sort +// of Objective-C file. See: cs/google3/devtools/search/lang/recognize_language_classifiers_data + +#import + +#include +#include + +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/uuid.h" + +@class GNCBLEGATTClient; + +namespace nearby { +namespace apple { + +class GattClient : public api::ble_v2::GattClient { + public: + explicit GattClient(GNCBLEGATTClient *gatt_client_); + ~GattClient() override = default; + + // Discovers the specified characteristics of a service. + // + // This method blocks until discovery has finished. + // + // Returns whether or not discovery finished successfully. + bool DiscoverServiceAndCharacteristics(const Uuid &service_uuid, + const std::vector &characteristic_uuids) override; + + // Retrieves a GATT characteristic. + // + // DiscoverServiceAndCharacteristics() must be called before this method to fetch all available + // services and characteristics first. + // + // On success, returns the characteristic. On error, returns nullptr. + std::optional GetCharacteristic( + const Uuid &service_uuid, const Uuid &characteristic_uuid) override; + + // Reads the requested characteristic from the associated remote device. + // + // On success, returns the characteristic's value. On error, returns nullptr. + std::optional ReadCharacteristic( + const api::ble_v2::GattCharacteristic &characteristic) override; + + // Writes a given characteristic and its values to the associated remote device. + // + // Returns whether or not the write was successful. + bool WriteCharacteristic(const api::ble_v2::GattCharacteristic &characteristic, + absl::string_view value, + api::ble_v2::GattClient::WriteType type) override; + + // Enable or disable notifications/indications for a given characteristic. + // + // Once notifications are enabled for a characteristic, on_characteristic_changed_cb will be + // triggered if the remote device indicates that the given characteristic has changed. + // + // Returns whether or not the subscription was successful. + bool SetCharacteristicSubscription( + const api::ble_v2::GattCharacteristic &characteristic, bool enable, + absl::AnyInvocable on_characteristic_changed_cb) override; + + // Disconnects an established connection, or cancels a connection attempt currently in progress. + void Disconnect() override; + + private: + GNCBLEGATTClient *gatt_client_; +}; + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_gatt_client.mm b/internal/platform/implementation/apple/ble_gatt_client.mm new file mode 100644 index 00000000..13cbb684 --- /dev/null +++ b/internal/platform/implementation/apple/ble_gatt_client.mm @@ -0,0 +1,134 @@ +// 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. + +#import "internal/platform/implementation/apple/ble_gatt_client.h" + +#import +#import + +#include +#include +#include + +#include "internal/platform/implementation/ble_v2.h" + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h" +#import "internal/platform/implementation/apple/ble_utils.h" +#import "GoogleToolboxForMac/GTMLogger.h" + +namespace nearby { +namespace apple { + +GattClient::GattClient(GNCBLEGATTClient *gatt_client) : gatt_client_(gatt_client) {} + +bool GattClient::DiscoverServiceAndCharacteristics(const Uuid &service_uuid, + const std::vector &characteristic_uuids) { + CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid); + NSMutableArray *characteristics = [[NSMutableArray alloc] init]; + for (const auto &uuid : characteristic_uuids) { + [characteristics addObject:CBUUID128FromCPP(uuid)]; + } + + NSCondition *condition = [[NSCondition alloc] init]; + [condition lock]; + __block NSError *blockError = nil; + [gatt_client_ discoverCharacteristicsWithUUIDs:characteristics + serviceUUID:serviceUUID + completionHandler:^(NSError *error) { + [condition lock]; + if (error != nil) { + GTMLoggerError(@"Error discovering characteristics: %@", error); + } + blockError = error; + [condition signal]; + [condition unlock]; + }]; + [condition wait]; + [condition unlock]; + return blockError == nil; +} + +std::optional GattClient::GetCharacteristic( + const Uuid &service_uuid, const Uuid &characteristic_uuid) { + CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid); + CBUUID *characteristicUUID = CBUUID128FromCPP(characteristic_uuid); + + NSCondition *condition = [[NSCondition alloc] init]; + [condition lock]; + __block GNCBLEGATTCharacteristic *blockCharacteristic = nil; + __block NSError *blockError = nil; + [gatt_client_ characteristicWithUUID:characteristicUUID + serviceUUID:serviceUUID + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, NSError *error) { + [condition lock]; + if (error != nil) { + GTMLoggerError(@"Error retrieving characteristic: %@", error); + } + blockCharacteristic = characteristic; + blockError = error; + [condition signal]; + [condition unlock]; + }]; + [condition wait]; + [condition unlock]; + if (blockCharacteristic == nil) { + return std::nullopt; + } + return CPPGATTCharacteristicFromObjC(blockCharacteristic); +} + +std::optional GattClient::ReadCharacteristic( + const api::ble_v2::GattCharacteristic &characteristic) { + NSCondition *condition = [[NSCondition alloc] init]; + [condition lock]; + __block NSData *blockValue = nil; + __block NSError *blockError = nil; + [gatt_client_ readValueForCharacteristic:ObjCGATTCharacteristicFromCPP(characteristic) + completionHandler:^(NSData *value, NSError *error) { + [condition lock]; + if (error != nil) { + GTMLoggerError(@"Error reading characteristic: %@", error); + } + blockValue = value; + blockError = error; + [condition signal]; + [condition unlock]; + }]; + [condition wait]; + [condition unlock]; + if (blockValue == nil) { + return std::nullopt; + } + return std::string((const char *)blockValue.bytes, blockValue.length); +} + +// TODO(b/290385712): Implement. +bool GattClient::WriteCharacteristic(const api::ble_v2::GattCharacteristic &characteristic, + absl::string_view value, + api::ble_v2::GattClient::WriteType type) { + return false; +} + +// TODO(b/290385712): Implement. +bool GattClient::SetCharacteristicSubscription( + const api::ble_v2::GattCharacteristic &characteristic, bool enable, + absl::AnyInvocable on_characteristic_changed_cb) { + return false; +} + +// TODO(b/290385712): Implement. +void GattClient::Disconnect() {} + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_gatt_server.h b/internal/platform/implementation/apple/ble_gatt_server.h new file mode 100644 index 00000000..abf5e8ea --- /dev/null +++ b/internal/platform/implementation/apple/ble_gatt_server.h @@ -0,0 +1,78 @@ +// 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. + +// Note: File language is detected using heuristics. Many Objective-C++ headers are incorrectly +// classified as C++ resulting in invalid linter errors. The use of "NSArray" and other Foundation +// classes like "NSData", "NSDictionary" and "NSUUID" are highly weighted for Objective-C and +// Objective-C++ scores. Oddly, "#import " does not contribute any points. +// This comment alone should be enough to trick the IDE in to believing this is actually some sort +// of Objective-C file. See: cs/google3/devtools/search/lang/recognize_language_classifiers_data + +#import + +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/uuid.h" + +#import "internal/platform/implementation/apple/ble_peripheral.h" + +@class GNCBLEGATTServer; + +namespace nearby { +namespace apple { + +class GattServer : public api::ble_v2::GattServer { + public: + explicit GattServer(GNCBLEGATTServer *gatt_server_); + ~GattServer() override = default; + + // Returns an empty BlePeripheral object. + // + // Use of this method should be avoided and its only purpose seems to be a check that the GATT + // server is valid. + api::ble_v2::BlePeripheral &GetBlePeripheral() override; + + // Creates a characteristic and adds it to the GATT server under the given characteristic and + // service UUIDs. + // + // Characteristics of the same service UUID will be put under one service rather than many + // services with the same UUID. + // + // Returns no value upon error. + std::optional CreateCharacteristic( + const Uuid &service_uuid, const Uuid &characteristic_uuid, + api::ble_v2::GattCharacteristic::Permission permission, + api::ble_v2::GattCharacteristic::Property property) override; + + // Updates a local characteristic with the provided value. + // + // Returns whether or not the update was successful. + bool UpdateCharacteristic(const api::ble_v2::GattCharacteristic &characteristic, + const nearby::ByteArray &value) override; + + // Send a notification or indication that a local characteristic has been updated. + // + // Returns an absl::Status indicating success or what went wrong. + absl::Status NotifyCharacteristicChanged(const api::ble_v2::GattCharacteristic &characteristic, + bool confirm, const ByteArray &new_value) override; + + // Stops a GATT server. + void Stop() override; + + private: + GNCBLEGATTServer *gatt_server_; + EmptyBlePeripheral peripheral_; +}; + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_gatt_server.mm b/internal/platform/implementation/apple/ble_gatt_server.mm new file mode 100644 index 00000000..57682c73 --- /dev/null +++ b/internal/platform/implementation/apple/ble_gatt_server.mm @@ -0,0 +1,104 @@ +// 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. + +#import "internal/platform/implementation/apple/ble_gatt_server.h" + +#import +#import + +#include "internal/platform/implementation/ble_v2.h" + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h" +#import "internal/platform/implementation/apple/ble_utils.h" +#import "internal/platform/implementation/apple/utils.h" +#import "GoogleToolboxForMac/GTMLogger.h" + +namespace nearby { +namespace apple { + +GattServer::GattServer(GNCBLEGATTServer *gatt_server) : gatt_server_(gatt_server) {} + +std::optional GattServer::CreateCharacteristic( + const Uuid &service_uuid, const Uuid &characteristic_uuid, + api::ble_v2::GattCharacteristic::Permission permission, + api::ble_v2::GattCharacteristic::Property property) { + CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid); + CBUUID *characteristicUUID = CBUUID128FromCPP(characteristic_uuid); + CBAttributePermissions permissions = CBAttributePermissionsFromCPP(permission); + CBCharacteristicProperties properties = CBCharacteristicPropertiesFromCPP(property); + + NSCondition *condition = [[NSCondition alloc] init]; + [condition lock]; + __block GNCBLEGATTCharacteristic *blockCharacteristic = nil; + [gatt_server_ createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID + permissions:permissions + properties:properties + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + [condition lock]; + if (error != nil) { + GTMLoggerError(@"Error creating characteristic: %@", error); + } + blockCharacteristic = characteristic; + [condition signal]; + [condition unlock]; + }]; + [condition wait]; + [condition unlock]; + if (blockCharacteristic == nil) { + return std::nullopt; + } + return CPPGATTCharacteristicFromObjC(blockCharacteristic); +} + +bool GattServer::UpdateCharacteristic(const api::ble_v2::GattCharacteristic &characteristic, + const nearby::ByteArray &value) { + NSCondition *condition = [[NSCondition alloc] init]; + [condition lock]; + __block NSError *blockError = nil; + [gatt_server_ updateCharacteristic:ObjCGATTCharacteristicFromCPP(characteristic) + value:NSDataFromByteArray(value) + completionHandler:^(NSError *error) { + [condition lock]; + if (error != nil) { + GTMLoggerError(@"Error updating characteristic: %@", error); + } + blockError = error; + [condition signal]; + [condition unlock]; + }]; + [condition wait]; + [condition unlock]; + return blockError == nil; +} + +// TODO(b/290385712): Implement. +absl::Status GattServer::NotifyCharacteristicChanged( + const api::ble_v2::GattCharacteristic &characteristic, bool confirm, + const ByteArray &new_value) { + return absl::UnimplementedError(""); +} + +void GattServer::Stop() { + [gatt_server_ stop]; +} + +// TODO(b/290385712): Implement. +api::ble_v2::BlePeripheral &GattServer::GetBlePeripheral() { + return peripheral_; +} + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_medium.h b/internal/platform/implementation/apple/ble_medium.h new file mode 100644 index 00000000..7b00fed3 --- /dev/null +++ b/internal/platform/implementation/apple/ble_medium.h @@ -0,0 +1,164 @@ +// Copyright 2022 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. + +// Note: File language is detected using heuristics. Many Objective-C++ headers are incorrectly +// classified as C++ resulting in invalid linter errors. The use of "NSArray" and other Foundation +// classes like "NSData", "NSDictionary" and "NSUUID" are highly weighted for Objective-C and +// Objective-C++ scores. Oddly, "#import " does not contribute any points. +// This comment alone should be enough to trick the IDE in to believing this is actually some sort +// of Objective-C file. See: cs/google3/devtools/search/lang/recognize_language_classifiers_data + +#import + +#include +#include + +#include "internal/platform/cancellation_flag.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/bluetooth_adapter.h" +#include "internal/platform/uuid.h" + +#import "internal/platform/implementation/apple/ble_peripheral.h" +#import "internal/platform/implementation/apple/ble_server_socket.h" +#import "internal/platform/implementation/apple/bluetooth_adapter_v2.h" + +@class GNCBLEMedium; +@class GNSCentralManager; +@class GNSPeripheralManager; +@class GNSPeripheralServiceManager; + +namespace nearby { +namespace apple { + +// The main BLE medium used inside of Nearby. This serves as the entry point for all BLE and GATT +// related operations. +class BleMedium : public api::ble_v2::BleMedium { + public: + BleMedium(); + ~BleMedium() override = default; + + // Async interface for StartAdvertising. + // + // Result status will be passed to start_advertising_result callback. To stop advertising, invoke + // the stop_advertising callback in AdvertisingSession. + // + // Advertising must be stopped before attempting to start advertising again. + std::unique_ptr StartAdvertising( + const api::ble_v2::BleAdvertisementData &advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters, + api::ble_v2::BleMedium::AdvertisingCallback callback) override; + + // Starts BLE advertising and returns whether or not it was successful. + // + // Advertising must be stopped before attempting to start advertising again. + bool StartAdvertising(const api::ble_v2::BleAdvertisementData &advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters) override; + + // Stops advertising. + // + // Returns whether or not advertising was successfully stopped. + bool StopAdvertising() override; + + // Async interface for StartScanning. + // + // Result status will be passed to start_scanning_result callback on a private queue. To stop + // scanning, invoke the stop_scanning callback in ScanningSession. + // + // Scanning must be stopped before attempting to start scanning again. + std::unique_ptr StartScanning( + const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::BleMedium::ScanningCallback callback) override; + + // Starts scanning and returns whether or not it was successful. + // + // Scanning must be stopped before attempting to start scanning again. + bool StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::BleMedium::ScanCallback callback) override; + + // Stops scanning. + // + // Returns whether or not scanning was successfully stopped. + bool StopScanning() override; + + // TODO(b/290385712): ServerGattConnectionCallback methods are not yet implemented. + // + // Starts a GATT server. Returns a nullptr upon error. + std::unique_ptr StartGattServer( + api::ble_v2::ServerGattConnectionCallback callback) override; + + // Connects to a GATT server and negotiates the specified connection parameters. Returns nullptr + // upon error. + // + // The peripheral must outlive the GATT client or undefined behavior will occur. The peripheral + // should not be modified by this method. + std::unique_ptr ConnectToGattServer( + api::ble_v2::BlePeripheral &peripheral, api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::ClientGattConnectionCallback callback) override; + + // Opens a BLE server socket based on service ID. + // + // On success, returns a new BleServerSocket. On error, returns nullptr. + std::unique_ptr OpenServerSocket( + const std::string &service_id) override; + + // TODO(b/290385712): cancellation_flag support is not yet implemented. + // + // Connects to a BLE peripheral. + // + // The peripheral must outlive the socket or undefined behavior will occur. The peripheral + // should not be modified by this method. + // + // On success, returns a new BleSocket. On error, returns nullptr. + std::unique_ptr Connect(const std::string &service_id, + api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::BlePeripheral &peripheral, + CancellationFlag *cancellation_flag) override; + + // Returns whether the hardware supports BOTH advertising extensions and extended scans. + // + // This is currently always false for all Apple hardware. + bool IsExtendedAdvertisementsAvailable() override; + + // A peripheral cannot be retreived via MAC address on Apple platforms. + // + // This always returns false and does not call the callback. + bool GetRemotePeripheral(const std::string &mac_address, + api::ble_v2::BleMedium::GetRemotePeripheralCallback callback) override; + + // Returns true if `id` refers to a known BLE peripheral and calls `callback` with a reference to + // said peripheral that is only guaranteed to be available for the duration of the callback. + // Otherwise, does not call the callback and returns false. + bool GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id, + api::ble_v2::BleMedium::GetRemotePeripheralCallback callback) override; + + private: + void HandleAdvertisementFound( + id peripheral, NSDictionary *serviceData, + absl::AnyInvocable + callback); + + GNCBLEMedium *medium_; + + absl::Mutex peripherals_mutex_; + absl::flat_hash_map> + peripherals_ ABSL_GUARDED_BY(peripherals_mutex_); + + GNSPeripheralServiceManager *socketPeripheralServiceManager_; + GNSPeripheralManager *socketPeripheralManager_; + GNSCentralManager *socketCentralManager_; +}; + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_medium.mm b/internal/platform/implementation/apple/ble_medium.mm new file mode 100644 index 00000000..ae64d334 --- /dev/null +++ b/internal/platform/implementation/apple/ble_medium.mm @@ -0,0 +1,384 @@ +// Copyright 2022 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. + +#import "internal/platform/implementation/apple/ble_medium.h" +#import "internal/platform/implementation/apple/utils.h" + +#import +#import + +#include +#include +#include +#include + +#include "internal/platform/implementation/apple/ble_utils.h" +#include "internal/platform/implementation/apple/utils.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/bluetooth_adapter.h" + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h" +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h" +#import "internal/platform/implementation/apple/ble_gatt_client.h" +#import "internal/platform/implementation/apple/ble_gatt_server.h" +#import "internal/platform/implementation/apple/ble_peripheral.h" +#import "internal/platform/implementation/apple/ble_server_socket.h" +#import "internal/platform/implementation/apple/ble_socket.h" +#import "internal/platform/implementation/apple/bluetooth_adapter_v2.h" +#import "GoogleToolboxForMac/GTMLogger.h" + +// TODO(b/293336684): Old Weave imports that need to be deleted once shared Weave is complete. +#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleConnection.h" +#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleUtils.h" +#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Central/GNSCentralManager.h" +#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Central/GNSCentralPeerManager.h" +#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Peripheral/GNSPeripheralManager.h" +#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Peripheral/GNSPeripheralServiceManager.h" + +static NSString *const kWeaveServiceUUID = @"FEF3"; + +namespace nearby { +namespace apple { + +BleMedium::BleMedium() : medium_([[GNCBLEMedium alloc] init]) {} + +std::unique_ptr BleMedium::StartAdvertising( + const api::ble_v2::BleAdvertisementData &advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters, + api::ble_v2::BleMedium::AdvertisingCallback callback) { + NSMutableDictionary *serviceData = + ObjCServiceDataFromCPP(advertising_data.service_data); + + __block api::ble_v2::BleMedium::AdvertisingCallback blockCallback = std::move(callback); + + [medium_ startAdvertisingData:serviceData + completionHandler:^(NSError *error) { + blockCallback.start_advertising_result( + error == nil ? absl::OkStatus() + : absl::InternalError(error.localizedDescription.UTF8String)); + }]; + + return std::make_unique(AdvertisingSession{.stop_advertising = [this] { + return StopAdvertising() ? absl::OkStatus() : absl::InternalError("Failed to stop advertising"); + }}); +} + +bool BleMedium::StartAdvertising(const api::ble_v2::BleAdvertisementData &advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters) { + NSMutableDictionary *serviceData = + ObjCServiceDataFromCPP(advertising_data.service_data); + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block NSError *blockError = nil; + [medium_ startAdvertisingData:serviceData + completionHandler:^(NSError *error) { + if (error != nil) { + GTMLoggerError(@"Failed to start advertising: %@", error); + } + blockError = error; + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + return blockError == nil; +} + +bool BleMedium::StopAdvertising() { + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block NSError *blockError = nil; + [medium_ stopAdvertisingWithCompletionHandler:^(NSError *error) { + if (error != nil) { + GTMLoggerError(@"Failed to stop advertising: %@", error); + } + blockError = error; + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + return blockError == nil; +} + +void BleMedium::HandleAdvertisementFound( + id peripheral, NSDictionary *serviceData, + absl::AnyInvocable + callback) { + absl::MutexLock lock(&peripherals_mutex_); + [socketCentralManager_ retrievePeripheralWithIdentifier:peripheral.identifier + advertisementData:@{}]; + + api::ble_v2::BleAdvertisementData data; + for (CBUUID *key in serviceData.allKeys) { + data.service_data[CPPUUIDFromObjC(key)] = ByteArrayFromNSData(serviceData[key]); + } + + // Add the peripheral to the map if we haven't discovered it yet. + auto ble_peripheral = std::make_unique(peripheral); + auto unique_id = ble_peripheral->GetUniqueId(); + auto it = peripherals_.find(unique_id); + if (it == peripherals_.end()) { + peripherals_[unique_id] = std::move(ble_peripheral); + } + callback(*peripherals_[unique_id], data); +} + +std::unique_ptr BleMedium::StartScanning( + const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::BleMedium::ScanningCallback callback) { + CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid); + __block api::ble_v2::BleMedium::ScanningCallback blockCallback = std::move(callback); + + socketCentralManager_ = [[GNSCentralManager alloc] initWithSocketServiceUUID:serviceUUID]; + [socketCentralManager_ startNoScanModeWithAdvertisedServiceUUIDs:@[ serviceUUID ]]; + + [medium_ startScanningForService:serviceUUID + advertisementFoundHandler:^(id peripheral, + NSDictionary *serviceData) { + HandleAdvertisementFound(peripheral, serviceData, + std::move(blockCallback.advertisement_found_cb)); + } + completionHandler:^(NSError *error) { + blockCallback.start_scanning_result( + error == nil ? absl::OkStatus() + : absl::InternalError(error.localizedDescription.UTF8String)); + }]; + + return std::make_unique(ScanningSession{.stop_scanning = [this] { + return StopScanning() ? absl::OkStatus() : absl::InternalError("Failed to stop scanning"); + }}); +} + +bool BleMedium::StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::BleMedium::ScanCallback callback) { + CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid); + __block api::ble_v2::BleMedium::ScanCallback blockCallback = std::move(callback); + + socketCentralManager_ = [[GNSCentralManager alloc] initWithSocketServiceUUID:serviceUUID]; + [socketCentralManager_ startNoScanModeWithAdvertisedServiceUUIDs:@[ serviceUUID ]]; + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block NSError *blockError = nil; + [medium_ startScanningForService:serviceUUID + advertisementFoundHandler:^(id peripheral, + NSDictionary *serviceData) { + HandleAdvertisementFound(peripheral, serviceData, + std::move(blockCallback.advertisement_found_cb)); + } + completionHandler:^(NSError *error) { + if (error != nil) { + GTMLoggerError(@"Failed to start scanning: %@", error); + } + blockError = error; + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + return blockError == nil; +} + +bool BleMedium::StopScanning() { + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block NSError *blockError = nil; + [medium_ stopScanningWithCompletionHandler:^(NSError *error) { + if (error != nil) { + GTMLoggerError(@"Failed to stop scanning: %@", error); + } + blockError = error; + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + return blockError == nil; +} + +// TODO(b/290385712): Add implementation that calls ServerGattConnectionCallback methods. +std::unique_ptr BleMedium::StartGattServer( + api::ble_v2::ServerGattConnectionCallback callback) { + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block GNCBLEGATTServer *blockServer = nil; + [medium_ startGATTServerWithCompletionHandler:^(GNCBLEGATTServer *server, NSError *error) { + if (error != nil) { + GTMLoggerError(@"Error starting GATT server: %@", error); + } + blockServer = server; + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (!blockServer) { + return nullptr; + } + return std::make_unique(blockServer); +} + +std::unique_ptr BleMedium::ConnectToGattServer( + api::ble_v2::BlePeripheral &peripheral, api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::ClientGattConnectionCallback callback) { + // Check that the @c api::ble_v2::BlePeripheral is a @c nearby::apple::BlePeripheral and not a + // @c nearby::apple::EmptyBlePeripheral instance, so we can retreive the CBPeripheral object. + BlePeripheral *non_empty_peripheral = dynamic_cast(&peripheral); + if (non_empty_peripheral == nullptr) { + return nullptr; + } + + __block api::ble_v2::ClientGattConnectionCallback blockCallback = std::move(callback); + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block GNCBLEGATTClient *blockClient = nil; + [medium_ connectToGATTServerForPeripheral:non_empty_peripheral->GetPeripheral() + disconnectionHandler:^(void) { + blockCallback.disconnected_cb(); + } + completionHandler:^(GNCBLEGATTClient *client, NSError *error) { + if (error != nil) { + GTMLoggerError(@"Error connecting to GATT server: %@", error); + } + blockClient = client; + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (!blockClient) { + return nullptr; + } + return std::make_unique(blockClient); +} + +// TODO(b/293336684): Old Weave code that need to be deleted once shared Weave is complete. +std::unique_ptr BleMedium::OpenServerSocket( + const std::string &service_id) { + __block auto server_socket = std::make_unique(); + socketPeripheralServiceManager_ = [[GNSPeripheralServiceManager alloc] + initWithBleServiceUUID:[CBUUID UUIDWithString:kWeaveServiceUUID] + addPairingCharacteristic:NO + shouldAcceptSocketHandler:^BOOL(GNSSocket *socket) { + GNCMWaitForConnection(socket, ^(BOOL didConnect) { + GNCMBleConnection *connection = + [GNCMBleConnection connectionWithSocket:socket + serviceID:@(service_id.c_str()) + expectedIntroPacket:YES + callbackQueue:dispatch_get_main_queue()]; + + auto socket = std::make_unique(connection); + connection.connectionHandlers = socket->GetInputStream().GetConnectionHandlers(); + server_socket->Connect(std::move(socket)); + }); + return YES; + }]; + socketPeripheralManager_ = [[GNSPeripheralManager alloc] initWithAdvertisedName:nil + restoreIdentifier:nil]; + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block NSError *blockError = nil; + [socketPeripheralManager_ addPeripheralServiceManager:socketPeripheralServiceManager_ + bleServiceAddedCompletion:^(NSError *error) { + if (error != nil) { + GTMLoggerError(@"Failed to add Weave service: %@", error); + } + blockError = error; + dispatch_semaphore_signal(semaphore); + }]; + [socketPeripheralManager_ start]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (blockError != nil) { + return nullptr; + } + return std::move(server_socket); +} + +// TODO(b/290385712): Add support for @c cancellation_flag. +// TODO(b/293336684): Old Weave code that need to be deleted once shared Weave is complete. +std::unique_ptr BleMedium::Connect(const std::string &service_id, + api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::BlePeripheral &peripheral, + CancellationFlag *cancellation_flag) { + // Check that the @c api::ble_v2::BlePeripheral is a @c nearby::apple::BlePeripheral and not a + // @c nearby::apple::EmptyBlePeripheral instance, so we can retreive the CBPeripheral object. + BlePeripheral *non_empty_peripheral = dynamic_cast(&peripheral); + if (non_empty_peripheral == nullptr) { + return nullptr; + } + + GNSCentralPeerManager *updatedCentralPeerManager = [socketCentralManager_ + retrieveCentralPeerWithIdentifier:non_empty_peripheral->GetPeripheral().identifier]; + if (!updatedCentralPeerManager) { + return nullptr; + } + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block std::unique_ptr socket; + [updatedCentralPeerManager + socketWithPairingCharacteristic:NO + completion:^(GNSSocket *nssocket, NSError *error) { + if (error) { + dispatch_semaphore_signal(semaphore); + return; + } + GNCMWaitForConnection(nssocket, ^(BOOL didConnect) { + if (!didConnect) { + dispatch_semaphore_signal(semaphore); + return; + } + + GNCMBleConnection *connection = [GNCMBleConnection + connectionWithSocket:nssocket + serviceID:@(service_id.c_str()) + expectedIntroPacket:NO + callbackQueue:dispatch_get_main_queue()]; + socket = + std::make_unique(connection, non_empty_peripheral); + connection.connectionHandlers = + socket->GetInputStream().GetConnectionHandlers(); + dispatch_semaphore_signal(semaphore); + }); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (socket == nullptr) { + return nullptr; + } + + // Send the (empty) intro packet, which the BLE advertiser is expecting. + socket->GetOutputStream().Write(ByteArray()); + return std::move(socket); +} + +bool BleMedium::IsExtendedAdvertisementsAvailable() { + return [medium_ supportsExtendedAdvertisements]; +} + +bool BleMedium::GetRemotePeripheral(const std::string &mac_address, + api::ble_v2::BleMedium::GetRemotePeripheralCallback callback) { + // Apple does not expose MAC address information, so we cannot retreive a peripheral via MAC + // address. + return false; +} + +bool BleMedium::GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId unique_id, + api::ble_v2::BleMedium::GetRemotePeripheralCallback callback) { + BlePeripheral *peripheral; + { + absl::MutexLock lock(&peripherals_mutex_); + auto it = peripherals_.find(unique_id); + if (it == peripherals_.end()) { + return false; + } + peripheral = it->second.get(); + if (peripheral == nullptr) { + return false; + } + } + // We need to unlock before calling the callback, otherwise we will deadlock. + callback(*peripheral); + return true; +} + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_peripheral.h b/internal/platform/implementation/apple/ble_peripheral.h new file mode 100644 index 00000000..a1d23680 --- /dev/null +++ b/internal/platform/implementation/apple/ble_peripheral.h @@ -0,0 +1,84 @@ +// 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. + +// Note: File language is detected using heuristics. Many Objective-C++ headers are incorrectly +// classified as C++ resulting in invalid linter errors. The use of "NSArray" and other Foundation +// classes like "NSData", "NSDictionary" and "NSUUID" are highly weighted for Objective-C and +// Objective-C++ scores. Oddly, "#import " does not contribute any points. +// This comment alone should be enough to trick the IDE in to believing this is actually some sort +// of Objective-C file. See: cs/google3/devtools/search/lang/recognize_language_classifiers_data + +#import +#import + +#include + +#include "internal/platform/implementation/ble_v2.h" + +@protocol GNCPeripheral; + +namespace nearby { +namespace apple { + +// An empty peripheral. +// +// Apple APIs do not expose a peripheral's MAC address and does not provide a +// way to directly connect to a given MAC address. Instead a connection can only +// be made using a CoreBluetooth peripheral object. Many times a CoreBluetooth +// peripheral is not available, namely, when the remote device is a central. For +// these cases, an EmptyBlePeripheral should be used. +class EmptyBlePeripheral : public api::ble_v2::BlePeripheral { + public: + EmptyBlePeripheral(); + ~EmptyBlePeripheral() override = default; + + // Returns an empty string. + std::string GetAddress() const override; + + // Returns an immutable unique identifier. The identifier does not change when + // the peripheral's address is rotated. + api::ble_v2::BlePeripheral::UniqueId GetUniqueId() const override; + + private: + api::ble_v2::BlePeripheral::UniqueId unique_id_; +}; + +// A wrapper of a CoreBluetooth peripheral object. This can be used to uniquely +// identify a peripheral and connect to its GATT server. +// +// Many times a CoreBluetooth peripheral is not available, namely, when the +// remote device is a central. For these cases, an EmptyBlePeripheral should be +// used instead. +class BlePeripheral : public api::ble_v2::BlePeripheral { + public: + explicit BlePeripheral(id peripheral); + ~BlePeripheral() override = default; + + // Returns an empty string. + std::string GetAddress() const override; + + // Returns an immutable unique identifier. The identifier does not change when + // the peripheral's address is rotated. + api::ble_v2::BlePeripheral::UniqueId GetUniqueId() const override; + + // Returns the CoreBluetooth peripheral object. + id GetPeripheral() const; + + private: + id peripheral_; + api::ble_v2::BlePeripheral::UniqueId unique_id_; +}; + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_peripheral.mm b/internal/platform/implementation/apple/ble_peripheral.mm new file mode 100644 index 00000000..e19646f9 --- /dev/null +++ b/internal/platform/implementation/apple/ble_peripheral.mm @@ -0,0 +1,50 @@ +// 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. + +#import "internal/platform/implementation/apple/ble_peripheral.h" + +#import +#import + +#include + +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/prng.h" + +#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h" + +namespace nearby { +namespace apple { + +#pragma mark - EmptyBlePeripheral + +EmptyBlePeripheral::EmptyBlePeripheral() : unique_id_(Prng().NextInt64()) {} + +std::string EmptyBlePeripheral::GetAddress() const { return ""; } + +api::ble_v2::BlePeripheral::UniqueId EmptyBlePeripheral::GetUniqueId() const { return unique_id_; } + +#pragma mark - BlePeripheral + +BlePeripheral::BlePeripheral(id peripheral) + : peripheral_(peripheral), unique_id_(peripheral.identifier.hash) {} + +std::string BlePeripheral::GetAddress() const { return ""; } + +api::ble_v2::BlePeripheral::UniqueId BlePeripheral::GetUniqueId() const { return unique_id_; } + +id BlePeripheral::GetPeripheral() const { return peripheral_; } + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_server_socket.h b/internal/platform/implementation/apple/ble_server_socket.h new file mode 100644 index 00000000..f4758e0c --- /dev/null +++ b/internal/platform/implementation/apple/ble_server_socket.h @@ -0,0 +1,76 @@ +// 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. + +// Note: File language is detected using heuristics. Many Objective-C++ headers are incorrectly +// classified as C++ resulting in invalid linter errors. The use of "NSArray" and other Foundation +// classes like "NSData", "NSDictionary" and "NSUUID" are highly weighted for Objective-C and +// Objective-C++ scores. Oddly, "#import " does not contribute any points. +// This comment alone should be enough to trick the IDE in to believing this is actually some sort +// of Objective-C file. See: cs/google3/devtools/search/lang/recognize_language_classifiers_data + +// TODO(b/293336684): Remove this file when shared Weave is complete. + +#import + +#include + +#include "absl/functional/any_invocable.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/ble_v2.h" + +#import "internal/platform/implementation/apple/ble_socket.h" + +namespace nearby { +namespace apple { + +// A BLE server socket for listening for incoming Weave sockets. +class BleServerSocket : public api::ble_v2::BleServerSocket { + public: + BleServerSocket() = default; + ~BleServerSocket() override; + + // Wait for an available socket. + // + // Blocks until either: + // - at least one incoming connection request is available, or + // - ServerSocket is closed. + // + // On success, returns connected socket, ready to exchange data or nullptr on + // error. Once error is reported, it is permanent, and ServerSocket must be + // closed. + std::unique_ptr Accept() override + ABSL_LOCKS_EXCLUDED(mutex_); + + // Close the server socket. + // + // Returns Exception::kIo on error, otherwise Exception::kSuccess. + Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + + bool Connect(std::unique_ptr socket) ABSL_LOCKS_EXCLUDED(mutex_); + void SetCloseNotifier(absl::AnyInvocable notifier) + ABSL_LOCKS_EXCLUDED(mutex_); + + private: + Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + mutable absl::Mutex mutex_; + absl::CondVar cond_; + absl::flat_hash_set> pending_sockets_ + ABSL_GUARDED_BY(mutex_); + absl::AnyInvocable close_notifier_ ABSL_GUARDED_BY(mutex_); + bool closed_ ABSL_GUARDED_BY(mutex_) = false; +}; + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_server_socket.mm b/internal/platform/implementation/apple/ble_server_socket.mm new file mode 100644 index 00000000..42c2d1ef --- /dev/null +++ b/internal/platform/implementation/apple/ble_server_socket.mm @@ -0,0 +1,82 @@ +// 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. + +// TODO(b/293336684): Remove this file when shared Weave is complete. + +#import "internal/platform/implementation/apple/ble_server_socket.h" + +#import + +#include +#include + +namespace nearby { +namespace apple { + +BleServerSocket::~BleServerSocket() { + absl::MutexLock lock(&mutex_); + DoClose(); +} + +std::unique_ptr BleServerSocket::Accept() { + absl::MutexLock lock(&mutex_); + while (!closed_ && pending_sockets_.empty()) { + cond_.Wait(&mutex_); + } + if (closed_) return {}; + + std::unique_ptr remote_socket = + std::move(pending_sockets_.extract(pending_sockets_.begin()).value()); + return std::move(remote_socket); +} + +bool BleServerSocket::Connect(std::unique_ptr socket) { + absl::MutexLock lock(&mutex_); + if (closed_) { + return false; + } + pending_sockets_.insert(std::move(socket)); + cond_.SignalAll(); + return !closed_; +} + +void BleServerSocket::SetCloseNotifier(absl::AnyInvocable notifier) { + absl::MutexLock lock(&mutex_); + close_notifier_ = std::move(notifier); +} + +Exception BleServerSocket::Close() { + absl::MutexLock lock(&mutex_); + return DoClose(); +} + +Exception BleServerSocket::DoClose() { + bool should_notify = !closed_; + closed_ = true; + if (should_notify) { + cond_.SignalAll(); + if (close_notifier_) { + auto notifier = std::move(close_notifier_); + mutex_.Unlock(); + // Notifier may contain calls to public API, and may cause deadlock, if + // mutex_ is held during the call. + notifier(); + mutex_.Lock(); + } + } + return {Exception::kSuccess}; +} + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_socket.h b/internal/platform/implementation/apple/ble_socket.h new file mode 100644 index 00000000..6c64f7b5 --- /dev/null +++ b/internal/platform/implementation/apple/ble_socket.h @@ -0,0 +1,134 @@ +// 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. + +// Note: File language is detected using heuristics. Many Objective-C++ headers are incorrectly +// classified as C++ resulting in invalid linter errors. The use of "NSArray" and other Foundation +// classes like "NSData", "NSDictionary" and "NSUUID" are highly weighted for Objective-C and +// Objective-C++ scores. Oddly, "#import " does not contribute any points. +// This comment alone should be enough to trick the IDE in to believing this is actually some sort +// of Objective-C file. See: cs/google3/devtools/search/lang/recognize_language_classifiers_data + +// TODO(b/293336684): Remove this file when shared Weave is complete. + +#import + +#include + +#include "internal/platform/implementation/ble_v2.h" + +#import "internal/platform/implementation/apple/ble_peripheral.h" + +@class GNCMConnectionHandlers; +@protocol GNCMConnection; + +namespace nearby { +namespace apple { + +// A readable stream of bytes. +class BleInputStream : public InputStream { + public: + BleInputStream(); + ~BleInputStream() override; + + // Reads at most `size` bytes from the input stream. + // + // Returns an empty byte array on end of file, or Exception::kIo on error. + ExceptionOr Read(std::int64_t size) override; + + // Closes the stream preventing further reads. + // + // Returns Exception::kIo on error, otherwise Exception::kSuccess. + Exception Close() override; + + GNCMConnectionHandlers *GetConnectionHandlers() { return connectionHandlers_; } + + private: + GNCMConnectionHandlers *connectionHandlers_; + NSMutableArray *newDataPackets_; + NSMutableData *accumulatedData_; + NSCondition *condition_; +}; + +// A writable stream of bytes. +class BleOutputStream : public OutputStream { + public: + explicit BleOutputStream(id connection) + : connection_(connection), condition_([[NSCondition alloc] init]) {} + ~BleOutputStream() override; + + // Write the provided bytes to the output stream. + // + // Returns Exception::kIo on error, otherwise Exception::kSuccess. + Exception Write(const ByteArray &data) override; + + // no-op + // + // Always returns Exception::kSuccess. + Exception Flush() override; + + // Closes the stream preventing further writes. + // + // Returns Exception::kIo on error, otherwise Exception::kSuccess. + Exception Close() override; + + private: + id connection_; + NSCondition *condition_; +}; + +// A BLE Weave socket. +class BleSocket : public api::ble_v2::BleSocket { + public: + explicit BleSocket(id connection); + + // The peripheral used to create the socket must outlive the socket or undefined behavior will + // occur. + BleSocket(id connection, api::ble_v2::BlePeripheral *peripheral); + ~BleSocket() override; + + // Returns the InputStream of the BleSocket. + // On error, returned stream will report Exception::kIo on any operation. + // + // The returned object is not owned by the caller, and can be invalidated once + // the BleSocket object is destroyed. + BleInputStream &GetInputStream() override { return *input_stream_; } + + // Returns the OutputStream of the BleSocket. + // On error, returned stream will report Exception::kIo on any operation. + // + // The returned object is not owned by the caller, and can be invalidated once + // the BleSocket object is destroyed. + BleOutputStream &GetOutputStream() override { return *output_stream_; } + + // Returns Exception::kIo on error, otherwise Exception::kSuccess. + Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns valid BlePeripheral pointer if there is a connection, and + // nullptr otherwise. + api::ble_v2::BlePeripheral *GetRemotePeripheral() override { return peripheral_; } + + bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_); + + private: + void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + mutable absl::Mutex mutex_; + bool closed_ ABSL_GUARDED_BY(mutex_) = false; + std::unique_ptr input_stream_; + std::unique_ptr output_stream_; + api::ble_v2::BlePeripheral *peripheral_; +}; + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_socket.mm b/internal/platform/implementation/apple/ble_socket.mm new file mode 100644 index 00000000..b150e0a9 --- /dev/null +++ b/internal/platform/implementation/apple/ble_socket.mm @@ -0,0 +1,215 @@ +// 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. + +#import "internal/platform/implementation/apple/ble_socket.h" + +#include "internal/platform/implementation/ble_v2.h" + +#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleConnection.h" +#import "internal/platform/implementation/apple/ble_peripheral.h" +#import "internal/platform/implementation/apple/ble_utils.h" +#import "internal/platform/implementation/apple/utils.h" + +// TODO(b/293336684): Remove this file when shared Weave is complete. + +namespace nearby { +namespace apple { + +#pragma mark - BleInputStream + +BleInputStream::BleInputStream() + : newDataPackets_([NSMutableArray array]), + accumulatedData_([NSMutableData data]), + condition_([[NSCondition alloc] init]) { + // Create the handlers of incoming data from the remote endpoint. + connectionHandlers_ = [GNCMConnectionHandlers + payloadHandler:^(NSData *data) { + [condition_ lock]; + // Add the incoming data to the data packet array to be processed in read() below. + [newDataPackets_ addObject:data]; + [condition_ broadcast]; + [condition_ unlock]; + } + disconnectedHandler:^{ + [condition_ lock]; + // Release the data packet array, meaning the stream has been closed or severed. + newDataPackets_ = nil; + [condition_ broadcast]; + [condition_ unlock]; + }]; +} + +BleInputStream::~BleInputStream() { + NSCAssert(!newDataPackets_, @"BleInputStream not closed before destruction"); +} + +ExceptionOr BleInputStream::Read(std::int64_t size) { + // Block until either (a) the connection has been closed, (b) we have enough data to return. + NSData *dataToReturn; + [condition_ lock]; + while (true) { + // Check if the stream has been closed or severed. + if (!newDataPackets_) break; + + if (newDataPackets_.count > 0) { + // Add the packet data to the accumulated data. + for (NSData *data in newDataPackets_) { + if (data.length > 0) { + [accumulatedData_ appendData:data]; + } + } + [newDataPackets_ removeAllObjects]; + } + + if ((size == -1) && (accumulatedData_.length > 0)) { + // Return all of the data. + dataToReturn = accumulatedData_; + accumulatedData_ = [NSMutableData data]; + break; + } else if (accumulatedData_.length > 0) { + // Return up to |size| bytes of the data. + std::int64_t sizeToReturn = (accumulatedData_.length < size) ? accumulatedData_.length : size; + NSRange range = NSMakeRange(0, (NSUInteger)sizeToReturn); + dataToReturn = [accumulatedData_ subdataWithRange:range]; + [accumulatedData_ replaceBytesInRange:range withBytes:nil length:0]; + break; + } + + [condition_ wait]; + } + [condition_ unlock]; + + if (dataToReturn) { + NSLog(@"[NEARBY] Input stream: Received data of size: %lu", (unsigned long)dataToReturn.length); + return ExceptionOr(ByteArrayFromNSData(dataToReturn)); + } else { + return ExceptionOr{Exception::kIo}; + } +} + +Exception BleInputStream::Close() { + // Unblock pending read operation. + [condition_ lock]; + newDataPackets_ = nil; + [condition_ broadcast]; + [condition_ unlock]; + return {Exception::kSuccess}; +} + +#pragma mark - BleOutputStream + +BleOutputStream::~BleOutputStream() { + NSCAssert(!connection_, @"BleOutputStream not closed before destruction"); +} + +Exception BleOutputStream::Write(const ByteArray &data) { + [condition_ lock]; + NSLog(@"[NEARBY] Sending data of size: %lu", NSDataFromByteArray(data).length); + + if (!connection_) { + [condition_ unlock]; + return {Exception::kIo}; + } + + NSMutableData *packet = [NSMutableData dataWithData:NSDataFromByteArray(data)]; + + // Send the data, blocking until the completion handler is called. + __block bool isComplete = NO; + __block GNCMPayloadResult sendResult = GNCMPayloadResultFailure; + NSCondition *condition = condition_; // don't capture |this| in completion + + [connection_ sendData:packet + progressHandler:^(size_t count) { + } + completion:^(GNCMPayloadResult result) { + [condition lock]; + // Make sure we haven't already reported completion before. This prevents a crash + // where we try leaving a dispatch group more times than we entered it. + // b/79095653. + if (isComplete) { + [condition unlock]; + return; + } + isComplete = YES; + sendResult = result; + [condition broadcast]; + [condition unlock]; + }]; + + while (connection_ && !isComplete) { + [condition_ wait]; + } + + if (sendResult == GNCMPayloadResultSuccess) { + [condition_ unlock]; + return {Exception::kSuccess}; + } else { + [condition_ unlock]; + return {Exception::kIo}; + } +} + +Exception BleOutputStream::Flush() { + // The write() function blocks until the data is received by the remote endpoint, so there's + // nothing to do here. + return {Exception::kSuccess}; +} + +Exception BleOutputStream::Close() { + // Unblock pending write operation. + [condition_ lock]; + connection_ = nil; + [condition_ broadcast]; + [condition_ unlock]; + return {Exception::kSuccess}; +} + +#pragma mark - BleSocket + +BleSocket::BleSocket(id connection) + : input_stream_(new BleInputStream()), + output_stream_(new BleOutputStream(connection)), + peripheral_(new EmptyBlePeripheral()) {} + +BleSocket::BleSocket(id connection, api::ble_v2::BlePeripheral *peripheral) + : input_stream_(new BleInputStream()), + output_stream_(new BleOutputStream(connection)), + peripheral_(peripheral) {} + +BleSocket::~BleSocket() { + absl::MutexLock lock(&mutex_); + DoClose(); +} + +bool BleSocket::IsClosed() const { + absl::MutexLock lock(&mutex_); + return closed_; +} + +Exception BleSocket::Close() { + absl::MutexLock lock(&mutex_); + DoClose(); + return {Exception::kSuccess}; +} + +void BleSocket::DoClose() { + if (!closed_) { + input_stream_->Close(); + output_stream_->Close(); + closed_ = true; + } +} + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/ble_utils.h b/internal/platform/implementation/apple/ble_utils.h index 209298fb..4477c403 100644 --- a/internal/platform/implementation/apple/ble_utils.h +++ b/internal/platform/implementation/apple/ble_utils.h @@ -56,6 +56,9 @@ CBCharacteristicProperties CBCharacteristicPropertiesFromCPP( /** Converts a C++ characteristic to an Objective-C characteristic. */ GNCBLEGATTCharacteristic *ObjCGATTCharacteristicFromCPP(const api::ble_v2::GattCharacteristic &c); +NSMutableDictionary *ObjCServiceDataFromCPP( + const absl::flat_hash_map &sd); + /** Converts a 16 or 128 bit CoreBluetooth UUID to a C++ UUID. */ Uuid CPPUUIDFromObjC(CBUUID *uuid); diff --git a/internal/platform/implementation/apple/ble_utils.mm b/internal/platform/implementation/apple/ble_utils.mm index cf08649e..cd9f3cdb 100644 --- a/internal/platform/implementation/apple/ble_utils.mm +++ b/internal/platform/implementation/apple/ble_utils.mm @@ -20,6 +20,7 @@ #include #import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h" +#import "internal/platform/implementation/apple/utils.h" namespace nearby { namespace apple { @@ -98,6 +99,17 @@ GNCBLEGATTCharacteristic *ObjCGATTCharacteristicFromCPP(const GattCharacteristic properties:properties]; } +NSMutableDictionary *ObjCServiceDataFromCPP( + const absl::flat_hash_map &sd) { + NSMutableDictionary *serviceData = [NSMutableDictionary dictionary]; + for (const auto &pair : sd) { + CBUUID *key = CBUUID16FromCPP(pair.first); + NSData *data = NSDataFromByteArray(pair.second); + [serviceData setObject:data forKey:key]; + } + return serviceData; +} + Uuid CPPUUIDFromObjC(CBUUID *uuid) { NSString *uuidString = uuid.UUIDString; if (uuidString.length == 4) { diff --git a/internal/platform/implementation/apple/bluetooth_adapter.h b/internal/platform/implementation/apple/bluetooth_adapter.h deleted file mode 100644 index ce08753f..00000000 --- a/internal/platform/implementation/apple/bluetooth_adapter.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2022 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_INTERNAL_PLATFORM_IMPLEMENTATION_APPLE_BLUETOOTH_ADAPTER_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_APPLE_BLUETOOTH_ADAPTER_H_ - -#include - -#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleCentral.h" -#include "internal/platform/implementation/ble_v2.h" -#include "internal/platform/implementation/bluetooth_adapter.h" -#include "internal/platform/prng.h" - -namespace nearby { -namespace apple { - -class BluetoothAdapter; - -// Concrete BlePeripheral implementation. -class BlePeripheral : public api::ble_v2::BlePeripheral { - public: - std::string GetAddress() const override; - - api::ble_v2::BlePeripheral::UniqueId GetUniqueId() const override { - return unique_id_; - } - - std::string GetPeripheralId() const { return peripheral_id_; } - - void SetPeripheralId(const std::string& peripheral_id) { - peripheral_id_ = peripheral_id; - } - - void SetConnectionRequester(GNCMBleConnectionRequester connection_requester) { - connection_requester_ = connection_requester; - } - - GNCMBleConnectionRequester GetConnectionRequester() { - return connection_requester_; - } - - private: - // Only BluetoothAdapter may instantiate BlePeripheral. - friend class BluetoothAdapter; - - explicit BlePeripheral(BluetoothAdapter* adapter) : adapter_(*adapter) { - unique_id_ = Prng().NextInt64(); - } - - BluetoothAdapter& adapter_; - std::string peripheral_id_; - GNCMBleConnectionRequester connection_requester_; - api::ble_v2::BlePeripheral::UniqueId unique_id_; -}; - -// Concrete BluetoothAdapter implementation. -class BluetoothAdapter : public api::BluetoothAdapter { - public: - using Status = api::BluetoothAdapter::Status; - using ScanMode = api::BluetoothAdapter::ScanMode; - - ~BluetoothAdapter() override { SetStatus(Status::kDisabled); } - - bool SetStatus(Status status) override { - enabled_ = status == Status::kEnabled; - return true; - } - bool IsEnabled() const override { return enabled_; } - ScanMode GetScanMode() const override { return mode_; } - bool SetScanMode(ScanMode mode) override { return false; } - std::string GetName() const override { return name_; } - bool SetName(absl::string_view name) { - return SetName(name, /* persist= */ true); - } - bool SetName(absl::string_view name, bool persist) override { - name_ = std::string(name); - return true; - } - std::string GetMacAddress() const override { return mac_address_; } - void SetMacAddress(absl::string_view mac_address) { - mac_address_ = std::string(mac_address); - } - - BlePeripheral& GetPeripheral() { return peripheral_; } - - private: - BlePeripheral peripheral_{this}; - ScanMode mode_ = ScanMode::kNone; - std::string name_; - std::string mac_address_; - bool enabled_ = true; -}; - -} // namespace apple -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_APPLE_BLUETOOTH_ADAPTER_H_ diff --git a/internal/platform/implementation/apple/bluetooth_adapter.mm b/internal/platform/implementation/apple/bluetooth_adapter.mm deleted file mode 100644 index 7369e63c..00000000 --- a/internal/platform/implementation/apple/bluetooth_adapter.mm +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2022 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 "internal/platform/implementation/apple/bluetooth_adapter.h" - -#include - -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/bluetooth_adapter.h" - -namespace nearby { -namespace apple { - -std::string BlePeripheral::GetAddress() const { return adapter_.GetMacAddress(); } - -} // namespace apple -} // namespace nearby diff --git a/internal/platform/implementation/apple/bluetooth_adapter_v2.h b/internal/platform/implementation/apple/bluetooth_adapter_v2.h new file mode 100644 index 00000000..f1c09b3e --- /dev/null +++ b/internal/platform/implementation/apple/bluetooth_adapter_v2.h @@ -0,0 +1,90 @@ +// Copyright 2022 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. + +// Note: File language is detected using heuristics. Many Objective-C++ headers are incorrectly +// classified as C++ resulting in invalid linter errors. The use of "NSArray" and other Foundation +// classes like "NSData", "NSDictionary" and "NSUUID" are highly weighted for Objective-C and +// Objective-C++ scores. Oddly, "#import " does not contribute any points. +// This comment alone should be enough to trick the IDE in to believing this is actually some sort +// of Objective-C file. See: cs/google3/devtools/search/lang/recognize_language_classifiers_data + +#import + +#include + +#include "absl/strings/string_view.h" +#include "internal/platform/implementation/bluetooth_adapter.h" + +namespace nearby { +namespace apple { + +// Concrete implementation representing the local device Bluetooth adapter. +class BluetoothAdapter : public api::BluetoothAdapter { + public: + BluetoothAdapter() = default; + ~BluetoothAdapter() override = default; + + // Synchronously sets the status of the BluetoothAdapter to @c status, and + // returns true if the operation was a success. + bool SetStatus(api::BluetoothAdapter::Status status) override; + + // Returns true if the BluetoothAdapter's current status is @c kEnabled. + bool IsEnabled() const override; + + // Get the current Bluetooth scan mode of the local Bluetooth adapter. + // + // The Bluetooth scan mode determines if the local adapter is connectable + // and/or discoverable from remote Bluetooth devices. + // + // Possible values are: @c kNone, @c kConnectable, + // @c kConnectableDiscoverable. + // + // Returns @c kUnknown on error. + api::BluetoothAdapter::ScanMode GetScanMode() const override; + + // Synchronously sets the scan mode of the adapter, and returns true if the + // operation was a success. + bool SetScanMode(api::BluetoothAdapter::ScanMode scan_mode) override; + + // Get the friendly Bluetooth name of the local Bluetooth adapter. + // + // Returns an empty string on error + std::string GetName() const override; + + // Set and persist the friendly Bluetooth name of the local Bluetooth adapter. + // + // This name is visible to remote Bluetooth devices. + // + // Valid Bluetooth names are a maximum of 248 bytes using UTF-8 encoding, + // although many remote devices can only display the first 40 characters, and + // some may be limited to just 20. + bool SetName(absl::string_view name) override; + + // Set the friendly Bluetooth name of the local Bluetooth adapter. + // + // This name is visible to remote Bluetooth devices. + // + // Valid Bluetooth names are a maximum of 248 bytes using UTF-8 encoding, + // although many remote devices can only display the first 40 characters, and + // some may be limited to just 20. + // + // If persist is false, we will restore the original radio names when complete. + bool SetName(absl::string_view name, bool persist) override; + + // Returns BT MAC address assigned to this adapter. + std::string GetMacAddress() const override; +}; + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/bluetooth_adapter_v2.mm b/internal/platform/implementation/apple/bluetooth_adapter_v2.mm new file mode 100644 index 00000000..a6c6bfe7 --- /dev/null +++ b/internal/platform/implementation/apple/bluetooth_adapter_v2.mm @@ -0,0 +1,71 @@ +// Copyright 2022 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. + +#import "internal/platform/implementation/apple/bluetooth_adapter_v2.h" + +#import + +#include + +#include "absl/strings/string_view.h" +#include "internal/platform/implementation/bluetooth_adapter.h" + +namespace nearby { +namespace apple { + +bool BluetoothAdapter::SetStatus(api::BluetoothAdapter::Status status) { + // We can't force a radio state in macOS/iOS. + // NOTE: This is supposed to return the success/failure of the change (which should always be + // "fail" for our case). However, usage in the codebase expects this to return with "success" if + // the radio is on, so we just return whether the radio is currently enabled. + return IsEnabled(); +} + +// TODO(b/290385712): Implement. +bool BluetoothAdapter::IsEnabled() const { + return true; +} + +// TODO(b/290385712): Implement. +api::BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const { + return api::BluetoothAdapter::ScanMode::kUnknown; +} + +// TODO(b/290385712): Implement. +bool BluetoothAdapter::SetScanMode(api::BluetoothAdapter::ScanMode scan_mode) { + return false; +} + +// TODO(b/290385712): Implement. +std::string BluetoothAdapter::GetName() const { + return ""; +} + +// TODO(b/290385712): Implement. +bool BluetoothAdapter::SetName(absl::string_view name) { + return false; +} + +// TODO(b/290385712): Implement. +bool BluetoothAdapter::SetName(absl::string_view name, bool persist) { + return false; +} + +// TODO(b/290385712): Implement. +std::string BluetoothAdapter::GetMacAddress() const { + return ""; +} + +} // namespace apple +} // namespace nearby diff --git a/internal/platform/implementation/apple/device_info.h b/internal/platform/implementation/apple/device_info.h index 953f54c4..4315040c 100644 --- a/internal/platform/implementation/apple/device_info.h +++ b/internal/platform/implementation/apple/device_info.h @@ -58,6 +58,20 @@ class DeviceInfo : public api::DeviceInfo { std::function callback) override; void UnregisterScreenLockedListener(absl::string_view listener_name) override; + + // Request the system to prevent the device from going to sleep. + // + // To allow the system to sleep again, call @c AllowSleep(). + // + // Returns @c true on success or if the platform does not allow preventing + // sleep. Returns @c false on any other error. + bool PreventSleep() override; + + // Release any requests preventing the device from going to sleep. + // + // Returns @c true on success or if the system is already allowed to sleep. + // Returns @c false if an error occurred. + bool AllowSleep() override; }; } // namespace apple diff --git a/internal/platform/implementation/apple/device_info.mm b/internal/platform/implementation/apple/device_info.mm index b5053759..ee0104dd 100644 --- a/internal/platform/implementation/apple/device_info.mm +++ b/internal/platform/implementation/apple/device_info.mm @@ -168,5 +168,9 @@ void DeviceInfo::RegisterScreenLockedListener( void DeviceInfo::UnregisterScreenLockedListener(absl::string_view listener_name) {} +bool DeviceInfo::PreventSleep() { return true; } + +bool DeviceInfo::AllowSleep() { return true; } + } // namespace apple } // namespace nearby diff --git a/internal/platform/implementation/apple/platform.mm b/internal/platform/implementation/apple/platform.mm index f23a112b..781a50ea 100644 --- a/internal/platform/implementation/apple/platform.mm +++ b/internal/platform/implementation/apple/platform.mm @@ -44,37 +44,45 @@ namespace api { std::string ImplementationPlatform::GetCustomSavePath(const std::string& parent_folder, const std::string& file_name) { - NSFileManager* manager = [NSFileManager defaultManager]; + // Collapse any path escaping characters. + NSString* parentFolder = [@(parent_folder.c_str()) stringByReplacingOccurrencesOfString:@"../" + withString:@""]; + NSURL* parentFolderURL = [NSURL fileURLWithPath:parentFolder]; - NSURL* parentFolder = [NSURL fileURLWithPath:@(parent_folder.c_str())]; - - NSString* fileName = @(file_name.c_str()); + // The only reserved character in a file name on macOS is the forward-slash. It's unclear if iOS + // has any additional restrictions. + // + // """ + // In the Finder, filenames containing `/` can be created, but `/` is stored as a colon (:) in the + // filesystem, and is shown as such on the command line. Filenames containing `:` created from the + // command line are shown with `/` instead of `:` in the Finder, so that it is impossible to + // create a file that the Finder shows as having a `:` in its filename. + // """ + // + // See: https://en.wikipedia.org/wiki/Filename + NSString* fileName = [@(file_name.c_str()) stringByReplacingOccurrencesOfString:@"/" + withString:@":"]; NSString* baseName = [fileName stringByDeletingPathExtension]; NSString* extension = [fileName pathExtension]; - NSURL* url = [parentFolder URLByAppendingPathComponent:fileName]; + NSURL* url = [parentFolderURL URLByAppendingPathComponent:fileName]; NSInteger index = 1; - while ([manager fileExistsAtPath:url.path]) { + while ([NSFileManager.defaultManager fileExistsAtPath:url.path]) { index++; NSString* fileName = [NSString stringWithFormat:@"%@ %@.%@", baseName, [@(index) stringValue], extension]; - url = [parentFolder URLByAppendingPathComponent:fileName]; + url = [parentFolderURL URLByAppendingPathComponent:fileName]; } - return [url.path UTF8String]; + return url.path.UTF8String; } std::string ImplementationPlatform::GetDownloadPath(const std::string& parent_folder, const std::string& file_name) { - // TODO(jfcarroll): This needs to be done correctly, we now have a file name and parent folder, - // they should be combined with the default download path - NSString* fileName = ObjCStringFromCppString(file_name); - - // TODO(b/227535777): If file name matches an existing file, it will be overwritten. Append a - // number until a unique file name is reached 'foobar (2).png'. - - return CppStringFromObjCString([NSTemporaryDirectory() stringByAppendingPathComponent:fileName]); + NSString* customSavePath = + [NSTemporaryDirectory() stringByAppendingPathComponent:@(parent_folder.c_str())]; + return GetCustomSavePath(customSavePath.UTF8String, file_name); } OSName ImplementationPlatform::GetCurrentOS() { return OSName::kApple; } @@ -162,7 +170,7 @@ std::unique_ptr ImplementationPlatform::CreateBleMedium(api::Bluetoot std::unique_ptr ImplementationPlatform::CreateBleV2Medium( api::BluetoothAdapter& adapter) { - return std::make_unique(adapter); + return std::make_unique(); } std::unique_ptr ImplementationPlatform::CreateServerSyncMedium() { diff --git a/internal/platform/implementation/ble.h b/internal/platform/implementation/ble.h index c97b17de..b8be0f52 100644 --- a/internal/platform/implementation/ble.h +++ b/internal/platform/implementation/ble.h @@ -99,10 +99,8 @@ class BleMedium { virtual bool StopScanning(const std::string& service_id) = 0; // Callback that is invoked when a new connection is accepted. - struct AcceptedConnectionCallback { - absl::AnyInvocable - accepted_cb = DefaultCallback(); - }; + using AcceptedConnectionCallback = absl::AnyInvocable; // Returns true once BLE socket connection requests to service_id can be // accepted. diff --git a/internal/platform/implementation/ble_v2.h b/internal/platform/implementation/ble_v2.h index 3c1bca53..f1a31b14 100644 --- a/internal/platform/implementation/ble_v2.h +++ b/internal/platform/implementation/ble_v2.h @@ -92,6 +92,8 @@ class BlePeripheral { // https://developer.android.com/reference/android/bluetooth/BluetoothDevice#getAddress() // // Returns the current address. + // + // This will always be an empty string on Apple platforms. virtual std::string GetAddress() const = 0; // Returns an immutable unique identifier. The identifier must not change when @@ -510,6 +512,9 @@ class BleMedium { // Calls `callback` and returns true if `mac_address` is a valid BLE address. // Otherwise, does not call the callback and returns false. + // + // This method is not available on Apple platforms and will always return + // false, ignoring the callback. virtual bool GetRemotePeripheral(const std::string& mac_address, GetRemotePeripheralCallback callback) = 0; diff --git a/internal/platform/implementation/device_info.h b/internal/platform/implementation/device_info.h index da35de37..a3b7b5f5 100644 --- a/internal/platform/implementation/device_info.h +++ b/internal/platform/implementation/device_info.h @@ -59,6 +59,10 @@ class DeviceInfo { std::function callback) = 0; virtual void UnregisterScreenLockedListener( absl::string_view listener_name) = 0; + + // Control device sleep + virtual bool PreventSleep() = 0; + virtual bool AllowSleep() = 0; }; } // namespace api diff --git a/internal/platform/implementation/g3/BUILD b/internal/platform/implementation/g3/BUILD index b20cd459..9a4359d6 100644 --- a/internal/platform/implementation/g3/BUILD +++ b/internal/platform/implementation/g3/BUILD @@ -30,7 +30,6 @@ cc_library( "log_message.h", "multi_thread_executor.h", "mutex.h", - "pipe.h", "preferences_manager.h", "scheduled_executor.h", "single_thread_executor.h", @@ -44,8 +43,8 @@ cc_library( deps = [ ":preferences_repository", "//internal/platform:base", - "//internal/platform:logging", "//internal/platform:test_util", + "//internal/platform:types", "//internal/platform:util", "//internal/platform/implementation:types", "//internal/platform/implementation/shared:count_down_latch", @@ -85,6 +84,7 @@ cc_library( "bluetooth_adapter.h", "bluetooth_classic.h", "credential_storage_impl.h", + "socket_base.h", "webrtc.h", "wifi.h", "wifi_direct.h", @@ -97,13 +97,15 @@ cc_library( "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/log:check", "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/synchronization", "//internal/platform:base", "//internal/platform:cancellation_flag", - "//internal/platform:logging", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform:uuid", diff --git a/internal/platform/implementation/g3/ble.cc b/internal/platform/implementation/g3/ble.cc index 95bbfe47..f60b2391 100644 --- a/internal/platform/implementation/g3/ble.cc +++ b/internal/platform/implementation/g3/ble.cc @@ -17,10 +17,18 @@ #include #include #include +#include +#include "absl/functional/any_invocable.h" +#include "absl/log/check.h" #include "absl/synchronization/mutex.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/cancellation_flag_listener.h" +#include "internal/platform/exception.h" #include "internal/platform/implementation/ble.h" +#include "internal/platform/implementation/bluetooth_adapter.h" +#include "internal/platform/implementation/g3/bluetooth_adapter.h" #include "internal/platform/implementation/shared/count_down_latch.h" #include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" @@ -28,76 +36,11 @@ namespace nearby { namespace g3 { -BleSocket::~BleSocket() { - absl::MutexLock lock(&mutex_); - DoClose(); -} - -void BleSocket::Connect(BleSocket& other) { - absl::MutexLock lock(&mutex_); - remote_socket_ = &other; - input_ = other.output_; -} - -InputStream& BleSocket::GetInputStream() { - auto* remote_socket = GetRemoteSocket(); - CHECK(remote_socket != nullptr); - return remote_socket->GetLocalInputStream(); -} - -OutputStream& BleSocket::GetOutputStream() { return GetLocalOutputStream(); } - -BleSocket* BleSocket::GetRemoteSocket() { - absl::MutexLock lock(&mutex_); - return remote_socket_; -} - -bool BleSocket::IsConnected() const { - absl::MutexLock lock(&mutex_); - return IsConnectedLocked(); -} - -bool BleSocket::IsClosed() const { - absl::MutexLock lock(&mutex_); - return closed_; -} - -Exception BleSocket::Close() { - absl::MutexLock lock(&mutex_); - DoClose(); - return {Exception::kSuccess}; -} - BlePeripheral* BleSocket::GetRemotePeripheral() { absl::MutexLock lock(&mutex_); return peripheral_; } -void BleSocket::DoClose() { - if (!closed_) { - remote_socket_ = nullptr; - output_->GetOutputStream().Close(); - output_->GetInputStream().Close(); - if (IsConnectedLocked()) { - input_->GetOutputStream().Close(); - input_->GetInputStream().Close(); - } - closed_ = true; - } -} - -bool BleSocket::IsConnectedLocked() const { return input_ != nullptr; } - -InputStream& BleSocket::GetLocalInputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetInputStream(); -} - -OutputStream& BleSocket::GetLocalOutputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetOutputStream(); -} - std::unique_ptr BleServerSocket::Accept( BlePeripheral* peripheral) { absl::MutexLock lock(&mutex_); diff --git a/internal/platform/implementation/g3/ble.h b/internal/platform/implementation/g3/ble.h index 2c8fd4c0..243468ff 100644 --- a/internal/platform/implementation/g3/ble.h +++ b/internal/platform/implementation/g3/ble.h @@ -27,7 +27,7 @@ #include "internal/platform/implementation/g3/bluetooth_adapter.h" #include "internal/platform/implementation/g3/bluetooth_classic.h" #include "internal/platform/implementation/g3/multi_thread_executor.h" -#include "internal/platform/implementation/g3/pipe.h" +#include "internal/platform/implementation/g3/socket_base.h" #include "internal/platform/input_stream.h" #include "internal/platform/output_stream.h" @@ -36,64 +36,36 @@ namespace g3 { class BleMedium; -class BleSocket : public api::BleSocket { +class BleSocket : public api::BleSocket, public SocketBase { public: BleSocket() = default; explicit BleSocket(BlePeripheral* peripheral) : peripheral_(peripheral) {} - ~BleSocket() override; - - // Connect to another BleSocket, to form a functional low-level channel. - // from this point on, and until Close is called, connection exists. - void Connect(BleSocket& other) ABSL_LOCKS_EXCLUDED(mutex_); // Returns the InputStream of this connected BleSocket. - InputStream& GetInputStream() override ABSL_LOCKS_EXCLUDED(mutex_); + InputStream& GetInputStream() override { + return SocketBase::GetInputStream(); + } // Returns the OutputStream of this connected BleSocket. // This stream is for local side to write. - OutputStream& GetOutputStream() override ABSL_LOCKS_EXCLUDED(mutex_); + OutputStream& GetOutputStream() override { + return SocketBase::GetOutputStream(); + } // Returns address of a remote BleSocket or nullptr. - BleSocket* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if socket is closed. - bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_); + BleSocket* GetRemoteSocket() { + return static_cast(SocketBase::GetRemoteSocket()); + } // Returns Exception::kIo on error, Exception::kSuccess otherwise. - Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + Exception Close() override { return SocketBase::Close(); } // Returns valid BlePeripheral pointer if there is a connection, and // nullptr otherwise. BlePeripheral* GetRemotePeripheral() override ABSL_LOCKS_EXCLUDED(mutex_); private: - void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns InputStream of our side of a connection. - // This is what the remote side is supposed to read from. - // This is a helper for GetInputStream() method. - InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns OutputStream of our side of a connection. - // This is what the local size is supposed to write to. - // This is a helper for GetOutputStream() method. - OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - // Output pipe is initialized by constructor, it remains always valid, until - // it is closed. it represents output part of a local socket. Input part of a - // local socket comes from the peer socket, after connection. - std::shared_ptr output_{new Pipe}; - std::shared_ptr input_; - mutable absl::Mutex mutex_; BlePeripheral* peripheral_; - BleSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr; - bool closed_ ABSL_GUARDED_BY(mutex_) = false; }; class BleServerSocket { diff --git a/internal/platform/implementation/g3/ble_v2.cc b/internal/platform/implementation/g3/ble_v2.cc index 78886b95..dce7d554 100644 --- a/internal/platform/implementation/g3/ble_v2.cc +++ b/internal/platform/implementation/g3/ble_v2.cc @@ -15,7 +15,6 @@ #include "internal/platform/implementation/g3/ble_v2.h" #include -#include #include #include #include @@ -23,15 +22,26 @@ #include #include +#include "absl/functional/any_invocable.h" +#include "absl/log/check.h" #include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" +#include "internal/platform/borrowable.h" +#include "internal/platform/byte_array.h" #include "internal/platform/cancellation_flag_listener.h" #include "internal/platform/count_down_latch.h" +#include "internal/platform/exception.h" #include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/bluetooth_adapter.h" #include "internal/platform/implementation/g3/bluetooth_adapter.h" #include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" +#include "internal/platform/prng.h" +#include "internal/platform/uuid.h" namespace nearby { namespace g3 { @@ -69,82 +79,14 @@ api::ble_v2::BlePeripheral::UniqueId BleV2Peripheral::GetUniqueId() const { return adapter_.GetUniqueId(); } -BleV2Socket::~BleV2Socket() { - absl::MutexLock lock(&mutex_); - DoClose(); -} - -void BleV2Socket::Connect(BleV2Socket& other) { - absl::MutexLock lock(&mutex_); - remote_socket_ = &other; - input_ = other.output_; -} - -InputStream& BleV2Socket::GetInputStream() { - auto* remote_socket = GetRemoteSocket(); - CHECK(remote_socket != nullptr); - return remote_socket->GetLocalInputStream(); -} - -OutputStream& BleV2Socket::GetOutputStream() { return GetLocalOutputStream(); } - -BleV2Socket* BleV2Socket::GetRemoteSocket() { - absl::MutexLock lock(&mutex_); - return remote_socket_; -} - -bool BleV2Socket::IsConnected() const { - absl::MutexLock lock(&mutex_); - return IsConnectedLocked(); -} - -bool BleV2Socket::IsClosed() const { - absl::MutexLock lock(&mutex_); - return closed_; -} - -Exception BleV2Socket::Close() { - absl::MutexLock lock(&mutex_); - DoClose(); - return {Exception::kSuccess}; -} - BleV2Peripheral* BleV2Socket::GetRemotePeripheral() { - BluetoothAdapter* remote_adapter = nullptr; - { - absl::MutexLock lock(&mutex_); - if (remote_socket_ == nullptr || remote_socket_->adapter_ == nullptr) { - return nullptr; - } - remote_adapter = remote_socket_->adapter_; - } - if (remote_adapter == nullptr || remote_adapter->GetBleV2Medium() == nullptr) + BleV2Socket* remote_socket = GetRemoteSocket(); + if (remote_socket == nullptr || remote_socket->adapter_ == nullptr || + remote_socket->adapter_->GetBleV2Medium() == nullptr) { return nullptr; - return &(static_cast(remote_adapter->GetBleV2Medium()) - ->GetPeripheral()); -} - -void BleV2Socket::DoClose() { - if (!closed_) { - remote_socket_ = nullptr; - output_->GetOutputStream().Close(); - output_->GetInputStream().Close(); - input_->GetOutputStream().Close(); - input_->GetInputStream().Close(); - closed_ = true; } -} - -bool BleV2Socket::IsConnectedLocked() const { return input_ != nullptr; } - -InputStream& BleV2Socket::GetLocalInputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetInputStream(); -} - -OutputStream& BleV2Socket::GetLocalOutputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetOutputStream(); + return &(static_cast(remote_socket->adapter_->GetBleV2Medium()) + ->GetPeripheral()); } std::unique_ptr BleV2ServerSocket::Accept() { diff --git a/internal/platform/implementation/g3/ble_v2.h b/internal/platform/implementation/g3/ble_v2.h index 9b993086..2165c014 100644 --- a/internal/platform/implementation/g3/ble_v2.h +++ b/internal/platform/implementation/g3/ble_v2.h @@ -29,7 +29,7 @@ #include "internal/platform/byte_array.h" #include "internal/platform/implementation/ble_v2.h" #include "internal/platform/implementation/g3/bluetooth_adapter.h" -#include "internal/platform/implementation/g3/pipe.h" +#include "internal/platform/implementation/g3/socket_base.h" #include "internal/platform/medium_environment.h" #include "internal/platform/prng.h" #include "internal/platform/uuid.h" @@ -50,67 +50,35 @@ class BleV2Peripheral : public api::ble_v2::BlePeripheral { BluetoothAdapter& adapter_; }; -class BleV2Socket : public api::ble_v2::BleSocket { +class BleV2Socket : public api::ble_v2::BleSocket, public SocketBase { public: explicit BleV2Socket(BluetoothAdapter* adapter) : adapter_(adapter) {} - BleV2Socket(const BleV2Socket&) = default; - BleV2Socket& operator=(const BleV2Socket&) = default; - BleV2Socket(BleV2Socket&&) = default; - BleV2Socket& operator=(BleV2Socket&&) = default; - ~BleV2Socket() override; - - // Connect to another BleSocket, to form a functional low-level channel. - // from this point on, and until Close is called, connection exists. - void Connect(BleV2Socket& other) ABSL_LOCKS_EXCLUDED(mutex_); // Returns the InputStream of this connected BleSocket. - InputStream& GetInputStream() override ABSL_LOCKS_EXCLUDED(mutex_); + InputStream& GetInputStream() override { + return SocketBase::GetInputStream(); + } // Returns the OutputStream of this connected BleSocket. // This stream is for local side to write. - OutputStream& GetOutputStream() override ABSL_LOCKS_EXCLUDED(mutex_); + OutputStream& GetOutputStream() override { + return SocketBase::GetOutputStream(); + } // Returns address of a remote BleSocket or nullptr. - BleV2Socket* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if socket is closed. - bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_); + BleV2Socket* GetRemoteSocket() { + return static_cast(SocketBase::GetRemoteSocket()); + } // Returns Exception::kIo on error, Exception::kSuccess otherwise. - Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + Exception Close() override { return SocketBase::Close(); } // Returns valid BlePeripheral pointer if there is a connection, and // nullptr otherwise. BleV2Peripheral* GetRemotePeripheral() override ABSL_LOCKS_EXCLUDED(mutex_); private: - void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns InputStream of our side of a connection. - // This is what the remote side is supposed to read from. - // This is a helper for GetInputStream() method. - InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns OutputStream of our side of a connection. - // This is what the local size is supposed to write to. - // This is a helper for GetOutputStream() method. - OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - // Output pipe is initialized by constructor, it remains always valid, until - // it is closed. it represents output part of a local socket. Input part of a - // local socket comes from the peer socket, after connection. - std::shared_ptr output_{new Pipe}; - std::shared_ptr input_; - mutable absl::Mutex mutex_; BluetoothAdapter* adapter_ = nullptr; // Our Adapter. Read only. - BleV2Socket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr; - bool closed_ ABSL_GUARDED_BY(mutex_) = false; }; class BleV2ServerSocket : public api::ble_v2::BleServerSocket { diff --git a/internal/platform/implementation/g3/bluetooth_classic.cc b/internal/platform/implementation/g3/bluetooth_classic.cc index 58f2b7f0..a4d7b121 100644 --- a/internal/platform/implementation/g3/bluetooth_classic.cc +++ b/internal/platform/implementation/g3/bluetooth_classic.cc @@ -17,92 +17,31 @@ #include #include #include +#include +#include "absl/functional/any_invocable.h" +#include "absl/log/check.h" +#include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/cancellation_flag_listener.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/bluetooth_adapter.h" #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/g3/bluetooth_adapter.h" -#include "internal/platform/input_stream.h" #include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" namespace nearby { namespace g3 { -BluetoothSocket::~BluetoothSocket() { - absl::MutexLock lock(&mutex_); - DoClose(); -} - -void BluetoothSocket::Connect(BluetoothSocket& other) { - absl::MutexLock lock(&mutex_); - remote_socket_ = &other; - input_ = other.output_; -} - -bool BluetoothSocket::IsConnected() const { - absl::MutexLock lock(&mutex_); - return IsConnectedLocked(); -} - -bool BluetoothSocket::IsClosed() const { - absl::MutexLock lock(&mutex_); - return closed_; -} - -bool BluetoothSocket::IsConnectedLocked() const { return input_ != nullptr; } - -InputStream& BluetoothSocket::GetInputStream() { - absl::MutexLock lock(&mutex_); - if (IsConnectedLocked()) { - return input_->GetInputStream(); - } else { - return invalid_input_stream_; - } -} - -OutputStream& BluetoothSocket::GetOutputStream() { - return GetLocalOutputStream(); -} - -InputStream& BluetoothSocket::GetLocalInputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetInputStream(); -} - -OutputStream& BluetoothSocket::GetLocalOutputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetOutputStream(); -} - -Exception BluetoothSocket::Close() { - absl::MutexLock lock(&mutex_); - DoClose(); - return {Exception::kSuccess}; -} - -void BluetoothSocket::DoClose() { - if (!closed_) { - remote_socket_ = nullptr; - output_->GetOutputStream().Close(); - output_->GetInputStream().Close(); - input_->GetOutputStream().Close(); - input_->GetInputStream().Close(); - input_.reset(); - closed_ = true; - } -} - BluetoothDevice* BluetoothSocket::GetRemoteDevice() { - BluetoothAdapter* remote_adapter = nullptr; - { - absl::MutexLock lock(&mutex_); - if (remote_socket_ == nullptr || remote_socket_->adapter_ == nullptr) { - return nullptr; - } - remote_adapter = remote_socket_->adapter_; + BluetoothSocket* remote_socket = + static_cast(GetRemoteSocket()); + if (remote_socket == nullptr || remote_socket->adapter_ == nullptr) { + return nullptr; } - return remote_adapter ? &remote_adapter->GetDevice() : nullptr; + return &remote_socket->adapter_->GetDevice(); } std::unique_ptr BluetoothServerSocket::Accept() { diff --git a/internal/platform/implementation/g3/bluetooth_classic.h b/internal/platform/implementation/g3/bluetooth_classic.h index 140bdc12..9c4d4257 100644 --- a/internal/platform/implementation/g3/bluetooth_classic.h +++ b/internal/platform/implementation/g3/bluetooth_classic.h @@ -26,7 +26,7 @@ #include "internal/platform/exception.h" #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/g3/bluetooth_adapter.h" -#include "internal/platform/implementation/g3/pipe.h" +#include "internal/platform/implementation/g3/socket_base.h" #include "internal/platform/input_stream.h" #include "internal/platform/listeners.h" #include "internal/platform/output_stream.h" @@ -35,83 +35,34 @@ namespace nearby { namespace g3 { // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html. -class BluetoothSocket : public api::BluetoothSocket { +class BluetoothSocket : public api::BluetoothSocket, public SocketBase { public: BluetoothSocket() = default; explicit BluetoothSocket(BluetoothAdapter* adapter) : adapter_(adapter) {} - ~BluetoothSocket() override; - - // Connects to another BluetoothSocket, to form a functional low-level - // channel. From this point on, and until Close is called, connection exists. - void Connect(BluetoothSocket& other); - - // NOTE: - // It is an undefined behavior if GetInputStream() or GetOutputStream() is - // called for a not-connected BluetoothSocket, i.e. any object that is not - // returned by BluetoothClassicMedium::ConnectToService() for client side or - // BluetoothServerSocket::Accept() for server side of connection. // Returns the InputStream of this connected BluetoothSocket. - InputStream& GetInputStream() override; + InputStream& GetInputStream() override { + return SocketBase::GetInputStream(); + } // Returns the OutputStream of this connected BluetoothSocket. // This stream is for local side to write. - OutputStream& GetOutputStream() override; - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if socket is closed. - bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_); + OutputStream& GetOutputStream() override { + return SocketBase::GetOutputStream(); + } // Closes both input and output streams, marks Socket as closed. // After this call object should be treated as not connected. // Returns Exception::kIo on error, Exception::kSuccess otherwise. - Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + Exception Close() override { return SocketBase::Close(); } // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#getRemoteDevice() // Returns valid BluetoothDevice pointer if there is a connection, and // nullptr otherwise. - BluetoothDevice* GetRemoteDevice() override ABSL_LOCKS_EXCLUDED(mutex_); + BluetoothDevice* GetRemoteDevice() override; private: - void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns InputStream of our side of a connection. - // This is what the remote side is supposed to read from. - // This is a helper for GetInputStream() method. - InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns OutputStream of our side of a connection. - // This is what the local size is supposed to write to. - // This is a helper for GetOutputStream() method. - OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - class InvalidInputStream : public InputStream { - public: - ExceptionOr Read(std::int64_t size) override { - return ExceptionOr(Exception::kIo); - } - ExceptionOr Skip(size_t offset) override { - return ExceptionOr(Exception::kIo); - } - Exception Close() override { return {Exception::kIo}; } - }; - // Returned to the caller if the remote socket is destroyed. - InvalidInputStream invalid_input_stream_; - - // Output pipe is initialized by constructor, it remains always valid, until - // it is closed. it represents output part of a local socket. Input part of a - // local socket comes from the peer socket, after connection. - std::shared_ptr output_{new Pipe}; - std::shared_ptr input_; - mutable absl::Mutex mutex_; BluetoothAdapter* adapter_ = nullptr; // Our Adapter. Read only. - BluetoothSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr; - bool closed_ ABSL_GUARDED_BY(mutex_) = false; }; // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html. diff --git a/internal/platform/implementation/g3/device_info.h b/internal/platform/implementation/g3/device_info.h index e9a90ff3..87d6a958 100644 --- a/internal/platform/implementation/g3/device_info.h +++ b/internal/platform/implementation/g3/device_info.h @@ -38,7 +38,7 @@ class DeviceInfo : public api::DeviceInfo { return api::DeviceInfo::DeviceType::kLaptop; } - api::DeviceInfo::OsType GetOsType() const override{ + api::DeviceInfo::OsType GetOsType() const override { return api::DeviceInfo::OsType::kChromeOs; } @@ -92,6 +92,10 @@ class DeviceInfo : public api::DeviceInfo { screen_locked_listeners_.erase(listener_name); } + bool PreventSleep() override { return true; } + + bool AllowSleep() override { return true; } + private: absl::flat_hash_map> diff --git a/internal/platform/implementation/g3/pipe.h b/internal/platform/implementation/g3/pipe.h deleted file mode 100644 index 3c2f7f24..00000000 --- a/internal/platform/implementation/g3/pipe.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2020 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 PLATFORM_IMPL_G3_PIPE_H_ -#define PLATFORM_IMPL_G3_PIPE_H_ - -#include - -#include "internal/platform/base_pipe.h" -#include "internal/platform/implementation/g3/condition_variable.h" -#include "internal/platform/implementation/g3/mutex.h" - -namespace nearby { -namespace g3 { - -class Pipe : public BasePipe { - public: - Pipe() { - auto mutex = std::make_unique(/*check=*/true); - auto cond = std::make_unique(mutex.get()); - Setup(std::move(mutex), std::move(cond)); - } - ~Pipe() override = default; - Pipe(Pipe&&) = delete; - Pipe& operator=(Pipe&&) = delete; -}; - -} // namespace g3 -} // namespace nearby - -#endif // PLATFORM_IMPL_G3_PIPE_H_ diff --git a/internal/platform/implementation/g3/socket_base.h b/internal/platform/implementation/g3/socket_base.h new file mode 100644 index 00000000..7678a9e6 --- /dev/null +++ b/internal/platform/implementation/g3/socket_base.h @@ -0,0 +1,156 @@ +// 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_INTERNAL_PLATFORM_IMPLEMENTATION_G3_SOCKET_BASE_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_G3_SOCKET_BASE_H_ + +#include +#include +#include +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/output_stream.h" +#include "internal/platform/pipe.h" + +namespace nearby { +namespace g3 { + +// Common base for BT, BLE and Wifi socket implementations. +class SocketBase { + public: + SocketBase() { std::tie(input_for_remote_, output_) = CreatePipe(); } + virtual ~SocketBase() { + absl::MutexLock lock(&mutex_); + DoClose(); + } + + // Connects to another Socket, to form a functional low-level + // channel. From this point on, and until Close is called, connection exists. + void Connect(SocketBase& other) ABSL_LOCKS_EXCLUDED(mutex_) { + absl::MutexLock lock(&mutex_); + remote_socket_ = &other; + input_ = std::move(other.input_for_remote_); + } + + // Returns the InputStream of this connected socket. + InputStream& GetInputStream() { return input_proxy_; } + + // Returns the OutputStream of this connected socket. + // This stream is for local side to write. + OutputStream& GetOutputStream() ABSL_LOCKS_EXCLUDED(mutex_) { + absl::MutexLock lock(&mutex_); + return *output_; + } + + // Returns true if connection exists to the (possibly closed) remote socket. + bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_) { + absl::MutexLock lock(&mutex_); + return IsConnectedLocked(); + } + + // Returns true if socket is closed. + bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_) { + absl::MutexLock lock(&mutex_); + return closed_; + } + + // Closes both input and output streams, marks Socket as closed. + // After this call object should be treated as not connected. + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + Exception Close() ABSL_LOCKS_EXCLUDED(mutex_) { + absl::MutexLock lock(&mutex_); + DoClose(); + return {Exception::kSuccess}; + } + + SocketBase* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_) { + absl::MutexLock lock(&mutex_); + return remote_socket_; + } + + protected: + mutable absl::Mutex mutex_; + + private: + void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_) { + if (!closed_) { + remote_socket_ = nullptr; + // The client can hold references to `output_` and `input_` streams. We + // can close them but we cannot destroy them. + output_->Close(); + if (input_) { + input_->Close(); + } + // The client does not hold a reference to `input_for_remote_`, so we can + // destroy it. Connecting to this socket will fail after that. + input_for_remote_.reset(); + closed_ = true; + } + } + + // Returns true if connection exists to the (possibly closed) remote socket. + bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_) { + return input_ != nullptr; + } + + class InputProxyStream : public InputStream { + public: + explicit InputProxyStream(SocketBase* socket) : socket_(socket) {} + ExceptionOr Read(std::int64_t size) override { + if (!socket_->IsConnected()) { + return ExceptionOr(Exception::kIo); + } + return socket_->input_->Read(size); + } + ExceptionOr Skip(size_t offset) override { + if (!socket_->IsConnected()) { + return ExceptionOr(Exception::kIo); + } + return socket_->input_->Skip(offset); + } + Exception Close() override { + if (!socket_->IsConnected()) { + return {Exception::kIo}; + } + return socket_->input_->Close(); + } + + private: + SocketBase* socket_; + }; + InputProxyStream input_proxy_{this}; + + // Output stream is initialized by constructor, it remains always valid. It + // represents output part of a local socket. Input stream of a local socket + // comes from the peer socket, after connection. + std::unique_ptr output_; + std::unique_ptr input_; + // `input_for_remote_` is the other end of the pipe formed with `output_`. We + // give this stream to the remote socket when they connect to us, and it + // becomes their `input_` stream. + std::unique_ptr input_for_remote_; + SocketBase* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr; + bool closed_ ABSL_GUARDED_BY(mutex_) = false; +}; + +} // namespace g3 +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_G3_SOCKET_BASE_H_ diff --git a/internal/platform/implementation/g3/wifi_direct.cc b/internal/platform/implementation/g3/wifi_direct.cc index e0d2cdbe..8e49f7f4 100644 --- a/internal/platform/implementation/g3/wifi_direct.cc +++ b/internal/platform/implementation/g3/wifi_direct.cc @@ -16,80 +16,25 @@ #include #include -#include #include #include +#include "absl/log/check.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" +#include "internal/platform/cancellation_flag.h" +#include "internal/platform/exception.h" #include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" +#include "internal/platform/prng.h" +#include "internal/platform/wifi_credential.h" namespace nearby { namespace g3 { -// Code for WifiDirectSocket -WifiDirectSocket::~WifiDirectSocket() { - absl::MutexLock lock(&mutex_); - DoClose(); -} - -void WifiDirectSocket::Connect(WifiDirectSocket& other) { - absl::MutexLock lock(&mutex_); - remote_socket_ = &other; - input_ = other.output_; -} - -InputStream& WifiDirectSocket::GetInputStream() { - auto* remote_socket = GetRemoteSocket(); - CHECK(remote_socket != nullptr); - return remote_socket->GetLocalInputStream(); -} - -OutputStream& WifiDirectSocket::GetOutputStream() { - return GetLocalOutputStream(); -} - -WifiDirectSocket* WifiDirectSocket::GetRemoteSocket() { - absl::MutexLock lock(&mutex_); - return remote_socket_; -} - -bool WifiDirectSocket::IsConnected() const { - absl::MutexLock lock(&mutex_); - return IsConnectedLocked(); -} - -Exception WifiDirectSocket::Close() { - absl::MutexLock lock(&mutex_); - DoClose(); - return {Exception::kSuccess}; -} - -void WifiDirectSocket::DoClose() { - if (!closed_) { - remote_socket_ = nullptr; - output_->GetOutputStream().Close(); - output_->GetInputStream().Close(); - input_->GetOutputStream().Close(); - input_->GetInputStream().Close(); - closed_ = true; - } -} - -bool WifiDirectSocket::IsConnectedLocked() const { return input_ != nullptr; } - -InputStream& WifiDirectSocket::GetLocalInputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetInputStream(); -} - -OutputStream& WifiDirectSocket::GetLocalOutputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetOutputStream(); -} - // Code for WifiDirectServerSocket std::string WifiDirectServerSocket::GetName(absl::string_view ip_address, int port) { diff --git a/internal/platform/implementation/g3/wifi_direct.h b/internal/platform/implementation/g3/wifi_direct.h index bab8ef25..d4b07504 100644 --- a/internal/platform/implementation/g3/wifi_direct.h +++ b/internal/platform/implementation/g3/wifi_direct.h @@ -22,7 +22,7 @@ #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/g3/multi_thread_executor.h" -#include "internal/platform/implementation/g3/pipe.h" +#include "internal/platform/implementation/g3/socket_base.h" #include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/input_stream.h" #include "internal/platform/output_stream.h" @@ -32,66 +32,28 @@ namespace g3 { class WifiDirectMedium; -class WifiDirectSocket : public api::WifiDirectSocket { +class WifiDirectSocket : public api::WifiDirectSocket, public SocketBase { public: - WifiDirectSocket() = default; - ~WifiDirectSocket() override; - WifiDirectSocket(const WifiDirectSocket&) = default; - WifiDirectSocket(WifiDirectSocket&&) = default; - WifiDirectSocket& operator=(const WifiDirectSocket&) = default; - WifiDirectSocket& operator=(WifiDirectSocket&&) = default; - - // Connect to another WifiDirectSocket, to form a functional low-level - // channel. from this point on, and until Close is called, connection exists. - void Connect(WifiDirectSocket& other) ABSL_LOCKS_EXCLUDED(mutex_); - // Returns the InputStream of the WifiDirectSocket. // On error, returned stream will report Exception::kIo on any operation. // // The returned object is not owned by the caller, and can be invalidated once // the WifiDirectSocket object is destroyed. - InputStream& GetInputStream() override ABSL_LOCKS_EXCLUDED(mutex_); + InputStream& GetInputStream() override { + return SocketBase::GetInputStream(); + } // Returns the OutputStream of the WifiDirectSocket. // On error, returned stream will report Exception::kIo on any operation. // // The returned object is not owned by the caller, and can be invalidated once // the WifiDirectSocket object is destroyed. - OutputStream& GetOutputStream() override ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns address of a remote WifiDirectSocket or nullptr. - WifiDirectSocket* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_); + OutputStream& GetOutputStream() override { + return SocketBase::GetOutputStream(); + } // Returns Exception::kIo on error, Exception::kSuccess otherwise. - Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); - - private: - void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns InputStream of our side of a connection. - // This is what the remote side is supposed to read from. - // This is a helper for GetInputStream() method. - InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns OutputStream of our side of a connection. - // This is what the local size is supposed to write to. - // This is a helper for GetOutputStream() method. - OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - // Output pipe is initialized by constructor, it remains always valid, until - // it is closed. it represents output part of a local socket. Input part of a - // local socket comes from the peer socket, after connection. - std::shared_ptr output_{new Pipe}; - std::shared_ptr input_; - mutable absl::Mutex mutex_; - WifiDirectSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr; - bool closed_ ABSL_GUARDED_BY(mutex_) = false; + Exception Close() override { return SocketBase::Close(); } }; // WifiDirectServerSocket provides the support to server socket, this server diff --git a/internal/platform/implementation/g3/wifi_hotspot.cc b/internal/platform/implementation/g3/wifi_hotspot.cc index 49875714..b8da8859 100644 --- a/internal/platform/implementation/g3/wifi_hotspot.cc +++ b/internal/platform/implementation/g3/wifi_hotspot.cc @@ -16,86 +16,26 @@ #include #include -#include #include #include +#include "absl/log/check.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/cancellation_flag_listener.h" +#include "internal/platform/exception.h" #include "internal/platform/implementation/wifi_hotspot.h" #include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" +#include "internal/platform/prng.h" +#include "internal/platform/wifi_credential.h" namespace nearby { namespace g3 { -// Code for WifiHotspotSocket -WifiHotspotSocket::~WifiHotspotSocket() { - absl::MutexLock lock(&mutex_); - DoClose(); -} - -void WifiHotspotSocket::Connect(WifiHotspotSocket& other) { - absl::MutexLock lock(&mutex_); - remote_socket_ = &other; - input_ = other.output_; -} - -InputStream& WifiHotspotSocket::GetInputStream() { - auto* remote_socket = GetRemoteSocket(); - CHECK(remote_socket != nullptr); - return remote_socket->GetLocalInputStream(); -} - -OutputStream& WifiHotspotSocket::GetOutputStream() { - return GetLocalOutputStream(); -} - -WifiHotspotSocket* WifiHotspotSocket::GetRemoteSocket() { - absl::MutexLock lock(&mutex_); - return remote_socket_; -} - -bool WifiHotspotSocket::IsConnected() const { - absl::MutexLock lock(&mutex_); - return IsConnectedLocked(); -} - -bool WifiHotspotSocket::IsClosed() const { - absl::MutexLock lock(&mutex_); - return closed_; -} - -Exception WifiHotspotSocket::Close() { - absl::MutexLock lock(&mutex_); - DoClose(); - return {Exception::kSuccess}; -} - -void WifiHotspotSocket::DoClose() { - if (!closed_) { - remote_socket_ = nullptr; - output_->GetOutputStream().Close(); - output_->GetInputStream().Close(); - input_->GetOutputStream().Close(); - input_->GetInputStream().Close(); - closed_ = true; - } -} - -bool WifiHotspotSocket::IsConnectedLocked() const { return input_ != nullptr; } - -InputStream& WifiHotspotSocket::GetLocalInputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetInputStream(); -} - -OutputStream& WifiHotspotSocket::GetLocalOutputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetOutputStream(); -} - // Code for WifiHotspotServerSocket std::string WifiHotspotServerSocket::GetName(absl::string_view ip_address, int port) { diff --git a/internal/platform/implementation/g3/wifi_hotspot.h b/internal/platform/implementation/g3/wifi_hotspot.h index d4682621..a3b3e69f 100644 --- a/internal/platform/implementation/g3/wifi_hotspot.h +++ b/internal/platform/implementation/g3/wifi_hotspot.h @@ -23,7 +23,7 @@ #include "absl/synchronization/mutex.h" #include "internal/platform/byte_array.h" #include "internal/platform/implementation/g3/multi_thread_executor.h" -#include "internal/platform/implementation/g3/pipe.h" +#include "internal/platform/implementation/g3/socket_base.h" #include "internal/platform/implementation/wifi_hotspot.h" #include "internal/platform/input_stream.h" #include "internal/platform/output_stream.h" @@ -33,69 +33,28 @@ namespace g3 { class WifiHotspotMedium; -class WifiHotspotSocket : public api::WifiHotspotSocket { +class WifiHotspotSocket : public api::WifiHotspotSocket, public SocketBase { public: - WifiHotspotSocket() = default; - ~WifiHotspotSocket() override; - WifiHotspotSocket(const WifiHotspotSocket&) = default; - WifiHotspotSocket(WifiHotspotSocket&&) = default; - WifiHotspotSocket& operator=(const WifiHotspotSocket&) = default; - WifiHotspotSocket& operator=(WifiHotspotSocket&&) = default; - - // Connect to another WifiHotspotSocket, to form a functional low-level - // channel. from this point on, and until Close is called, connection exists. - void Connect(WifiHotspotSocket& other) ABSL_LOCKS_EXCLUDED(mutex_); - // Returns the InputStream of the WifiHotspotSocket. // On error, returned stream will report Exception::kIo on any operation. // // The returned object is not owned by the caller, and can be invalidated once // the WifiHotspotSocket object is destroyed. - InputStream& GetInputStream() override ABSL_LOCKS_EXCLUDED(mutex_); + InputStream& GetInputStream() override { + return SocketBase::GetInputStream(); + } // Returns the OutputStream of the WifiHotspotSocket. // On error, returned stream will report Exception::kIo on any operation. // // The returned object is not owned by the caller, and can be invalidated once // the WifiHotspotSocket object is destroyed. - OutputStream& GetOutputStream() override ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns address of a remote WifiHotspotSocket or nullptr. - WifiHotspotSocket* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if socket is closed. - bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_); + OutputStream& GetOutputStream() override { + return SocketBase::GetOutputStream(); + } // Returns Exception::kIo on error, Exception::kSuccess otherwise. - Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); - - private: - void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns InputStream of our side of a connection. - // This is what the remote side is supposed to read from. - // This is a helper for GetInputStream() method. - InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns OutputStream of our side of a connection. - // This is what the local size is supposed to write to. - // This is a helper for GetOutputStream() method. - OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - // Output pipe is initialized by constructor, it remains always valid, until - // it is closed. it represents output part of a local socket. Input part of a - // local socket comes from the peer socket, after connection. - std::shared_ptr output_{new Pipe}; - std::shared_ptr input_; - mutable absl::Mutex mutex_; - WifiHotspotSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr; - bool closed_ ABSL_GUARDED_BY(mutex_) = false; + Exception Close() override { return SocketBase::Close(); } }; // WifiHotspotServerSocket provides the support to server socket, this server diff --git a/internal/platform/implementation/g3/wifi_lan.cc b/internal/platform/implementation/g3/wifi_lan.cc index 043f921f..8d4626e3 100644 --- a/internal/platform/implementation/g3/wifi_lan.cc +++ b/internal/platform/implementation/g3/wifi_lan.cc @@ -19,10 +19,13 @@ #include #include -#include "absl/strings/escaping.h" +#include "absl/log/check.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/synchronization/mutex.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/cancellation_flag_listener.h" +#include "internal/platform/exception.h" #include "internal/platform/implementation/wifi_lan.h" #include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" @@ -31,71 +34,6 @@ namespace nearby { namespace g3 { -WifiLanSocket::~WifiLanSocket() { - absl::MutexLock lock(&mutex_); - DoClose(); -} - -void WifiLanSocket::Connect(WifiLanSocket& other) { - absl::MutexLock lock(&mutex_); - remote_socket_ = &other; - input_ = other.output_; -} - -InputStream& WifiLanSocket::GetInputStream() { - auto* remote_socket = GetRemoteSocket(); - CHECK(remote_socket != nullptr); - return remote_socket->GetLocalInputStream(); -} - -OutputStream& WifiLanSocket::GetOutputStream() { - return GetLocalOutputStream(); -} - -WifiLanSocket* WifiLanSocket::GetRemoteSocket() { - absl::MutexLock lock(&mutex_); - return remote_socket_; -} - -bool WifiLanSocket::IsConnected() const { - absl::MutexLock lock(&mutex_); - return IsConnectedLocked(); -} - -bool WifiLanSocket::IsClosed() const { - absl::MutexLock lock(&mutex_); - return closed_; -} - -Exception WifiLanSocket::Close() { - absl::MutexLock lock(&mutex_); - DoClose(); - return {Exception::kSuccess}; -} - -void WifiLanSocket::DoClose() { - if (!closed_) { - remote_socket_ = nullptr; - output_->GetOutputStream().Close(); - output_->GetInputStream().Close(); - input_->GetOutputStream().Close(); - input_->GetInputStream().Close(); - closed_ = true; - } -} - -bool WifiLanSocket::IsConnectedLocked() const { return input_ != nullptr; } - -InputStream& WifiLanSocket::GetLocalInputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetInputStream(); -} - -OutputStream& WifiLanSocket::GetLocalOutputStream() { - absl::MutexLock lock(&mutex_); - return output_->GetOutputStream(); -} - std::string WifiLanServerSocket::GetName(const std::string& ip_address, int port) { std::string dot_delimited_string; diff --git a/internal/platform/implementation/g3/wifi_lan.h b/internal/platform/implementation/g3/wifi_lan.h index 398f2c51..b51f05fd 100644 --- a/internal/platform/implementation/g3/wifi_lan.h +++ b/internal/platform/implementation/g3/wifi_lan.h @@ -24,7 +24,7 @@ #include "absl/synchronization/mutex.h" #include "internal/platform/byte_array.h" #include "internal/platform/implementation/g3/multi_thread_executor.h" -#include "internal/platform/implementation/g3/pipe.h" +#include "internal/platform/implementation/g3/socket_base.h" #include "internal/platform/implementation/wifi_lan.h" #include "internal/platform/input_stream.h" #include "internal/platform/nsd_service_info.h" @@ -35,58 +35,26 @@ namespace g3 { class WifiLanMedium; -class WifiLanSocket : public api::WifiLanSocket { +class WifiLanSocket : public api::WifiLanSocket, public SocketBase { public: - WifiLanSocket() = default; - ~WifiLanSocket() override; - - // Connect to another WifiLanSocket, to form a functional low-level channel. - // from this point on, and until Close is called, connection exists. - void Connect(WifiLanSocket& other) ABSL_LOCKS_EXCLUDED(mutex_); - // Returns the InputStream of this connected WifiLanSocket. - InputStream& GetInputStream() override ABSL_LOCKS_EXCLUDED(mutex_); + InputStream& GetInputStream() override { + return SocketBase::GetInputStream(); + } // Returns the OutputStream of this connected WifiLanSocket. // This stream is for local side to write. - OutputStream& GetOutputStream() override ABSL_LOCKS_EXCLUDED(mutex_); + OutputStream& GetOutputStream() override { + return SocketBase::GetOutputStream(); + } // Returns address of a remote WifiLanSocket or nullptr. - WifiLanSocket* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if socket is closed. - bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_); + WifiLanSocket* GetRemoteSocket() { + return static_cast(SocketBase::GetRemoteSocket()); + } // Returns Exception::kIo on error, Exception::kSuccess otherwise. - Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); - - private: - void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns true if connection exists to the (possibly closed) remote socket. - bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns InputStream of our side of a connection. - // This is what the remote side is supposed to read from. - // This is a helper for GetInputStream() method. - InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns OutputStream of our side of a connection. - // This is what the local size is supposed to write to. - // This is a helper for GetOutputStream() method. - OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_); - - // Output pipe is initialized by constructor, it remains always valid, until - // it is closed. it represents output part of a local socket. Input part of a - // local socket comes from the peer socket, after connection. - std::shared_ptr output_{new Pipe}; - std::shared_ptr input_; - mutable absl::Mutex mutex_; - WifiLanSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr; - bool closed_ ABSL_GUARDED_BY(mutex_) = false; + Exception Close() override { return SocketBase::Close(); } }; class WifiLanServerSocket : public api::WifiLanServerSocket { diff --git a/internal/platform/implementation/windows/BUILD b/internal/platform/implementation/windows/BUILD index 4ba8c0de..8f615664 100644 --- a/internal/platform/implementation/windows/BUILD +++ b/internal/platform/implementation/windows/BUILD @@ -11,6 +11,7 @@ # 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. + licenses(["notice"]) cc_library( @@ -49,7 +50,6 @@ cc_library( "//base:stringprintf", "//internal/base:bluetooth_address", "//internal/platform:base", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform:uuid", "//internal/platform/implementation:types", @@ -95,6 +95,7 @@ cc_library( "mutex.h", "scheduled_executor.h", "server_sync.h", + "session_manager.h", "submittable_executor.h", "thread_pool.h", "webrtc.h", @@ -166,6 +167,7 @@ cc_library( "preferences_repository.cc", "preferences_repository.h", "scheduled_executor.cc", + "session_manager.cc", "submittable_executor.cc", "system_clock.cc", "thread_pool.cc", @@ -202,7 +204,6 @@ cc_library( "//internal/platform:base", "//internal/platform:cancellation_flag", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform:uuid", "//internal/platform/flags:platform_flags", @@ -283,7 +284,7 @@ cc_test( ":types", ":windows", "//internal/platform:base", - "//internal/platform:logging", + "//internal/platform:types", "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", "//internal/platform/implementation:types", diff --git a/internal/platform/implementation/windows/ble_v2.cc b/internal/platform/implementation/windows/ble_v2.cc index afe45ecc..eb607be1 100644 --- a/internal/platform/implementation/windows/ble_v2.cc +++ b/internal/platform/implementation/windows/ble_v2.cc @@ -47,6 +47,7 @@ #include "winrt/Windows.Devices.Bluetooth.Advertisement.h" #include "winrt/Windows.Devices.Bluetooth.h" #include "winrt/Windows.Foundation.Collections.h" +#include "winrt/Windows.Storage.Streams.h" // NOLINT(misc-include-cleaner) namespace nearby { namespace windows { @@ -68,6 +69,8 @@ using ::winrt::Windows::Devices::Bluetooth::Advertisement:: BluetoothLEAdvertisementDataSection; using ::winrt::Windows::Devices::Bluetooth::Advertisement:: BluetoothLEAdvertisementDataTypes; +using ::winrt::Windows::Devices::Bluetooth::Advertisement:: + BluetoothLEAdvertisementFilter; // NOLINT(misc-include-cleaner) using ::winrt::Windows::Devices::Bluetooth::Advertisement:: BluetoothLEAdvertisementPublisher; using ::winrt::Windows::Devices::Bluetooth::Advertisement:: @@ -230,9 +233,19 @@ bool BleV2Medium::StartScanning(const Uuid& service_uuid, // Active mode indicates that scan request packets will be sent to query for // Scan Response watcher_.ScanningMode(BluetoothLEScanningMode::Active); - ::winrt::Windows::Devices::Bluetooth::BluetoothSignalStrengthFilter filter; - filter.SamplingInterval(TimeSpan(std::chrono::seconds(2))); - watcher_.SignalStrengthFilter(filter); + + BluetoothLEAdvertisementDataSection data_section; + data_section.DataType(0x16); + DataWriter data_writer; // NOLINT(misc-include-cleaner) + std::array service_id_data = service_uuid_.data(); + data_writer.WriteByte(service_id_data[3] & 0xff); + data_writer.WriteByte(service_id_data[2] & 0xff); + data_section.Data(data_writer.DetachBuffer()); + BluetoothLEAdvertisement advertisement; + advertisement.DataSections().Append(data_section); + BluetoothLEAdvertisementFilter advertisement_filter; + advertisement_filter.Advertisement(advertisement); + watcher_.AdvertisementFilter(advertisement_filter); watcher_.Start(); is_watcher_started_ = true; diff --git a/internal/platform/implementation/windows/bluetooth_classic_medium.cc b/internal/platform/implementation/windows/bluetooth_classic_medium.cc index 431400ba..9daaa8d7 100644 --- a/internal/platform/implementation/windows/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/windows/bluetooth_classic_medium.cc @@ -311,7 +311,10 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( RfcommDeviceService requested_service( GetRequestedService(current_device, service)); - if (!CheckSdp(requested_service)) { + if (!FeatureFlags::GetInstance() + .GetFlags() + .skip_service_discovery_before_connecting_to_rfcomm && + !CheckSdp(requested_service)) { NEARBY_LOGS(ERROR) << __func__ << ": Invalid SDP."; return nullptr; } diff --git a/internal/platform/implementation/windows/device_info.cc b/internal/platform/implementation/windows/device_info.cc index c9ef9adb..5978f27c 100644 --- a/internal/platform/implementation/windows/device_info.cc +++ b/internal/platform/implementation/windows/device_info.cc @@ -23,11 +23,14 @@ #include #include #include +#include #include "absl/container/flat_hash_map.h" #include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" #include "internal/base/bluetooth_address.h" #include "internal/platform/implementation/device_info.h" +#include "internal/platform/implementation/windows/session_manager.h" #include "internal/platform/logging.h" #include "winrt/Windows.Foundation.Collections.h" #include "winrt/Windows.Foundation.h" @@ -49,89 +52,10 @@ using IVectorView = winrt::Windows::Foundation::Collections::IVectorView; template using IAsyncOperation = winrt::Windows::Foundation::IAsyncOperation; -constexpr char window_class_name[] = "NearbySharingDLL_MessageWindowClass"; -constexpr char window_name[] = "NearbySharingDLL_MessageWindow"; constexpr char logs_relative_path[] = "Google\\Nearby\\Sharing\\Logs"; constexpr char crash_dumps_relative_path[] = "Google\\Nearby\\Sharing\\CrashDumps"; -namespace { -// This WindowProc method must be static for the successful initialization of -// WNDCLASS -// window_class.lpfnWndProc = (WNDPROC) &DeviceInfo::WindowProc; -// where a WNDPROC typed function pointer is expected -// typedef LRESULT (CALLBACK* WNDPROC)(HWND,UINT,WPARAM,LPARAM) -// the calling convention used here CALLBACK is a macro defined as -// #define CALLBACK __stdcall -// -// If WindProc is not static and defined as a member function, it uses the -// __thiscall calling convention instead -// https://docs.microsoft.com/en-us/cpp/cpp/thiscall?view=msvc-170 -// https://isocpp.org/wiki/faq/pointers-to-members -// https://en.cppreference.com/w/cpp/language/pointer -// -// This is problematic because the function pointer now looks like this -// typedef LRESULT (CALLBACK* DeviceInfo_WNDPROC)(DeviceInfo* -// this,HWND,UINT,WPARAM,LPARAM) -// which causes casting errors -LRESULT CALLBACK WindowProc(HWND window_handle, UINT message, WPARAM wparam, - LPARAM lparam) { - DeviceInfo* self = reinterpret_cast( - GetWindowLongPtr(window_handle, GWLP_USERDATA)); - CREATESTRUCT* create_struct = reinterpret_cast(lparam); - LONG_PTR result = 0L; - switch (message) { - case WM_CREATE: - self = reinterpret_cast(create_struct->lpCreateParams); - self->message_window_handle_ = window_handle; - - // Store pointer to the self to the window's user data. - SetLastError(0); - result = SetWindowLongPtr(window_handle, GWLP_USERDATA, - reinterpret_cast(self)); - if (result == 0 && GetLastError() != 0) { - NEARBY_LOGS(ERROR) - << __func__ - << ": Error connecting message window to Nearby Sharing DLL."; - } - break; - case WM_WTSSESSION_CHANGE: - if (self) { - switch (wparam) { - case WTS_SESSION_LOCK: - for (auto& listener : self->screen_locked_listeners_) { - listener.second(api::DeviceInfo::ScreenStatus:: - kLocked); // Trigger registered callbacks - } - break; - case WTS_SESSION_UNLOCK: - for (auto& listener : self->screen_locked_listeners_) { - listener.second(api::DeviceInfo::ScreenStatus:: - kUnlocked); // Trigger registered callbacks - } - break; - } - } - break; - case WM_DESTROY: - SetLastError(0); - result = SetWindowLongPtr(window_handle, GWLP_USERDATA, NULL); - if (result == 0 && GetLastError() != 0) { - NEARBY_LOGS(ERROR) - << __func__ - << ": Error disconnecting message window to Nearby Sharing DLL."; - } - break; - } - - return DefWindowProc(window_handle, message, wparam, lparam); -} -} // namespace - -DeviceInfo::~DeviceInfo() { - UnregisterClass(MAKEINTATOM(registered_class_), instance_); -} - std::optional DeviceInfo::GetOsDeviceName() const { DWORD size = 0; @@ -404,78 +328,39 @@ std::optional DeviceInfo::GetCrashDumpPath() const { } bool DeviceInfo::IsScreenLocked() const { - DWORD session_id = WTSGetActiveConsoleSessionId(); - WTS_INFO_CLASS wts_info_class = WTSSessionInfoEx; - LPTSTR session_info_buffer = nullptr; - DWORD session_info_buffer_size_bytes = 0; - - WTSINFOEXW* wts_info = nullptr; - LONG session_state = WTS_SESSIONSTATE_UNKNOWN; - - if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session_id, - wts_info_class, &session_info_buffer, - &session_info_buffer_size_bytes)) { - if (session_info_buffer_size_bytes > 0) { - wts_info = (WTSINFOEXW*)session_info_buffer; - if (wts_info->Level == 1) { - session_state = wts_info->Data.WTSInfoExLevel1.SessionFlags; - } - } - WTSFreeMemory(session_info_buffer); - session_info_buffer = nullptr; - } - - return (session_state == WTS_SESSIONSTATE_LOCK); + absl::MutexLock lock(&mutex_); + return session_manager_.IsScreenLocked(); } void DeviceInfo::RegisterScreenLockedListener( absl::string_view listener_name, std::function callback) { - if (message_window_handle_ == nullptr) { - instance_ = (HINSTANCE)GetModuleHandle(NULL); - - WNDCLASS window_class; - window_class.style = 0; - window_class.lpfnWndProc = (WNDPROC)&WindowProc; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = instance_; - window_class.hIcon = nullptr; - window_class.hCursor = nullptr; - window_class.hbrBackground = nullptr; - window_class.lpszMenuName = nullptr; - window_class.lpszClassName = window_class_name; - - registered_class_ = RegisterClass(&window_class); - - message_window_handle_ = CreateWindow( - MAKEINTATOM(registered_class_), // class atom from RegisterClass - window_name, // window name - 0, // window style - 0, // initial x position of window - 0, // initial y position of window - 0, // width - 0, // height - HWND_MESSAGE, // handle to the parent of window - // (message-only window in this case) - nullptr, // handle to a menu - instance_, // handle to the instance of the module - // associated to the window - this); // pointer to be passed to the window for additional data - - if (!message_window_handle_) { - NEARBY_LOGS(ERROR) - << __func__ - << ": Failed to create message window for Nearby Sharing DLL."; - } - } - - screen_locked_listeners_.emplace(listener_name, callback); + absl::MutexLock lock(&mutex_); + session_manager_.RegisterSessionListener( + listener_name, + [callback = std::move(callback)](SessionManager::SessionState state) { + if (state == SessionManager::SessionState::kLock) { + callback(api::DeviceInfo::ScreenStatus::kLocked); + } else if (state == SessionManager::SessionState::kUnlock) { + callback(api::DeviceInfo::ScreenStatus::kUnlocked); + } + }); } void DeviceInfo::UnregisterScreenLockedListener( absl::string_view listener_name) { - screen_locked_listeners_.erase(listener_name); + absl::MutexLock lock(&mutex_); + session_manager_.UnregisterSessionListener(listener_name); +} + +bool DeviceInfo::PreventSleep() { + absl::MutexLock lock(&mutex_); + return session_manager_.PreventSleep(); +} + +bool DeviceInfo::AllowSleep() { + absl::MutexLock lock(&mutex_); + return session_manager_.AllowSleep(); } } // namespace windows diff --git a/internal/platform/implementation/windows/device_info.h b/internal/platform/implementation/windows/device_info.h index b8ea3995..79c96771 100644 --- a/internal/platform/implementation/windows/device_info.h +++ b/internal/platform/implementation/windows/device_info.h @@ -1,4 +1,4 @@ -// Copyright 2021 Google LLC +// Copyright 2021-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. @@ -15,25 +15,21 @@ #ifndef PLATFORM_IMPL_WINDOWS_DEVICE_INFO_H_ #define PLATFORM_IMPL_WINDOWS_DEVICE_INFO_H_ -#include -#include - -#include #include #include -#include -#include "absl/container/flat_hash_map.h" +#include "absl/base/thread_annotations.h" #include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" #include "internal/platform/implementation/device_info.h" -#include "winrt/Windows.Foundation.h" +#include "internal/platform/implementation/windows/session_manager.h" namespace nearby { namespace windows { class DeviceInfo : public api::DeviceInfo { public: - ~DeviceInfo() override; + ~DeviceInfo() override = default; std::optional GetOsDeviceName() const override; api::DeviceInfo::DeviceType GetDeviceType() const override; @@ -55,13 +51,13 @@ class DeviceInfo : public api::DeviceInfo { absl::string_view listener_name, std::function callback) override; void UnregisterScreenLockedListener(absl::string_view listener_name) override; - absl::flat_hash_map> - screen_locked_listeners_; - HINSTANCE instance_ = nullptr; - ATOM registered_class_ = NULL; - HWND message_window_handle_ = nullptr; + bool PreventSleep() override; + bool AllowSleep() override; + + private: + mutable absl::Mutex mutex_; + SessionManager session_manager_ ABSL_GUARDED_BY(mutex_); }; } // namespace windows diff --git a/internal/platform/implementation/windows/device_info_test.cc b/internal/platform/implementation/windows/device_info_test.cc index 89c076b3..d19c4370 100644 --- a/internal/platform/implementation/windows/device_info_test.cc +++ b/internal/platform/implementation/windows/device_info_test.cc @@ -77,59 +77,12 @@ TEST(DeviceInfo, DISABLED_IsScreenLocked) { EXPECT_FALSE(DeviceInfo().IsScreenLocked()); } -TEST(DeviceInfo, DISABLED_RegisterScreenLockedListener) { - std::function listener_1 = - [](api::DeviceInfo::ScreenStatus) {}; - std::function listener_2 = - [](api::DeviceInfo::ScreenStatus) {}; - - DeviceInfo device_info; - EXPECT_EQ(device_info.screen_locked_listeners_.size(), 0); - - device_info.RegisterScreenLockedListener("listener_1", listener_1); - EXPECT_EQ(device_info.screen_locked_listeners_.size(), 1); - - device_info.RegisterScreenLockedListener("listener_2", listener_2); - EXPECT_EQ(device_info.screen_locked_listeners_.size(), 2); +TEST(DeviceInfo, DISABLED_PreventSleep) { + EXPECT_TRUE(DeviceInfo().PreventSleep()); } -TEST(DeviceInfo, DISABLED_UnregisterScreenLockedListener) { - std::function listener_1 = - [](api::DeviceInfo::ScreenStatus) {}; - std::function listener_2 = - [](api::DeviceInfo::ScreenStatus) {}; - - DeviceInfo device_info; - EXPECT_EQ(device_info.screen_locked_listeners_.size(), 0); - - device_info.RegisterScreenLockedListener("listener_1", listener_1); - device_info.RegisterScreenLockedListener("listener_2", listener_2); - EXPECT_EQ(device_info.screen_locked_listeners_.size(), 2); - - device_info.UnregisterScreenLockedListener("listener_1"); - EXPECT_EQ(device_info.screen_locked_listeners_.size(), 1); - - device_info.UnregisterScreenLockedListener("listener_2"); - EXPECT_EQ(device_info.screen_locked_listeners_.size(), 0); -} - -TEST(DeviceInfo, DISABLED_UpdateScreenLockedListener) { - absl::Notification notification; - - api::DeviceInfo::ScreenStatus screen_locked_tracker = - api::DeviceInfo::ScreenStatus::kUndetermined; - - std::function listener = - [&screen_locked_tracker, - ¬ification](api::DeviceInfo::ScreenStatus status) { - screen_locked_tracker = api::DeviceInfo::ScreenStatus::kLocked; - notification.Notify(); - }; - - DeviceInfo device_info; - device_info.RegisterScreenLockedListener("listener", listener); - EXPECT_TRUE(notification.WaitForNotificationWithTimeout(absl::Seconds(5))); - EXPECT_EQ(screen_locked_tracker, api::DeviceInfo::ScreenStatus::kLocked); +TEST(DeviceInfo, DISABLED_AllowSleep) { + EXPECT_TRUE(DeviceInfo().AllowSleep()); } } // namespace diff --git a/internal/platform/implementation/windows/session_manager.cc b/internal/platform/implementation/windows/session_manager.cc new file mode 100644 index 00000000..3624a3ae --- /dev/null +++ b/internal/platform/implementation/windows/session_manager.cc @@ -0,0 +1,290 @@ +// 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 "internal/platform/implementation/windows/session_manager.h" + +#include +#include + +#include +#include + +#include "absl/base/attributes.h" +#include "absl/base/const_init.h" +#include "absl/container/flat_hash_map.h" +#include "absl/functional/any_invocable.h" +#include "absl/synchronization/mutex.h" +#include "absl/synchronization/notification.h" +#include "internal/platform/implementation/windows/submittable_executor.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace windows { +namespace { + +constexpr char kMessageWindowClass[] = "Nearby Message Window Class"; +constexpr char kMessageWindowTitle[] = "Nearby Message Dummy Window"; + +LRESULT CALLBACK NearbyWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) { + switch (uMsg) { + case WM_DESTROY: + PostQuitMessage(0); + break; + case WM_WTSSESSION_CHANGE: + if (wParam == WTS_SESSION_LOCK) { + SessionManager::NotifySessionState(SessionManager::SessionState::kLock); + } else if (wParam == WTS_SESSION_UNLOCK) { + SessionManager::NotifySessionState( + SessionManager::SessionState::kUnlock); + } + break; + } + + // NOLINTNEXTLINE(misc-include-cleaner) + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +HWND CreateNearbyWindow() { + HINSTANCE instance = (HINSTANCE)GetModuleHandle(nullptr); + + WNDCLASS window_class = {}; + window_class.lpfnWndProc = NearbyWindowProc; + window_class.hInstance = instance; + window_class.lpszClassName = kMessageWindowClass; + + RegisterClass(&window_class); + + HWND hwnd = + CreateWindowA(kMessageWindowClass, kMessageWindowTitle, /*dwStyle=*/0, + /*X=*/0, /*Y=*/0, /*nWidth=*/0, /*nHeight=*/0, HWND_MESSAGE, + /*hMenu=*/nullptr, instance, + /*lpParam=*/nullptr); + + return hwnd; +} + +} // namespace + +// Initialize class static variables. +ABSL_CONST_INIT absl::Mutex SessionManager::session_mutex_{absl::kConstInit}; +HWND SessionManager::session_hwnd_ = nullptr; +SubmittableExecutor* SessionManager::session_thread_ = nullptr; +absl::flat_hash_map>* + SessionManager::session_callbacks_ = nullptr; + +SessionManager::~SessionManager() { StopSession(); } + +bool SessionManager::RegisterSessionListener( + absl::string_view listener_name, + absl::AnyInvocable callback) { + absl::MutexLock lock(&session_mutex_); + NEARBY_LOGS(INFO) << __func__ << ": Registering listener: " << listener_name; + + // Create session thread if no running thread. + if (session_thread_ == nullptr) { + absl::Notification notification; + session_thread_ = new SubmittableExecutor(); + session_callbacks_ = new absl::flat_hash_map< + std::string, absl::AnyInvocable>(); + session_thread_->Execute( + [this, ¬ification]() { StartSession(notification); }); + notification.WaitForNotification(); + if (session_thread_ == nullptr) { + return false; + } + } + + if (session_callbacks_->contains(listener_name) || + listeners_.contains(listener_name)) { + return false; + } + + session_callbacks_->emplace(listener_name, std::move(callback)); + listeners_.emplace(listener_name); + NEARBY_LOGS(INFO) << __func__ << ": Session listener: " << listener_name + << " is registered."; + return true; +} + +bool SessionManager::UnregisterSessionListener( + absl::string_view listener_name) { + absl::MutexLock lock(&session_mutex_); + NEARBY_LOGS(INFO) << __func__ + << ": Unregistering listener: " << listener_name; + if (session_thread_ == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": No running listener."; + return false; + } + if (!session_callbacks_->contains(listener_name) || + !listeners_.contains(listener_name)) { + NEARBY_LOGS(ERROR) << __func__ + << ": No listener with name:" << listener_name; + return false; + } + session_callbacks_->erase(listener_name); + listeners_.erase(listener_name); + + if (!session_callbacks_->empty()) { + NEARBY_LOGS(INFO) << __func__ << ": Session listener: " << listener_name + << " is unregistered."; + return true; + } + + CleanUp(); + NEARBY_LOGS(INFO) << __func__ << ": Session listener: " << listener_name + << " is unregistered."; + return true; +} + +bool SessionManager::IsScreenLocked() const { + DWORD session_id = WTSGetActiveConsoleSessionId(); + WTS_INFO_CLASS wts_info_class = WTSSessionInfoEx; + LPTSTR session_info_buffer = nullptr; + DWORD session_info_buffer_size_bytes = 0; + + WTSINFOEXW* wts_info = nullptr; + LONG session_state = WTS_SESSIONSTATE_UNKNOWN; + + if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session_id, + wts_info_class, &session_info_buffer, + &session_info_buffer_size_bytes)) { + if (session_info_buffer_size_bytes > 0) { + wts_info = (WTSINFOEXW*)session_info_buffer; + if (wts_info->Level == 1) { + session_state = wts_info->Data.WTSInfoExLevel1.SessionFlags; + } + } + WTSFreeMemory(session_info_buffer); + session_info_buffer = nullptr; + } + + return (session_state == WTS_SESSIONSTATE_LOCK); +} + +bool SessionManager::PreventSleep() const { + EXECUTION_STATE execution_state = + SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); + if (execution_state == 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to set execution state of the thread."; + return false; + } + return true; +} + +bool SessionManager::AllowSleep() const { + EXECUTION_STATE execution_state = SetThreadExecutionState(ES_CONTINUOUS); + if (execution_state == 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to set execution state of the thread."; + return false; + } + return true; +} + +void SessionManager::NotifySessionState(SessionState state) { + NEARBY_LOGS(INFO) << __func__ + << ": Notifying session state: " << static_cast(state); + if (state == SessionManager::SessionState::kLock) { + absl::MutexLock lock(&session_mutex_); + for (auto& it : *SessionManager::session_callbacks_) { + it.second(SessionManager::SessionState::kLock); + } + } else if (state == SessionManager::SessionState::kUnlock) { + absl::MutexLock lock(&session_mutex_); + for (auto& it : *SessionManager::session_callbacks_) { + it.second(SessionManager::SessionState::kUnlock); + } + } +} + +void SessionManager::StartSession(absl::Notification& notification) { + session_hwnd_ = CreateNearbyWindow(); + if (session_hwnd_ == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": Failed to create session Window."; + return; + } + + if (!WTSRegisterSessionNotification(session_hwnd_, NOTIFY_FOR_THIS_SESSION)) { + NEARBY_LOGS(ERROR) << __func__ + << ":Failed to register session notification."; + return; + } + + notification.Notify(); + + NEARBY_LOGS(INFO) << __func__ << ": Session thread started."; + + // Main message loop + MSG msg = {}; + // NOLINTNEXTLINE(misc-include-cleaner) + while (GetMessage(&msg, session_hwnd_, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (!WTSUnRegisterSessionNotification(session_hwnd_)) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to register session notification."; + return; + } + + if (!UnregisterClassA(/*lpClassName=*/kMessageWindowClass, + /*hInstance=*/(HINSTANCE)GetModuleHandle(nullptr))) { + NEARBY_LOGS(ERROR) << __func__ << ": Failed to unregister window class."; + } + + NEARBY_LOGS(INFO) << __func__ << ": Completed Message loop."; +} + +void SessionManager::StopSession() { + if (session_thread_ == nullptr) { + return; + } + + absl::MutexLock lock(&session_mutex_); + if (session_thread_ == nullptr) { + return; + } + for (const auto& it : listeners_) { + session_callbacks_->erase(it); + } + + listeners_.clear(); + if (!session_callbacks_->empty()) { + return; + } + + CleanUp(); +} + +void SessionManager::CleanUp() { + if (session_hwnd_ != nullptr) { + // Send message to destroy message window. + // NOLINTNEXTLINE(misc-include-cleaner) + PostMessageA(session_hwnd_, WM_DESTROY, 0, 0); + } + + session_thread_->Shutdown(); + delete session_thread_; + delete session_callbacks_; + session_thread_ = nullptr; + session_callbacks_ = nullptr; + session_hwnd_ = nullptr; +} + +} // namespace windows +} // namespace nearby diff --git a/internal/platform/implementation/windows/session_manager.h b/internal/platform/implementation/windows/session_manager.h new file mode 100644 index 00000000..e3faf4b8 --- /dev/null +++ b/internal/platform/implementation/windows/session_manager.h @@ -0,0 +1,76 @@ +// 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_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_SESSION_MANAGER_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_SESSION_MANAGER_H_ + +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "absl/synchronization/notification.h" +#include "internal/platform/implementation/windows/submittable_executor.h" + +namespace nearby { +namespace windows { + +// SessionManager provides methods to access/control platform session. +class SessionManager { + public: + enum class SessionState { kLock, kUnlock }; + ~SessionManager(); + + // Setups session listener. + // listener_name - Listener name. it should be unique in the SDK level. + // callback - It will be called when session state changed, such as + // lock/unlock screen. + bool RegisterSessionListener(absl::string_view listener_name, + absl::AnyInvocable callback); + + // Removes session listener by its name. + bool UnregisterSessionListener(absl::string_view listener_name); + + bool IsScreenLocked() const; + + // Prevents the Windows device from sleeping state. + bool PreventSleep() const; + + // Allows the Windows device to sleep state. + bool AllowSleep() const; + + static void NotifySessionState(SessionState state); + + private: + void StartSession(absl::Notification& notification); + void StopSession(); + void CleanUp(); + + absl::flat_hash_set listeners_; + + // Static class members + static absl::Mutex session_mutex_; + static HWND session_hwnd_; + static SubmittableExecutor* session_thread_; + static absl::flat_hash_map< + std::string, absl::AnyInvocable>* + session_callbacks_; +}; + +} // namespace windows +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_SESSION_MANAGER_H_ diff --git a/internal/platform/implementation/windows/timer.cc b/internal/platform/implementation/windows/timer.cc index c4e35241..c27846ef 100644 --- a/internal/platform/implementation/windows/timer.cc +++ b/internal/platform/implementation/windows/timer.cc @@ -1,4 +1,4 @@ -// Copyright 2021-2023 Google LLC +// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,9 +14,10 @@ #include "internal/platform/implementation/windows/timer.h" -#include "absl/functional/any_invocable.h" +#include + +#include "absl/synchronization/mutex.h" #include "internal/platform/logging.h" -#include "internal/platform/mutex_lock.h" namespace nearby { namespace windows { @@ -25,7 +26,7 @@ Timer::~Timer() { Stop(); } bool Timer::Create(int delay, int interval, absl::AnyInvocable callback) { - MutexLock lock(&mutex_); + absl::MutexLock lock(&mutex_); if ((delay < 0) || (interval < 0)) { NEARBY_LOGS(WARNING) << "Delay and interval shouldn\'t be negative value."; @@ -45,17 +46,10 @@ bool Timer::Create(int delay, int interval, delay_ = delay; interval_ = interval; callback_ = std::move(callback); - timer_callback_ = [&]() { - MutexLock lock(&mutex_); - if (timer_queue_handle_ != nullptr && callback_ != nullptr) { - callback_(); - } - }; if (!CreateTimerQueueTimer(&handle_, timer_queue_handle_, static_cast(TimerRoutine), - &timer_callback_, delay, interval, - WT_EXECUTEDEFAULT)) { + &callback_, delay, interval, WT_EXECUTEDEFAULT)) { if (!DeleteTimerQueueEx(timer_queue_handle_, nullptr)) { NEARBY_LOGS(ERROR) << "Failed to create timer in timer queue."; } @@ -67,7 +61,7 @@ bool Timer::Create(int delay, int interval, } bool Timer::Stop() { - MutexLock lock(&mutex_); + absl::MutexLock lock(&mutex_); if (timer_queue_handle_ == nullptr) { return true; @@ -92,7 +86,7 @@ bool Timer::Stop() { } bool Timer::FireNow() { - MutexLock lock(&mutex_); + absl::MutexLock lock(&mutex_); if (!timer_queue_handle_ || !callback_) { return false; @@ -107,7 +101,8 @@ bool Timer::FireNow() { << "Failed to fire the task due to cannot create executor."; return false; } - task_executor_->Execute([&]() { timer_callback_(); }); + + task_executor_->Execute([&]() { callback_(); }); return true; } diff --git a/internal/platform/implementation/windows/timer.h b/internal/platform/implementation/windows/timer.h index fe2d2ae9..8b9d9806 100644 --- a/internal/platform/implementation/windows/timer.h +++ b/internal/platform/implementation/windows/timer.h @@ -1,4 +1,4 @@ -// Copyright 2021-2023 Google LLC +// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,10 +20,9 @@ #include #include "absl/base/thread_annotations.h" -#include "absl/functional/any_invocable.h" +#include "absl/synchronization/mutex.h" #include "internal/platform/implementation/timer.h" #include "internal/platform/implementation/windows/submittable_executor.h" -#include "internal/platform/mutex.h" namespace nearby { namespace windows { @@ -42,11 +41,10 @@ class Timer : public api::Timer { private: static void CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired); - mutable RecursiveMutex mutex_; + mutable absl::Mutex mutex_; int delay_ ABSL_GUARDED_BY(mutex_); int interval_ ABSL_GUARDED_BY(mutex_); absl::AnyInvocable callback_; - absl::AnyInvocable timer_callback_ = nullptr; HANDLE handle_ ABSL_GUARDED_BY(mutex_) = nullptr; HANDLE timer_queue_handle_ ABSL_GUARDED_BY(mutex_) = nullptr; std::unique_ptr task_executor_ ABSL_GUARDED_BY(mutex_) = diff --git a/internal/platform/implementation/windows/timer_test.cc b/internal/platform/implementation/windows/timer_test.cc index be3e7964..725397cd 100644 --- a/internal/platform/implementation/windows/timer_test.cc +++ b/internal/platform/implementation/windows/timer_test.cc @@ -1,4 +1,4 @@ -// Copyright 2021-2023 Google LLC +// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,8 +14,12 @@ #include "internal/platform/implementation/timer.h" +#include // NOLINT +// NOLINT +#include +#include // NOLINT + #include "gtest/gtest.h" -#include "absl/time/time.h" #include "internal/platform/implementation/platform.h" namespace nearby { @@ -42,7 +46,7 @@ TEST(Timer, DISABLED_TestRepeatTimer) { ASSERT_TRUE(timer != nullptr); EXPECT_TRUE(timer->Create(300, 300, [&]() { ++count; })); - absl::SleepFor(absl::Seconds(1)); + std::this_thread::sleep_for(std::chrono::seconds(1)); EXPECT_TRUE(timer->Stop()); EXPECT_EQ(count, 3); } @@ -53,27 +57,8 @@ TEST(Timer, DISABLED_TestFireNow) { auto timer = nearby::api::ImplementationPlatform::CreateTimer(); EXPECT_TRUE(timer != nullptr); - EXPECT_TRUE(timer->Create(3000, 3000, [&]() { - absl::SleepFor(absl::Milliseconds(1000)); - ++count; - })); + EXPECT_TRUE(timer->Create(3000, 3000, [&]() { ++count; })); EXPECT_TRUE(timer->FireNow()); - absl::SleepFor(absl::Milliseconds(100)); - EXPECT_TRUE(timer->Stop()); - EXPECT_EQ(count, 1); -} - -TEST(Timer, DISABLED_TestWaitForRunningCallback) { - int count = 0; - - auto timer = nearby::api::ImplementationPlatform::CreateTimer(); - - EXPECT_TRUE(timer != nullptr); - EXPECT_TRUE(timer->Create(1000, 0, [&]() { - absl::SleepFor(absl::Milliseconds(3000)); - ++count; - })); - absl::SleepFor(absl::Milliseconds(1050)); EXPECT_TRUE(timer->Stop()); EXPECT_EQ(count, 1); } diff --git a/internal/platform/implementation/windows/wifi_hotspot.h b/internal/platform/implementation/windows/wifi_hotspot.h index ba019179..5c34e414 100644 --- a/internal/platform/implementation/windows/wifi_hotspot.h +++ b/internal/platform/implementation/windows/wifi_hotspot.h @@ -16,8 +16,8 @@ #define PLATFORM_IMPL_WINDOWS_WIFI_HOTSPOT_H_ // Windows headers -#include #include +#include #include // Standard C/C++ headers @@ -27,6 +27,7 @@ #include // Nearby connections headers +#include "absl/strings/string_view.h" #include "internal/platform/implementation/wifi_hotspot.h" #include "internal/platform/implementation/windows/scheduled_executor.h" #include "internal/platform/implementation/windows/submittable_executor.h" @@ -123,7 +124,7 @@ class WifiHotspotSocket : public api::WifiHotspotSocket { Exception Close() override; private: - enum class SocketType {kWinRTSocket = 0, kWin32Socket}; + enum class SocketType { kWinRTSocket = 0, kWin32Socket }; // A simple wrapper to handle input stream of socket class SocketInputStream : public InputStream { public: @@ -204,6 +205,10 @@ class WifiHotspotServerSocket : public api::WifiHotspotServerSocket { bool listen(); private: + static constexpr int kSocketEventsCount = 2; + static constexpr int kSocketEventListen = 0; + static constexpr int kSocketEventClose = 1; + // The listener is accepting incoming connections fire_and_forget Listener_ConnectionReceived( StreamSocketListener listener, @@ -214,6 +219,8 @@ class WifiHotspotServerSocket : public api::WifiHotspotServerSocket { // Retrieves hotspot IP address from local machine std::string GetHotspotIpAddress() const; + void SocketErrorNotice(absl::string_view reason); + mutable absl::Mutex mutex_; absl::CondVar cond_; SubmittableExecutor submittable_executor_; @@ -225,6 +232,13 @@ class WifiHotspotServerSocket : public api::WifiHotspotServerSocket { std::deque pending_client_sockets_ ABSL_GUARDED_BY(mutex_); SOCKET listen_socket_ = INVALID_SOCKET; SOCKET client_socket_ = INVALID_SOCKET; + + // closesocket cannot trigger FD_CLOSE on listener socket. In order to avoid + // blocking in WSAWaitForMultipleEvents, we use a socket event to trigger + // WSAWaitForMultipleEvents safely. + // The socket_events_ has 2 events, the first one is to handle normal socket + // event, and the second one is to handle event to close the socket manually. + WSAEVENT socket_events_[kSocketEventsCount]; // Close notifier absl::AnyInvocable close_notifier_ = nullptr; diff --git a/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc b/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc index 35429cbb..a9d2f6f2 100644 --- a/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc @@ -36,7 +36,11 @@ namespace { using ::winrt::Windows::Networking::Sockets::SocketQualityOfService; } // namespace -WifiHotspotServerSocket::WifiHotspotServerSocket(int port) : port_(port) {} +WifiHotspotServerSocket::WifiHotspotServerSocket(int port) : port_(port) { + for (auto &it : socket_events_) { + it = WSA_INVALID_EVENT; + } +} WifiHotspotServerSocket::~WifiHotspotServerSocket() { Close(); } @@ -55,7 +59,7 @@ std::string WifiHotspotServerSocket::GetIPAddress() const { std::string hotspot_ip_address = GetHotspotIpAddress(); NEARBY_LOGS(INFO) << __func__ - << ": Return hotspot IP address: " << hotspot_ip_address; + << ": Return hotspot IP address: " << hotspot_ip_address; return hotspot_ip_address; } @@ -126,18 +130,26 @@ Exception WifiHotspotServerSocket::Close() { kEnableHotspotWin32Socket)) { if (listen_socket_ != INVALID_SOCKET) { NEARBY_LOGS(INFO) << ": Close listen_socket_: " << listen_socket_; + // Trigger close event manually + WSASetEvent(socket_events_[kSocketEventClose]); + shutdown(listen_socket_, 2); + shutdown(client_socket_, 2); closesocket(listen_socket_); closesocket(client_socket_); - listen_socket_ = INVALID_SOCKET; - client_socket_ = INVALID_SOCKET; for (const auto &pending_socket : pending_client_sockets_) { if (pending_socket != INVALID_SOCKET) closesocket(pending_socket); } + submittable_executor_.Shutdown(); + listen_socket_ = INVALID_SOCKET; + client_socket_ = INVALID_SOCKET; + for (auto &it : socket_events_) { + WSACloseEvent(it); + it = WSA_INVALID_EVENT; + } WSACleanup(); pending_client_sockets_ = {}; } - submittable_executor_.Shutdown(); } else { if (stream_socket_listener_ != nullptr) { stream_socket_listener_.ConnectionReceived(listener_event_token_); @@ -254,14 +266,16 @@ bool WifiHotspotServerSocket::SetupServerSocketWinRT() { return false; } -// Checks for SOCKET_ERROR, this error can come up when trying to bind, listen, -// Getsockname, WSACreateEvent, WSAEventSelect etc. -void SocketErrorNotice(SOCKET socket_to_close, const char *action) { - // const char *actionAttempted = action; - NEARBY_LOGS(WARNING) << "socket error. " << action +void WifiHotspotServerSocket::SocketErrorNotice(absl::string_view reason) { + NEARBY_LOGS(WARNING) << "socket error. " << reason << " failed with error: " << WSAGetLastError(); - - closesocket(socket_to_close); + for (auto &it : socket_events_) { + if (it != WSA_INVALID_EVENT) { + WSACloseEvent(it); + it = WSA_INVALID_EVENT; + } + } + closesocket(listen_socket_); WSACleanup(); } @@ -293,7 +307,7 @@ bool WifiHotspotServerSocket::SetupServerSocketWinSock() { sizeof(flag)); if (bind(listen_socket_, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR) { - SocketErrorNotice(listen_socket_, "Bind"); + SocketErrorNotice("Bind"); return false; } NEARBY_LOGS(INFO) << "Bind socket successful"; @@ -302,50 +316,63 @@ bool WifiHotspotServerSocket::SetupServerSocketWinSock() { memset(&serv_addr, 0, size); if (getsockname(listen_socket_, (struct sockaddr *)&serv_addr, &size) == SOCKET_ERROR) { - SocketErrorNotice(listen_socket_, "Getsockname"); + SocketErrorNotice("Getsockname"); return false; } port_ = ntohs(serv_addr.sin_port); NEARBY_LOGS(INFO) << "Hotspot Server bound to port: " << port_; - socket_event = WSACreateEvent(); - if (socket_event == nullptr) { - SocketErrorNotice(listen_socket_, "WSACreateEvent"); + socket_events_[kSocketEventListen] = WSACreateEvent(); + if (socket_events_[kSocketEventListen] == WSA_INVALID_EVENT) { + SocketErrorNotice("WSACreateEvent"); return false; } + + socket_events_[kSocketEventClose] = WSACreateEvent(); + if (socket_events_[kSocketEventClose] == WSA_INVALID_EVENT) { + SocketErrorNotice("WSACreateEvent"); + return false; + } + // Associate event types FD_ACCEPT and FD_CLOSE with the listen_socket_ and // socket_event - if (WSAEventSelect(listen_socket_, socket_event, FD_ACCEPT | FD_CLOSE) == - SOCKET_ERROR) { - SocketErrorNotice(listen_socket_, "WSAEventSelect"); + if (WSAEventSelect(listen_socket_, socket_events_[kSocketEventListen], + FD_ACCEPT | FD_CLOSE) == SOCKET_ERROR) { + SocketErrorNotice("WSAEventSelect"); return false; } if (::listen(listen_socket_, SOMAXCONN) == SOCKET_ERROR) { - SocketErrorNotice(listen_socket_, "Listen"); + SocketErrorNotice("Listen"); return false; } NEARBY_LOGS(INFO) << "Hotspot Server Socket " << listen_socket_ << " started to listen with socket event: " << socket_event; - submittable_executor_.Execute([this, socket_event]() { + submittable_executor_.Execute([this]() { DWORD index; WSANETWORKEVENTS network_events; // Wait for network events on all sockets - index = - WSAWaitForMultipleEvents(1, &socket_event, FALSE, WSA_INFINITE, FALSE); + index = WSAWaitForMultipleEvents(kSocketEventsCount, socket_events_, FALSE, + WSA_INFINITE, FALSE); NEARBY_LOGS(INFO) << "Hotspot Server Socket " << listen_socket_ - << " received event: " << socket_event; + << " received event index: " << index; if (index == WSA_WAIT_TIMEOUT || index == WSA_WAIT_FAILED) { NEARBY_LOGS(INFO) << "Hotspot Server Socket timout or failed "; return false; } index = index - WSA_WAIT_EVENT_0; + if (index == kSocketEventClose) { + // the socket is closed by SDK + NEARBY_LOGS(INFO) << "listner socket is closed."; + return false; + } + // Iterate through all events and enumerate - if (WSAEnumNetworkEvents(listen_socket_, socket_event, &network_events) == - SOCKET_ERROR) { + if (WSAEnumNetworkEvents(listen_socket_, socket_events_[index], + &network_events) == SOCKET_ERROR) { NEARBY_LOGS(INFO) << "Iterate through all events failed"; return false; } @@ -361,7 +388,8 @@ bool WifiHotspotServerSocket::SetupServerSocketWinSock() { return false; } - if (WSAEventSelect(listen_socket_, socket_event, 0) == SOCKET_ERROR) { + if (WSAEventSelect(listen_socket_, socket_events_[kSocketEventListen], + 0) == SOCKET_ERROR) { NEARBY_LOGS(WARNING) << "Remove association between listen_socket_ and event failed: " << WSAGetLastError(); diff --git a/internal/platform/medium_environment.cc b/internal/platform/medium_environment.cc index c3395776..8ed0d104 100644 --- a/internal/platform/medium_environment.cc +++ b/internal/platform/medium_environment.cc @@ -576,7 +576,9 @@ void MediumEnvironment::CallBleAcceptedConnectionCallback( return; } auto& info = item->second; - info.accepted_connection_callback.accepted_cb(socket, service_id); + if (info.accepted_connection_callback) { + info.accepted_connection_callback(socket, service_id); + } }); } @@ -936,8 +938,8 @@ api::WifiLanMedium* MediumEnvironment::GetWifiLanMedium( return; } } - latch.CountDown(); } + latch.CountDown(); }); latch.Await(); return result; diff --git a/internal/platform/monitored_runnable.cc b/internal/platform/monitored_runnable.cc index e0952298..792a580f 100644 --- a/internal/platform/monitored_runnable.cc +++ b/internal/platform/monitored_runnable.cc @@ -16,11 +16,13 @@ #include +// TODO: Support thread status #include "internal/platform/logging.h" #include "internal/platform/pending_job_registry.h" -namespace nearby { +#define SET_THREAD_STATUS(NAME) +namespace nearby { namespace { absl::Duration kMinReportedStartDelay = absl::Seconds(5); absl::Duration kMinReportedTaskDuration = absl::Seconds(10); @@ -36,6 +38,7 @@ MonitoredRunnable::MonitoredRunnable(const std::string& name, } void MonitoredRunnable::operator()() { + SET_THREAD_STATUS(name_.c_str()); auto start_time = SystemClock::ElapsedRealtime(); auto start_delay = start_time - post_time_; if (start_delay >= kMinReportedStartDelay) { diff --git a/internal/platform/pipe.cc b/internal/platform/pipe.cc index 25a0b9e9..8249686d 100644 --- a/internal/platform/pipe.cc +++ b/internal/platform/pipe.cc @@ -14,25 +14,181 @@ #include "internal/platform/pipe.h" +#include +#include +#include +#include +#include + +#include "absl/base/thread_annotations.h" +#include "internal/platform/base_mutex_lock.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" #include "internal/platform/implementation/condition_variable.h" #include "internal/platform/implementation/mutex.h" #include "internal/platform/implementation/platform.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/output_stream.h" namespace nearby { namespace { using Platform = api::ImplementationPlatform; -} +class Pipe { + public: + Pipe() { #pragma push_macro("CreateMutex") #undef CreateMutex + mutex_ = Platform::CreateMutex(api::Mutex::Mode::kRegular); +#pragma pop_macro("CreateMutex") + cond_ = Platform::CreateConditionVariable(mutex_.get()); + } -Pipe::Pipe() { - auto mutex = Platform::CreateMutex(api::Mutex::Mode::kRegular); - auto cond = Platform::CreateConditionVariable(mutex.get()); - Setup(std::move(mutex), std::move(cond)); + class PipeInputStream : public InputStream { + public: + explicit PipeInputStream(std::shared_ptr pipe) : pipe_(pipe) {} + ~PipeInputStream() override { DoClose(); } + + ExceptionOr Read(std::int64_t size) override { + return pipe_->Read(size); + } + Exception Close() override { return DoClose(); } + + private: + Exception DoClose() { + pipe_->MarkInputStreamClosed(); + return {Exception::kSuccess}; + } + std::shared_ptr pipe_; + }; + + class PipeOutputStream : public OutputStream { + public: + explicit PipeOutputStream(std::shared_ptr pipe) : pipe_(pipe) {} + ~PipeOutputStream() override { DoClose(); } + + Exception Write(const ByteArray& data) override { + return pipe_->Write(data); + } + Exception Flush() override { return {Exception::kSuccess}; } + Exception Close() override { return DoClose(); } + + private: + Exception DoClose() { + pipe_->MarkOutputStreamClosed(); + return {Exception::kSuccess}; + } + std::shared_ptr pipe_; + }; + + private: + ExceptionOr Read(size_t size) ABSL_LOCKS_EXCLUDED(mutex_); + Exception Write(const ByteArray& data) ABSL_LOCKS_EXCLUDED(mutex_); + + void MarkInputStreamClosed() ABSL_LOCKS_EXCLUDED(mutex_); + void MarkOutputStreamClosed() ABSL_LOCKS_EXCLUDED(mutex_); + + Exception WriteLocked(const ByteArray& data) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + bool input_stream_closed_ ABSL_GUARDED_BY(mutex_) = false; + bool output_stream_closed_ ABSL_GUARDED_BY(mutex_) = false; + bool read_all_chunks_ ABSL_GUARDED_BY(mutex_) = false; + + std::deque ABSL_GUARDED_BY(mutex_) buffer_; + // Order of declaration matters: + // - mutex must be defined before condvar; + std::unique_ptr mutex_; + std::unique_ptr cond_; +}; + +ExceptionOr Pipe::Read(size_t size) { + BaseMutexLock lock(mutex_.get()); + + // We're done reading all the chunks that were written before the OutputStream + // was closed, so there's nothing to do here other than return an empty chunk + // to serve as an EOF indication to callers. + if (read_all_chunks_) { + return ExceptionOr{ByteArray{}}; + } + + while (buffer_.empty() && !input_stream_closed_) { + Exception wait_exception = cond_->Wait(); + + if (wait_exception.Raised()) { + return ExceptionOr{wait_exception}; + } + } + + // If we received our sentinel chunk, mark the fact that there cannot + // possibly be any more chunks to read here on in, and return an empty chunk + // to serve as an EOF indication to callers. + if (buffer_.empty() || buffer_.front().Empty()) { + read_all_chunks_ = true; + return ExceptionOr{ByteArray{}}; + } + + ByteArray first_chunk{buffer_.front()}; + buffer_.pop_front(); + + // If first_chunk is small enough to not overshoot the requested 'size', just + // return that. + if (first_chunk.size() <= size) { + return ExceptionOr{first_chunk}; + } else { + // Break first_chunk into 2 parts -- the first one of which (next_chunk) + // will be 'size' bytes long, and will be returned, and the second one of + // which (overflow_chunk) will be re-inserted into buffer_, at the head of + // the queue, to be served up in the next call to read(). + ByteArray next_chunk(first_chunk.data(), size); + buffer_.push_front( + ByteArray(first_chunk.data() + size, first_chunk.size() - size)); + return ExceptionOr{next_chunk}; + } } -#pragma pop_macro("CreateMutex") +Exception Pipe::Write(const ByteArray& data) { + BaseMutexLock lock(mutex_.get()); + return WriteLocked(data); +} + +void Pipe::MarkInputStreamClosed() { + BaseMutexLock lock(mutex_.get()); + if (input_stream_closed_) return; + input_stream_closed_ = true; + // Trigger cond_ to unblock a potentially-blocked call to read(), and to let + // it know to return Exception::IO. + cond_->Notify(); +} + +void Pipe::MarkOutputStreamClosed() { + BaseMutexLock lock(mutex_.get()); + if (output_stream_closed_) return; + // Write a sentinel null chunk before marking output_stream_closed as true. + WriteLocked(ByteArray{}); + output_stream_closed_ = true; +} + +Exception Pipe::WriteLocked(const ByteArray& data) { + if (input_stream_closed_ || output_stream_closed_) { + return {Exception::kIo}; + } + + buffer_.push_back(data); + // Trigger cond_ to unblock a potentially-blocked call to read(), now that + // there's more data for it to consume. + cond_->Notify(); + return {Exception::kSuccess}; +} + +} // namespace + +std::pair, std::unique_ptr> +CreatePipe() { + auto pipe = std::make_shared(); + return std::make_pair(std::make_unique(pipe), + std::make_unique(pipe)); +} } // namespace nearby diff --git a/internal/platform/pipe.h b/internal/platform/pipe.h index a96bfbbc..4d0af630 100644 --- a/internal/platform/pipe.h +++ b/internal/platform/pipe.h @@ -15,19 +15,23 @@ #ifndef PLATFORM_PUBLIC_PIPE_H_ #define PLATFORM_PUBLIC_PIPE_H_ -#include "internal/platform/base_pipe.h" +#include +#include + +#include "internal/platform/input_stream.h" +#include "internal/platform/output_stream.h" namespace nearby { -// See for details: -// http://google3/platform/base/base_pipe.h -class Pipe final : public BasePipe { - public: - Pipe(); - ~Pipe() override = default; - Pipe(Pipe&&) = delete; - Pipe& operator=(Pipe&&) = delete; -}; +// Creates a pipe for streaming data between threads. +// ``` +// auto [input, output] = CreatePipe(); +// ReaderThread(std::move(input)); +// WriterThread(std::move(output)); +// ``` +// Pipe stays valid as long as either `input` or `output` exist. +std::pair, std::unique_ptr> +CreatePipe(); } // namespace nearby diff --git a/internal/platform/pipe_test.cc b/internal/platform/pipe_test.cc index 08312836..23ee4da0 100644 --- a/internal/platform/pipe_test.cc +++ b/internal/platform/pipe_test.cc @@ -17,141 +17,137 @@ #include #include +#include #include +#include #include #include +#include #include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/output_stream.h" #include "internal/platform/prng.h" #include "internal/platform/runnable.h" namespace nearby { +namespace { +constexpr size_t kChunkSize = 64 * 1024; +} + TEST(PipeTest, ConstructorDestructorWorks) { - Pipe pipe; + auto [input_stream, output_stream] = CreatePipe(); SUCCEED(); } TEST(PipeTest, SimpleWriteRead) { - Pipe pipe; - InputStream& input_stream{pipe.GetInputStream()}; - OutputStream& output_stream{pipe.GetOutputStream()}; - + auto [input_stream, output_stream] = CreatePipe(); std::string data("ABCD"); - EXPECT_TRUE(output_stream.Write(ByteArray(data)).Ok()); + EXPECT_TRUE(output_stream->Write(ByteArray(data)).Ok()); - ExceptionOr read_data = input_stream.Read(Pipe::kChunkSize); + ExceptionOr read_data = input_stream->Read(kChunkSize); EXPECT_TRUE(read_data.ok()); EXPECT_EQ(data, std::string(read_data.result())); } TEST(PipeTest, WriteEndClosedBeforeRead) { - Pipe pipe; - InputStream& input_stream{pipe.GetInputStream()}; - OutputStream& output_stream{pipe.GetOutputStream()}; + auto [input_stream, output_stream] = CreatePipe(); std::string data("ABCD"); - EXPECT_TRUE(output_stream.Write(ByteArray(data)).Ok()); + EXPECT_TRUE(output_stream->Write(ByteArray(data)).Ok()); // Close the write end before the read end has even begun reading. - EXPECT_TRUE(output_stream.Close().Ok()); + EXPECT_TRUE(output_stream->Close().Ok()); // We should still be able to read what was written. - ExceptionOr read_data = input_stream.Read(Pipe::kChunkSize); + ExceptionOr read_data = input_stream->Read(kChunkSize); EXPECT_TRUE(read_data.ok()); EXPECT_EQ(data, std::string(read_data.result())); // And after that, we should get our indication that all the data that could // ever be read, has already been read. - read_data = input_stream.Read(Pipe::kChunkSize); + read_data = input_stream->Read(kChunkSize); EXPECT_TRUE(read_data.ok()); EXPECT_TRUE(read_data.result().Empty()); } TEST(PipeTest, ReadEndClosedBeforeWrite) { - Pipe pipe; - InputStream& input_stream{pipe.GetInputStream()}; - OutputStream& output_stream{pipe.GetOutputStream()}; + auto [input_stream, output_stream] = CreatePipe(); // Close the read end before the write end has even begun writing. - EXPECT_TRUE(input_stream.Close().Ok()); + EXPECT_TRUE(input_stream->Close().Ok()); std::string data("ABCD"); - EXPECT_TRUE(output_stream.Write(ByteArray(data)).Raised(Exception::kIo)); + EXPECT_TRUE(output_stream->Write(ByteArray(data)).Raised(Exception::kIo)); } TEST(PipeTest, SizedReadMoreThanFirstChunkSize) { - Pipe pipe; - InputStream& input_stream{pipe.GetInputStream()}; - OutputStream& output_stream{pipe.GetOutputStream()}; + auto [input_stream, output_stream] = CreatePipe(); std::string data("ABCD"); - EXPECT_TRUE(output_stream.Write(ByteArray(data)).Ok()); + EXPECT_TRUE(output_stream->Write(ByteArray(data)).Ok()); // Even though we ask for double of what's there in the first chunk, we should // get back only what's there in that first chunk, and that's alright. - ExceptionOr read_data = input_stream.Read(data.size() * 2); + ExceptionOr read_data = input_stream->Read(data.size() * 2); EXPECT_TRUE(read_data.ok()); EXPECT_EQ(data, std::string(read_data.result())); } TEST(PipeTest, SizedReadLessThanFirstChunkSize) { - Pipe pipe; - InputStream& input_stream{pipe.GetInputStream()}; - OutputStream& output_stream{pipe.GetOutputStream()}; - + auto [input_stream, output_stream] = CreatePipe(); std::string data_first_part("ABCD"); std::string data_second_part("EFGHIJ"); std::string data = data_first_part + data_second_part; - EXPECT_TRUE(output_stream.Write(ByteArray(data)).Ok()); + EXPECT_TRUE(output_stream->Write(ByteArray(data)).Ok()); // When we ask for less than what's there in the first chunk, we should get // back exactly what we asked for, with the remainder still being available // for the next read. std::int64_t desired_size = data_first_part.size(); - ExceptionOr first_read_data = input_stream.Read(desired_size); + ExceptionOr first_read_data = input_stream->Read(desired_size); EXPECT_TRUE(first_read_data.ok()); EXPECT_EQ(data_first_part, std::string(first_read_data.result())); // Now read the remainder, and get everything that ought to have been left. - ExceptionOr second_read_data = input_stream.Read(Pipe::kChunkSize); + ExceptionOr second_read_data = input_stream->Read(kChunkSize); EXPECT_TRUE(second_read_data.ok()); EXPECT_EQ(data_second_part, std::string(second_read_data.result())); } TEST(PipeTest, ReadAfterInputStreamClosed) { - Pipe pipe; - InputStream& input_stream{pipe.GetInputStream()}; + auto [input_stream, output_stream] = CreatePipe(); - input_stream.Close(); + input_stream->Close(); - ExceptionOr read_data = input_stream.Read(Pipe::kChunkSize); + ExceptionOr read_data = input_stream->Read(kChunkSize); EXPECT_TRUE(read_data.ok()); EXPECT_TRUE(read_data.GetResult().Empty()); } TEST(PipeTest, WriteAfterOutputStreamClosed) { - Pipe pipe; - OutputStream& output_stream{pipe.GetOutputStream()}; + auto [input_stream, output_stream] = CreatePipe(); - output_stream.Close(); + output_stream->Close(); std::string data("ABCD"); - EXPECT_TRUE(output_stream.Write(ByteArray(data)).Raised(Exception::kIo)); + EXPECT_TRUE(output_stream->Write(ByteArray(data)).Raised(Exception::kIo)); } TEST(PipeTest, RepeatedClose) { - Pipe pipe; - InputStream& input_stream{pipe.GetInputStream()}; - OutputStream& output_stream{pipe.GetOutputStream()}; + auto [input_stream, output_stream] = CreatePipe(); - EXPECT_TRUE(output_stream.Close().Ok()); - EXPECT_TRUE(output_stream.Close().Ok()); - EXPECT_TRUE(output_stream.Close().Ok()); + EXPECT_TRUE(output_stream->Close().Ok()); + EXPECT_TRUE(output_stream->Close().Ok()); + EXPECT_TRUE(output_stream->Close().Ok()); - EXPECT_TRUE(input_stream.Close().Ok()); - EXPECT_TRUE(input_stream.Close().Ok()); - EXPECT_TRUE(input_stream.Close().Ok()); + EXPECT_TRUE(input_stream->Close().Ok()); + EXPECT_TRUE(input_stream->Close().Ok()); + EXPECT_TRUE(input_stream->Close().Ok()); } class Thread { @@ -186,17 +182,18 @@ TEST(PipeTest, ReadBlockedUntilWrite) { class ReaderRunnable { public: - ReaderRunnable(InputStream* input_stream, + ReaderRunnable(std::unique_ptr input_stream, absl::string_view expected_read_data, CrossThreadBool* ok_for_read_to_unblock) - : input_stream_(input_stream), + : input_stream_(std::move(input_stream)), expected_read_data_(expected_read_data), ok_for_read_to_unblock_(ok_for_read_to_unblock) {} + ReaderRunnable(ReaderRunnable&&) = default; ~ReaderRunnable() = default; // Signature "void()" satisfies Runnable. void operator()() { - ExceptionOr read_data = input_stream_->Read(Pipe::kChunkSize); + ExceptionOr read_data = input_stream_->Read(kChunkSize); // Make sure read() doesn't return before it's appropriate. if (!*ok_for_read_to_unblock_) { @@ -210,13 +207,12 @@ TEST(PipeTest, ReadBlockedUntilWrite) { } private: - InputStream* input_stream_; + std::unique_ptr input_stream_; const std::string expected_read_data_; CrossThreadBool* ok_for_read_to_unblock_; }; - Pipe pipe; - OutputStream& output_stream{pipe.GetOutputStream()}; + auto [input_stream, output_stream] = CreatePipe(); // State shared between this thread (the writer) and reader_thread. CrossThreadBool ok_for_read_to_unblock = false; @@ -225,7 +221,7 @@ TEST(PipeTest, ReadBlockedUntilWrite) { // Kick off reader_thread. Thread reader_thread; reader_thread.Start( - ReaderRunnable(&pipe.GetInputStream(), data, &ok_for_read_to_unblock)); + ReaderRunnable(std::move(input_stream), data, &ok_for_read_to_unblock)); // Introduce a delay before we actually write anything. absl::SleepFor(absl::Seconds(5)); @@ -236,7 +232,7 @@ TEST(PipeTest, ReadBlockedUntilWrite) { ok_for_read_to_unblock = true; // Perform the actual write. - EXPECT_TRUE(output_stream.Write(ByteArray(data)).Ok()); + EXPECT_TRUE(output_stream->Write(ByteArray(data)).Ok()); // And wait for reader_thread to finish. reader_thread.Join(); @@ -247,6 +243,7 @@ TEST(PipeTest, ConcurrentWriteAndRead) { protected: explicit BaseRunnable(const std::vector& chunks) : chunks_(chunks) {} + BaseRunnable(BaseRunnable&&) = default; virtual ~BaseRunnable() = default; void RandomSleep() { @@ -267,9 +264,10 @@ TEST(PipeTest, ConcurrentWriteAndRead) { class WriterRunnable : public BaseRunnable { public: - WriterRunnable(OutputStream* output_stream, + WriterRunnable(std::unique_ptr output_stream, const std::vector& chunks) - : BaseRunnable(chunks), output_stream_(output_stream) {} + : BaseRunnable(chunks), output_stream_(std::move(output_stream)) {} + WriterRunnable(WriterRunnable&&) = default; ~WriterRunnable() override = default; void operator()() { @@ -283,14 +281,15 @@ TEST(PipeTest, ConcurrentWriteAndRead) { } private: - OutputStream* output_stream_; + std::unique_ptr output_stream_; }; class ReaderRunnable : public BaseRunnable { public: - ReaderRunnable(InputStream* input_stream, + ReaderRunnable(std::unique_ptr input_stream, const std::vector& chunks) - : BaseRunnable(chunks), input_stream_(input_stream) {} + : BaseRunnable(chunks), input_stream_(std::move(input_stream)) {} + ReaderRunnable(ReaderRunnable&&) = default; ~ReaderRunnable() override = default; void operator()() { @@ -304,8 +303,7 @@ TEST(PipeTest, ConcurrentWriteAndRead) { std::string actual_data; while (true) { RandomSleep(); // Random pauses before each read. - ExceptionOr read_data = - input_stream_->Read(Pipe::kChunkSize); + ExceptionOr read_data = input_stream_->Read(kChunkSize); if (read_data.ok()) { ByteArray result = read_data.result(); if (result.Empty()) { @@ -322,11 +320,10 @@ TEST(PipeTest, ConcurrentWriteAndRead) { } private: - InputStream* input_stream_; + std::unique_ptr input_stream_; }; - Pipe pipe; - + auto [input_stream, output_stream] = CreatePipe(); std::vector chunks; chunks.push_back("ABCD"); chunks.push_back("EFGH"); @@ -334,8 +331,8 @@ TEST(PipeTest, ConcurrentWriteAndRead) { Thread writer_thread; Thread reader_thread; - writer_thread.Start(WriterRunnable(&pipe.GetOutputStream(), chunks)); - reader_thread.Start(ReaderRunnable(&pipe.GetInputStream(), chunks)); + writer_thread.Start(WriterRunnable(std::move(output_stream), chunks)); + reader_thread.Start(ReaderRunnable(std::move(input_stream), chunks)); writer_thread.Join(); reader_thread.Join(); } diff --git a/internal/proto/analytics/BUILD b/internal/proto/analytics/BUILD index ea1b3b08..904d2182 100644 --- a/internal/proto/analytics/BUILD +++ b/internal/proto/analytics/BUILD @@ -64,7 +64,7 @@ cc_test( shard_count = 16, deps = [ ":connections_log_cc_proto", - "//internal/platform:logging", + "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep "//proto:connections_enums_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", diff --git a/internal/proto/credential.proto b/internal/proto/credential.proto index 5451d27b..42836b1d 100644 --- a/internal/proto/credential.proto +++ b/internal/proto/credential.proto @@ -43,7 +43,7 @@ enum CredentialType { // The shared credential is derived from local credential, and distributed to // remote devices based on the trust token for identity decryption and // authentication. -// NEXT_ID=14 +// NEXT_ID=16 // LINT.IfChange(SharedCredential) message SharedCredential { // The randomly generated unique id of the public credential. @@ -62,8 +62,8 @@ message SharedCredential { // metadata_encryption_key. bytes encrypted_metadata_bytes_v0 = 5; - // The tag for verifying metadata_encryption_key for an unsigned adv. - bytes metadata_encryption_key_unsigned_adv_tag = 6; + // The tag for verifying metadata_encryption_key for a V0 advertisement. + bytes metadata_encryption_key_tag_v0 = 6; // The public key is used to create a secure connection with the device. bytes connection_signature_verification_key = 7; @@ -92,7 +92,14 @@ message SharedCredential { // metadata_encryption_key. bytes encrypted_metadata_bytes_v1 = 12; - // The tag for verifying metadata_encryption_key for a signed V1 adv. - bytes metadata_encryption_key_signed_adv_tag = 13; + // The tag for verifying metadata_encryption_key for an unsigned V1 adv. + bytes metadata_encryption_key_unsigned_adv_tag_v1 = 13; + + // The randomly generated positive unique id of the shared credential. + int64 id = 14; + + // The DUSI number related to the uploader of this shared credential. Debug + // purpose only. + string dusi = 15; } // LINT.ThenChange(//depot/google3/google/internal/location/nearby/presence/v1/nearby_resources.proto:SharedCredential) diff --git a/internal/proto/local_credential.proto b/internal/proto/local_credential.proto index 29844c15..7fbcada0 100644 --- a/internal/proto/local_credential.proto +++ b/internal/proto/local_credential.proto @@ -28,6 +28,7 @@ option optimize_for = LITE_RUNTIME; // The local credential contains information of a local device for // identity encryption and authentication. It should never leave the generating // device. +// NEXT_ID=11 message LocalCredential { // Private encryption key descriptor. // Usually, either `certificate_alias` or `key` is set. @@ -71,4 +72,8 @@ message LocalCredential { // The 16 bytes aes key to encrypt metadata in PublicCredential. bytes metadata_encryption_key_v1 = 10; + + // The positive unique id of (and hashed based on) a pair of Secret Key and + // X509Certificate's public key. + int64 id = 11; } diff --git a/internal/test/fake_device_info.h b/internal/test/fake_device_info.h index 4f296702..b7fbf160 100644 --- a/internal/test/fake_device_info.h +++ b/internal/test/fake_device_info.h @@ -86,6 +86,10 @@ class FakeDeviceInfo : public DeviceInfo { screen_locked_listeners_.erase(listener_name); } + bool PreventSleep() override { return true; } + + bool AllowSleep() override { return true; } + int GetScreenLockedListenerCount() { return screen_locked_listeners_.size(); } // Mock methods. diff --git a/internal/test/fake_device_info_test.cc b/internal/test/fake_device_info_test.cc index 53ffc093..16935c43 100644 --- a/internal/test/fake_device_info_test.cc +++ b/internal/test/fake_device_info_test.cc @@ -188,5 +188,15 @@ TEST(FakeDeviceInfo, UpdateScreenLockedListener) { EXPECT_EQ(screen_locked_tracker_2, api::DeviceInfo::ScreenStatus::kUnlocked); } +TEST(FakeDeviceInfo, PreventSleep) { + FakeDeviceInfo device_info; + EXPECT_TRUE(device_info.PreventSleep()); +} + +TEST(FakeDeviceInfo, AllowSleep) { + FakeDeviceInfo device_info; + EXPECT_TRUE(device_info.AllowSleep()); +} + } // namespace } // namespace nearby diff --git a/presence/BUILD b/presence/BUILD index 9645c99c..c4b38578 100644 --- a/presence/BUILD +++ b/presence/BUILD @@ -91,7 +91,7 @@ cc_library( "//internal/interop:device", "//internal/platform:base", "//internal/platform:connection_info", - "//internal/platform:logging", + "//internal/platform:types", "//internal/platform/implementation:types", "//internal/proto:credential_cc_proto", "//internal/proto:metadata_cc_proto", @@ -122,7 +122,7 @@ cc_test( ":types", "//connections/implementation/proto:offline_wire_formats_cc_proto", "//internal/platform:connection_info", - "//internal/platform:logging", + "//internal/platform:types", "//internal/proto:credential_cc_proto", "//internal/proto:metadata_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", diff --git a/presence/fake_presence_client.cc b/presence/fake_presence_client.cc index a6fbe881..44e73440 100644 --- a/presence/fake_presence_client.cc +++ b/presence/fake_presence_client.cc @@ -23,17 +23,6 @@ #include "presence/presence_device.h" #include "presence/scan_request.h" -namespace { - -::nearby::internal::Metadata BuildTestMetadata() { - ::nearby::internal::Metadata metadata; - metadata.set_bluetooth_mac_address("01234567"); - metadata.set_device_name("Pepper's device"); - return metadata; -} - -} // namespace - namespace nearby { namespace presence { @@ -62,19 +51,16 @@ void FakePresenceClient::CallStartScanCallback(absl::Status status) { callback_.start_scan_cb(status); } -void FakePresenceClient::CallOnDiscovered() { - PresenceDevice device{BuildTestMetadata()}; - callback_.on_discovered_cb(std::move(device)); +void FakePresenceClient::CallOnDiscovered(PresenceDevice device) { + callback_.on_discovered_cb(device); } -void FakePresenceClient::CallOnUpdated() { - PresenceDevice device{BuildTestMetadata()}; - callback_.on_updated_cb(std::move(device)); +void FakePresenceClient::CallOnUpdated(PresenceDevice device) { + callback_.on_updated_cb(device); } -void FakePresenceClient::CallOnLost() { - PresenceDevice device{BuildTestMetadata()}; - callback_.on_lost_cb(std::move(device)); +void FakePresenceClient::CallOnLost(PresenceDevice device) { + callback_.on_lost_cb(device); } } // namespace presence diff --git a/presence/fake_presence_client.h b/presence/fake_presence_client.h index 7bb8fffe..b2a6d816 100644 --- a/presence/fake_presence_client.h +++ b/presence/fake_presence_client.h @@ -15,7 +15,6 @@ #ifndef THIRD_PARTY_NEARBY_PRESENCE_FAKE_PRESENCE_CLIENT_H_ #define THIRD_PARTY_NEARBY_PRESENCE_FAKE_PRESENCE_CLIENT_H_ - #include #include @@ -55,21 +54,17 @@ class FakePresenceClient : public PresenceClient { return std::nullopt; } - void SetNextScanSessionSuccess(bool success) { - next_scan_should_succeed_ = success; - } std::vector GetActiveScanSessions(); void CallStartScanCallback(absl::Status status); - void CallOnDiscovered(); - void CallOnUpdated(); - void CallOnLost(); + void CallOnDiscovered(PresenceDevice device); + void CallOnUpdated(PresenceDevice device); + void CallOnLost(PresenceDevice device); private: uint64_t current_scan_session_id_; ScanCallback callback_; std::vector active_scan_sessions_; - bool next_scan_should_succeed_ = true; }; } // namespace presence diff --git a/presence/fpp/BUILD b/presence/fpp/BUILD index f551c07b..931c75a2 100644 --- a/presence/fpp/BUILD +++ b/presence/fpp/BUILD @@ -24,13 +24,28 @@ cc_library( "//presence:__subpackages__", ], deps = [ - "//internal/platform:logging", + "//internal/platform:types", "//presence:types", "//presence/fpp/fpp_c_ffi", "//presence/implementation:sensor_fusion", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/status", - "@com_google_absl//absl/types:optional", + ], +) + +cc_library( + name = "sensor_fusion_impl", + srcs = [ + "sensor_fusion_impl.cc", + ], + hdrs = ["sensor_fusion_impl.h"], + visibility = [ + "//presence:__subpackages__", + ], + deps = [ + ":fpp_manager", + "//presence/implementation:sensor_fusion", + "@com_google_absl//absl/status", ], ) @@ -40,6 +55,27 @@ cc_test( srcs = ["fpp_manager_test.cc"], deps = [ ":fpp_manager", + "//presence/implementation:sensor_fusion", + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/status", + "@com_google_googletest//:gtest_main", + ] + select({ + "@platforms//os:windows": [ + "//internal/platform/implementation/windows", + ], + "//conditions:default": [ + "//internal/platform/implementation/g3", + ], + }), +) + +cc_test( + name = "sensor_fusion_test", + size = "small", + srcs = ["sensor_fusion_test.cc"], + deps = [ + ":sensor_fusion_impl", + "//presence/implementation:sensor_fusion", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/status", "@com_google_googletest//:gtest_main", diff --git a/presence/fpp/fpp_c_ffi/src/lib.rs b/presence/fpp/fpp_c_ffi/src/lib.rs index 6300a64b..b0c536f7 100644 --- a/presence/fpp/fpp_c_ffi/src/lib.rs +++ b/presence/fpp/fpp_c_ffi/src/lib.rs @@ -35,29 +35,31 @@ pub struct PresenceDetectorHandle { handle: u64, } -/// Error enum class representing possible errors +/// Enum class representing possible outputs of proximity data processing call #[repr(C)] -pub enum ProximityEstimateError { - /// Returned if the handle is invalid - InvalidPresenceDetectorHandle, - /// Returned if the output parameter is null - NullOutputParameter, +pub enum ComputationStatus { + /// Returned if the proximity estimate calculation was successful + Success, /// Returned if there is no computed proximity estimate NoComputedProximityEstimate, + /// Returned if the handle is invalid + InvalidPresenceDetectorHandleError, + /// Returned if the output parameter is null + NullOutputParameterError, } -impl ProximityEstimateError { - fn to_error_code(&self) -> i32 { +impl ComputationStatus { + fn to_status_code(&self) -> i32 { match self { - Self::InvalidPresenceDetectorHandle => -1, - Self::NullOutputParameter => -2, - Self::NoComputedProximityEstimate => -3, + /// Status codes 100+ are considered errors + Self::Success => 1, + Self::NoComputedProximityEstimate => 2, + Self::InvalidPresenceDetectorHandleError => 101, + Self::NullOutputParameterError => 102, } } } -const SUCCESS: i32 = 0; - /// Creates a new presence detector object and returns the handle for the new /// object #[no_mangle] @@ -86,15 +88,15 @@ pub unsafe extern "C" fn update_ble_scan_result( { if let Some(proximity_estimate) = proximity_estimate.as_mut() { *proximity_estimate = current_proximity_estimate; - SUCCESS + ComputationStatus::Success.to_status_code() } else { - ProximityEstimateError::NullOutputParameter.to_error_code() + ComputationStatus::NullOutputParameterError.to_status_code() } } else { - ProximityEstimateError::NoComputedProximityEstimate.to_error_code() + ComputationStatus::NoComputedProximityEstimate.to_status_code() } } else { - ProximityEstimateError::InvalidPresenceDetectorHandle.to_error_code() + ComputationStatus::InvalidPresenceDetectorHandleError.to_status_code() } } @@ -115,13 +117,13 @@ pub unsafe extern "C" fn get_proximity_estimate( presence_detector.get_proximity_estimate(device_id).map(|current_proximity_estimate| { if let Some(proximity_estimate) = proximity_estimate.as_mut() { *proximity_estimate = current_proximity_estimate; - return SUCCESS; + return ComputationStatus::Success.to_status_code(); } - ProximityEstimateError::NullOutputParameter.to_error_code() + ComputationStatus::NullOutputParameterError.to_status_code() }); } - ProximityEstimateError::InvalidPresenceDetectorHandle.to_error_code() + ComputationStatus::InvalidPresenceDetectorHandleError.to_status_code() } /// De-allocates memory for a presence detector object @@ -133,7 +135,7 @@ pub extern "C" fn presence_detector_free( get_presence_detector_handle_map().remove(&presence_detector_handle.handle) { let _ = *presence_detector; - return SUCCESS; + return ComputationStatus::Success.to_status_code(); } - ProximityEstimateError::InvalidPresenceDetectorHandle.to_error_code() + ComputationStatus::InvalidPresenceDetectorHandleError.to_status_code() } diff --git a/presence/fpp/fpp_manager.cc b/presence/fpp/fpp_manager.cc index a70265a4..dfe2f4d4 100644 --- a/presence/fpp/fpp_manager.cc +++ b/presence/fpp/fpp_manager.cc @@ -17,40 +17,34 @@ #include #include #include +#include #include "absl/status/status.h" #include "internal/platform/logging.h" #include "presence/fpp/fpp_c_ffi/include/presence_detector.h" +#include "presence/implementation/sensor_fusion.h" #include "presence/presence_zone.h" namespace nearby { namespace presence { namespace { -constexpr int kSuccess = 0; -constexpr int kInvalidPresenceDetectorHandle = -1; -constexpr int kNullOutputParameter = -2; -constexpr int kNoComputedProximityEstimate = -3; +// See +// https://source.corp.google.com/piper///depot/google3/third_party/nearby/presence/fpp/fpp_c_ffi/src/lib.rs;l=49 +// for constants definition +constexpr int kSuccess = 1; +constexpr int kNoComputedProximityEstimate = 2; +constexpr int kInvalidPresenceDetectorHandleError = 101; +constexpr int kNullOutputParameterError = 102; // Converts optional tx power to the rust api compatible equivalent -MaybeTxPower ConvertTxPower(absl::optional txPower) { +MaybeTxPower ConvertTxPower(std::optional txPower) { if (txPower.has_value()) { return {MaybeTxPower::Tag::Valid, {txPower.value()}}; } return {MaybeTxPower::Tag::Invalid, {}}; } -std::string GetStatusStringFromCode(int status_code) { - switch (status_code) { - case kInvalidPresenceDetectorHandle: - return "INVALID_PRESENCE_DETECTOR_HANDLE"; - case kNullOutputParameter: - return "NULL_OUTPUT_PARAMETER"; - default: - return "UNKNOWN_ERROR"; - } -} - // Converts FPP ProximityState struct to NP RangeType struct PresenceZone::DistanceBoundary::RangeType ConvertProximityStateToRangeType( ProximityState proximity_state) { @@ -65,6 +59,7 @@ PresenceZone::DistanceBoundary::RangeType ConvertProximityStateToRangeType( return PresenceZone::DistanceBoundary::RangeType::kFar; case ProximityState::Unknown: default: + NEARBY_LOGS(WARNING) << "Proximity state is unknown"; return PresenceZone::DistanceBoundary::RangeType::kRangeUnknown; } } @@ -74,13 +69,16 @@ absl::Status FppManager::UpdateBleScanResult(uint64_t device_id, std::optional txPower, int rssi, uint64_t elapsed_realtime_millis) { + if (zone_transition_callbacks_.empty()) { + return absl::InternalError("No callback registered"); + } BleScanResult ble_scan_result = {device_id, ConvertTxPower(txPower), rssi, elapsed_realtime_millis}; ProximityEstimate default_proximity_estimate = ProximityEstimate{device_id, - 0.0, + /*distanceMeters=*/0.0, MeasurementConfidence::Unknown, - 0, + /*elapsedRealtime=*/0, ProximityState::Unknown, PresenceDataSource::Ble}; ProximityEstimate old_proximity_estimate = @@ -104,13 +102,12 @@ absl::Status FppManager::UpdateBleScanResult(uint64_t device_id, NEARBY_LOGS(WARNING) << "Could not successfully update FPP with new scan result: Error code=" << status_code; - return absl::Status(absl::StatusCode::kInternal, - GetStatusStringFromCode(status_code)); + return absl::InternalError(GetStatusStringFromCode(status_code)); } void FppManager::RegisterZoneTransitionListener( uint64_t callback_id, ZoneTransitionCallback callback) { - zone_transition_callbacks_[callback_id] = callback; + zone_transition_callbacks_[callback_id] = std::move(callback); } void FppManager::UnregisterZoneTransitionListener(uint64_t callback_id) { @@ -130,12 +127,13 @@ std::optional FppManager::GetRangingData(uint64_t device_id) { RangingData FppManager::ConvertProximityEstimateToRangingData( ProximityEstimate estimate) { RangingMeasurement ranging_measurement = { - 0.0, static_cast(estimate.distance_meters)}; - RangingPosition ranging_position = {ranging_measurement, absl::nullopt, - absl::nullopt, - estimate.elapsed_real_time_millis}; + /*confidenceLevel=*/0.0, static_cast(estimate.distance_meters)}; + RangingPosition ranging_position = { + ranging_measurement, /*azimuth=*/std::nullopt, + /*elevation=*/std::nullopt, estimate.elapsed_real_time_millis}; ZoneTransition zone_transition = { - ConvertProximityStateToRangeType(estimate.proximity_state), 0.0}; + ConvertProximityStateToRangeType(estimate.proximity_state), + /*confidenceLevel=*/0.0}; return {DataSource::kBle, ranging_position, zone_transition, std::vector()}; } @@ -147,12 +145,25 @@ void FppManager::CheckPresenceZoneChanged(uint64_t device_id, NEARBY_LOG(WARNING, "Updating zone transition callbacks with new zone. Zone=%p", new_estimate.proximity_state); - for (const auto& pair : zone_transition_callbacks_) { - pair.second(device_id, ConvertProximityStateToRangeType( - new_estimate.proximity_state)); + for (auto& pair : zone_transition_callbacks_) { + pair.second.on_proximity_zone_changed( + device_id, + ConvertProximityStateToRangeType(new_estimate.proximity_state)); } } } +std::string FppManager::GetStatusStringFromCode(int status_code) { + switch (status_code) { + case kInvalidPresenceDetectorHandleError: + return "INVALID_PRESENCE_DETECTOR_HANDLE"; + case kNullOutputParameterError: + return "NULL_OUTPUT_PARAMETER"; + default: + NEARBY_LOGS(WARNING) << "Error code is unknown"; + return "UNKNOWN_ERROR"; + } +} + } // namespace presence } // namespace nearby diff --git a/presence/fpp/fpp_manager.h b/presence/fpp/fpp_manager.h index 50b616af..cecdb21e 100644 --- a/presence/fpp/fpp_manager.h +++ b/presence/fpp/fpp_manager.h @@ -31,7 +31,6 @@ namespace presence { // between fpp and NP sensor fusion class FppManager { public: - using ZoneTransitionCallback = SensorFusion::ZoneTransitionCallback; using RangeType = PresenceZone::DistanceBoundary::RangeType; FppManager() { presence_detector_handle_ = presence_detector_create(); } @@ -67,6 +66,11 @@ class FppManager { */ std::optional GetRangingData(uint64_t device_id); + /* + * Converts a status code to a string representation + */ + std::string GetStatusStringFromCode(int status_code); + private: void CheckPresenceZoneChanged(uint64_t device_id, ProximityEstimate old_estimate, diff --git a/presence/fpp/fpp_manager_test.cc b/presence/fpp/fpp_manager_test.cc index b7ed5e72..6911e06f 100644 --- a/presence/fpp/fpp_manager_test.cc +++ b/presence/fpp/fpp_manager_test.cc @@ -19,6 +19,8 @@ #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/status/status.h" +#include "presence/implementation/sensor_fusion.h" namespace nearby { namespace presence { @@ -33,15 +35,17 @@ TEST(FppManager, UpdateBleScanResultSuccess) { bool callback_called = false; manager.RegisterZoneTransitionListener( kCallbackId, - [&callback_called](uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType range_type) { - callback_called = true; - }); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + {.on_proximity_zone_changed = + [&callback_called]( + uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + callback_called = true; + }}); + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/0)); // State is only computed after second consecutive scan is fulfilled - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/2000)); EXPECT_EQ(manager.GetRangingData(kDeviceId) @@ -56,15 +60,17 @@ TEST(FppManager, ZoneTransitionDetected) { bool callback_called = false; manager.RegisterZoneTransitionListener( kCallbackId, - [&callback_called](uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType range_type) { - callback_called = true; - }); + {.on_proximity_zone_changed = + [&callback_called]( + uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + callback_called = true; + }}); // ProximityEstimate is only computed after consecutive scans is fulfilled - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/0)); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/2000)); EXPECT_EQ(manager.GetRangingData(kDeviceId) @@ -75,7 +81,7 @@ TEST(FppManager, ZoneTransitionDetected) { callback_called = false; // Update with new zone - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kShortRangeRssi, /*elapsed_real_time_millis=*/0)); EXPECT_EQ(manager.GetRangingData(kDeviceId) @@ -84,7 +90,7 @@ TEST(FppManager, ZoneTransitionDetected) { PresenceZone::DistanceBoundary::RangeType::kWithinReach); EXPECT_FALSE(callback_called); // Update with consecutive scan of new zone - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kShortRangeRssi, /*elapsed_real_time_millis=*/0)); EXPECT_EQ(manager.GetRangingData(kDeviceId) @@ -139,10 +145,12 @@ TEST(FppManager, UpdateBleScanResultWithTxPowerSuccess) { bool callback_called = false; manager.RegisterZoneTransitionListener( kCallbackId, - [&callback_called](uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType range_type) { - callback_called = true; - }); + {.on_proximity_zone_changed = + [&callback_called]( + uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + callback_called = true; + }}); EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/20, kReachRssi, /*elapsed_real_time_millis=*/0)); EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/20, kReachRssi, @@ -159,14 +167,16 @@ TEST(FppManager, UnregisterZoneTransitionListener) { bool callback_called = false; manager.RegisterZoneTransitionListener( kCallbackId, - [&callback_called](uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType range_type) { - callback_called = true; - }); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + {.on_proximity_zone_changed = + [&callback_called]( + uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + callback_called = true; + }}); + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/0)); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/2000)); EXPECT_TRUE(callback_called); @@ -174,15 +184,60 @@ TEST(FppManager, UnregisterZoneTransitionListener) { // Unregister listener and update with new zone manager.UnregisterZoneTransitionListener(kCallbackId); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, - kShortRangeRssi, - /*elapsed_real_time_millis=*/0)); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, - kShortRangeRssi, - /*elapsed_real_time_millis=*/0)); + EXPECT_EQ(manager + .UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, + kShortRangeRssi, + /*elapsed_real_time_millis=*/0) + .code(), + absl::StatusCode::kInternal); + EXPECT_EQ(manager + .UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, + kShortRangeRssi, + /*elapsed_real_time_millis=*/0) + .code(), + absl::StatusCode::kInternal); EXPECT_FALSE(callback_called); } +TEST(FppManager, ResetProximityStateData) { + FppManager manager; + bool callback_called = false; + manager.RegisterZoneTransitionListener( + kCallbackId, + {.on_proximity_zone_changed = + [&callback_called]( + uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + callback_called = true; + }}); + ASSERT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, + kReachRssi, + /*elapsed_real_time_millis=*/0)); + // State is only computed after second consecutive scan is fulfilled + ASSERT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, + kReachRssi, + /*elapsed_real_time_millis=*/2000)); + EXPECT_EQ(manager.GetRangingData(kDeviceId) + ->zone_transition.value() + .distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kWithinReach); + EXPECT_TRUE(callback_called); + + // Reset proximity state data + manager.ResetProximityStateData(); + EXPECT_EQ(manager.GetRangingData(kDeviceId) + ->zone_transition.value() + .distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kRangeUnknown); +} + +TEST(FppManager, GetStatusStringFromCode) { + FppManager manager; + EXPECT_EQ(manager.GetStatusStringFromCode(101), + "INVALID_PRESENCE_DETECTOR_HANDLE"); + EXPECT_EQ(manager.GetStatusStringFromCode(102), "NULL_OUTPUT_PARAMETER"); +} + } // namespace } // namespace presence } // namespace nearby diff --git a/presence/fpp/sensor_fusion_impl.cc b/presence/fpp/sensor_fusion_impl.cc new file mode 100644 index 00000000..2bda18b5 --- /dev/null +++ b/presence/fpp/sensor_fusion_impl.cc @@ -0,0 +1,68 @@ +// 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 +// +// 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 "presence/fpp/sensor_fusion_impl.h" + +#include +#include +#include + +#include "absl/status/status.h" +#include "presence/fpp/fpp_manager.h" + +namespace nearby { +namespace presence { +std::vector SensorFusionImpl::GetDataSources( + uint64_t elapsed_realtime_millis, + const std::vector& available_sources) { + // TODO(b/264547688) - Implement + return std::vector(); +} +absl::Status SensorFusionImpl::UpdateBleScanResult( + uint64_t device_id, std::optional txPower, int rssi, + uint64_t elapsed_realtime_millis) { + return fpp_manager_.UpdateBleScanResult(device_id, txPower, rssi, + elapsed_realtime_millis); +} +void SensorFusionImpl::UpdateUwbRangingResult(uint64_t device_id, + RangingPosition position) { + // TODO(b/264547688) - Implement +} + +void SensorFusionImpl::RequestZoneTransitionUpdates( + ZoneTransitionCallback callback) { + int callback_id = ++id_generator_; + callback.on_callback_id_generated(callback_id); + fpp_manager_.RegisterZoneTransitionListener(callback_id, std::move(callback)); +} + +void SensorFusionImpl::RequestDeviceMotionUpdates( + SensorFusion::DeviceMotionCallback callback) { + // TODO(b/264547688) - Implement +} +void SensorFusionImpl::RemoveDeviceMotionUpdates( + SensorFusion::DeviceMotionCallback callback) { + // TODO(b/264547688) - Implement +} + +void SensorFusionImpl::RemoveZoneTransitionUpdates(uint64_t callback_id) { + fpp_manager_.UnregisterZoneTransitionListener(callback_id); +} + +std::optional SensorFusionImpl::GetRangingData( + uint64_t device_id) { + return fpp_manager_.GetRangingData(device_id); +} +} // namespace presence +} // namespace nearby diff --git a/presence/fpp/sensor_fusion_impl.h b/presence/fpp/sensor_fusion_impl.h new file mode 100644 index 00000000..ac37b6a8 --- /dev/null +++ b/presence/fpp/sensor_fusion_impl.h @@ -0,0 +1,51 @@ +// 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 +// +// 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. + +#ifndef THIRD_PARTY_NEARBY_PRESENCE_FPP_SENSOR_FUSION_IMPL_H_ +#define THIRD_PARTY_NEARBY_PRESENCE_FPP_SENSOR_FUSION_IMPL_H_ + +#include +#include + +#include "presence/fpp/fpp_manager.h" +#include "presence/implementation/sensor_fusion.h" + +namespace nearby { +namespace presence { + +class SensorFusionImpl : public SensorFusion { + public: + ~SensorFusionImpl() = default; + std::vector GetDataSources( + uint64_t elapsed_realtime_millis, + const std::vector& available_sources) override; + absl::Status UpdateBleScanResult(uint64_t device_id, + std::optional txPower, int rssi, + uint64_t elapsed_realtime_millis) override; + void UpdateUwbRangingResult(uint64_t device_id, + RangingPosition position) override; + void RequestZoneTransitionUpdates(ZoneTransitionCallback callback) override; + void RemoveZoneTransitionUpdates(uint64_t callback_id) override; + void RequestDeviceMotionUpdates(DeviceMotionCallback callback) override; + void RemoveDeviceMotionUpdates(DeviceMotionCallback callback) override; + std::optional GetRangingData(uint64_t device_id) override; + + private: + FppManager fpp_manager_; + int id_generator_ = 0; +}; +} // namespace presence +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_PRESENCE_FPP_SENSOR_FUSION_IMPL_H_ diff --git a/presence/fpp/sensor_fusion_test.cc b/presence/fpp/sensor_fusion_test.cc new file mode 100644 index 00000000..aee34d7b --- /dev/null +++ b/presence/fpp/sensor_fusion_test.cc @@ -0,0 +1,110 @@ +// 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 +// +// 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 +#include + +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" +#include "absl/status/status.h" +#include "presence/fpp/sensor_fusion_impl.h" + +namespace nearby { +namespace presence { +namespace { +constexpr uint64_t kDeviceId = 1234; +constexpr int kReachRssi = -40; + +TEST(SensorFusion, RequestZoneTransitionUpdatesSuccess) { + SensorFusionImpl sensor_fusion_impl; + bool callback_called = false; + bool callback2_called = false; + sensor_fusion_impl.RequestZoneTransitionUpdates( + {.on_callback_id_generated = [&callback_called](uint64_t callback_id) { + callback_called = true; + EXPECT_EQ(callback_id, 1); + }}); + sensor_fusion_impl.RequestZoneTransitionUpdates( + {.on_callback_id_generated = [&callback2_called](uint64_t callback_id2) { + callback2_called = true; + EXPECT_EQ(callback_id2, 2); + }}); + EXPECT_TRUE(callback2_called); +} + +TEST(SensorFusion, RemoveZoneTransitionUpdates) { + SensorFusionImpl sensor_fusion_impl; + bool callback_called = false; + sensor_fusion_impl.RequestZoneTransitionUpdates( + {.on_callback_id_generated = [&callback_called](uint64_t callback_id) { + callback_called = true; + EXPECT_EQ(callback_id, 1); + }}); + sensor_fusion_impl.RemoveZoneTransitionUpdates(1); + EXPECT_EQ( + sensor_fusion_impl + .UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, + /*elapsed_real_time_millis=*/0) + .code(), + absl::StatusCode::kInternal); +} + +TEST(SensorFusion, UpdateBleScanResult) { + SensorFusionImpl sensor_fusion_impl; + bool proximity_zone_changed_called = false; + sensor_fusion_impl.RequestZoneTransitionUpdates( + {.on_proximity_zone_changed = + [&proximity_zone_changed_called]( + uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + proximity_zone_changed_called = true; + }}); + EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( + kDeviceId, /*txPower=*/std::nullopt, kReachRssi, + /*elapsed_real_time_millis=*/0)); + EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( + kDeviceId, /*txPower=*/std::nullopt, kReachRssi, + /*elapsed_real_time_millis=*/0)); + + EXPECT_TRUE(proximity_zone_changed_called); +} + +TEST(SensorFusion, GetRangingData) { + SensorFusionImpl sensor_fusion_impl; + bool proximity_zone_changed_called = false; + sensor_fusion_impl.RequestZoneTransitionUpdates( + {.on_proximity_zone_changed = + [&proximity_zone_changed_called]( + uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + proximity_zone_changed_called = true; + }}); + EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( + kDeviceId, /*txPower=*/std::nullopt, kReachRssi, + /*elapsed_real_time_millis=*/0)); + EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( + kDeviceId, /*txPower=*/std::nullopt, kReachRssi, + /*elapsed_real_time_millis=*/0)); + + EXPECT_TRUE(proximity_zone_changed_called); + + EXPECT_EQ(sensor_fusion_impl.GetRangingData(kDeviceId) + ->zone_transition.value() + .distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kWithinReach); +} +} // namespace +} // namespace presence +} // namespace nearby diff --git a/presence/implementation/BUILD b/presence/implementation/BUILD index 97fc31b2..a7b9de53 100644 --- a/presence/implementation/BUILD +++ b/presence/implementation/BUILD @@ -87,7 +87,6 @@ cc_library( "//internal/crypto_cros", "//internal/platform:base", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform:uuid", "//internal/platform/implementation:comm", @@ -126,7 +125,8 @@ cc_library( ], deps = [ "//presence:types", - "@com_google_absl//absl/types:optional", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/status", ], ) diff --git a/presence/implementation/advertisement_decoder.cc b/presence/implementation/advertisement_decoder.cc index ff292cb2..53102ac9 100644 --- a/presence/implementation/advertisement_decoder.cc +++ b/presence/implementation/advertisement_decoder.cc @@ -214,7 +214,7 @@ absl::StatusOr AdvertisementDecoder::DecryptLdt( for (const auto& credential : credentials) { absl::StatusOr encryptor = LdtEncryptor::Create( credential.key_seed(), - credential.metadata_encryption_key_unsigned_adv_tag()); + credential.metadata_encryption_key_tag_v0()); if (encryptor.ok()) { absl::StatusOr result = encryptor->DecryptAndVerify(data_elements, salt); diff --git a/presence/implementation/advertisement_decoder_test.cc b/presence/implementation/advertisement_decoder_test.cc index 0807cad4..8b532ef7 100644 --- a/presence/implementation/advertisement_decoder_test.cc +++ b/presence/implementation/advertisement_decoder_test.cc @@ -78,7 +78,7 @@ SharedCredential GetPublicCredential() { 163, 203, 100, 235, 53, 65, 202, 97, 75, 180}); SharedCredential public_credential; public_credential.set_key_seed(seed.AsStringView()); - public_credential.set_metadata_encryption_key_unsigned_adv_tag( + public_credential.set_metadata_encryption_key_tag_v0( known_mac.AsStringView()); return public_credential; } diff --git a/presence/implementation/credential_manager_impl.cc b/presence/implementation/credential_manager_impl.cc index 7696ce0b..f5bafad8 100644 --- a/presence/implementation/credential_manager_impl.cc +++ b/presence/implementation/credential_manager_impl.cc @@ -245,7 +245,7 @@ SharedCredential CredentialManagerImpl::CreatePublicCredential( auto metadata_encryption_key_tag = Crypto::Sha256(private_credential.metadata_encryption_key_v0()); - public_credential.set_metadata_encryption_key_unsigned_adv_tag( + public_credential.set_metadata_encryption_key_tag_v0( std::string(metadata_encryption_key_tag.AsStringView())); // Encrypt the device metadata diff --git a/presence/implementation/credential_manager_impl_test.cc b/presence/implementation/credential_manager_impl_test.cc index a19f4eac..2d3b34bf 100644 --- a/presence/implementation/credential_manager_impl_test.cc +++ b/presence/implementation/credential_manager_impl_test.cc @@ -175,7 +175,7 @@ TEST_F(CredentialManagerImplTest, CreateOneCredentialSuccessfully) { absl::ToUnixMillis(kEndTime + absl::Hours(3))); EXPECT_EQ(Crypto::Sha256(private_credential.metadata_encryption_key_v0()) .AsStringView(), - public_credential.metadata_encryption_key_unsigned_adv_tag()); + public_credential.metadata_encryption_key_tag_v0()); EXPECT_FALSE( public_credential.connection_signature_verification_key().empty()); EXPECT_FALSE(public_credential.encrypted_metadata_bytes_v0().empty()); diff --git a/presence/implementation/ldt_test.cc b/presence/implementation/ldt_test.cc index 88eadfe8..fbbd2581 100644 --- a/presence/implementation/ldt_test.cc +++ b/presence/implementation/ldt_test.cc @@ -89,7 +89,7 @@ TEST(Ldt, DecryptAndroidData) { absl::HexStringToBytes(kSharedCredentialBase16))); absl::StatusOr encryptor = LdtEncryptor::Create( shared_credential.key_seed(), - shared_credential.metadata_encryption_key_unsigned_adv_tag()); + shared_credential.metadata_encryption_key_tag_v0()); ASSERT_OK(encryptor); absl::StatusOr decrypted = diff --git a/presence/implementation/sensor_fusion.h b/presence/implementation/sensor_fusion.h index 452b01fd..31639bd7 100644 --- a/presence/implementation/sensor_fusion.h +++ b/presence/implementation/sensor_fusion.h @@ -17,9 +17,11 @@ #include #include +#include #include -#include "absl/types/optional.h" +#include "absl/functional/any_invocable.h" +#include "absl/status/status.h" #include "presence/device_motion.h" #include "presence/presence_zone.h" @@ -41,8 +43,8 @@ struct RangingMeasurement { struct RangingPosition { RangingMeasurement distance; - absl::optional azimuth; - absl::optional elevation; + std::optional azimuth; + std::optional elevation; uint64_t elapsed_realtime_millis; }; @@ -54,20 +56,25 @@ struct ZoneTransition { struct RangingData { DataSource data_source; RangingPosition position; - absl::optional zone_transition; + std::optional zone_transition; std::vector device_motions; }; +struct ZoneTransitionCallback { + absl::AnyInvocable + on_proximity_zone_changed = + [](uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType proximity_zone) {}; + absl::AnyInvocable on_callback_id_generated = + [](uint64_t callback_id) {}; +}; + class SensorFusion { public: virtual ~SensorFusion() = default; - // Called when the proximity zone to a nearby peer device has changed. - typedef std::function - ZoneTransitionCallback; - // Called when a device motion gesture is detected. typedef std::function DeviceMotionCallback; @@ -84,62 +91,63 @@ class SensorFusion { * source query. * @param available_sources A bit mask of data sources that are available. */ - virtual std::vector getDataSources( + virtual std::vector GetDataSources( uint64_t elapsed_realtime_millis, - std::vector available_sources); + const std::vector& available_sources) = 0; /** * Updates BLE scanned results to Sensor Fusion. * * @param device_id A unique device id of the peer device. * @param txPower Calibrated TX power of the scan result, {@code - * absl::nullopt} if the calibrated TX power is not available. + * std::nullopt} if the calibrated TX power is not available. * @param rssi Received signal strength indicator for the scan result. * @param elapsed_realtime_millis Elapsed timestamp since boot when the * scan result is discovered. */ - virtual void updateBleScanResult(uint64_t device_id, - absl::optional txPower, int rssi, - uint64_t elapsed_realtime_millis); - + virtual absl::Status UpdateBleScanResult( + uint64_t device_id, std::optional txPower, int rssi, + uint64_t elapsed_realtime_millis) = 0; /** * Updates UWB ranging results to Sensor Fusion. * * @param device_id A unique device id of the peer device. * @param position UWB ranging result (distance and optionally angle) */ - virtual void updateUwbRangingResult(uint64_t device_id, - RangingPosition position); + virtual void UpdateUwbRangingResult(uint64_t device_id, + RangingPosition position) = 0; /** * Adds callback for updates of proximity zone transitions. */ - virtual void requestZoneTransitionUpdates(ZoneTransitionCallback callback); + virtual void RequestZoneTransitionUpdates( + ZoneTransitionCallback callback) = 0; /** * Removes callback for updates of proximity zone transitions. */ - virtual void removeZoneTransitionUpdates(ZoneTransitionCallback callback); + virtual void RemoveZoneTransitionUpdates(uint64_t callback_id) = 0; /** * Adds callback for updates of device motion events. */ - virtual void requestDeviceMotionUpdates(DeviceMotionCallback callback); + virtual void RequestDeviceMotionUpdates(DeviceMotionCallback callback) = 0; /** * Remove callback for updates of device motion events. */ - virtual void removeDeviceMotionUpdates(DeviceMotionCallback callback); + virtual void RemoveDeviceMotionUpdates(DeviceMotionCallback callback) = 0; /** * Returns the best ranging estimate to a given device. Returns {@code - * absl::nullopt} if the sensor fusion cannot produce a ranging estimate. + * std::nullopt} if the sensor fusion cannot produce a ranging estimate. * * @param device_id Id of the peer device. */ - virtual absl::optional getRangingData(uint64_t device_id); + virtual std::optional GetRangingData(uint64_t device_id) = 0; }; } // namespace presence } // namespace nearby #endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SENSOR_FUSION_H_ + diff --git a/presence/proto/presence_frame.proto b/presence/proto/presence_frame.proto index 62fd7d47..5b4ba2ff 100644 --- a/presence/proto/presence_frame.proto +++ b/presence/proto/presence_frame.proto @@ -117,7 +117,15 @@ message UwbControleeCapabilities { optional bool is_ranging_interval_reconfigure_supported = 14 [default = false]; repeated int32 supported_slot_durations = 15 [packed = true]; - repeated int32 supported_ranging_intervals = 16 [packed = true]; + repeated int32 supported_ranging_update_rates = 16 [packed = true]; + optional int32 chip_count = 17 [default = 1]; + repeated UwbMultiChipInfo multi_chip_info = 18; +} + +/* A frame containing info needed per chip in a multi-chip environment. */ +message UwbMultiChipInfo { + optional bytes controlee_address = 1; + optional string chip_id = 2; } /** diff --git a/proto/BUILD b/proto/BUILD index 1d40471a..7abb0cd9 100644 --- a/proto/BUILD +++ b/proto/BUILD @@ -14,6 +14,7 @@ # Proto for Nearby products +# Placeholder: load py_proto_library load("@rules_cc//cc:defs.bzl", "cc_proto_library") licenses(["notice"]) diff --git a/proto/connections_enums.proto b/proto/connections_enums.proto index 8af849d9..c5d25ae5 100644 --- a/proto/connections_enums.proto +++ b/proto/connections_enums.proto @@ -822,6 +822,10 @@ enum OperationResultDetail { CONNECTIVITY_WIFI_AWARE_DISCOVERED_PEER_NULL = 3552; // Failed to write chunk to endpoint channel CONNECTIVITY_GENERIC_PAYLOAD_SENT_ERROR = 3553; + // L2CAP server socket creation failure (SecurityException) + CONNECTIVITY_L2CAP_SERVER_SOCKET_CREATION_SECURITY_EXCEPTION_FAILURE = 3554; + // BT server socket creation failure (SecurityException) + CONNECTIVITY_BT_SERVER_SOCKET_CREATION_SECURITY_EXCEPTION_FAILURE = 3555; // Section of CATEGORY_NEARBY_ERROR, from 4500 // NO BLE MAC address associated to the GATT advertisement diff --git a/proto/sharing_enums.proto b/proto/sharing_enums.proto index f34d8f7e..196adf2f 100644 --- a/proto/sharing_enums.proto +++ b/proto/sharing_enums.proto @@ -30,7 +30,7 @@ option objc_class_prefix = "GNSHP"; // in NearbyClearcutLogger (for android, or clearcut_event_logger as the // equivalence for Windows) for all events (may exclude settings), and // session_id for a pair of events (start and end of a session). -// Next id: 63 +// Next id: 65 enum EventType { UNKNOWN_EVENT_TYPE = 0; @@ -232,6 +232,12 @@ enum EventType { // Send desktop notification. SEND_DESKTOP_NOTIFICATION = 62; + // User sets account preference + SET_ACCOUNT = 63; + + // Decrypt certificate failure + DECRYPT_CERTIFICATE_FAILURE = 64; + // LINT.ThenChange(//depot/google3/location/nearby/proto/nearby_event_codes.proto:SharingEventCode) } @@ -277,6 +283,12 @@ enum EstablishConnectionStatus { CONNECTION_STATUS_SUCCESS = 1; CONNECTION_STATUS_FAILURE = 2; CONNECTION_STATUS_CANCELLATION = 3; + CONNECTION_STATUS_MEDIA_UNAVAILABLE_ATTACHMENT = 4; + CONNECTION_STATUS_FAILED_PAIRED_KEYHANDSHAKE = 5; + CONNECTION_STATUS_FAILED_WRITE_INTRODUCTION = 6; + CONNECTION_STATUS_FAILED_NULL_CONNECTION = 7; + CONNECTION_STATUS_FAILED_NO_TRANSFER_UPDATE_CALLBACK = 8; + CONNECTION_STATUS_LOST_CONNECTIVITY = 9; } // The status of sending and receiving attachments. Used by SEND_ATTACHMENTS. @@ -287,26 +299,103 @@ enum AttachmentTransmissionStatus { CANCELED_ATTACHMENT_TRANSMISSION_STATUS = 2; FAILED_ATTACHMENT_TRANSMISSION_STATUS = 3; - REJECTED_ATTACHMENT = 4; - TIMED_OUT_ATTACHMENT = 5; + REJECTED_ATTACHMENT = 4 [deprecated = true]; + TIMED_OUT_ATTACHMENT = 5 [deprecated = true]; AWAITING_REMOTE_ACCEPTANCE_FAILED_ATTACHMENT = 6 [deprecated = true]; - NOT_ENOUGH_SPACE_ATTACHMENT = 7; - FAILED_NO_TRANSFER_UPDATE_CALLBACK = 8; - MEDIA_UNAVAILABLE_ATTACHMENT = 9; - UNSUPPORTED_ATTACHMENT_TYPE_ATTACHMENT = 10; - NO_ATTACHMENT_FOUND = 11; - FAILED_NO_SHARE_TARGET_ENDPOINT = 12; - FAILED_PAIRED_KEYHANDSHAKE = 13; - FAILED_NULL_CONNECTION = 14; - FAILED_NO_PAYLOAD = 15; - FAILED_WRITE_INTRODUCTION = 16; + NOT_ENOUGH_SPACE_ATTACHMENT = 7 [deprecated = true]; + FAILED_NO_TRANSFER_UPDATE_CALLBACK = 8 [deprecated = true]; + MEDIA_UNAVAILABLE_ATTACHMENT = 9 [deprecated = true]; + UNSUPPORTED_ATTACHMENT_TYPE_ATTACHMENT = 10 [deprecated = true]; + NO_ATTACHMENT_FOUND = 11 [deprecated = true]; + FAILED_NO_SHARE_TARGET_ENDPOINT = 12 [deprecated = true]; + FAILED_PAIRED_KEYHANDSHAKE = 13 [deprecated = true]; + FAILED_NULL_CONNECTION = 14 [deprecated = true]; + FAILED_NO_PAYLOAD = 15 [deprecated = true]; + FAILED_WRITE_INTRODUCTION = 16 [deprecated = true]; // The remote response is either missing or has an unknown type. - FAILED_UNKNOWN_REMOTE_RESPONSE = 17; + FAILED_UNKNOWN_REMOTE_RESPONSE = 17 [deprecated = true]; // Breakdowns of FAILED_NULL_CONNECTION (Desktop side) FAILED_NULL_CONNECTION_INIT_OUTGOING = 18; FAILED_NULL_CONNECTION_DISCONNECTED = 19; + + // Breakdowns of FAILED_NULL_CONNECTION (android side) + // Connection failed due to Wifi is disconnected or Bluetooth setting is off + // or user turn on airplane mode. + FAILED_NULL_CONNECTION_LOST_CONNECTIVITY = 20 [deprecated = true]; + // Unexpected connection failure. + FAILED_NULL_CONNECTION_FAILURE = 21 [deprecated = true]; + + REJECTED_ATTACHMENT_TRANSMISSION_STATUS = 22; + TIMED_OUT_ATTACHMENT_TRANSMISSION_STATUS = 23; + NOT_ENOUGH_SPACE_ATTACHMENT_TRANSMISSION_STATUS = 24; + UNSUPPORTED_ATTACHMENT_TYPE_ATTACHMENT_TRANSMISSION_STATUS = 25; + FAILED_UNKNOWN_REMOTE_RESPONSE_TRANSMISSION_STATUS = 26; + // Connection failed due to Wifi is disconnected or Bluetooth setting is off + // or user turn on airplane mode. + NO_RESPONSE_FRAME_CONNECTION_CLOSED_LOST_CONNECTIVITY_TRANSMISSION_STATUS = 27 + [deprecated = true]; + // Unexpected connection failure due to no response frame. + NO_RESPONSE_FRAME_CONNECTION_CLOSED_TRANSMISSION_STATUS = 28; + // Connection failed due to Wifi is disconnected or Bluetooth setting is off + // or user turn on airplane mode. + LOST_CONNECTIVITY_TRANSMISSION_STATUS = 29; +} + +// Generic result status of NearbyConnections API calls. +enum ConnectionLayerStatus { + // No status is available + CONNECTION_LAYER_STATUS_UNKNOWN = 0; + // The operation was successful. + CONNECTION_LAYER_STATUS_SUCCESS = 1; + // The operation failed, without any more information. + CONNECTION_LAYER_STATUS_ERROR = 2; + // The app called an API method out of order (i.e. another method is expected + // to be called first). + CONNECTION_LAYER_STATUS_OUT_OF_ORDER_API_CALL = 3; + // The app already has active operations (advertising, discovering, or + // connected to other devices) with another Strategy. Stop these operations on + // the current Strategy before trying to advertise or discover with a new + // Strategy. + CONNECTION_LAYER_STATUS_ALREADY_HAVE_ACTIVE_STRATEGY = 4; + // The app is already advertising; call StopAdvertising() before trying to + // advertise again. + CONNECTION_LAYER_STATUS_ALREADY_ADVERTISING = 5; + // The app is already discovering; call StopDiscovery() before trying to + // discover again. + CONNECTION_LAYER_STATUS_ALREADY_DISCOVERING = 6; + // NC is already listening for incoming connections from remote endpoints. + CONNECTION_LAYER_STATUS_ALREADY_LISTENING = 7; + // An attempt to read from/write to a connected remote endpoint failed. If + // this occurs repeatedly, consider invoking DisconnectFromEndpoint(). + CONNECTION_LAYER_STATUS_END_POINT_IO_ERROR = 8; + // An attempt to interact with a remote endpoint failed because it's unknown + // to us -- it's either an endpoint that was never discovered, or an endpoint + // that never connected to us (both of which are indicative of bad input from + // the client app). + CONNECTION_LAYER_STATUS_END_POINT_UNKNOWN = 9; + // The remote endpoint rejected the connection request. + CONNECTION_LAYER_STATUS_CONNECTION_REJECTED = 10; + // The app is already connected to the specified endpoint. Multiple + // connections to a remote endpoint cannot be maintained simultaneously. + CONNECTION_LAYER_STATUS_ALREADY_CONNECTED_TO_END_POINT = 11; + // The remote endpoint is not connected; messages cannot be sent to it. + CONNECTION_LAYER_STATUS_NOT_CONNECTED_TO_END_POINT = 12; + // There was an error trying to use the device's Bluetooth capabilities. + CONNECTION_LAYER_STATUS_BLUETOOTH_ERROR = 13; + // There was an error trying to use the device's Bluetooth Low Energy + // capabilities. + CONNECTION_LAYER_STATUS_BLE_ERROR = 14; + // There was an error trying to use the device's Wi-Fi capabilities. + CONNECTION_LAYER_STATUS_WIFI_LAN_ERROR = 15; + // An attempt to interact with an in-flight Payload failed because it's + // unknown to us. + CONNECTION_LAYER_STATUS_PAYLOAD_UNKNOWN = 16; + // The connection was reset + CONNECTION_LAYER_STATUS_RESET = 17; + // The connection timed out + CONNECTION_LAYER_STATUS_TIMEOUT = 18; } // The status of processing attachments after receiver received payloads @@ -431,6 +520,49 @@ enum ServerResponseState { SERVER_RESPONSE_NOT_CONNECTED_TO_INTERNET = 10; } +// The purpose of requesting the server request. +enum SyncPurpose { + SYNC_PURPOSE_UNKNOWN = 0; + // When NearbySharingChimeraService#sync() is called. + SYNC_PURPOSE_ON_DEMAND_SYNC = 1; + // Requested by chime notification. + SYNC_PURPOSE_CHIME_NOTIFICATION = 2; + // For reqular daily sync. + SYNC_PURPOSE_DAILY_SYNC = 3; + // Wen a device opts into Nearby Share. + SYNC_PURPOSE_OPT_IN_FIRST_SYNC = 4; + // Requested when Nearby Share automatically enables a device that shares + // a single account that has already opted in on another device. + SYNC_PURPOSE_CHECK_DEFAULT_OPT_IN = 5; + // When a device enables Nearby Share. + SYNC_PURPOSE_NEARBY_SHARE_ENABLED = 6; + // When a device is in fast init advertising. + SYNC_PURPOSE_SYNC_AT_FAST_INIT = 7; + // When device start discovery. + SYNC_PURPOSE_SYNC_AT_DISCOVERY = 8; + // When device tries to load valid private certificate. + SYNC_PURPOSE_SYNC_AT_LOAD_PRIVATE_CERTIFICATE = 9; + // When device start advertiseement. + SYNC_PURPOSE_SYNC_AT_ADVERTISEMENT = 10; + // When device contacts list changes. + SYNC_PURPOSE_CONTACT_LIST_CHANGE = 11; + // When showing the C11 banner in Neary Share setting. + SYNC_PURPOSE_SHOW_C11N_VIEW = 12; + // For regular check contact reachability. + SYNC_PURPOSE_REGULAR_CHECK_CONTACT_REACHABILITY = 13; + // When selected contacts list changes in visibility setting. + SYNC_PURPOSE_VISIBILITY_SELECTED_CONTACT_CHANGE = 14; + // When switching account. + SYNC_PURPOSE_ACCOUNT_CHANGE = 15; +} + +// The device role to trigger the server request. +enum ClientRole { + CLIENT_ROLE_UNKNOWN = 0; + CLIENT_ROLE_SENDER = 1; + CLIENT_ROLE_RECEIVER = 2; +} + // The type of Nearby Sharing scanning. enum ScanType { UNKNOWN_SCAN_TYPE = 0; @@ -443,7 +575,12 @@ enum ScanType { // The type of parsing endpoint id failed type. enum ParsingFailedType { FAILED_UNKNOWN_TYPE = 0; + // NULL advertisement is returned due to sender failing to parse advertisement + // from endpointInfo byte stream from receiver advertisement. FAILED_PARSE_ADVERTISEMENT = 1; + // NULL shareTarget is returned due to sender failing to create shareTarget + // from a valid parsed advertisement stemming from issues in certificates, QR + // code tokens or device names. FAILED_CONVERT_SHARE_TARGET = 2; } @@ -456,6 +593,15 @@ enum AdvertisingMode { FOREGROUND_ADVERTISING_MODE = 4; } +// The Nearby Sharing discovery mode. +enum DiscoveryMode { + UNKNOWN_DISCOVERY_MODE = 0; + SCREEN_OFF_DISCOVERY_MODE = 1; + BACKGROUND_DISCOVERY_MODE = 2; + MIDGROUND_DISCOVERY_MODE = 3; + FOREGROUND_DISCOVERY_MODE = 4; +} + // The class name of chimera activity. enum ActivityName { UNKNOWN_ACTIVITY = 0; @@ -649,6 +795,16 @@ enum DesktopTransferEventType { DESKTOP_TRANSFER_EVENT_SEND_TYPE_SENT = 8; DESKTOP_TRANSFER_EVENT_SEND_TYPE_ERROR = 9; } + +enum DecryptCertificateFailureStatus { + DECRYPT_CERT_UNKNOWN_FAILURE = 0; + DECRYPT_CERT_NO_SUCH_ALGORITHM_FAILURE = 1; + DECRYPT_CERT_NO_SUCH_PADDING_FAILURE = 2; + DECRYPT_CERT_INVALID_KEY_FAILURE = 3; + DECRYPT_CERT_INVALID_ALGORITHM_PARAMETER_FAILURE = 4; + DECRYPT_CERT_ILLEGAL_BLOCK_SIZE_FAILURE = 5; + DECRYPT_CERT_BAD_PADDING_FAILURE = 6; +} // LINT.ThenChange( // //depot/google3/location/nearby/cpp/sharing/clients/dart/platform/lib/types/models.dart // )