// Copyright 2025 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. // Simple example: Send a text message to nearby device // // Usage: // Terminal 1 (Receiver): ./simple_receiver // Terminal 2 (Sender): ./simple_sender "Hello World" #include #include #include #include #include #include "sharing/linux/nearby_sharing_service_linux.h" #include "sharing/attachment_container.h" #include "sharing/text_attachment.h" #include "sharing/share_target.h" #include "sharing/transfer_metadata.h" #include "sharing/transfer_update_callback.h" #include "sharing/share_target_discovered_callback.h" using namespace nearby::sharing; using namespace nearby::sharing::linux; // Simple callback that automatically accepts incoming transfers class SimpleReceiverCallback : public TransferUpdateCallback { public: explicit SimpleReceiverCallback(NearbySharingServiceLinux* service) : service_(service) {} void OnTransferUpdate(const ShareTarget& share_target, const AttachmentContainer& attachment_container, const TransferMetadata& transfer_metadata) override { std::cout << "\n[Receiver] Transfer Update from: " << share_target.device_name << std::endl; std::cout << "[Receiver] Status: " << TransferMetadata::StatusToString(transfer_metadata.status()) << std::endl; // Auto-accept incoming transfers if (transfer_metadata.status() == TransferMetadata::Status::kAwaitingLocalConfirmation) { std::cout << "[Receiver] Auto-accepting transfer..." << std::endl; service_->Accept(share_target.id, [](auto status) { std::cout << "[Receiver] Accept status: " << NearbySharingService::StatusCodeToString(status) << std::endl; }); } // Show received content when complete if (transfer_metadata.status() == TransferMetadata::Status::kComplete) { std::cout << "\n[Receiver] ✓ Transfer Complete!" << std::endl; // Display received text for (const auto& text : attachment_container.GetTextAttachments()) { std::cout << "[Receiver] Received text: \"" << text.text_body() << "\"" << std::endl; } // Display received files for (const auto& file : attachment_container.GetFileAttachments()) { std::cout << "[Receiver] Received file: " << file.file_name() << std::endl; } } } private: NearbySharingServiceLinux* service_; }; // Callback for discovering nearby devices class SimpleSenderCallback : public ShareTargetDiscoveredCallback { public: void OnShareTargetDiscovered(const ShareTarget& share_target) override { std::cout << "\n[Sender] Found device: " << share_target.device_name << " (ID: " << share_target.id << ")" << std::endl; discovered_target_ = share_target; has_target_ = true; } void OnShareTargetLost(const ShareTarget& share_target) override { std::cout << "[Sender] Lost device: " << share_target.device_name << std::endl; if (has_target_ && discovered_target_.id == share_target.id) { has_target_ = false; } } void OnShareTargetUpdated(const ShareTarget& share_target) override {} bool HasTarget() const { return has_target_; } const ShareTarget& GetTarget() const { return discovered_target_; } private: ShareTarget discovered_target_; bool has_target_ = false; }; // Transfer progress callback for sender class SimpleSenderTransferCallback : public TransferUpdateCallback { public: void OnTransferUpdate(const ShareTarget& share_target, const AttachmentContainer& attachment_container, const TransferMetadata& transfer_metadata) override { std::cout << "[Sender] Transfer to " << share_target.device_name << ": " << TransferMetadata::StatusToString(transfer_metadata.status()) << " (" << (transfer_metadata.progress() * 100) << "%)" << std::endl; if (transfer_metadata.status() == TransferMetadata::Status::kComplete) { std::cout << "[Sender] ✓ Transfer Complete!" << std::endl; transfer_complete_ = true; } else if (transfer_metadata.status() == TransferMetadata::Status::kFailed) { std::cout << "[Sender] ✗ Transfer Failed!" << std::endl; transfer_complete_ = true; } } bool IsTransferComplete() const { return transfer_complete_; } private: bool transfer_complete_ = false; }; int main(int argc, char* argv[]) { if (argc < 2) { std::cout << "Usage: " << argv[0] << " [message]" << std::endl; std::cout << "Examples:" << std::endl; std::cout << " " << argv[0] << " receiver # Start as receiver" << std::endl; std::cout << " " << argv[0] << " sender \"Hello!\" # Send text message" << std::endl; return 1; } std::string mode = argv[1]; if (mode == "receiver") { // ============= RECEIVER MODE ============= std::cout << "=== Nearby Sharing Receiver ===" << std::endl; NearbySharingServiceLinux service("Receiver-Device"); SimpleReceiverCallback callback(&service); // Register as a receiver (advertise to nearby devices) service.RegisterReceiveSurface( &callback, NearbySharingService::ReceiveSurfaceState::kForeground, Advertisement::BlockedVendorId::kNone, [](auto status) { if (status == NearbySharingService::StatusCodes::kOk) { std::cout << "[Receiver] ✓ Advertising started" << std::endl; std::cout << "[Receiver] Waiting for incoming transfers..." << std::endl; } else { std::cout << "[Receiver] ✗ Failed to start: " << NearbySharingService::StatusCodeToString(status) << std::endl; } }); // Keep running to receive transfers std::cout << "\nPress Ctrl+C to exit..." << std::endl; while (true) { std::this_thread::sleep_for(std::chrono::seconds(1)); } } else if (mode == "sender") { // ============= SENDER MODE ============= std::string message = "Hello from Nearby Sharing!"; if (argc > 2) { message = argv[2]; } std::cout << "=== Nearby Sharing Sender ===" << std::endl; std::cout << "[Sender] Message to send: \"" << message << "\"" << std::endl; NearbySharingServiceLinux service("Sender-Device"); SimpleSenderCallback discovery_callback; SimpleSenderTransferCallback transfer_callback; // Register as sender (scan for nearby devices) service.RegisterSendSurface( &transfer_callback, &discovery_callback, NearbySharingService::SendSurfaceState::kForeground, Advertisement::BlockedVendorId::kNone, false, [](auto status) { if (status == NearbySharingService::StatusCodes::kOk) { std::cout << "[Sender] ✓ Scanning started" << std::endl; } else { std::cout << "[Sender] ✗ Failed to start: " << NearbySharingService::StatusCodeToString(status) << std::endl; } }); // Wait for device discovery std::cout << "[Sender] Scanning for nearby devices..." << std::endl; int wait_time = 0; while (!discovery_callback.HasTarget() && wait_time < 10) { std::this_thread::sleep_for(std::chrono::seconds(1)); wait_time++; std::cout << "." << std::flush; } std::cout << std::endl; if (!discovery_callback.HasTarget()) { std::cout << "[Sender] ✗ No devices found. Make sure receiver is running!" << std::endl; return 1; } // Create text attachment auto attachment_container = std::make_unique(); attachment_container->AddTextAttachment(TextAttachment( nearby::sharing::service::proto::TextMetadata::TEXT, message, std::nullopt, std::nullopt )); // Send to discovered device const auto& target = discovery_callback.GetTarget(); std::cout << "\n[Sender] Sending to: " << target.device_name << std::endl; service.SendAttachments( target.id, std::move(attachment_container), [](auto status) { std::cout << "[Sender] Send initiated: " << NearbySharingService::StatusCodeToString(status) << std::endl; }); // Wait for transfer to complete std::cout << "[Sender] Transferring..." << std::endl; while (!transfer_callback.IsTransferComplete()) { std::this_thread::sleep_for(std::chrono::milliseconds(500)); } std::cout << "\n[Sender] Done!" << std::endl; } else { std::cout << "Invalid mode. Use 'receiver' or 'sender'" << std::endl; return 1; } return 0; }