mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
refactored linux sharing platform
This commit is contained in:
@@ -1,292 +0,0 @@
|
||||
# Nearby Sharing Linux - Known Limitations and Compatibility
|
||||
|
||||
## Authentication Failure Issue
|
||||
|
||||
### Problem
|
||||
|
||||
When trying to connect between the Linux implementation and Android Nearby Share, you may see:
|
||||
```
|
||||
[NS_AUTH] send-side ConnectionFailure
|
||||
AUTH_FAILURE
|
||||
```
|
||||
|
||||
### Root Cause
|
||||
|
||||
The current Linux implementation (`nearby_sharing_service_linux`) is a **simplified version** that:
|
||||
- ✅ Implements device discovery (BLE advertising/scanning)
|
||||
- ✅ Implements connection establishment (via Nearby Connections)
|
||||
- ✅ Implements basic payload transfer
|
||||
- ❌ **Does NOT implement the full Nearby Sharing protocol**
|
||||
|
||||
The full Nearby Sharing protocol (used by Android/ChromeOS) requires:
|
||||
|
||||
1. **Introduction Frame Exchange**
|
||||
- Sender sends an introduction with file metadata
|
||||
- Receiver parses and displays file info before accepting
|
||||
|
||||
2. **Paired Key Verification**
|
||||
- Security handshake using certificates
|
||||
- PIN/Token verification for untrusted devices
|
||||
- Requires `NearbyShareCertificateManager`
|
||||
|
||||
3. **Protocol Frames**
|
||||
- Structured message format (protobuf-based)
|
||||
- Control frames for connection, progress, cancellation
|
||||
- Metadata exchange before file transfer
|
||||
|
||||
4. **Certificate Management**
|
||||
- Public/Private certificate pairs
|
||||
- Contact-based sharing
|
||||
- Visibility controls
|
||||
|
||||
### What the Linux Implementation Lacks
|
||||
|
||||
```cpp
|
||||
// Missing in nearby_sharing_service_linux.cc:
|
||||
|
||||
// 1. Certificate Manager (returns nullptr)
|
||||
NearbyShareCertificateManager* GetCertificateManager() {
|
||||
return nullptr; // ❌ Not implemented
|
||||
}
|
||||
|
||||
// 2. Contact Manager (returns nullptr)
|
||||
NearbyShareContactManager* GetContactManager() {
|
||||
return nullptr; // ❌ Not implemented
|
||||
}
|
||||
|
||||
// 3. Settings Manager (returns nullptr)
|
||||
NearbyShareSettings* GetSettings() {
|
||||
return nullptr; // ❌ Not implemented
|
||||
}
|
||||
|
||||
// 4. No introduction frame exchange
|
||||
// 5. No paired key verification
|
||||
// 6. No protocol frame parsing
|
||||
```
|
||||
|
||||
## Workarounds
|
||||
|
||||
### Option 1: Linux-to-Linux Only
|
||||
|
||||
The current implementation **DOES work** for Linux-to-Linux transfers:
|
||||
|
||||
```bash
|
||||
# Device 1
|
||||
./nearby_sharing_app
|
||||
> Choose 1 (Start as Receiver)
|
||||
|
||||
# Device 2
|
||||
./nearby_sharing_app
|
||||
> Choose 2 (Start as Sender)
|
||||
> Choose 4 (Send file)
|
||||
```
|
||||
|
||||
Both devices use the same simplified protocol, so they can communicate.
|
||||
|
||||
### Option 2: Use the Full Implementation
|
||||
|
||||
To communicate with Android/ChromeOS, you need the **full Nearby Sharing implementation** which is located in:
|
||||
|
||||
```
|
||||
sharing/nearby_sharing_service_impl.h
|
||||
sharing/nearby_sharing_service_impl.cc
|
||||
```
|
||||
|
||||
This is the complete implementation used by ChromeOS and includes all the protocol handling.
|
||||
|
||||
**However**, this requires:
|
||||
- Platform-specific implementations (preferences, UI, etc.)
|
||||
- Certificate storage and management
|
||||
- Contact synchronization
|
||||
- More complex setup
|
||||
|
||||
### Option 3: Implement Protocol Handlers
|
||||
|
||||
Add the missing protocol components to `nearby_sharing_service_linux`:
|
||||
|
||||
#### A. Add Introduction Frame Support
|
||||
|
||||
```cpp
|
||||
// sharing/linux/nearby_sharing_service_linux.cc
|
||||
|
||||
#include "sharing/proto/wire_format.pb.h"
|
||||
|
||||
void NearbySharingServiceLinux::SendIntroductionFrame(
|
||||
const std::string& endpoint_id,
|
||||
const AttachmentContainer& attachments) {
|
||||
|
||||
// Build introduction message
|
||||
nearby::sharing::service::proto::V1Frame frame;
|
||||
frame.set_type(nearby::sharing::service::proto::V1Frame::INTRODUCTION);
|
||||
|
||||
auto* intro = frame.mutable_introduction();
|
||||
|
||||
// Add file metadata
|
||||
for (const auto& file : attachments.GetFileAttachments()) {
|
||||
auto* file_meta = intro->add_file_metadata();
|
||||
file_meta->set_name(std::string(file.file_name()));
|
||||
file_meta->set_size(file.size());
|
||||
file_meta->set_mime_type(std::string(file.mime_type()));
|
||||
file_meta->set_type(file.type());
|
||||
}
|
||||
|
||||
// Add text metadata
|
||||
for (const auto& text : attachments.GetTextAttachments()) {
|
||||
auto* text_meta = intro->add_text_metadata();
|
||||
text_meta->set_text_title(std::string(text.text_title()));
|
||||
text_meta->set_size(text.size());
|
||||
text_meta->set_type(text.type());
|
||||
}
|
||||
|
||||
// Serialize and send
|
||||
std::string serialized;
|
||||
frame.SerializeToString(&serialized);
|
||||
|
||||
auto payload = std::make_unique<connections::Payload>(
|
||||
ByteArray(serialized));
|
||||
|
||||
std::vector<std::string> endpoints = {endpoint_id};
|
||||
core_->SendPayload(endpoints, std::move(*payload), [](auto status) {});
|
||||
}
|
||||
```
|
||||
|
||||
#### B. Add Certificate Stubs
|
||||
|
||||
```cpp
|
||||
// For basic interop without real security:
|
||||
|
||||
class SimpleCertificateManager : public NearbyShareCertificateManager {
|
||||
public:
|
||||
// Return a dummy certificate
|
||||
std::optional<NearbySharePrivateCertificate> GetPrivateCertificate() {
|
||||
// Create minimal valid certificate
|
||||
return CreateDummyCertificate();
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### C. Handle Paired Key Verification
|
||||
|
||||
```cpp
|
||||
void NearbySharingServiceLinux::HandleConnectionAccepted(...) {
|
||||
// Send connection response frame
|
||||
nearby::sharing::service::proto::V1Frame frame;
|
||||
frame.set_type(V1Frame::CONNECTION_RESPONSE);
|
||||
|
||||
auto* response = frame.mutable_connection_response();
|
||||
response->set_status(ConnectionResponseFrame::ACCEPT);
|
||||
|
||||
// Send frame...
|
||||
|
||||
// Then send introduction
|
||||
SendIntroductionFrame(endpoint_id, attachments);
|
||||
|
||||
// Wait for response before sending payloads
|
||||
}
|
||||
```
|
||||
|
||||
## Full Protocol Flow (What's Missing)
|
||||
|
||||
### Android/ChromeOS Protocol:
|
||||
|
||||
```
|
||||
Sender Receiver
|
||||
| |
|
||||
| 1. Request Connection |
|
||||
|------------------------------ >|
|
||||
| |
|
||||
| 2. Connection Initiated |
|
||||
|< -----------------------------|
|
||||
| |
|
||||
| 3. Accept Connection |
|
||||
|------------------------------ >|
|
||||
| |
|
||||
| 4. Send Introduction Frame | ← MISSING IN LINUX
|
||||
| (file metadata, etc) |
|
||||
|------------------------------ >|
|
||||
| |
|
||||
| | 5. Parse Introduction
|
||||
| | 6. Show UI to user
|
||||
| | 7. User accepts
|
||||
| |
|
||||
| 8. Send Connection Response | ← MISSING IN LINUX
|
||||
| (ACCEPT/REJECT) |
|
||||
|< -----------------------------|
|
||||
| |
|
||||
| 9. Paired Key Frame (optional) | ← MISSING IN LINUX
|
||||
|< -----------------------------|
|
||||
| |
|
||||
| 10. Send Payloads |
|
||||
|============================== >|
|
||||
| |
|
||||
```
|
||||
|
||||
### Linux Implementation (Current):
|
||||
|
||||
```
|
||||
Sender Receiver
|
||||
| |
|
||||
| 1. Request Connection |
|
||||
|------------------------------ >|
|
||||
| |
|
||||
| 2. Accept Connection |
|
||||
|< -----------------------------|
|
||||
| |
|
||||
| 3. Send Payloads (DIRECTLY) | ← Android rejects this
|
||||
|============================== >|
|
||||
| |
|
||||
```
|
||||
|
||||
## Recommended Solution
|
||||
|
||||
For **production use** with Android/ChromeOS devices:
|
||||
|
||||
1. **Use nearby_sharing_service_impl.h** - The full implementation
|
||||
2. **Implement platform layer** - Provide Linux implementations of:
|
||||
- PreferenceManager
|
||||
- Context
|
||||
- UI callbacks
|
||||
- Certificate storage
|
||||
|
||||
Example structure:
|
||||
```cpp
|
||||
// Create Linux platform implementation
|
||||
class LinuxNearbyShareContext : public Context { ... };
|
||||
class LinuxPreferenceManager : public PreferenceManager { ... };
|
||||
|
||||
// Use full service implementation
|
||||
auto service = NearbySharingServiceFactory::CreateNearbySharingService(
|
||||
preference_manager,
|
||||
notification_delegate,
|
||||
context,
|
||||
account_manager,
|
||||
device_info);
|
||||
```
|
||||
|
||||
For **testing/development** between Linux devices:
|
||||
|
||||
Continue using `nearby_sharing_service_linux` - it works fine for Linux-to-Linux transfers since both sides use the same simplified protocol.
|
||||
|
||||
## References
|
||||
|
||||
- Full implementation: `sharing/nearby_sharing_service_impl.{h,cc}`
|
||||
- Protocol definitions: `sharing/proto/wire_format.proto`
|
||||
- Certificate manager: `sharing/certificates/nearby_share_certificate_manager.h`
|
||||
- Incoming frames reader: `sharing/incoming_frames_reader.{h,cc}`
|
||||
- Outgoing frames writer: (implicitly in share sessions)
|
||||
|
||||
## Summary
|
||||
|
||||
| Feature | Linux Implementation | Full Implementation |
|
||||
|---------|---------------------|---------------------|
|
||||
| Discovery | ✅ Working | ✅ Working |
|
||||
| Advertising | ✅ Working | ✅ Working |
|
||||
| Connection | ✅ Basic | ✅ Full protocol |
|
||||
| Introduction frames | ❌ Missing | ✅ Implemented |
|
||||
| Certificates | ❌ Stub only | ✅ Full PKI |
|
||||
| Android compat | ❌ Auth fails | ✅ Full compat |
|
||||
| Linux-to-Linux | ✅ Working | ✅ Working |
|
||||
| File transfer | ✅ Basic | ✅ Full |
|
||||
| Progress tracking | ✅ Basic | ✅ Detailed |
|
||||
|
||||
The auth failure you're seeing is **expected behavior** - the Android side is correctly rejecting connections that don't follow the full Nearby Sharing protocol.
|
||||
+35
-100
@@ -19,12 +19,13 @@ load("@rules_cc//cc/private/rules_impl:cc_static_library.bzl", "cc_static_librar
|
||||
load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands")
|
||||
|
||||
refresh_compile_commands(
|
||||
name = "refresh_compile_commands_sharing",
|
||||
name = "refresh_compile_commands",
|
||||
|
||||
# Specify the targets of interest.
|
||||
# For example, specify a dict of targets and any flags required to build.
|
||||
targets = {
|
||||
":linux_fast_init": "",
|
||||
":fast_init": "",
|
||||
":nearby_connections_manager": "",
|
||||
},
|
||||
# No need to add flags already in .bazelrc. They're automatically picked up.
|
||||
# If you don't need flags, a list of targets is also okay, as is a single target string.
|
||||
@@ -35,7 +36,7 @@ refresh_compile_commands(
|
||||
|
||||
|
||||
cc_library(
|
||||
name = "linux_fast_init",
|
||||
name = "fast_init",
|
||||
hdrs = [
|
||||
"nearby_fast_init_ble_beacon.h",
|
||||
"nearby_fast_init_manager.h",
|
||||
@@ -50,29 +51,55 @@ cc_library(
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
cc_binary(
|
||||
name = "fast_init_test",
|
||||
srcs = ["nearby_fast_init.cc"],
|
||||
deps = [":linux_fast_init"]
|
||||
deps = [":fast_init"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "nearby_connections",
|
||||
srcs = [
|
||||
"nearby_connections.cc",
|
||||
],
|
||||
deps = [
|
||||
":nearby_connections_manager",
|
||||
":fast_init",
|
||||
"//connections:core",
|
||||
"//internal/platform/implementation/linux:linux"
|
||||
]
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "linux_sharing_platform",
|
||||
srcs = ["platform/linux_sharing_platform.cc"],
|
||||
srcs = [
|
||||
"platform/linux_account_manager.cc",
|
||||
"platform/linux_account_manager.h",
|
||||
"platform/linux_platform_components.cc",
|
||||
"platform/linux_platform_components.h",
|
||||
"platform/linux_preference_manager.cc",
|
||||
"platform/linux_preference_manager.h",
|
||||
"platform/linux_sharing_platform.cc",
|
||||
"platform/platform_util.cc",
|
||||
"platform/platform_util.h",
|
||||
],
|
||||
hdrs = ["platform/linux_sharing_platform.h"],
|
||||
visibility = ["//visibility:private"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":fast_init",
|
||||
"//internal/base:file_path",
|
||||
"//internal/base:files",
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:logging",
|
||||
"//internal/platform:mac_address",
|
||||
"//internal/platform:types",
|
||||
"//internal/platform:uuid",
|
||||
"//internal/platform/implementation:account_manager",
|
||||
"//internal/platform/implementation:platform",
|
||||
"//internal/platform/implementation:signin_attempt",
|
||||
"//internal/platform/implementation:types",
|
||||
"//internal/platform/implementation/linux",
|
||||
"//location/nearby/sharing/lib/account:account_manager",
|
||||
"//location/nearby/sharing/lib/sync:sync_binding_prefs_cc_proto",
|
||||
"//sharing/internal/api:platform",
|
||||
"//sharing/internal/public:pref_names",
|
||||
"//sharing/proto:share_cc_proto",
|
||||
@@ -86,95 +113,3 @@ cc_library(
|
||||
"@nlohmann_json//:json",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "nearby_sharing_api",
|
||||
srcs = ["nearby_sharing_api.cc"],
|
||||
hdrs = ["nearby_sharing_api.h"],
|
||||
alwayslink = True,
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":linux_sharing_platform",
|
||||
"//internal/base:file_path",
|
||||
"//internal/platform/implementation/linux:system_clock",
|
||||
"//sharing:attachments",
|
||||
"//sharing:nearby_sharing_service",
|
||||
"//sharing/analytics",
|
||||
"//sharing/local_device_data",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "nearby_connections_api",
|
||||
srcs = ["nearby_connections_api.cc"],
|
||||
hdrs = ["nearby_connections_api.h"],
|
||||
alwayslink = True,
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//internal/platform:base",
|
||||
":linux_sharing_platform",
|
||||
"//internal/base:file_path",
|
||||
"//sharing/internal/public:nearby_context",
|
||||
"//sharing:nearby_sharing_service",
|
||||
],
|
||||
)
|
||||
|
||||
cc_static_library(
|
||||
name = "nearby_sharing_api_static",
|
||||
deps = [":nearby_sharing_api"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "nearby_sharing_api_shared",
|
||||
linkshared = True,
|
||||
srcs = [
|
||||
"nearby_sharing_api.cc",
|
||||
"nearby_sharing_api.h",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
linkopts = [
|
||||
"-Wl,--exclude-libs,ALL",
|
||||
],
|
||||
deps = [
|
||||
"//internal/platform:base",
|
||||
":linux_sharing_platform",
|
||||
"//internal/base:file_path",
|
||||
"//internal/platform/implementation:platform",
|
||||
"//internal/platform/implementation/linux",
|
||||
"//internal/platform/implementation/linux:system_clock",
|
||||
"//sharing:attachments",
|
||||
"//sharing:nearby_sharing_service",
|
||||
"//sharing/analytics",
|
||||
"//sharing/local_device_data",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "nearby_connections_api_shared",
|
||||
linkshared = True,
|
||||
srcs = [
|
||||
"nearby_connections_api.cc",
|
||||
"nearby_connections_api.h",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
linkopts = [
|
||||
"-Wl,--exclude-libs,ALL",
|
||||
],
|
||||
deps = [
|
||||
":linux_sharing_platform",
|
||||
"//internal/base:file_path",
|
||||
"//internal/platform/implementation:platform",
|
||||
"//internal/platform/implementation/linux",
|
||||
"//sharing/internal/public:nearby_context",
|
||||
"//sharing:nearby_sharing_service",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "nearby_connections_api_test",
|
||||
srcs = ["nearby_connections_api_test.cc"],
|
||||
deps = [
|
||||
":nearby_connections_api",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,592 +0,0 @@
|
||||
# Nearby Sharing Service Linux - Architecture & Implementation Guide
|
||||
|
||||
## Table of Contents
|
||||
1. [Architecture Overview](#architecture-overview)
|
||||
2. [How It Works](#how-it-works)
|
||||
3. [Implementation Guide](#implementation-guide)
|
||||
4. [Code Examples](#code-examples)
|
||||
5. [Best Practices](#best-practices)
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Component Hierarchy
|
||||
|
||||
```
|
||||
NearbySharingServiceLinux
|
||||
├── Connections Core (nearby connections layer)
|
||||
│ ├── ServiceControllerRouter
|
||||
│ └── Medium Management (BLE, WiFi)
|
||||
├── Observers (UI/App notifications)
|
||||
├── Send Surfaces (outgoing transfers)
|
||||
│ ├── Transfer Callbacks
|
||||
│ └── Discovery Callbacks
|
||||
├── Receive Surfaces (incoming transfers)
|
||||
│ └── Transfer Callbacks
|
||||
└── Active Transfers
|
||||
├── Endpoint Mapping
|
||||
├── Transfer State
|
||||
└── Attachment Container
|
||||
```
|
||||
|
||||
### Key Classes
|
||||
|
||||
**NearbySharingServiceLinux**: Main service class
|
||||
- Manages discovery, advertising, and transfers
|
||||
- Built on top of Nearby Connections Core
|
||||
- Handles lifecycle of send/receive surfaces
|
||||
|
||||
**TransferUpdateCallback**: Interface for transfer notifications
|
||||
- Called on status changes (connecting, in-progress, complete)
|
||||
- Provides progress information
|
||||
- Reports errors and completion
|
||||
|
||||
**ShareTargetDiscoveredCallback**: Interface for discovery notifications
|
||||
- Called when devices are found
|
||||
- Called when devices are lost
|
||||
- Called when device info updates
|
||||
|
||||
**AttachmentContainer**: Container for files and text
|
||||
- Manages multiple attachments
|
||||
- Supports files, text, and WiFi credentials
|
||||
- Handles attachment lifecycle
|
||||
|
||||
## How It Works
|
||||
|
||||
### 1. Discovery & Advertising Flow
|
||||
|
||||
#### Sender (Discovers devices):
|
||||
```
|
||||
RegisterSendSurface (Foreground)
|
||||
↓
|
||||
StartDiscoveryIfNeeded()
|
||||
↓
|
||||
core_->StartDiscovery()
|
||||
↓
|
||||
[BLE Scanning Starts]
|
||||
↓
|
||||
endpoint_found_cb → ParseAdvertisement()
|
||||
↓
|
||||
ShareTarget created
|
||||
↓
|
||||
OnShareTargetDiscovered() callback
|
||||
```
|
||||
|
||||
#### Receiver (Advertises availability):
|
||||
```
|
||||
RegisterReceiveSurface (Foreground)
|
||||
↓
|
||||
StartAdvertisingIfNeeded()
|
||||
↓
|
||||
BuildAdvertisement()
|
||||
↓
|
||||
core_->StartAdvertising()
|
||||
↓
|
||||
[BLE Advertising Starts]
|
||||
↓
|
||||
[Visible to nearby senders]
|
||||
```
|
||||
|
||||
### 2. Connection Establishment
|
||||
|
||||
```
|
||||
Sender Receiver
|
||||
| |
|
||||
| RequestConnection() |
|
||||
|------------------------------->|
|
||||
| | connection_initiated_cb
|
||||
| | (auto or manual accept)
|
||||
| connection_initiated_cb |
|
||||
|<-------------------------------|
|
||||
| |
|
||||
| AcceptConnection() | AcceptConnection()
|
||||
|------------------------------->|
|
||||
|<-------------------------------|
|
||||
| |
|
||||
| connection_accepted_cb | connection_accepted_cb
|
||||
| |
|
||||
[Connected - Ready for transfer]
|
||||
```
|
||||
|
||||
### 3. File Transfer Flow
|
||||
|
||||
```
|
||||
Sender Receiver
|
||||
| |
|
||||
| SendAttachments() |
|
||||
| - Create AttachmentContainer |
|
||||
| - Add FileAttachment |
|
||||
| |
|
||||
| RequestConnection() |
|
||||
|------------------------------->|
|
||||
| Status: kAwaitingLocalConfirmation
|
||||
| |
|
||||
| | Accept()
|
||||
| |
|
||||
| AcceptConnection() | AcceptConnection()
|
||||
| + PayloadListener | + PayloadListener
|
||||
| |
|
||||
| Status: kConnecting |
|
||||
| |
|
||||
| Send Payloads |
|
||||
|=============================> |
|
||||
| (File data chunks) |
|
||||
| |
|
||||
| Status: kInProgress |
|
||||
| Progress: 0% → 100% |
|
||||
| |
|
||||
| payload_progress_cb | payload_progress_cb
|
||||
| |
|
||||
| Status: kComplete |
|
||||
| |
|
||||
```
|
||||
|
||||
### 4. Advertisement Format
|
||||
|
||||
The service creates custom BLE advertisements with device information:
|
||||
|
||||
```
|
||||
Byte Layout:
|
||||
[0] Header Byte
|
||||
- Bits 7-5: Version (3 bits)
|
||||
- Bit 4: Visibility (0=visible, 1=hidden)
|
||||
- Bits 3-1: Device Type (3 bits)
|
||||
- Bit 0: Reserved
|
||||
|
||||
[1-2] Salt (2 random bytes)
|
||||
|
||||
[3-16] Metadata Key (14 bytes - for encryption)
|
||||
|
||||
[17+] TLV Fields (Type-Length-Value)
|
||||
- Vendor ID (1 byte)
|
||||
- QR Code data (variable)
|
||||
- Other metadata
|
||||
|
||||
[N+] Device Name (optional, UTF-8)
|
||||
```
|
||||
|
||||
**Device Types:**
|
||||
- 0: Unknown
|
||||
- 1: Phone
|
||||
- 2: Tablet
|
||||
- 3: Laptop
|
||||
- 4: Unknown
|
||||
|
||||
### 5. State Management
|
||||
|
||||
```cpp
|
||||
struct TransferState {
|
||||
AttachmentContainer attachments; // Files/text being transferred
|
||||
TransferUpdateCallback* callback; // Where to send updates
|
||||
bool is_incoming; // Direction of transfer
|
||||
};
|
||||
|
||||
// Mappings
|
||||
endpoint_to_target_ // endpoint_id → ShareTarget
|
||||
target_id_to_endpoint_ // share_target_id → endpoint_id
|
||||
active_transfers_ // endpoint_id → TransferState
|
||||
```
|
||||
|
||||
## Implementation Guide
|
||||
|
||||
### Step 1: Create Service Instance
|
||||
|
||||
```cpp
|
||||
#include "sharing/linux/nearby_sharing_service_linux.h"
|
||||
|
||||
// Create service with custom device name
|
||||
NearbySharingServiceLinux service("MyLinuxDevice");
|
||||
|
||||
// Or let it auto-detect from system
|
||||
NearbySharingServiceLinux service;
|
||||
```
|
||||
|
||||
### Step 2: Implement Callbacks
|
||||
|
||||
```cpp
|
||||
class MyTransferCallback : public TransferUpdateCallback {
|
||||
public:
|
||||
void OnTransferUpdate(const ShareTarget& share_target,
|
||||
const AttachmentContainer& attachment_container,
|
||||
const TransferMetadata& transfer_metadata) override {
|
||||
// Handle transfer status changes
|
||||
switch (transfer_metadata.status()) {
|
||||
case TransferMetadata::Status::kAwaitingLocalConfirmation:
|
||||
// Incoming transfer - need to accept/reject
|
||||
HandleIncomingRequest(share_target);
|
||||
break;
|
||||
|
||||
case TransferMetadata::Status::kInProgress:
|
||||
// Show progress
|
||||
UpdateProgress(transfer_metadata.progress());
|
||||
break;
|
||||
|
||||
case TransferMetadata::Status::kComplete:
|
||||
// Transfer done - access attachments
|
||||
HandleCompletedTransfer(attachment_container);
|
||||
break;
|
||||
|
||||
case TransferMetadata::Status::kFailed:
|
||||
// Handle error
|
||||
HandleError();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MyDiscoveryCallback : public ShareTargetDiscoveredCallback {
|
||||
public:
|
||||
void OnShareTargetDiscovered(const ShareTarget& share_target) override {
|
||||
// New device found
|
||||
devices_.push_back(share_target);
|
||||
NotifyUI();
|
||||
}
|
||||
|
||||
void OnShareTargetLost(const ShareTarget& share_target) override {
|
||||
// Device went away
|
||||
RemoveDevice(share_target.id);
|
||||
}
|
||||
|
||||
void OnShareTargetUpdated(const ShareTarget& share_target) override {
|
||||
// Device info changed
|
||||
UpdateDevice(share_target);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Step 3: Register Surfaces
|
||||
|
||||
```cpp
|
||||
MyTransferCallback transfer_callback;
|
||||
MyDiscoveryCallback discovery_callback;
|
||||
|
||||
// To receive files
|
||||
service.RegisterReceiveSurface(
|
||||
&transfer_callback,
|
||||
NearbySharingService::ReceiveSurfaceState::kForeground,
|
||||
Advertisement::BlockedVendorId::kNone,
|
||||
[](auto status) {
|
||||
if (status == NearbySharingService::StatusCodes::kOk) {
|
||||
std::cout << "Now advertising to nearby devices" << std::endl;
|
||||
}
|
||||
});
|
||||
|
||||
// To send files
|
||||
service.RegisterSendSurface(
|
||||
&transfer_callback,
|
||||
&discovery_callback,
|
||||
NearbySharingService::SendSurfaceState::kForeground,
|
||||
Advertisement::BlockedVendorId::kNone,
|
||||
false, // don't disable wifi hotspot
|
||||
[](auto status) {
|
||||
if (status == NearbySharingService::StatusCodes::kOk) {
|
||||
std::cout << "Now scanning for nearby devices" << std::endl;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Step 4: Send Content
|
||||
|
||||
```cpp
|
||||
// Send a file
|
||||
void SendFile(int64_t target_id, const std::string& file_path) {
|
||||
auto container = std::make_unique<AttachmentContainer>();
|
||||
|
||||
FileAttachment attachment(FilePath(file_path));
|
||||
container->AddFileAttachment(std::move(attachment));
|
||||
|
||||
service.SendAttachments(target_id, std::move(container),
|
||||
[](auto status) {
|
||||
std::cout << "Send status: "
|
||||
<< NearbySharingService::StatusCodeToString(status)
|
||||
<< std::endl;
|
||||
});
|
||||
}
|
||||
|
||||
// Send text
|
||||
void SendText(int64_t target_id, const std::string& text) {
|
||||
auto container = std::make_unique<AttachmentContainer>();
|
||||
|
||||
TextAttachment attachment(
|
||||
TextAttachment::Type::TEXT,
|
||||
text,
|
||||
std::nullopt, // no title
|
||||
std::nullopt // no mime type
|
||||
);
|
||||
container->AddTextAttachment(std::move(attachment));
|
||||
|
||||
service.SendAttachments(target_id, std::move(container),
|
||||
[](auto status) { /* ... */ });
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Handle Incoming Transfers
|
||||
|
||||
```cpp
|
||||
void HandleIncomingRequest(const ShareTarget& target) {
|
||||
// Show confirmation dialog to user
|
||||
std::cout << "Accept file from " << target.device_name << "? (y/n): ";
|
||||
char choice;
|
||||
std::cin >> choice;
|
||||
|
||||
if (choice == 'y') {
|
||||
service.Accept(target.id, [](auto status) {
|
||||
std::cout << "Accepted!" << std::endl;
|
||||
});
|
||||
} else {
|
||||
service.Reject(target.id, [](auto status) {
|
||||
std::cout << "Rejected!" << std::endl;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void HandleCompletedTransfer(const AttachmentContainer& container) {
|
||||
// Process received files
|
||||
for (const auto& file : container.GetFileAttachments()) {
|
||||
std::cout << "Received: " << file.file_name() << std::endl;
|
||||
if (file.file_path().has_value()) {
|
||||
std::cout << "Saved to: " << file.file_path()->string() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Process received text
|
||||
for (const auto& text : container.GetTextAttachments()) {
|
||||
std::cout << "Received text: " << text.text_body() << std::endl;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Code Examples
|
||||
|
||||
### Example 1: Simple File Sender
|
||||
|
||||
```cpp
|
||||
#include "sharing/linux/nearby_sharing_service_linux.h"
|
||||
#include "sharing/file_attachment.h"
|
||||
#include <thread>
|
||||
|
||||
int main() {
|
||||
NearbySharingServiceLinux service("FileSender");
|
||||
|
||||
// Setup callbacks
|
||||
class SimpleCallback : public TransferUpdateCallback {
|
||||
void OnTransferUpdate(...) override {
|
||||
std::cout << "Progress: " << transfer_metadata.progress() * 100 << "%" << std::endl;
|
||||
}
|
||||
} transfer_cb;
|
||||
|
||||
class SimpleDiscovery : public ShareTargetDiscoveredCallback {
|
||||
int64_t target_id = -1;
|
||||
void OnShareTargetDiscovered(const ShareTarget& t) override {
|
||||
target_id = t.id;
|
||||
std::cout << "Found: " << t.device_name << std::endl;
|
||||
}
|
||||
void OnShareTargetLost(...) override {}
|
||||
void OnShareTargetUpdated(...) override {}
|
||||
} discovery_cb;
|
||||
|
||||
// Start scanning
|
||||
service.RegisterSendSurface(&transfer_cb, &discovery_cb,
|
||||
NearbySharingService::SendSurfaceState::kForeground,
|
||||
Advertisement::BlockedVendorId::kNone, false, [](auto) {});
|
||||
|
||||
// Wait for discovery
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
|
||||
if (discovery_cb.target_id != -1) {
|
||||
// Send file
|
||||
auto container = std::make_unique<AttachmentContainer>();
|
||||
container->AddFileAttachment(FileAttachment(FilePath("/path/to/file.txt")));
|
||||
service.SendAttachments(discovery_cb.target_id, std::move(container), [](auto) {});
|
||||
|
||||
// Wait for completion
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Auto-Accepting Receiver
|
||||
|
||||
```cpp
|
||||
class AutoAcceptCallback : public TransferUpdateCallback {
|
||||
public:
|
||||
AutoAcceptCallback(NearbySharingServiceLinux* service) : service_(service) {}
|
||||
|
||||
void OnTransferUpdate(const ShareTarget& share_target,
|
||||
const AttachmentContainer& attachment_container,
|
||||
const TransferMetadata& transfer_metadata) override {
|
||||
// Auto-accept all incoming transfers
|
||||
if (transfer_metadata.status() == TransferMetadata::Status::kAwaitingLocalConfirmation) {
|
||||
service_->Accept(share_target.id, [](auto) {});
|
||||
}
|
||||
|
||||
// Save received files
|
||||
if (transfer_metadata.status() == TransferMetadata::Status::kComplete) {
|
||||
for (const auto& file : attachment_container.GetFileAttachments()) {
|
||||
std::cout << "Saved: " << file.file_name() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
NearbySharingServiceLinux* service_;
|
||||
};
|
||||
|
||||
int main() {
|
||||
NearbySharingServiceLinux service("AutoReceiver");
|
||||
AutoAcceptCallback callback(&service);
|
||||
|
||||
service.RegisterReceiveSurface(&callback,
|
||||
NearbySharingService::ReceiveSurfaceState::kForeground,
|
||||
Advertisement::BlockedVendorId::kNone, [](auto) {});
|
||||
|
||||
// Keep running
|
||||
while (true) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Callback Lifetime Management
|
||||
|
||||
```cpp
|
||||
// DON'T: Callbacks going out of scope
|
||||
void BadExample() {
|
||||
MyTransferCallback callback; // Stack allocated
|
||||
service.RegisterSendSurface(&callback, ...);
|
||||
// callback destroyed when function exits!
|
||||
}
|
||||
|
||||
// DO: Keep callbacks alive
|
||||
class App {
|
||||
MyTransferCallback callback_; // Member variable
|
||||
|
||||
void Setup() {
|
||||
service.RegisterSendSurface(&callback_, ...);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Error Handling
|
||||
|
||||
```cpp
|
||||
service.SendAttachments(target_id, container,
|
||||
[this](NearbySharingService::StatusCodes status) {
|
||||
switch (status) {
|
||||
case StatusCodes::kOk:
|
||||
// Success
|
||||
break;
|
||||
case StatusCodes::kInvalidArgument:
|
||||
// Bad target_id or empty container
|
||||
LogError("Invalid arguments");
|
||||
break;
|
||||
case StatusCodes::kNoAvailableConnectionMedium:
|
||||
// Bluetooth/WiFi not available
|
||||
NotifyUserToEnableBluetooth();
|
||||
break;
|
||||
default:
|
||||
LogError("Transfer failed");
|
||||
break;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Resource Cleanup
|
||||
|
||||
```cpp
|
||||
class ProperCleanup {
|
||||
public:
|
||||
~ProperCleanup() {
|
||||
// Unregister surfaces before destroying callbacks
|
||||
service_.UnregisterSendSurface(&transfer_callback_, [](auto) {});
|
||||
service_.UnregisterReceiveSurface(&transfer_callback_, [](auto) {});
|
||||
|
||||
// Shutdown service
|
||||
service_.Shutdown([](auto) {});
|
||||
}
|
||||
|
||||
private:
|
||||
NearbySharingServiceLinux service_;
|
||||
MyTransferCallback transfer_callback_;
|
||||
};
|
||||
```
|
||||
|
||||
### 4. Thread Safety
|
||||
|
||||
```cpp
|
||||
// The service is NOT thread-safe
|
||||
// All calls should be from the same thread or synchronized
|
||||
|
||||
class ThreadSafeApp {
|
||||
public:
|
||||
void SendFromAnyThread(int64_t target_id, const std::string& file) {
|
||||
task_runner_.PostTask([this, target_id, file]() {
|
||||
// All service calls happen on same thread
|
||||
auto container = std::make_unique<AttachmentContainer>();
|
||||
container->AddFileAttachment(FileAttachment(FilePath(file)));
|
||||
service_.SendAttachments(target_id, std::move(container), [](auto) {});
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
NearbySharingServiceLinux service_;
|
||||
TaskRunner task_runner_; // Your threading implementation
|
||||
};
|
||||
```
|
||||
|
||||
### 5. State Tracking
|
||||
|
||||
```cpp
|
||||
class StatefulApp {
|
||||
public:
|
||||
void OnTransferUpdate(...) override {
|
||||
current_state_ = transfer_metadata.status();
|
||||
|
||||
// Track progress
|
||||
if (transfer_metadata.status() == Status::kInProgress) {
|
||||
progress_map_[share_target.id] = transfer_metadata.progress();
|
||||
}
|
||||
|
||||
// Cleanup on completion
|
||||
if (TransferMetadata::IsFinalStatus(transfer_metadata.status())) {
|
||||
progress_map_.erase(share_target.id);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
TransferMetadata::Status current_state_;
|
||||
std::unordered_map<int64_t, float> progress_map_;
|
||||
};
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Discovery Not Working
|
||||
- Check Bluetooth is enabled: `IsBluetoothPowered()`
|
||||
- Verify sender is in foreground state
|
||||
- Ensure receiver is advertising
|
||||
- Check for permission issues
|
||||
|
||||
### Transfers Failing
|
||||
- Verify file paths are valid and accessible
|
||||
- Check available disk space on receiver
|
||||
- Ensure stable Bluetooth connection
|
||||
- Monitor transfer callbacks for specific error status
|
||||
|
||||
### Connection Issues
|
||||
- Devices must be within Bluetooth range (~10m)
|
||||
- Minimize interference from other BLE devices
|
||||
- Ensure both devices support required BLE features
|
||||
- Check firewall settings for WiFi Direct
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Use appropriate surface states**: Background mode when not actively transferring
|
||||
2. **Unregister when not needed**: Stop scanning/advertising to save battery
|
||||
3. **Batch small files**: Combine into zip for better efficiency
|
||||
4. **Monitor transfer progress**: Cancel stalled transfers
|
||||
5. **Handle errors gracefully**: Retry with exponential backoff
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
# Nearby Sharing Linux - Quick Reference
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Build
|
||||
```bash
|
||||
bazel build //sharing/linux:simple_example
|
||||
bazel build //sharing/linux:nearby_sharing_app
|
||||
```
|
||||
|
||||
### Run Simple Example
|
||||
```bash
|
||||
# Terminal 1 (Receiver)
|
||||
./bazel-bin/sharing/linux/simple_example receiver
|
||||
|
||||
# Terminal 2 (Sender)
|
||||
./bazel-bin/sharing/linux/simple_example sender "Hello World!"
|
||||
```
|
||||
|
||||
### Run Full App
|
||||
```bash
|
||||
./bazel-bin/sharing/linux/nearby_sharing_app [device_name]
|
||||
```
|
||||
|
||||
## API Cheat Sheet
|
||||
|
||||
### Include Headers
|
||||
```cpp
|
||||
#include "sharing/linux/nearby_sharing_service_linux.h"
|
||||
#include "sharing/attachment_container.h"
|
||||
#include "sharing/file_attachment.h"
|
||||
#include "sharing/text_attachment.h"
|
||||
#include "sharing/share_target.h"
|
||||
#include "sharing/transfer_metadata.h"
|
||||
```
|
||||
|
||||
### Create Service
|
||||
```cpp
|
||||
using namespace nearby::sharing::linux;
|
||||
NearbySharingServiceLinux service("DeviceName");
|
||||
```
|
||||
|
||||
### Implement Callbacks
|
||||
```cpp
|
||||
// Transfer updates
|
||||
class MyCallback : public TransferUpdateCallback {
|
||||
void OnTransferUpdate(const ShareTarget& target,
|
||||
const AttachmentContainer& attachments,
|
||||
const TransferMetadata& metadata) override {
|
||||
// Handle status changes
|
||||
}
|
||||
};
|
||||
|
||||
// Device discovery
|
||||
class MyDiscovery : public ShareTargetDiscoveredCallback {
|
||||
void OnShareTargetDiscovered(const ShareTarget& target) override { }
|
||||
void OnShareTargetLost(const ShareTarget& target) override { }
|
||||
void OnShareTargetUpdated(const ShareTarget& target) override { }
|
||||
};
|
||||
```
|
||||
|
||||
### Register to Receive
|
||||
```cpp
|
||||
service.RegisterReceiveSurface(
|
||||
&transfer_callback,
|
||||
NearbySharingService::ReceiveSurfaceState::kForeground,
|
||||
Advertisement::BlockedVendorId::kNone,
|
||||
[](auto status) { /* callback */ });
|
||||
```
|
||||
|
||||
### Register to Send
|
||||
```cpp
|
||||
service.RegisterSendSurface(
|
||||
&transfer_callback,
|
||||
&discovery_callback,
|
||||
NearbySharingService::SendSurfaceState::kForeground,
|
||||
Advertisement::BlockedVendorId::kNone,
|
||||
false, // disable_wifi_hotspot
|
||||
[](auto status) { /* callback */ });
|
||||
```
|
||||
|
||||
### Send File
|
||||
```cpp
|
||||
auto container = std::make_unique<AttachmentContainer>();
|
||||
container->AddFileAttachment(FileAttachment(FilePath("/path/to/file")));
|
||||
service.SendAttachments(target_id, std::move(container), [](auto) {});
|
||||
```
|
||||
|
||||
### Send Text
|
||||
```cpp
|
||||
auto container = std::make_unique<AttachmentContainer>();
|
||||
container->AddTextAttachment(TextAttachment(
|
||||
TextAttachment::Type::TEXT, "message", std::nullopt, std::nullopt));
|
||||
service.SendAttachments(target_id, std::move(container), [](auto) {});
|
||||
```
|
||||
|
||||
### Accept/Reject/Cancel
|
||||
```cpp
|
||||
service.Accept(target_id, [](auto status) {});
|
||||
service.Reject(target_id, [](auto status) {});
|
||||
service.Cancel(target_id, [](auto status) {});
|
||||
```
|
||||
|
||||
### Check Status
|
||||
```cpp
|
||||
bool scanning = service.IsScanning();
|
||||
bool transferring = service.IsTransferring();
|
||||
bool bt_present = service.IsBluetoothPresent();
|
||||
bool bt_powered = service.IsBluetoothPowered();
|
||||
```
|
||||
|
||||
### Shutdown
|
||||
```cpp
|
||||
service.Shutdown([](auto status) {});
|
||||
```
|
||||
|
||||
## Transfer Statuses
|
||||
|
||||
| Status | Meaning | Action |
|
||||
|--------|---------|--------|
|
||||
| `kConnecting` | Establishing connection | Wait |
|
||||
| `kAwaitingLocalConfirmation` | Need to accept/reject | Call Accept() or Reject() |
|
||||
| `kAwaitingRemoteAcceptance` | Waiting for remote | Wait |
|
||||
| `kInProgress` | Transferring data | Show progress |
|
||||
| `kComplete` | Success | Access attachments |
|
||||
| `kFailed` | Error occurred | Check logs |
|
||||
| `kRejected` | User rejected | Retry or cancel |
|
||||
| `kCancelled` | Transfer cancelled | Cleanup |
|
||||
| `kTimedOut` | Connection timeout | Retry |
|
||||
|
||||
## Status Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| `kOk` | Success |
|
||||
| `kError` | General error |
|
||||
| `kOutOfOrderApiCall` | API called incorrectly |
|
||||
| `kTransferAlreadyInProgress` | Can't start new transfer |
|
||||
| `kNoAvailableConnectionMedium` | No Bluetooth/WiFi |
|
||||
| `kInvalidArgument` | Bad parameters |
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Auto-Accept Pattern
|
||||
```cpp
|
||||
class AutoAccept : public TransferUpdateCallback {
|
||||
void OnTransferUpdate(...) override {
|
||||
if (metadata.status() == Status::kAwaitingLocalConfirmation) {
|
||||
service_->Accept(target.id, [](auto) {});
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Progress Tracking Pattern
|
||||
```cpp
|
||||
void OnTransferUpdate(...) override {
|
||||
if (metadata.status() == Status::kInProgress) {
|
||||
int percent = metadata.progress() * 100;
|
||||
uint64_t bytes = metadata.transferred_bytes();
|
||||
std::cout << percent << "% (" << bytes << " bytes)" << std::endl;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Device Selection Pattern
|
||||
```cpp
|
||||
std::vector<ShareTarget> devices;
|
||||
|
||||
void OnShareTargetDiscovered(const ShareTarget& target) override {
|
||||
devices.push_back(target);
|
||||
std::cout << devices.size() << ". " << target.device_name << std::endl;
|
||||
}
|
||||
|
||||
void SendToDevice(size_t index) {
|
||||
if (index < devices.size()) {
|
||||
SendFile(devices[index].id, file_path);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling Pattern
|
||||
```cpp
|
||||
service.SendAttachments(target_id, container,
|
||||
[](NearbySharingService::StatusCodes status) {
|
||||
if (status != StatusCodes::kOk) {
|
||||
std::cerr << "Error: "
|
||||
<< NearbySharingService::StatusCodeToString(status)
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
std::cout << "Transfer initiated" << std::endl;
|
||||
});
|
||||
```
|
||||
|
||||
## Debugging Tips
|
||||
|
||||
### Enable Verbose Logging
|
||||
```cpp
|
||||
// Set environment variable
|
||||
export NEARBY_LOGS=VERBOSE
|
||||
```
|
||||
|
||||
### Check Bluetooth
|
||||
```cpp
|
||||
if (!service.IsBluetoothPresent()) {
|
||||
std::cout << "No Bluetooth adapter found" << std::endl;
|
||||
}
|
||||
if (!service.IsBluetoothPowered()) {
|
||||
std::cout << "Bluetooth is off" << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
### Dump Service State
|
||||
```cpp
|
||||
std::cout << service.Dump() << std::endl;
|
||||
// Output: "NearbySharingServiceLinux advertising=true scanning=false ..."
|
||||
```
|
||||
|
||||
### Monitor Callbacks
|
||||
```cpp
|
||||
void OnTransferUpdate(...) override {
|
||||
std::cout << "[Transfer] " << target.device_name
|
||||
<< " - " << TransferMetadata::StatusToString(metadata.status())
|
||||
<< " - " << (metadata.progress() * 100) << "%" << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
## File Locations
|
||||
|
||||
- **Service**: `sharing/linux/nearby_sharing_service_linux.{h,cc}`
|
||||
- **Simple Example**: `sharing/linux/simple_example.cc`
|
||||
- **Full App**: `sharing/linux/nearby_sharing_app.cc`
|
||||
- **README**: `sharing/linux/README.md`
|
||||
- **Implementation Guide**: `sharing/linux/IMPLEMENTATION_GUIDE.md`
|
||||
- **BUILD**: `sharing/linux/BUILD`
|
||||
|
||||
## Common Issues
|
||||
|
||||
### "No devices found"
|
||||
- Ensure receiver is running and advertising
|
||||
- Check Bluetooth is enabled on both devices
|
||||
- Verify devices are within range (~10m)
|
||||
- Try restarting Bluetooth
|
||||
|
||||
### "Transfer failed"
|
||||
- Check file permissions
|
||||
- Verify disk space
|
||||
- Ensure stable connection
|
||||
- Check firewall settings
|
||||
|
||||
### "Invalid argument"
|
||||
- Verify target_id is valid
|
||||
- Ensure container has attachments
|
||||
- Check surface is registered
|
||||
|
||||
### Callback not called
|
||||
- Verify callback lifetime (must outlive service)
|
||||
- Check registration was successful
|
||||
- Ensure main thread/event loop is running
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Send File Workflow
|
||||
```
|
||||
1. Create service
|
||||
2. Create callbacks
|
||||
3. RegisterSendSurface (foreground)
|
||||
4. Wait for OnShareTargetDiscovered
|
||||
5. Create AttachmentContainer
|
||||
6. Add FileAttachment
|
||||
7. SendAttachments(target_id, container)
|
||||
8. Wait for kComplete in OnTransferUpdate
|
||||
```
|
||||
|
||||
### Receive File Workflow
|
||||
```
|
||||
1. Create service
|
||||
2. Create callback
|
||||
3. RegisterReceiveSurface (foreground)
|
||||
4. Wait for kAwaitingLocalConfirmation
|
||||
5. Call Accept(target_id)
|
||||
6. Wait for kInProgress updates
|
||||
7. Wait for kComplete
|
||||
8. Access files from AttachmentContainer
|
||||
```
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- **Scanning**: Consumes battery, stop when not needed
|
||||
- **Advertising**: Minimal impact
|
||||
- **Transfer**: WiFi Direct faster than Bluetooth
|
||||
- **File Size**: Large files (>100MB) benefit from WiFi
|
||||
- **Small Files**: Bluetooth sufficient for <10MB
|
||||
|
||||
## Links
|
||||
|
||||
- [README.md](README.md) - Overview and features
|
||||
- [IMPLEMENTATION_GUIDE.md](IMPLEMENTATION_GUIDE.md) - Detailed architecture
|
||||
- [nearby_sharing_service.h](../nearby_sharing_service.h) - Base interface
|
||||
@@ -1,104 +0,0 @@
|
||||
# Nearby Sharing for Linux
|
||||
|
||||
This directory contains:
|
||||
- A Linux-facing Nearby Sharing library (`NearbySharingApi`)
|
||||
- A sample CLI app (`nearby_sharing_app`)
|
||||
- A Qt/QML tray sample app (`qml_tray_app`)
|
||||
|
||||
## Scope and Intended Use
|
||||
|
||||
This project is primarily intended to be used as a reusable library/API.
|
||||
|
||||
The sample applications are still supported and will continue to be supported because they are used in real day-to-day device sharing workflows.
|
||||
|
||||
## Current Status
|
||||
|
||||
The current implementation works with the reverse-engineered certificate manager currently used in this project.
|
||||
|
||||
Compatibility can still break if Google changes certificate manager behavior/protocol details. That component is closed source, so upstream changes can be difficult to inspect and adapt to quickly.
|
||||
|
||||
## Test Coverage and Session Notes
|
||||
|
||||
- Verified: single-file sharing flow.
|
||||
- Not fully verified: multiple transfers in one app lifetime.
|
||||
- Current practical testing pattern: restart the application before each new transfer.
|
||||
|
||||
For this README, a "session" means one process lifetime (app start to app exit).
|
||||
|
||||
After one transfer, some endpoints may close and internal state can reset/change. Multi-transfer handling in one live session is still under investigation.
|
||||
|
||||
## Known Issues
|
||||
|
||||
- Linux hotspot startup can be slow.
|
||||
- Connecting to a hotspot started on another device can be slow on Linux.
|
||||
- Android-initiated connection formation can be very slow.
|
||||
|
||||
The Android/Linux connection latency issue still needs deeper investigation. One possible cause is connection/negotiation behavior that Linux does not currently handle well.
|
||||
|
||||
## Wi-Fi Direct Status
|
||||
|
||||
Wi-Fi Direct is theoretically possible but not implemented yet.
|
||||
|
||||
Reason: NetworkManager does not natively support creating Wi-Fi Direct Group Owners in the way this project needs.
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. Install the shared library
|
||||
|
||||
From the repository root:
|
||||
|
||||
```bash
|
||||
./sharing/linux/install_nearby_sharing_service.sh
|
||||
```
|
||||
|
||||
This installs:
|
||||
- `libnearby_sharing_api_shared.so`
|
||||
- `sharing/linux/nearby_sharing_api.h`
|
||||
|
||||
### 2. Build and run the CLI sample app (optional)
|
||||
|
||||
From the repository root:
|
||||
|
||||
```bash
|
||||
bazel build //sharing/linux:nearby_sharing_app
|
||||
./bazel-bin/sharing/linux/nearby_sharing_app
|
||||
# Optional custom device name
|
||||
./bazel-bin/sharing/linux/nearby_sharing_app "MyDeviceName"
|
||||
```
|
||||
|
||||
### 3. Build and run the tray sample app (optional)
|
||||
|
||||
From `sharing/linux/qml_tray_app`:
|
||||
|
||||
```bash
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DNEARBY_PREFIX=/usr/local
|
||||
cmake --build build -j
|
||||
./build/nearby_qml_file_tray_app
|
||||
```
|
||||
|
||||
### 4. Install launcher entry (`.desktop`) for the tray app
|
||||
|
||||
From `sharing/linux/qml_tray_app`:
|
||||
|
||||
```bash
|
||||
mkdir -p "$HOME/.local/share/applications"
|
||||
install -m 0644 nearby-file-share.desktop "$HOME/.local/share/applications/nearby-file-share.desktop"
|
||||
sed -i "s|^Exec=.*|Exec=$(pwd)/build/nearby_qml_file_tray_app|" "$HOME/.local/share/applications/nearby-file-share.desktop"
|
||||
sed -i "s|^Icon=.*|Icon=$(pwd)/nearby-linux-desktop.png|" "$HOME/.local/share/applications/nearby-file-share.desktop"
|
||||
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
|
||||
```
|
||||
|
||||
After this, search for `Nearby File Share` in your desktop launcher.
|
||||
|
||||
## Documentation
|
||||
|
||||
Technical deep dives are being moved from README content to the wiki.
|
||||
|
||||
- Wiki: https://github.com/kidfromjupiter/nearby/wiki
|
||||
|
||||
This README stays focused on status, installation, and known limitations.
|
||||
|
||||
## Demo Assets (Planned)
|
||||
|
||||
- Video demo of end-to-end sharing flow.
|
||||
- GIF showing the sharing process.
|
||||
@@ -1,89 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#include "sharing/linux/nearby_connections_adapter.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace nearby::sharing::linux {
|
||||
|
||||
CoreNearbyConnectionsAdapter::CoreNearbyConnectionsAdapter()
|
||||
: router_(std::make_unique<connections::ServiceControllerRouter>()),
|
||||
core_(std::make_unique<connections::Core>(router_.get())) {}
|
||||
|
||||
CoreNearbyConnectionsAdapter::~CoreNearbyConnectionsAdapter() = default;
|
||||
|
||||
void CoreNearbyConnectionsAdapter::StartAdvertising(
|
||||
absl::string_view service_id,
|
||||
connections::AdvertisingOptions advertising_options,
|
||||
connections::ConnectionRequestInfo request_info,
|
||||
std::function<void(connections::Status)> callback) {
|
||||
core_->StartAdvertising(service_id, std::move(advertising_options),
|
||||
std::move(request_info), std::move(callback));
|
||||
}
|
||||
|
||||
void CoreNearbyConnectionsAdapter::StopAdvertising(
|
||||
std::function<void(connections::Status)> callback) {
|
||||
core_->StopAdvertising(std::move(callback));
|
||||
}
|
||||
|
||||
void CoreNearbyConnectionsAdapter::StartDiscovery(
|
||||
absl::string_view service_id,
|
||||
connections::DiscoveryOptions discovery_options,
|
||||
connections::DiscoveryListener discovery_listener,
|
||||
std::function<void(connections::Status)> callback) {
|
||||
core_->StartDiscovery(service_id, std::move(discovery_options),
|
||||
std::move(discovery_listener), std::move(callback));
|
||||
}
|
||||
|
||||
void CoreNearbyConnectionsAdapter::StopDiscovery(
|
||||
std::function<void(connections::Status)> callback) {
|
||||
core_->StopDiscovery(std::move(callback));
|
||||
}
|
||||
|
||||
void CoreNearbyConnectionsAdapter::RequestConnection(
|
||||
absl::string_view endpoint_id,
|
||||
connections::ConnectionRequestInfo request_info,
|
||||
connections::ConnectionOptions connection_options,
|
||||
std::function<void(connections::Status)> callback) {
|
||||
core_->RequestConnection(endpoint_id, std::move(request_info),
|
||||
std::move(connection_options), std::move(callback));
|
||||
}
|
||||
|
||||
void CoreNearbyConnectionsAdapter::AcceptConnection(
|
||||
absl::string_view endpoint_id, connections::PayloadListener listener,
|
||||
std::function<void(connections::Status)> callback) {
|
||||
core_->AcceptConnection(endpoint_id, std::move(listener), std::move(callback));
|
||||
}
|
||||
|
||||
void CoreNearbyConnectionsAdapter::RejectConnection(
|
||||
absl::string_view endpoint_id,
|
||||
std::function<void(connections::Status)> callback) {
|
||||
core_->RejectConnection(endpoint_id, std::move(callback));
|
||||
}
|
||||
|
||||
void CoreNearbyConnectionsAdapter::SendPayload(
|
||||
absl::Span<const std::string> endpoint_ids, connections::Payload payload,
|
||||
std::function<void(connections::Status)> callback) {
|
||||
core_->SendPayload(endpoint_ids, std::move(payload), std::move(callback));
|
||||
}
|
||||
|
||||
void CoreNearbyConnectionsAdapter::DisconnectFromEndpoint(
|
||||
absl::string_view endpoint_id,
|
||||
std::function<void(connections::Status)> callback) {
|
||||
core_->DisconnectFromEndpoint(endpoint_id, std::move(callback));
|
||||
}
|
||||
|
||||
} // namespace nearby::sharing::linux
|
||||
@@ -1,116 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef THIRD_PARTY_NEARBY_SHARING_LINUX_NEARBY_CONNECTIONS_ADAPTER_H_
|
||||
#define THIRD_PARTY_NEARBY_SHARING_LINUX_NEARBY_CONNECTIONS_ADAPTER_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/span.h"
|
||||
#include "connections/advertising_options.h"
|
||||
#include "connections/connection_options.h"
|
||||
#include "connections/core.h"
|
||||
#include "connections/discovery_options.h"
|
||||
#include "connections/implementation/service_controller_router.h"
|
||||
#include "connections/listeners.h"
|
||||
#include "connections/payload.h"
|
||||
#include "connections/status.h"
|
||||
|
||||
namespace nearby::sharing::linux {
|
||||
|
||||
class NearbyConnectionsAdapter {
|
||||
public:
|
||||
virtual ~NearbyConnectionsAdapter() = default;
|
||||
|
||||
virtual void StartAdvertising(
|
||||
absl::string_view service_id,
|
||||
connections::AdvertisingOptions advertising_options,
|
||||
connections::ConnectionRequestInfo request_info,
|
||||
std::function<void(connections::Status)> callback) = 0;
|
||||
virtual void StopAdvertising(
|
||||
std::function<void(connections::Status)> callback) = 0;
|
||||
virtual void StartDiscovery(
|
||||
absl::string_view service_id,
|
||||
connections::DiscoveryOptions discovery_options,
|
||||
connections::DiscoveryListener discovery_listener,
|
||||
std::function<void(connections::Status)> callback) = 0;
|
||||
virtual void StopDiscovery(
|
||||
std::function<void(connections::Status)> callback) = 0;
|
||||
virtual void RequestConnection(
|
||||
absl::string_view endpoint_id,
|
||||
connections::ConnectionRequestInfo request_info,
|
||||
connections::ConnectionOptions connection_options,
|
||||
std::function<void(connections::Status)> callback) = 0;
|
||||
virtual void AcceptConnection(
|
||||
absl::string_view endpoint_id, connections::PayloadListener listener,
|
||||
std::function<void(connections::Status)> callback) = 0;
|
||||
virtual void RejectConnection(
|
||||
absl::string_view endpoint_id,
|
||||
std::function<void(connections::Status)> callback) = 0;
|
||||
virtual void SendPayload(
|
||||
absl::Span<const std::string> endpoint_ids, connections::Payload payload,
|
||||
std::function<void(connections::Status)> callback) = 0;
|
||||
virtual void DisconnectFromEndpoint(
|
||||
absl::string_view endpoint_id,
|
||||
std::function<void(connections::Status)> callback) = 0;
|
||||
};
|
||||
|
||||
class CoreNearbyConnectionsAdapter : public NearbyConnectionsAdapter {
|
||||
public:
|
||||
CoreNearbyConnectionsAdapter();
|
||||
~CoreNearbyConnectionsAdapter() override;
|
||||
|
||||
void StartAdvertising(
|
||||
absl::string_view service_id,
|
||||
connections::AdvertisingOptions advertising_options,
|
||||
connections::ConnectionRequestInfo request_info,
|
||||
std::function<void(connections::Status)> callback) override;
|
||||
void StopAdvertising(
|
||||
std::function<void(connections::Status)> callback) override;
|
||||
void StartDiscovery(
|
||||
absl::string_view service_id,
|
||||
connections::DiscoveryOptions discovery_options,
|
||||
connections::DiscoveryListener discovery_listener,
|
||||
std::function<void(connections::Status)> callback) override;
|
||||
void StopDiscovery(
|
||||
std::function<void(connections::Status)> callback) override;
|
||||
void RequestConnection(
|
||||
absl::string_view endpoint_id,
|
||||
connections::ConnectionRequestInfo request_info,
|
||||
connections::ConnectionOptions connection_options,
|
||||
std::function<void(connections::Status)> callback) override;
|
||||
void AcceptConnection(
|
||||
absl::string_view endpoint_id, connections::PayloadListener listener,
|
||||
std::function<void(connections::Status)> callback) override;
|
||||
void RejectConnection(
|
||||
absl::string_view endpoint_id,
|
||||
std::function<void(connections::Status)> callback) override;
|
||||
void SendPayload(
|
||||
absl::Span<const std::string> endpoint_ids, connections::Payload payload,
|
||||
std::function<void(connections::Status)> callback) override;
|
||||
void DisconnectFromEndpoint(
|
||||
absl::string_view endpoint_id,
|
||||
std::function<void(connections::Status)> callback) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<connections::ServiceControllerRouter> router_;
|
||||
std::unique_ptr<connections::Core> core_;
|
||||
};
|
||||
|
||||
} // namespace nearby::sharing::linux
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_SHARING_LINUX_NEARBY_CONNECTIONS_ADAPTER_H_
|
||||
@@ -1,659 +0,0 @@
|
||||
#include "sharing/linux/nearby_connections_api.h"
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/base/file_path.h"
|
||||
#include "internal/interop/authentication_status.h"
|
||||
#include "sharing/internal/public/context_impl.h"
|
||||
#include "sharing/linux/platform/linux_sharing_platform.h"
|
||||
#include "sharing/nearby_connections_service.h"
|
||||
#include "sharing/nearby_connections_service_impl.h"
|
||||
|
||||
namespace nearby::sharing {
|
||||
|
||||
namespace {
|
||||
|
||||
using NativeService = nearby::sharing::NearbyConnectionsService;
|
||||
|
||||
NearbyConnectionsApi::StatusCode ToFacadeStatus(Status status) {
|
||||
switch (status) {
|
||||
case Status::kSuccess:
|
||||
return NearbyConnectionsApi::StatusCode::kSuccess;
|
||||
case Status::kError:
|
||||
return NearbyConnectionsApi::StatusCode::kError;
|
||||
case Status::kOutOfOrderApiCall:
|
||||
return NearbyConnectionsApi::StatusCode::kOutOfOrderApiCall;
|
||||
case Status::kAlreadyHaveActiveStrategy:
|
||||
return NearbyConnectionsApi::StatusCode::kAlreadyHaveActiveStrategy;
|
||||
case Status::kAlreadyAdvertising:
|
||||
return NearbyConnectionsApi::StatusCode::kAlreadyAdvertising;
|
||||
case Status::kAlreadyDiscovering:
|
||||
return NearbyConnectionsApi::StatusCode::kAlreadyDiscovering;
|
||||
case Status::kAlreadyListening:
|
||||
return NearbyConnectionsApi::StatusCode::kAlreadyListening;
|
||||
case Status::kEndpointIOError:
|
||||
return NearbyConnectionsApi::StatusCode::kEndpointIOError;
|
||||
case Status::kEndpointUnknown:
|
||||
return NearbyConnectionsApi::StatusCode::kEndpointUnknown;
|
||||
case Status::kConnectionRejected:
|
||||
return NearbyConnectionsApi::StatusCode::kConnectionRejected;
|
||||
case Status::kAlreadyConnectedToEndpoint:
|
||||
return NearbyConnectionsApi::StatusCode::kAlreadyConnectedToEndpoint;
|
||||
case Status::kNotConnectedToEndpoint:
|
||||
return NearbyConnectionsApi::StatusCode::kNotConnectedToEndpoint;
|
||||
case Status::kBluetoothError:
|
||||
return NearbyConnectionsApi::StatusCode::kBluetoothError;
|
||||
case Status::kBleError:
|
||||
return NearbyConnectionsApi::StatusCode::kBleError;
|
||||
case Status::kWifiLanError:
|
||||
return NearbyConnectionsApi::StatusCode::kWifiLanError;
|
||||
case Status::kPayloadUnknown:
|
||||
return NearbyConnectionsApi::StatusCode::kPayloadUnknown;
|
||||
case Status::kReset:
|
||||
return NearbyConnectionsApi::StatusCode::kReset;
|
||||
case Status::kTimeout:
|
||||
return NearbyConnectionsApi::StatusCode::kTimeout;
|
||||
case Status::kUnknown:
|
||||
return NearbyConnectionsApi::StatusCode::kUnknown;
|
||||
case Status::kNextValue:
|
||||
break;
|
||||
}
|
||||
return NearbyConnectionsApi::StatusCode::kUnknown;
|
||||
}
|
||||
|
||||
NearbyConnectionsApi::AuthenticationStatus ToFacadeAuthenticationStatus(
|
||||
::nearby::AuthenticationStatus status) {
|
||||
switch (status) {
|
||||
case ::nearby::AuthenticationStatus::kUnknown:
|
||||
return NearbyConnectionsApi::AuthenticationStatus::kUnknown;
|
||||
case ::nearby::AuthenticationStatus::kSuccess:
|
||||
return NearbyConnectionsApi::AuthenticationStatus::kSuccess;
|
||||
case ::nearby::AuthenticationStatus::kFailure:
|
||||
return NearbyConnectionsApi::AuthenticationStatus::kFailure;
|
||||
}
|
||||
return NearbyConnectionsApi::AuthenticationStatus::kUnknown;
|
||||
}
|
||||
|
||||
NearbyConnectionsApi::DistanceInfo ToFacadeDistanceInfo(
|
||||
nearby::sharing::DistanceInfo distance_info) {
|
||||
switch (distance_info) {
|
||||
case nearby::sharing::DistanceInfo::kUnknown:
|
||||
return NearbyConnectionsApi::DistanceInfo::kUnknown;
|
||||
case nearby::sharing::DistanceInfo::kVeryClose:
|
||||
return NearbyConnectionsApi::DistanceInfo::kVeryClose;
|
||||
case nearby::sharing::DistanceInfo::kClose:
|
||||
return NearbyConnectionsApi::DistanceInfo::kClose;
|
||||
case nearby::sharing::DistanceInfo::kFar:
|
||||
return NearbyConnectionsApi::DistanceInfo::kFar;
|
||||
}
|
||||
return NearbyConnectionsApi::DistanceInfo::kUnknown;
|
||||
}
|
||||
|
||||
NearbyConnectionsApi::Medium ToFacadeMedium(nearby::sharing::Medium medium) {
|
||||
switch (medium) {
|
||||
case nearby::sharing::Medium::kUnknown:
|
||||
return NearbyConnectionsApi::Medium::kUnknown;
|
||||
case nearby::sharing::Medium::kMdns:
|
||||
return NearbyConnectionsApi::Medium::kMdns;
|
||||
case nearby::sharing::Medium::kBluetooth:
|
||||
return NearbyConnectionsApi::Medium::kBluetooth;
|
||||
case nearby::sharing::Medium::kWifiHotspot:
|
||||
return NearbyConnectionsApi::Medium::kWifiHotspot;
|
||||
case nearby::sharing::Medium::kBle:
|
||||
return NearbyConnectionsApi::Medium::kBle;
|
||||
case nearby::sharing::Medium::kWifiLan:
|
||||
return NearbyConnectionsApi::Medium::kWifiLan;
|
||||
case nearby::sharing::Medium::kWifiAware:
|
||||
return NearbyConnectionsApi::Medium::kWifiAware;
|
||||
case nearby::sharing::Medium::kNfc:
|
||||
return NearbyConnectionsApi::Medium::kNfc;
|
||||
case nearby::sharing::Medium::kWifiDirect:
|
||||
return NearbyConnectionsApi::Medium::kWifiDirect;
|
||||
case nearby::sharing::Medium::kWebRtc:
|
||||
return NearbyConnectionsApi::Medium::kWebRtc;
|
||||
case nearby::sharing::Medium::kBleL2Cap:
|
||||
return NearbyConnectionsApi::Medium::kBleL2Cap;
|
||||
}
|
||||
return NearbyConnectionsApi::Medium::kUnknown;
|
||||
}
|
||||
|
||||
nearby::sharing::Strategy ToNativeStrategy(
|
||||
NearbyConnectionsApi::Strategy strategy) {
|
||||
switch (strategy) {
|
||||
case NearbyConnectionsApi::Strategy::kP2pCluster:
|
||||
return nearby::sharing::Strategy::kP2pCluster;
|
||||
case NearbyConnectionsApi::Strategy::kP2pStar:
|
||||
return nearby::sharing::Strategy::kP2pStar;
|
||||
case NearbyConnectionsApi::Strategy::kP2pPointToPoint:
|
||||
return nearby::sharing::Strategy::kP2pPointToPoint;
|
||||
}
|
||||
return nearby::sharing::Strategy::kP2pCluster;
|
||||
}
|
||||
|
||||
nearby::sharing::MediumSelection ToNativeMediumSelection(
|
||||
const NearbyConnectionsApi::MediumSelection& selection) {
|
||||
nearby::sharing::MediumSelection native_selection;
|
||||
native_selection.bluetooth = selection.bluetooth;
|
||||
native_selection.ble = selection.ble;
|
||||
native_selection.web_rtc = selection.web_rtc;
|
||||
native_selection.wifi_lan = selection.wifi_lan;
|
||||
native_selection.wifi_hotspot = selection.wifi_hotspot;
|
||||
return native_selection;
|
||||
}
|
||||
|
||||
nearby::sharing::AdvertisingOptions ToNativeAdvertisingOptions(
|
||||
const NearbyConnectionsApi::AdvertisingOptions& options) {
|
||||
nearby::sharing::AdvertisingOptions native_options;
|
||||
native_options.strategy = ToNativeStrategy(options.strategy);
|
||||
native_options.allowed_mediums =
|
||||
ToNativeMediumSelection(options.allowed_mediums);
|
||||
native_options.auto_upgrade_bandwidth = options.auto_upgrade_bandwidth;
|
||||
native_options.enforce_topology_constraints =
|
||||
options.enforce_topology_constraints;
|
||||
native_options.enable_bluetooth_listening =
|
||||
options.enable_bluetooth_listening;
|
||||
native_options.enable_webrtc_listening = options.enable_webrtc_listening;
|
||||
native_options.use_stable_endpoint_id = options.use_stable_endpoint_id;
|
||||
native_options.force_new_endpoint_id = options.force_new_endpoint_id;
|
||||
native_options.fast_advertisement_service_uuid =
|
||||
nearby::sharing::Uuid(options.fast_advertisement_service_uuid);
|
||||
return native_options;
|
||||
}
|
||||
|
||||
nearby::sharing::DiscoveryOptions ToNativeDiscoveryOptions(
|
||||
const NearbyConnectionsApi::DiscoveryOptions& options) {
|
||||
nearby::sharing::DiscoveryOptions native_options;
|
||||
native_options.strategy = ToNativeStrategy(options.strategy);
|
||||
native_options.allowed_mediums =
|
||||
ToNativeMediumSelection(options.allowed_mediums);
|
||||
if (options.has_fast_advertisement_service_uuid) {
|
||||
native_options.fast_advertisement_service_uuid =
|
||||
nearby::sharing::Uuid(options.fast_advertisement_service_uuid.uuid);
|
||||
}
|
||||
native_options.is_out_of_band_connection =
|
||||
options.is_out_of_band_connection;
|
||||
if (options.has_alternate_service_uuid) {
|
||||
native_options.alternate_service_uuid = options.alternate_service_uuid;
|
||||
}
|
||||
return native_options;
|
||||
}
|
||||
|
||||
nearby::sharing::ConnectionOptions ToNativeConnectionOptions(
|
||||
const NearbyConnectionsApi::ConnectionOptions& options) {
|
||||
nearby::sharing::ConnectionOptions native_options;
|
||||
native_options.allowed_mediums =
|
||||
ToNativeMediumSelection(options.allowed_mediums);
|
||||
if (!options.remote_bluetooth_mac_address.empty()) {
|
||||
native_options.remote_bluetooth_mac_address =
|
||||
options.remote_bluetooth_mac_address;
|
||||
}
|
||||
if (options.has_keep_alive_interval_millis &&
|
||||
options.keep_alive_interval_millis >= 0) {
|
||||
native_options.keep_alive_interval =
|
||||
absl::Milliseconds(options.keep_alive_interval_millis);
|
||||
}
|
||||
if (options.has_keep_alive_timeout_millis &&
|
||||
options.keep_alive_timeout_millis >= 0) {
|
||||
native_options.keep_alive_timeout =
|
||||
absl::Milliseconds(options.keep_alive_timeout_millis);
|
||||
}
|
||||
native_options.non_disruptive_hotspot_mode =
|
||||
options.non_disruptive_hotspot_mode;
|
||||
return native_options;
|
||||
}
|
||||
|
||||
NearbyConnectionsApi::ConnectionInfo ToFacadeConnectionInfo(
|
||||
const nearby::sharing::ConnectionInfo& info) {
|
||||
NearbyConnectionsApi::ConnectionInfo facade_info;
|
||||
facade_info.authentication_token = info.authentication_token;
|
||||
facade_info.raw_authentication_token = info.raw_authentication_token;
|
||||
facade_info.endpoint_info = info.endpoint_info;
|
||||
facade_info.is_incoming_connection = info.is_incoming_connection;
|
||||
facade_info.connection_layer_status =
|
||||
ToFacadeStatus(info.connection_layer_status);
|
||||
facade_info.authentication_status =
|
||||
ToFacadeAuthenticationStatus(info.authentication_status);
|
||||
return facade_info;
|
||||
}
|
||||
|
||||
NearbyConnectionsApi::DiscoveredEndpointInfo ToFacadeDiscoveredEndpointInfo(
|
||||
const nearby::sharing::DiscoveredEndpointInfo& info) {
|
||||
NearbyConnectionsApi::DiscoveredEndpointInfo facade_info;
|
||||
facade_info.endpoint_info = info.endpoint_info;
|
||||
facade_info.service_id = info.service_id;
|
||||
return facade_info;
|
||||
}
|
||||
|
||||
NearbyConnectionsApi::PayloadStatus ToFacadePayloadStatus(
|
||||
nearby::sharing::PayloadStatus status) {
|
||||
switch (status) {
|
||||
case nearby::sharing::PayloadStatus::kSuccess:
|
||||
return NearbyConnectionsApi::PayloadStatus::kSuccess;
|
||||
case nearby::sharing::PayloadStatus::kFailure:
|
||||
return NearbyConnectionsApi::PayloadStatus::kFailure;
|
||||
case nearby::sharing::PayloadStatus::kInProgress:
|
||||
return NearbyConnectionsApi::PayloadStatus::kInProgress;
|
||||
case nearby::sharing::PayloadStatus::kCanceled:
|
||||
return NearbyConnectionsApi::PayloadStatus::kCanceled;
|
||||
}
|
||||
return NearbyConnectionsApi::PayloadStatus::kFailure;
|
||||
}
|
||||
|
||||
NearbyConnectionsApi::Payload ToFacadePayload(
|
||||
const nearby::sharing::Payload& payload) {
|
||||
NearbyConnectionsApi::Payload facade_payload;
|
||||
facade_payload.id = payload.id;
|
||||
switch (payload.content.type) {
|
||||
case nearby::sharing::PayloadContent::Type::kBytes:
|
||||
facade_payload.type = NearbyConnectionsApi::PayloadType::kBytes;
|
||||
facade_payload.bytes = payload.content.bytes_payload.bytes;
|
||||
break;
|
||||
case nearby::sharing::PayloadContent::Type::kStream:
|
||||
facade_payload.type = NearbyConnectionsApi::PayloadType::kStream;
|
||||
facade_payload.stream_bytes = payload.content.stream_payload.bytes;
|
||||
break;
|
||||
case nearby::sharing::PayloadContent::Type::kFile:
|
||||
facade_payload.type = NearbyConnectionsApi::PayloadType::kFile;
|
||||
facade_payload.file_path =
|
||||
payload.content.file_payload.file_path.ToString();
|
||||
facade_payload.parent_folder = payload.content.file_payload.parent_folder;
|
||||
break;
|
||||
case nearby::sharing::PayloadContent::Type::kUnknown:
|
||||
facade_payload.type = NearbyConnectionsApi::PayloadType::kUnknown;
|
||||
break;
|
||||
}
|
||||
return facade_payload;
|
||||
}
|
||||
|
||||
std::unique_ptr<nearby::sharing::Payload> ToNativePayload(
|
||||
NearbyConnectionsApi::Payload payload) {
|
||||
switch (payload.type) {
|
||||
case NearbyConnectionsApi::PayloadType::kBytes:
|
||||
return std::make_unique<nearby::sharing::Payload>(
|
||||
payload.id, std::move(payload.bytes));
|
||||
case NearbyConnectionsApi::PayloadType::kFile:
|
||||
return std::make_unique<nearby::sharing::Payload>(
|
||||
payload.id, FilePath(payload.file_path), payload.parent_folder);
|
||||
case NearbyConnectionsApi::PayloadType::kStream: {
|
||||
nearby::sharing::StreamPayload stream_payload;
|
||||
stream_payload.bytes = std::move(payload.stream_bytes);
|
||||
stream_payload.input_stream = std::move(payload.stream_input);
|
||||
return std::make_unique<nearby::sharing::Payload>(payload.id,
|
||||
std::move(stream_payload));
|
||||
}
|
||||
case NearbyConnectionsApi::PayloadType::kUnknown:
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NearbyConnectionsApi::PayloadTransferUpdate ToFacadePayloadTransferUpdate(
|
||||
const nearby::sharing::PayloadTransferUpdate& update) {
|
||||
NearbyConnectionsApi::PayloadTransferUpdate facade_update;
|
||||
facade_update.payload_id = update.payload_id;
|
||||
facade_update.status = ToFacadePayloadStatus(update.status);
|
||||
facade_update.total_bytes = update.total_bytes;
|
||||
facade_update.bytes_transferred = update.bytes_transferred;
|
||||
return facade_update;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class NearbyConnectionsApi::Impl {
|
||||
public:
|
||||
struct ListenerState {
|
||||
std::mutex mutex;
|
||||
NearbyConnectionsApi::Listener listener;
|
||||
};
|
||||
|
||||
Impl()
|
||||
: platform(),
|
||||
context(platform),
|
||||
service(std::make_unique<NearbyConnectionsServiceImpl>(
|
||||
context.GetConnectivityManager(), /*event_logger=*/nullptr)),
|
||||
listener_state(std::make_shared<ListenerState>()) {}
|
||||
|
||||
static NearbyConnectionsApi::Listener CopyListener(
|
||||
const std::shared_ptr<ListenerState>& listener_state) {
|
||||
std::scoped_lock lock(listener_state->mutex);
|
||||
return listener_state->listener;
|
||||
}
|
||||
|
||||
static NativeService::ConnectionListener BuildConnectionListener(
|
||||
const std::shared_ptr<ListenerState>& listener_state) {
|
||||
NativeService::ConnectionListener listener;
|
||||
listener.initiated_cb =
|
||||
[listener_state](const std::string& endpoint_id,
|
||||
const nearby::sharing::ConnectionInfo& info) {
|
||||
NearbyConnectionsApi::Listener listener_copy =
|
||||
CopyListener(listener_state);
|
||||
if (!listener_copy.connection_initiated_cb) {
|
||||
return;
|
||||
}
|
||||
listener_copy.connection_initiated_cb(endpoint_id,
|
||||
ToFacadeConnectionInfo(info));
|
||||
};
|
||||
listener.accepted_cb = [listener_state](const std::string& endpoint_id) {
|
||||
NearbyConnectionsApi::Listener listener_copy =
|
||||
CopyListener(listener_state);
|
||||
if (listener_copy.connection_accepted_cb) {
|
||||
listener_copy.connection_accepted_cb(endpoint_id);
|
||||
}
|
||||
};
|
||||
listener.rejected_cb = [listener_state](const std::string& endpoint_id,
|
||||
Status status) {
|
||||
NearbyConnectionsApi::Listener listener_copy =
|
||||
CopyListener(listener_state);
|
||||
if (listener_copy.connection_rejected_cb) {
|
||||
listener_copy.connection_rejected_cb(endpoint_id,
|
||||
ToFacadeStatus(status));
|
||||
}
|
||||
};
|
||||
listener.disconnected_cb = [listener_state](const std::string& endpoint_id) {
|
||||
NearbyConnectionsApi::Listener listener_copy =
|
||||
CopyListener(listener_state);
|
||||
if (listener_copy.disconnected_cb) {
|
||||
listener_copy.disconnected_cb(endpoint_id);
|
||||
}
|
||||
};
|
||||
listener.bandwidth_changed_cb =
|
||||
[listener_state](const std::string& endpoint_id,
|
||||
nearby::sharing::Medium medium) {
|
||||
NearbyConnectionsApi::Listener listener_copy =
|
||||
CopyListener(listener_state);
|
||||
if (listener_copy.bandwidth_changed_cb) {
|
||||
listener_copy.bandwidth_changed_cb(endpoint_id,
|
||||
ToFacadeMedium(medium));
|
||||
}
|
||||
};
|
||||
return listener;
|
||||
}
|
||||
|
||||
static NativeService::DiscoveryListener BuildDiscoveryListener(
|
||||
const std::shared_ptr<ListenerState>& listener_state) {
|
||||
NativeService::DiscoveryListener listener;
|
||||
listener.endpoint_found_cb =
|
||||
[listener_state](const std::string& endpoint_id,
|
||||
const nearby::sharing::DiscoveredEndpointInfo& info) {
|
||||
NearbyConnectionsApi::Listener listener_copy =
|
||||
CopyListener(listener_state);
|
||||
if (listener_copy.endpoint_found_cb) {
|
||||
listener_copy.endpoint_found_cb(
|
||||
endpoint_id, ToFacadeDiscoveredEndpointInfo(info));
|
||||
}
|
||||
};
|
||||
listener.endpoint_lost_cb = [listener_state](const std::string& endpoint_id) {
|
||||
NearbyConnectionsApi::Listener listener_copy =
|
||||
CopyListener(listener_state);
|
||||
if (listener_copy.endpoint_lost_cb) {
|
||||
listener_copy.endpoint_lost_cb(endpoint_id);
|
||||
}
|
||||
};
|
||||
listener.endpoint_distance_changed_cb =
|
||||
[listener_state](const std::string& endpoint_id,
|
||||
nearby::sharing::DistanceInfo distance_info) {
|
||||
NearbyConnectionsApi::Listener listener_copy =
|
||||
CopyListener(listener_state);
|
||||
if (listener_copy.endpoint_distance_changed_cb) {
|
||||
listener_copy.endpoint_distance_changed_cb(
|
||||
endpoint_id, ToFacadeDistanceInfo(distance_info));
|
||||
}
|
||||
};
|
||||
return listener;
|
||||
}
|
||||
|
||||
static NativeService::PayloadListener BuildPayloadListener(
|
||||
const std::shared_ptr<ListenerState>& listener_state) {
|
||||
NativeService::PayloadListener listener;
|
||||
listener.payload_cb = [listener_state](absl::string_view endpoint_id,
|
||||
nearby::sharing::Payload payload) {
|
||||
NearbyConnectionsApi::Listener listener_copy =
|
||||
CopyListener(listener_state);
|
||||
if (listener_copy.payload_received_cb) {
|
||||
listener_copy.payload_received_cb(std::string(endpoint_id),
|
||||
ToFacadePayload(payload));
|
||||
}
|
||||
};
|
||||
listener.payload_progress_cb =
|
||||
[listener_state](
|
||||
absl::string_view endpoint_id,
|
||||
const nearby::sharing::PayloadTransferUpdate& update) {
|
||||
NearbyConnectionsApi::Listener listener_copy =
|
||||
CopyListener(listener_state);
|
||||
if (listener_copy.payload_transfer_update_cb) {
|
||||
listener_copy.payload_transfer_update_cb(
|
||||
std::string(endpoint_id), ToFacadePayloadTransferUpdate(update));
|
||||
}
|
||||
};
|
||||
return listener;
|
||||
}
|
||||
|
||||
LinuxSharingPlatform platform;
|
||||
::nearby::ContextImpl context;
|
||||
std::unique_ptr<NativeService> service;
|
||||
std::shared_ptr<ListenerState> listener_state;
|
||||
};
|
||||
|
||||
NearbyConnectionsApi::NearbyConnectionsApi() : impl_(std::make_unique<Impl>()) {}
|
||||
|
||||
NearbyConnectionsApi::~NearbyConnectionsApi() = default;
|
||||
|
||||
NearbyConnectionsApi::NearbyConnectionsApi(NearbyConnectionsApi&&) noexcept =
|
||||
default;
|
||||
|
||||
NearbyConnectionsApi& NearbyConnectionsApi::operator=(
|
||||
NearbyConnectionsApi&&) noexcept = default;
|
||||
|
||||
void NearbyConnectionsApi::SetListener(Listener listener) {
|
||||
std::scoped_lock lock(impl_->listener_state->mutex);
|
||||
impl_->listener_state->listener = std::move(listener);
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::StartAdvertising(
|
||||
const std::string& service_id, const std::vector<uint8_t>& endpoint_info,
|
||||
const AdvertisingOptions& options,
|
||||
std::function<void(StatusCode)> callback) {
|
||||
impl_->service->StartAdvertising(
|
||||
service_id, endpoint_info, ToNativeAdvertisingOptions(options),
|
||||
Impl::BuildConnectionListener(impl_->listener_state),
|
||||
[callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::StopAdvertising(
|
||||
const std::string& service_id, std::function<void(StatusCode)> callback) {
|
||||
impl_->service->StopAdvertising(
|
||||
service_id, [callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::StartDiscovery(
|
||||
const std::string& service_id, const DiscoveryOptions& options,
|
||||
std::function<void(StatusCode)> callback) {
|
||||
impl_->service->StartDiscovery(
|
||||
service_id, ToNativeDiscoveryOptions(options),
|
||||
Impl::BuildDiscoveryListener(impl_->listener_state),
|
||||
[callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::StopDiscovery(
|
||||
const std::string& service_id, std::function<void(StatusCode)> callback) {
|
||||
impl_->service->StopDiscovery(
|
||||
service_id, [callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::RequestConnection(
|
||||
const std::string& service_id, const std::vector<uint8_t>& endpoint_info,
|
||||
const std::string& endpoint_id, const ConnectionOptions& options,
|
||||
std::function<void(StatusCode)> callback) {
|
||||
impl_->service->RequestConnection(
|
||||
service_id, endpoint_info, endpoint_id, ToNativeConnectionOptions(options),
|
||||
Impl::BuildConnectionListener(impl_->listener_state),
|
||||
[callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::DisconnectFromEndpoint(
|
||||
const std::string& service_id, const std::string& endpoint_id,
|
||||
std::function<void(StatusCode)> callback) {
|
||||
impl_->service->DisconnectFromEndpoint(
|
||||
service_id, endpoint_id,
|
||||
[callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::SendPayload(
|
||||
const std::string& service_id, const std::vector<std::string>& endpoint_ids,
|
||||
Payload payload, std::function<void(StatusCode)> callback) {
|
||||
std::unique_ptr<nearby::sharing::Payload> native_payload =
|
||||
ToNativePayload(std::move(payload));
|
||||
if (native_payload == nullptr) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kError);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
impl_->service->SendPayload(
|
||||
service_id, endpoint_ids, std::move(native_payload),
|
||||
[callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::CancelPayload(
|
||||
const std::string& service_id, int64_t payload_id,
|
||||
std::function<void(StatusCode)> callback) {
|
||||
impl_->service->CancelPayload(
|
||||
service_id, payload_id,
|
||||
[callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::InitiateBandwidthUpgrade(
|
||||
const std::string& service_id, const std::string& endpoint_id,
|
||||
std::function<void(StatusCode)> callback) {
|
||||
impl_->service->InitiateBandwidthUpgrade(
|
||||
service_id, endpoint_id,
|
||||
[callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::AcceptConnection(
|
||||
const std::string& service_id, const std::string& endpoint_id,
|
||||
std::function<void(StatusCode)> callback) {
|
||||
impl_->service->AcceptConnection(
|
||||
service_id, endpoint_id, Impl::BuildPayloadListener(impl_->listener_state),
|
||||
[callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::StopAllEndpoints(
|
||||
std::function<void(StatusCode)> callback) {
|
||||
impl_->service->StopAllEndpoints(
|
||||
[callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::SetCustomSavePath(
|
||||
const std::string& path, std::function<void(StatusCode)> callback) {
|
||||
impl_->service->SetCustomSavePath(
|
||||
path, [callback = std::move(callback)](Status status) mutable {
|
||||
if (callback) {
|
||||
callback(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbyConnectionsApi::OverrideSavePath(const std::string& endpoint_id,
|
||||
const std::string& path) {
|
||||
impl_->service->OverrideSavePath(endpoint_id, path);
|
||||
}
|
||||
|
||||
std::string NearbyConnectionsApi::Dump() const { return impl_->service->Dump(); }
|
||||
|
||||
std::string NearbyConnectionsApi::StatusCodeToString(StatusCode status) {
|
||||
switch (status) {
|
||||
case StatusCode::kSuccess:
|
||||
return "Success";
|
||||
case StatusCode::kError:
|
||||
return "Error";
|
||||
case StatusCode::kOutOfOrderApiCall:
|
||||
return "OutOfOrderApiCall";
|
||||
case StatusCode::kAlreadyHaveActiveStrategy:
|
||||
return "AlreadyHaveActiveStrategy";
|
||||
case StatusCode::kAlreadyAdvertising:
|
||||
return "AlreadyAdvertising";
|
||||
case StatusCode::kAlreadyDiscovering:
|
||||
return "AlreadyDiscovering";
|
||||
case StatusCode::kAlreadyListening:
|
||||
return "AlreadyListening";
|
||||
case StatusCode::kEndpointIOError:
|
||||
return "EndpointIOError";
|
||||
case StatusCode::kEndpointUnknown:
|
||||
return "EndpointUnknown";
|
||||
case StatusCode::kConnectionRejected:
|
||||
return "ConnectionRejected";
|
||||
case StatusCode::kAlreadyConnectedToEndpoint:
|
||||
return "AlreadyConnectedToEndpoint";
|
||||
case StatusCode::kNotConnectedToEndpoint:
|
||||
return "NotConnectedToEndpoint";
|
||||
case StatusCode::kBluetoothError:
|
||||
return "BluetoothError";
|
||||
case StatusCode::kBleError:
|
||||
return "BleError";
|
||||
case StatusCode::kWifiLanError:
|
||||
return "WifiLanError";
|
||||
case StatusCode::kPayloadUnknown:
|
||||
return "PayloadUnknown";
|
||||
case StatusCode::kReset:
|
||||
return "Reset";
|
||||
case StatusCode::kTimeout:
|
||||
return "Timeout";
|
||||
case StatusCode::kUnknown:
|
||||
return "Unknown";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
} // namespace nearby::sharing
|
||||
@@ -1,290 +0,0 @@
|
||||
// Copyright 2026
|
||||
//
|
||||
// Thin app-facing API for NearbyConnectionsService on Linux that avoids
|
||||
// exposing internal Nearby headers to external consumers.
|
||||
|
||||
#ifndef SHARING_LINUX_NEARBY_CONNECTIONS_API_H_
|
||||
#define SHARING_LINUX_NEARBY_CONNECTIONS_API_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "internal/platform/input_stream.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace sharing {
|
||||
|
||||
class __attribute__((visibility("default"))) NearbyConnectionsApi {
|
||||
public:
|
||||
enum class StatusCode {
|
||||
kSuccess = 0,
|
||||
kError = 1,
|
||||
kOutOfOrderApiCall = 2,
|
||||
kAlreadyHaveActiveStrategy = 3,
|
||||
kAlreadyAdvertising = 4,
|
||||
kAlreadyDiscovering = 5,
|
||||
kAlreadyListening = 6,
|
||||
kEndpointIOError = 7,
|
||||
kEndpointUnknown = 8,
|
||||
kConnectionRejected = 9,
|
||||
kAlreadyConnectedToEndpoint = 10,
|
||||
kNotConnectedToEndpoint = 11,
|
||||
kBluetoothError = 12,
|
||||
kBleError = 13,
|
||||
kWifiLanError = 14,
|
||||
kPayloadUnknown = 15,
|
||||
kReset = 16,
|
||||
kTimeout = 17,
|
||||
kUnknown = 18,
|
||||
};
|
||||
|
||||
enum class Strategy {
|
||||
kP2pCluster = 0,
|
||||
kP2pStar = 1,
|
||||
kP2pPointToPoint = 2,
|
||||
};
|
||||
|
||||
enum class Medium {
|
||||
kUnknown = 0,
|
||||
kMdns = 1,
|
||||
kBluetooth = 2,
|
||||
kWifiHotspot = 3,
|
||||
kBle = 4,
|
||||
kWifiLan = 5,
|
||||
kWifiAware = 6,
|
||||
kNfc = 7,
|
||||
kWifiDirect = 8,
|
||||
kWebRtc = 9,
|
||||
kBleL2Cap = 10,
|
||||
};
|
||||
|
||||
enum class DistanceInfo {
|
||||
kUnknown = 1,
|
||||
kVeryClose = 2,
|
||||
kClose = 3,
|
||||
kFar = 4,
|
||||
};
|
||||
|
||||
enum class AuthenticationStatus {
|
||||
kUnknown = 0,
|
||||
kSuccess = 1,
|
||||
kFailure = 2,
|
||||
};
|
||||
|
||||
enum class PayloadType {
|
||||
kUnknown = 0,
|
||||
kBytes = 1,
|
||||
kFile = 2,
|
||||
kStream = 3,
|
||||
};
|
||||
|
||||
enum class PayloadStatus {
|
||||
kSuccess = 0,
|
||||
kFailure = 1,
|
||||
kInProgress = 2,
|
||||
kCanceled = 3,
|
||||
};
|
||||
|
||||
struct Uuid {
|
||||
std::string uuid;
|
||||
};
|
||||
|
||||
struct MediumSelection {
|
||||
bool bluetooth = true;
|
||||
bool ble = true;
|
||||
bool web_rtc = true;
|
||||
bool wifi_lan = true;
|
||||
bool wifi_hotspot = true;
|
||||
};
|
||||
|
||||
struct AdvertisingOptions {
|
||||
Strategy strategy = Strategy::kP2pCluster;
|
||||
MediumSelection allowed_mediums;
|
||||
bool auto_upgrade_bandwidth = true;
|
||||
bool enforce_topology_constraints = true;
|
||||
bool enable_bluetooth_listening = false;
|
||||
bool enable_webrtc_listening = false;
|
||||
bool use_stable_endpoint_id = false;
|
||||
bool force_new_endpoint_id = false;
|
||||
std::string fast_advertisement_service_uuid;
|
||||
};
|
||||
|
||||
struct DiscoveryOptions {
|
||||
Strategy strategy = Strategy::kP2pCluster;
|
||||
MediumSelection allowed_mediums;
|
||||
bool has_fast_advertisement_service_uuid = false;
|
||||
Uuid fast_advertisement_service_uuid;
|
||||
bool is_out_of_band_connection = false;
|
||||
bool has_alternate_service_uuid = false;
|
||||
uint16_t alternate_service_uuid = 0;
|
||||
};
|
||||
|
||||
struct ConnectionOptions {
|
||||
MediumSelection allowed_mediums;
|
||||
std::vector<uint8_t> remote_bluetooth_mac_address;
|
||||
bool has_keep_alive_interval_millis = false;
|
||||
int64_t keep_alive_interval_millis = 0;
|
||||
bool has_keep_alive_timeout_millis = false;
|
||||
int64_t keep_alive_timeout_millis = 0;
|
||||
bool non_disruptive_hotspot_mode = false;
|
||||
};
|
||||
|
||||
struct ConnectionInfo {
|
||||
std::string authentication_token;
|
||||
std::vector<uint8_t> raw_authentication_token;
|
||||
std::vector<uint8_t> endpoint_info;
|
||||
bool is_incoming_connection = false;
|
||||
StatusCode connection_layer_status = StatusCode::kUnknown;
|
||||
AuthenticationStatus authentication_status =
|
||||
AuthenticationStatus::kUnknown;
|
||||
};
|
||||
|
||||
struct DiscoveredEndpointInfo {
|
||||
std::vector<uint8_t> endpoint_info;
|
||||
std::string service_id;
|
||||
};
|
||||
|
||||
struct PayloadTransferUpdate {
|
||||
int64_t payload_id = 0;
|
||||
PayloadStatus status = PayloadStatus::kInProgress;
|
||||
uint64_t total_bytes = 0;
|
||||
uint64_t bytes_transferred = 0;
|
||||
};
|
||||
|
||||
struct Payload {
|
||||
int64_t id = 0;
|
||||
PayloadType type = PayloadType::kUnknown;
|
||||
std::vector<uint8_t> bytes;
|
||||
std::vector<uint8_t> stream_bytes;
|
||||
std::shared_ptr<nearby::InputStream> stream_input;
|
||||
std::string file_path;
|
||||
std::string parent_folder;
|
||||
|
||||
static Payload FromBytes(int64_t id, std::vector<uint8_t> bytes) {
|
||||
Payload payload;
|
||||
payload.id = id;
|
||||
payload.type = PayloadType::kBytes;
|
||||
payload.bytes = std::move(bytes);
|
||||
return payload;
|
||||
}
|
||||
|
||||
static Payload FromFile(int64_t id, std::string file_path,
|
||||
std::string parent_folder = {}) {
|
||||
Payload payload;
|
||||
payload.id = id;
|
||||
payload.type = PayloadType::kFile;
|
||||
payload.file_path = std::move(file_path);
|
||||
payload.parent_folder = std::move(parent_folder);
|
||||
return payload;
|
||||
}
|
||||
|
||||
static Payload FromStream(int64_t id, std::vector<uint8_t> stream_bytes) {
|
||||
Payload payload;
|
||||
payload.id = id;
|
||||
payload.type = PayloadType::kStream;
|
||||
payload.stream_bytes = std::move(stream_bytes);
|
||||
return payload;
|
||||
}
|
||||
|
||||
static Payload FromInputStream(int64_t id,
|
||||
std::shared_ptr<nearby::InputStream> stream_input) {
|
||||
Payload payload;
|
||||
payload.id = id;
|
||||
payload.type = PayloadType::kStream;
|
||||
payload.stream_input = std::move(stream_input);
|
||||
return payload;
|
||||
}
|
||||
};
|
||||
|
||||
struct Listener {
|
||||
std::function<void(const std::string&, const DiscoveredEndpointInfo&)>
|
||||
endpoint_found_cb;
|
||||
std::function<void(const std::string&)> endpoint_lost_cb;
|
||||
std::function<void(const std::string&, DistanceInfo)>
|
||||
endpoint_distance_changed_cb;
|
||||
|
||||
std::function<void(const std::string&, const ConnectionInfo&)>
|
||||
connection_initiated_cb;
|
||||
std::function<void(const std::string&)> connection_accepted_cb;
|
||||
std::function<void(const std::string&, StatusCode)> connection_rejected_cb;
|
||||
std::function<void(const std::string&)> disconnected_cb;
|
||||
std::function<void(const std::string&, Medium)> bandwidth_changed_cb;
|
||||
|
||||
std::function<void(const std::string&, const Payload&)>
|
||||
payload_received_cb;
|
||||
std::function<void(const std::string&, const PayloadTransferUpdate&)>
|
||||
payload_transfer_update_cb;
|
||||
};
|
||||
|
||||
NearbyConnectionsApi();
|
||||
~NearbyConnectionsApi();
|
||||
|
||||
NearbyConnectionsApi(const NearbyConnectionsApi&) = delete;
|
||||
NearbyConnectionsApi& operator=(const NearbyConnectionsApi&) = delete;
|
||||
NearbyConnectionsApi(NearbyConnectionsApi&&) noexcept;
|
||||
NearbyConnectionsApi& operator=(NearbyConnectionsApi&&) noexcept;
|
||||
|
||||
void SetListener(Listener listener);
|
||||
|
||||
void StartAdvertising(const std::string& service_id,
|
||||
const std::vector<uint8_t>& endpoint_info,
|
||||
const AdvertisingOptions& options,
|
||||
std::function<void(StatusCode)> callback);
|
||||
void StopAdvertising(const std::string& service_id,
|
||||
std::function<void(StatusCode)> callback);
|
||||
|
||||
void StartDiscovery(const std::string& service_id,
|
||||
const DiscoveryOptions& options,
|
||||
std::function<void(StatusCode)> callback);
|
||||
void StopDiscovery(const std::string& service_id,
|
||||
std::function<void(StatusCode)> callback);
|
||||
|
||||
void RequestConnection(const std::string& service_id,
|
||||
const std::vector<uint8_t>& endpoint_info,
|
||||
const std::string& endpoint_id,
|
||||
const ConnectionOptions& options,
|
||||
std::function<void(StatusCode)> callback);
|
||||
|
||||
void DisconnectFromEndpoint(const std::string& service_id,
|
||||
const std::string& endpoint_id,
|
||||
std::function<void(StatusCode)> callback);
|
||||
|
||||
void SendPayload(const std::string& service_id,
|
||||
const std::vector<std::string>& endpoint_ids,
|
||||
Payload payload,
|
||||
std::function<void(StatusCode)> callback);
|
||||
void CancelPayload(const std::string& service_id, int64_t payload_id,
|
||||
std::function<void(StatusCode)> callback);
|
||||
|
||||
void InitiateBandwidthUpgrade(const std::string& service_id,
|
||||
const std::string& endpoint_id,
|
||||
std::function<void(StatusCode)> callback);
|
||||
|
||||
void AcceptConnection(const std::string& service_id,
|
||||
const std::string& endpoint_id,
|
||||
std::function<void(StatusCode)> callback);
|
||||
|
||||
void StopAllEndpoints(std::function<void(StatusCode)> callback);
|
||||
|
||||
void SetCustomSavePath(const std::string& path,
|
||||
std::function<void(StatusCode)> callback);
|
||||
void OverrideSavePath(const std::string& endpoint_id,
|
||||
const std::string& path);
|
||||
|
||||
std::string Dump() const;
|
||||
|
||||
static std::string StatusCodeToString(StatusCode status);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
};
|
||||
|
||||
} // namespace sharing
|
||||
} // namespace nearby
|
||||
|
||||
#endif // SHARING_LINUX_NEARBY_CONNECTIONS_API_H_
|
||||
@@ -1,75 +0,0 @@
|
||||
#include "sharing/linux/nearby_connections_api.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "internal/platform/pipe.h"
|
||||
|
||||
namespace nearby::sharing {
|
||||
namespace {
|
||||
|
||||
TEST(NearbyConnectionsApiTest, PayloadFromBytesSetsFields) {
|
||||
NearbyConnectionsApi::Payload payload =
|
||||
NearbyConnectionsApi::Payload::FromBytes(42, {1, 2, 3});
|
||||
|
||||
EXPECT_EQ(payload.id, 42);
|
||||
EXPECT_EQ(payload.type, NearbyConnectionsApi::PayloadType::kBytes);
|
||||
EXPECT_EQ(payload.bytes, (std::vector<uint8_t>{1, 2, 3}));
|
||||
EXPECT_TRUE(payload.stream_bytes.empty());
|
||||
EXPECT_TRUE(payload.file_path.empty());
|
||||
}
|
||||
|
||||
TEST(NearbyConnectionsApiTest, PayloadFromFileSetsFields) {
|
||||
NearbyConnectionsApi::Payload payload =
|
||||
NearbyConnectionsApi::Payload::FromFile(7, "/tmp/test.txt", "tmp");
|
||||
|
||||
EXPECT_EQ(payload.id, 7);
|
||||
EXPECT_EQ(payload.type, NearbyConnectionsApi::PayloadType::kFile);
|
||||
EXPECT_EQ(payload.file_path, "/tmp/test.txt");
|
||||
EXPECT_EQ(payload.parent_folder, "tmp");
|
||||
EXPECT_TRUE(payload.bytes.empty());
|
||||
EXPECT_TRUE(payload.stream_bytes.empty());
|
||||
}
|
||||
|
||||
TEST(NearbyConnectionsApiTest, PayloadFromStreamSetsFields) {
|
||||
NearbyConnectionsApi::Payload payload =
|
||||
NearbyConnectionsApi::Payload::FromStream(9, {4, 5, 6});
|
||||
|
||||
EXPECT_EQ(payload.id, 9);
|
||||
EXPECT_EQ(payload.type, NearbyConnectionsApi::PayloadType::kStream);
|
||||
EXPECT_EQ(payload.stream_bytes, (std::vector<uint8_t>{4, 5, 6}));
|
||||
EXPECT_TRUE(payload.bytes.empty());
|
||||
EXPECT_TRUE(payload.file_path.empty());
|
||||
}
|
||||
|
||||
TEST(NearbyConnectionsApiTest, PayloadFromInputStreamSetsFields) {
|
||||
auto [input, output] = CreatePipe();
|
||||
(void)output;
|
||||
|
||||
NearbyConnectionsApi::Payload payload =
|
||||
NearbyConnectionsApi::Payload::FromInputStream(
|
||||
10, std::shared_ptr<nearby::InputStream>(std::move(input)));
|
||||
|
||||
EXPECT_EQ(payload.id, 10);
|
||||
EXPECT_EQ(payload.type, NearbyConnectionsApi::PayloadType::kStream);
|
||||
EXPECT_TRUE(payload.stream_bytes.empty());
|
||||
EXPECT_NE(payload.stream_input, nullptr);
|
||||
EXPECT_TRUE(payload.bytes.empty());
|
||||
EXPECT_TRUE(payload.file_path.empty());
|
||||
}
|
||||
|
||||
TEST(NearbyConnectionsApiTest, StatusCodeToStringCoversRepresentativeValues) {
|
||||
EXPECT_EQ(NearbyConnectionsApi::StatusCodeToString(
|
||||
NearbyConnectionsApi::StatusCode::kSuccess),
|
||||
"Success");
|
||||
EXPECT_EQ(NearbyConnectionsApi::StatusCodeToString(
|
||||
NearbyConnectionsApi::StatusCode::kConnectionRejected),
|
||||
"ConnectionRejected");
|
||||
EXPECT_EQ(NearbyConnectionsApi::StatusCodeToString(
|
||||
NearbyConnectionsApi::StatusCode::kUnknown),
|
||||
"Unknown");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby::sharing
|
||||
@@ -1,680 +0,0 @@
|
||||
#include "sharing/linux/nearby_sharing_api.h"
|
||||
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
|
||||
#include "internal/base/file_path.h"
|
||||
#include "internal/base/files.h"
|
||||
#include "internal/crypto_cros/ec_private_key.h"
|
||||
#include "internal/flags/nearby_flags.h"
|
||||
#include "internal/platform/implementation/linux/linux_flags.h"
|
||||
#include "sharing/analytics/analytics_recorder.h"
|
||||
#include "sharing/attachment_container.h"
|
||||
#include "sharing/file_attachment.h"
|
||||
#include "sharing/flags/generated/nearby_sharing_feature_flags.h"
|
||||
#include "sharing/linux/platform/linux_sharing_platform.h"
|
||||
#include "sharing/local_device_data/nearby_share_local_device_data_manager.h"
|
||||
#include "sharing/nearby_sharing_service_factory.h"
|
||||
#include "sharing/proto/enums.pb.h"
|
||||
#include "sharing/share_target_discovered_callback.h"
|
||||
#include "sharing/transfer_metadata.h"
|
||||
#include "sharing/transfer_update_callback.h"
|
||||
|
||||
namespace nearby::sharing {
|
||||
|
||||
namespace {
|
||||
|
||||
using NativeService = nearby::sharing::NearbySharingService;
|
||||
|
||||
void EnableBleL2capDefaults() {
|
||||
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
nearby::connections::config_package_nearby::nearby_connections_feature::
|
||||
kEnableBleL2cap,
|
||||
true);
|
||||
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
nearby::sharing::config_package_nearby::nearby_sharing_feature::
|
||||
kEnableBleForTransfer,
|
||||
true);
|
||||
//nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
// nearby::connections::config_package_nearby::nearby_connections_feature::
|
||||
// kRefactorBleL2cap,
|
||||
// false);
|
||||
}
|
||||
|
||||
NearbySharingApi::StatusCode ToFacadeStatus(
|
||||
nearby::sharing::NearbySharingService::StatusCodes status) {
|
||||
switch (status) {
|
||||
case nearby::sharing::NearbySharingService::StatusCodes::kOk:
|
||||
return NearbySharingApi::StatusCode::kOk;
|
||||
case nearby::sharing::NearbySharingService::StatusCodes::kError:
|
||||
return NearbySharingApi::StatusCode::kError;
|
||||
case nearby::sharing::NearbySharingService::StatusCodes::kOutOfOrderApiCall:
|
||||
return NearbySharingApi::StatusCode::kOutOfOrderApiCall;
|
||||
case nearby::sharing::NearbySharingService::StatusCodes::kStatusAlreadyStopped:
|
||||
return NearbySharingApi::StatusCode::kStatusAlreadyStopped;
|
||||
case nearby::sharing::NearbySharingService::StatusCodes::kTransferAlreadyInProgress:
|
||||
return NearbySharingApi::StatusCode::kTransferAlreadyInProgress;
|
||||
case nearby::sharing::NearbySharingService::StatusCodes::kNoAvailableConnectionMedium:
|
||||
return NearbySharingApi::StatusCode::kNoAvailableConnectionMedium;
|
||||
case nearby::sharing::NearbySharingService::StatusCodes::kIrrecoverableHardwareError:
|
||||
return NearbySharingApi::StatusCode::kIrrecoverableHardwareError;
|
||||
case nearby::sharing::NearbySharingService::StatusCodes::kInvalidArgument:
|
||||
return NearbySharingApi::StatusCode::kInvalidArgument;
|
||||
}
|
||||
return NearbySharingApi::StatusCode::kError;
|
||||
}
|
||||
|
||||
NearbySharingApi::TransferStatus ToFacadeTransferStatus(
|
||||
nearby::sharing::TransferMetadata::Status status) {
|
||||
using NativeStatus = nearby::sharing::TransferMetadata::Status;
|
||||
using FacadeStatus = NearbySharingApi::TransferStatus;
|
||||
switch (status) {
|
||||
case NativeStatus::kUnknown:
|
||||
return FacadeStatus::kUnknown;
|
||||
case NativeStatus::kConnecting:
|
||||
return FacadeStatus::kConnecting;
|
||||
case NativeStatus::kAwaitingLocalConfirmation:
|
||||
return FacadeStatus::kAwaitingLocalConfirmation;
|
||||
case NativeStatus::kAwaitingRemoteAcceptance:
|
||||
return FacadeStatus::kAwaitingRemoteAcceptance;
|
||||
case NativeStatus::kInProgress:
|
||||
return FacadeStatus::kInProgress;
|
||||
case NativeStatus::kComplete:
|
||||
return FacadeStatus::kComplete;
|
||||
case NativeStatus::kFailed:
|
||||
return FacadeStatus::kFailed;
|
||||
case NativeStatus::kRejected:
|
||||
return FacadeStatus::kRejected;
|
||||
case NativeStatus::kCancelled:
|
||||
return FacadeStatus::kCancelled;
|
||||
case NativeStatus::kTimedOut:
|
||||
return FacadeStatus::kTimedOut;
|
||||
case NativeStatus::kMediaUnavailable:
|
||||
return FacadeStatus::kMediaUnavailable;
|
||||
case NativeStatus::kNotEnoughSpace:
|
||||
return FacadeStatus::kNotEnoughSpace;
|
||||
case NativeStatus::kUnsupportedAttachmentType:
|
||||
return FacadeStatus::kUnsupportedAttachmentType;
|
||||
case NativeStatus::kDeviceAuthenticationFailed:
|
||||
return FacadeStatus::kDeviceAuthenticationFailed;
|
||||
case NativeStatus::kIncompletePayloads:
|
||||
return FacadeStatus::kIncompletePayloads;
|
||||
}
|
||||
return FacadeStatus::kUnknown;
|
||||
}
|
||||
|
||||
NearbySharingApi::TextAttachmentType ToFacadeTextAttachmentType(
|
||||
nearby::sharing::TextAttachment::Type type) {
|
||||
using FacadeType = NearbySharingApi::TextAttachmentType;
|
||||
switch (type) {
|
||||
case nearby::sharing::service::proto::TextMetadata::TEXT:
|
||||
return FacadeType::kText;
|
||||
case nearby::sharing::service::proto::TextMetadata::URL:
|
||||
return FacadeType::kUrl;
|
||||
case nearby::sharing::service::proto::TextMetadata::PHONE_NUMBER:
|
||||
return FacadeType::kPhoneNumber;
|
||||
case nearby::sharing::service::proto::TextMetadata::ADDRESS:
|
||||
return FacadeType::kAddress;
|
||||
case nearby::sharing::service::proto::TextMetadata::UNKNOWN:
|
||||
return FacadeType::kUnknown;
|
||||
}
|
||||
return FacadeType::kUnknown;
|
||||
}
|
||||
|
||||
float NormalizeFacadeProgress(float progress) {
|
||||
if (progress <= 0.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
if (progress >= 100.0f) {
|
||||
return 1.0f;
|
||||
}
|
||||
return progress / 100.0f;
|
||||
}
|
||||
|
||||
std::string GenerateQrCodeUrl() {
|
||||
auto ec_key = nearby::crypto::ECPrivateKey::Create();
|
||||
if (!ec_key) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const EC_KEY* raw_ec_key = EVP_PKEY_get0_EC_KEY(ec_key->key());
|
||||
if (!raw_ec_key) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const EC_GROUP* group = EC_KEY_get0_group(raw_ec_key);
|
||||
const EC_POINT* public_key = EC_KEY_get0_public_key(raw_ec_key);
|
||||
if (!group || !public_key) {
|
||||
return {};
|
||||
}
|
||||
|
||||
BIGNUM* x = BN_new();
|
||||
BIGNUM* y = BN_new();
|
||||
if (!x || !y) {
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(group, public_key, x, y, nullptr)) {
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> x_bytes(32, 0);
|
||||
const int x_len = BN_num_bytes(x);
|
||||
if (x_len > static_cast<int>(x_bytes.size())) {
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
return {};
|
||||
}
|
||||
BN_bn2bin(x, x_bytes.data() + (x_bytes.size() - x_len));
|
||||
|
||||
const uint8_t prefix = BN_is_odd(y) ? 0x03 : 0x02;
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
|
||||
std::vector<uint8_t> key_data;
|
||||
key_data.reserve(35);
|
||||
key_data.push_back(0x00);
|
||||
key_data.push_back(0x00);
|
||||
key_data.push_back(prefix);
|
||||
key_data.insert(key_data.end(), x_bytes.begin(), x_bytes.end());
|
||||
|
||||
std::string encoded;
|
||||
absl::WebSafeBase64Escape(
|
||||
std::string(reinterpret_cast<const char*>(key_data.data()),
|
||||
key_data.size()),
|
||||
&encoded);
|
||||
return "https://quickshare.google/qrcode#key=" + encoded;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class NearbySharingApi::Impl : public nearby::sharing::ShareTargetDiscoveredCallback,
|
||||
public nearby::sharing::TransferUpdateCallback {
|
||||
public:
|
||||
Impl()
|
||||
: analytics_recorder(0, nullptr),
|
||||
platform(),
|
||||
service(NearbySharingServiceFactory::GetInstance()->CreateSharingService(
|
||||
platform, &analytics_recorder, /*event_logger=*/nullptr,
|
||||
/*supports_file_sync=*/false)) {}
|
||||
|
||||
explicit Impl(std::string device_name_override)
|
||||
: analytics_recorder(0, nullptr),
|
||||
device_name_override(device_name_override),
|
||||
platform(device_name_override),
|
||||
service(NearbySharingServiceFactory::GetInstance()->CreateSharingService(
|
||||
platform, &analytics_recorder, /*event_logger=*/nullptr,
|
||||
/*supports_file_sync=*/false)) {
|
||||
if (service != nullptr && !device_name_override.empty() &&
|
||||
service->GetLocalDeviceDataManager() != nullptr) {
|
||||
service->GetLocalDeviceDataManager()->SetDeviceName(device_name_override);
|
||||
}
|
||||
}
|
||||
|
||||
void OnShareTargetDiscovered(const nearby::sharing::ShareTarget& share_target)
|
||||
override {
|
||||
Listener listener_copy;
|
||||
{
|
||||
std::scoped_lock lock(listener_mutex);
|
||||
listener_copy = listener;
|
||||
}
|
||||
if (!listener_copy.target_discovered_cb) {
|
||||
return;
|
||||
}
|
||||
listener_copy.target_discovered_cb(ToShareTargetInfo(share_target));
|
||||
}
|
||||
|
||||
void OnShareTargetLost(const nearby::sharing::ShareTarget& share_target)
|
||||
override {
|
||||
Listener listener_copy;
|
||||
{
|
||||
std::scoped_lock lock(listener_mutex);
|
||||
listener_copy = listener;
|
||||
}
|
||||
if (!listener_copy.target_lost_cb) {
|
||||
return;
|
||||
}
|
||||
listener_copy.target_lost_cb(share_target.id);
|
||||
}
|
||||
|
||||
void OnShareTargetUpdated(const nearby::sharing::ShareTarget& share_target)
|
||||
override {
|
||||
Listener listener_copy;
|
||||
{
|
||||
std::scoped_lock lock(listener_mutex);
|
||||
listener_copy = listener;
|
||||
}
|
||||
if (!listener_copy.target_updated_cb) {
|
||||
return;
|
||||
}
|
||||
listener_copy.target_updated_cb(ToShareTargetInfo(share_target));
|
||||
}
|
||||
|
||||
void OnTransferUpdate(
|
||||
const nearby::sharing::ShareTarget& share_target,
|
||||
const nearby::sharing::AttachmentContainer& attachment_container,
|
||||
const nearby::sharing::TransferMetadata& transfer_metadata) override {
|
||||
Listener listener_copy;
|
||||
{
|
||||
std::scoped_lock lock(listener_mutex);
|
||||
listener_copy = listener;
|
||||
}
|
||||
if (!listener_copy.transfer_update_cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
NearbySharingApi::TransferUpdateInfo info;
|
||||
info.share_target_id = share_target.id;
|
||||
info.device_name = share_target.device_name;
|
||||
info.is_incoming = share_target.is_incoming;
|
||||
info.status = ToFacadeTransferStatus(transfer_metadata.status());
|
||||
info.progress = NormalizeFacadeProgress(transfer_metadata.progress());
|
||||
info.transferred_bytes = transfer_metadata.transferred_bytes();
|
||||
info.total_attachments = transfer_metadata.total_attachments_count();
|
||||
info.transferred_attachments = transfer_metadata.transferred_attachments_count();
|
||||
if (!attachment_container.GetFileAttachments().empty()) {
|
||||
const nearby::sharing::FileAttachment& file =
|
||||
attachment_container.GetFileAttachments().front();
|
||||
info.first_file_name = std::string(file.file_name());
|
||||
if (file.file_path().has_value()) {
|
||||
info.first_file_path = file.file_path()->ToString();
|
||||
}
|
||||
}
|
||||
info.text_attachments.reserve(
|
||||
attachment_container.GetTextAttachments().size());
|
||||
for (const nearby::sharing::TextAttachment& text :
|
||||
attachment_container.GetTextAttachments()) {
|
||||
NearbySharingApi::TextAttachmentInfo text_info;
|
||||
text_info.type = ToFacadeTextAttachmentType(text.type());
|
||||
text_info.text_title = std::string(text.text_title());
|
||||
text_info.text_body = std::string(text.text_body());
|
||||
info.text_attachments.push_back(std::move(text_info));
|
||||
}
|
||||
listener_copy.transfer_update_cb(info);
|
||||
}
|
||||
|
||||
NearbySharingApi::ShareTargetInfo ToShareTargetInfo(
|
||||
const nearby::sharing::ShareTarget& share_target) {
|
||||
NearbySharingApi::ShareTargetInfo info;
|
||||
info.id = share_target.id;
|
||||
info.device_name = share_target.device_name;
|
||||
info.is_incoming = share_target.is_incoming;
|
||||
info.device_type = static_cast<int>(share_target.type);
|
||||
return info;
|
||||
}
|
||||
|
||||
nearby::sharing::analytics::AnalyticsRecorder analytics_recorder;
|
||||
std::string device_name_override;
|
||||
LinuxSharingPlatform platform;
|
||||
NativeService* service = nullptr;
|
||||
bool send_mode_started = false;
|
||||
bool receive_mode_started = false;
|
||||
std::string qr_code_url;
|
||||
std::mutex listener_mutex;
|
||||
NearbySharingApi::Listener listener;
|
||||
};
|
||||
|
||||
NearbySharingApi::NearbySharingApi() {
|
||||
EnableBleL2capDefaults();
|
||||
impl_ = std::make_unique<Impl>();
|
||||
}
|
||||
|
||||
NearbySharingApi::NearbySharingApi(std::string device_name_override)
|
||||
: impl_(nullptr) {
|
||||
EnableBleL2capDefaults();
|
||||
impl_ = std::make_unique<Impl>(std::move(device_name_override));
|
||||
}
|
||||
|
||||
NearbySharingApi::~NearbySharingApi() = default;
|
||||
|
||||
NearbySharingApi::NearbySharingApi(NearbySharingApi&&) noexcept = default;
|
||||
|
||||
NearbySharingApi& NearbySharingApi::operator=(NearbySharingApi&&) noexcept = default;
|
||||
|
||||
void NearbySharingApi::SetListener(Listener listener) {
|
||||
std::scoped_lock lock(impl_->listener_mutex);
|
||||
impl_->listener = std::move(listener);
|
||||
}
|
||||
|
||||
void NearbySharingApi::StartSendMode(std::function<void(StatusCode)> callback) {
|
||||
if (impl_->service == nullptr) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kError);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (impl_->send_mode_started) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kOk);
|
||||
}
|
||||
return;
|
||||
}
|
||||
impl_->service->RegisterSendSurface(
|
||||
impl_.get(), impl_.get(),
|
||||
nearby::sharing::NearbySharingService::SendSurfaceState::kForeground,
|
||||
nearby::sharing::Advertisement::BlockedVendorId::kNone,
|
||||
/*disable_wifi_hotspot=*/false,
|
||||
[this, cb = std::move(callback)](
|
||||
nearby::sharing::NearbySharingService::StatusCodes status) mutable {
|
||||
if (status == nearby::sharing::NearbySharingService::StatusCodes::kOk) {
|
||||
impl_->send_mode_started = true;
|
||||
}
|
||||
if (cb) {
|
||||
cb(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbySharingApi::StopSendMode(std::function<void(StatusCode)> callback) {
|
||||
if (impl_->service == nullptr) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kError);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!impl_->send_mode_started) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kStatusAlreadyStopped);
|
||||
}
|
||||
return;
|
||||
}
|
||||
impl_->service->UnregisterSendSurface(
|
||||
impl_.get(),
|
||||
[this, cb = std::move(callback)](
|
||||
nearby::sharing::NearbySharingService::StatusCodes status) mutable {
|
||||
if (status == nearby::sharing::NearbySharingService::StatusCodes::kOk) {
|
||||
impl_->send_mode_started = false;
|
||||
}
|
||||
if (cb) {
|
||||
cb(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbySharingApi::StartReceiveMode(std::function<void(StatusCode)> callback) {
|
||||
if (impl_->service == nullptr) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kError);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (impl_->receive_mode_started) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kOk);
|
||||
}
|
||||
return;
|
||||
}
|
||||
impl_->service->SetVisibility(
|
||||
nearby::sharing::proto::DeviceVisibility::DEVICE_VISIBILITY_EVERYONE,
|
||||
absl::Minutes(10),
|
||||
[this, cb = std::move(callback)](
|
||||
nearby::sharing::NearbySharingService::StatusCodes status) mutable {
|
||||
if (status != nearby::sharing::NearbySharingService::StatusCodes::kOk) {
|
||||
if (cb) {
|
||||
cb(ToFacadeStatus(status));
|
||||
}
|
||||
return;
|
||||
}
|
||||
impl_->service->RegisterReceiveSurface(
|
||||
impl_.get(),
|
||||
nearby::sharing::NearbySharingService::ReceiveSurfaceState::
|
||||
kForeground,
|
||||
nearby::sharing::Advertisement::BlockedVendorId::kNone,
|
||||
[this, cb = std::move(cb)](
|
||||
nearby::sharing::NearbySharingService::StatusCodes status)
|
||||
mutable {
|
||||
if (status ==
|
||||
nearby::sharing::NearbySharingService::StatusCodes::kOk) {
|
||||
impl_->receive_mode_started = true;
|
||||
}
|
||||
if (cb) {
|
||||
cb(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void NearbySharingApi::StopReceiveMode(std::function<void(StatusCode)> callback) {
|
||||
if (impl_->service == nullptr) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kError);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!impl_->receive_mode_started) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kStatusAlreadyStopped);
|
||||
}
|
||||
return;
|
||||
}
|
||||
impl_->service->UnregisterReceiveSurface(
|
||||
impl_.get(),
|
||||
[this, cb = std::move(callback)](
|
||||
nearby::sharing::NearbySharingService::StatusCodes status) mutable {
|
||||
if (status == nearby::sharing::NearbySharingService::StatusCodes::kOk) {
|
||||
impl_->receive_mode_started = false;
|
||||
}
|
||||
if (cb) {
|
||||
cb(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbySharingApi::SendFile(int64_t share_target_id,
|
||||
const std::string& file_path,
|
||||
std::function<void(StatusCode)> callback) {
|
||||
if (impl_->service == nullptr) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kError);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (file_path.empty()) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kInvalidArgument);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
FilePath path(file_path);
|
||||
std::optional<uintmax_t> file_size = nearby::Files::GetFileSize(path);
|
||||
if (!file_size.has_value() || *file_size == 0 ||
|
||||
*file_size >
|
||||
static_cast<uintmax_t>(std::numeric_limits<int64_t>::max())) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kInvalidArgument);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nearby::sharing::AttachmentContainer::Builder builder;
|
||||
nearby::sharing::FileAttachment attachment(path);
|
||||
attachment.set_size(static_cast<int64_t>(*file_size));
|
||||
builder.AddFileAttachment(std::move(attachment));
|
||||
std::unique_ptr<nearby::sharing::AttachmentContainer> attachments =
|
||||
builder.Build();
|
||||
if (!attachments || !attachments->HasAttachments()) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kInvalidArgument);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
impl_->service->SendAttachments(
|
||||
share_target_id, std::move(attachments),
|
||||
[cb = std::move(callback)](
|
||||
nearby::sharing::NearbySharingService::StatusCodes status) mutable {
|
||||
if (cb) {
|
||||
cb(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbySharingApi::Accept(int64_t share_target_id,
|
||||
std::function<void(StatusCode)> callback) {
|
||||
if (impl_->service == nullptr) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kError);
|
||||
}
|
||||
return;
|
||||
}
|
||||
impl_->service->Accept(
|
||||
share_target_id,
|
||||
[cb = std::move(callback)](
|
||||
nearby::sharing::NearbySharingService::StatusCodes status) mutable {
|
||||
if (cb) {
|
||||
cb(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbySharingApi::Reject(int64_t share_target_id,
|
||||
std::function<void(StatusCode)> callback) {
|
||||
if (impl_->service == nullptr) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kError);
|
||||
}
|
||||
return;
|
||||
}
|
||||
impl_->service->Reject(
|
||||
share_target_id,
|
||||
[cb = std::move(callback)](
|
||||
nearby::sharing::NearbySharingService::StatusCodes status) mutable {
|
||||
if (cb) {
|
||||
cb(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbySharingApi::Cancel(int64_t share_target_id,
|
||||
std::function<void(StatusCode)> callback) {
|
||||
if (impl_->service == nullptr) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kError);
|
||||
}
|
||||
return;
|
||||
}
|
||||
impl_->service->Cancel(
|
||||
share_target_id,
|
||||
[cb = std::move(callback)](
|
||||
nearby::sharing::NearbySharingService::StatusCodes status) mutable {
|
||||
if (cb) {
|
||||
cb(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NearbySharingApi::Set5GhzHotspotEnabled(bool enabled) {
|
||||
nearby::linux::Set5GhzHotspotEnabled(enabled);
|
||||
}
|
||||
|
||||
void NearbySharingApi::SetDeviceName(const std::string& device_name) {
|
||||
if (impl_->service == nullptr || device_name.empty()) {
|
||||
return;
|
||||
}
|
||||
if (impl_->service->GetLocalDeviceDataManager() == nullptr) {
|
||||
return;
|
||||
}
|
||||
impl_->service->GetLocalDeviceDataManager()->SetDeviceName(device_name);
|
||||
}
|
||||
|
||||
void NearbySharingApi::Shutdown(std::function<void(StatusCode)> callback) {
|
||||
if (impl_->service == nullptr) {
|
||||
if (callback) {
|
||||
callback(StatusCode::kError);
|
||||
}
|
||||
return;
|
||||
}
|
||||
impl_->service->Shutdown(
|
||||
[this, cb = std::move(callback)](
|
||||
nearby::sharing::NearbySharingService::StatusCodes status) mutable {
|
||||
if (status == nearby::sharing::NearbySharingService::StatusCodes::kOk) {
|
||||
impl_->send_mode_started = false;
|
||||
impl_->receive_mode_started = false;
|
||||
}
|
||||
if (cb) {
|
||||
cb(ToFacadeStatus(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::string NearbySharingApi::GetQrCodeUrl() const {
|
||||
if (impl_->qr_code_url.empty()) {
|
||||
impl_->qr_code_url = GenerateQrCodeUrl();
|
||||
}
|
||||
return impl_->qr_code_url;
|
||||
}
|
||||
|
||||
std::string NearbySharingApi::StatusCodeToString(StatusCode status) {
|
||||
switch (status) {
|
||||
case StatusCode::kOk:
|
||||
return "Ok";
|
||||
case StatusCode::kError:
|
||||
return "Error";
|
||||
case StatusCode::kOutOfOrderApiCall:
|
||||
return "OutOfOrderApiCall";
|
||||
case StatusCode::kStatusAlreadyStopped:
|
||||
return "StatusAlreadyStopped";
|
||||
case StatusCode::kTransferAlreadyInProgress:
|
||||
return "TransferAlreadyInProgress";
|
||||
case StatusCode::kNoAvailableConnectionMedium:
|
||||
return "NoAvailableConnectionMedium";
|
||||
case StatusCode::kIrrecoverableHardwareError:
|
||||
return "IrrecoverableHardwareError";
|
||||
case StatusCode::kInvalidArgument:
|
||||
return "InvalidArgument";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
|
||||
std::string NearbySharingApi::TransferStatusToString(TransferStatus status) {
|
||||
switch (status) {
|
||||
case TransferStatus::kUnknown:
|
||||
return "Unknown";
|
||||
case TransferStatus::kConnecting:
|
||||
return "Connecting";
|
||||
case TransferStatus::kAwaitingLocalConfirmation:
|
||||
return "AwaitingLocalConfirmation";
|
||||
case TransferStatus::kAwaitingRemoteAcceptance:
|
||||
return "AwaitingRemoteAcceptance";
|
||||
case TransferStatus::kInProgress:
|
||||
return "InProgress";
|
||||
case TransferStatus::kComplete:
|
||||
return "Complete";
|
||||
case TransferStatus::kFailed:
|
||||
return "Failed";
|
||||
case TransferStatus::kRejected:
|
||||
return "Rejected";
|
||||
case TransferStatus::kCancelled:
|
||||
return "Cancelled";
|
||||
case TransferStatus::kTimedOut:
|
||||
return "TimedOut";
|
||||
case TransferStatus::kMediaUnavailable:
|
||||
return "MediaUnavailable";
|
||||
case TransferStatus::kNotEnoughSpace:
|
||||
return "NotEnoughSpace";
|
||||
case TransferStatus::kUnsupportedAttachmentType:
|
||||
return "UnsupportedAttachmentType";
|
||||
case TransferStatus::kDeviceAuthenticationFailed:
|
||||
return "DeviceAuthenticationFailed";
|
||||
case TransferStatus::kIncompletePayloads:
|
||||
return "IncompletePayloads";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
} // namespace nearby::sharing
|
||||
@@ -1,131 +0,0 @@
|
||||
// Copyright 2026
|
||||
//
|
||||
// Thin app-facing API for NearbySharingServiceLinux that avoids exposing
|
||||
// internal Nearby headers to external consumers.
|
||||
|
||||
#ifndef SHARING_LINUX_NEARBY_SHARING_API_H_
|
||||
#define SHARING_LINUX_NEARBY_SHARING_API_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace nearby {
|
||||
namespace sharing {
|
||||
|
||||
class __attribute__((visibility("default"))) NearbySharingApi {
|
||||
public:
|
||||
enum class StatusCode {
|
||||
kOk = 0,
|
||||
kError = 1,
|
||||
kOutOfOrderApiCall = 2,
|
||||
kStatusAlreadyStopped = 3,
|
||||
kTransferAlreadyInProgress = 4,
|
||||
kNoAvailableConnectionMedium = 5,
|
||||
kIrrecoverableHardwareError = 6,
|
||||
kInvalidArgument = 7,
|
||||
};
|
||||
|
||||
enum class TransferStatus {
|
||||
kUnknown = 0,
|
||||
kConnecting = 1,
|
||||
kAwaitingLocalConfirmation = 2,
|
||||
kAwaitingRemoteAcceptance = 3,
|
||||
kInProgress = 4,
|
||||
kComplete = 5,
|
||||
kFailed = 6,
|
||||
kRejected = 7,
|
||||
kCancelled = 8,
|
||||
kTimedOut = 9,
|
||||
kMediaUnavailable = 10,
|
||||
kNotEnoughSpace = 11,
|
||||
kUnsupportedAttachmentType = 12,
|
||||
kDeviceAuthenticationFailed = 13,
|
||||
kIncompletePayloads = 14,
|
||||
};
|
||||
|
||||
enum class TextAttachmentType {
|
||||
kUnknown = 0,
|
||||
kText = 1,
|
||||
kUrl = 2,
|
||||
kPhoneNumber = 3,
|
||||
kAddress = 4,
|
||||
};
|
||||
|
||||
struct ShareTargetInfo {
|
||||
int64_t id = 0;
|
||||
std::string device_name;
|
||||
bool is_incoming = false;
|
||||
int device_type = 0;
|
||||
};
|
||||
|
||||
struct TextAttachmentInfo {
|
||||
TextAttachmentType type = TextAttachmentType::kUnknown;
|
||||
std::string text_title;
|
||||
std::string text_body;
|
||||
};
|
||||
|
||||
struct TransferUpdateInfo {
|
||||
int64_t share_target_id = 0;
|
||||
std::string device_name;
|
||||
bool is_incoming = false;
|
||||
TransferStatus status = TransferStatus::kUnknown;
|
||||
float progress = 0.0f;
|
||||
uint64_t transferred_bytes = 0;
|
||||
int total_attachments = 0;
|
||||
int transferred_attachments = 0;
|
||||
std::string first_file_name;
|
||||
std::string first_file_path;
|
||||
std::vector<TextAttachmentInfo> text_attachments;
|
||||
};
|
||||
|
||||
struct Listener {
|
||||
std::function<void(const ShareTargetInfo&)> target_discovered_cb;
|
||||
std::function<void(const ShareTargetInfo&)> target_updated_cb;
|
||||
std::function<void(int64_t)> target_lost_cb;
|
||||
std::function<void(const TransferUpdateInfo&)> transfer_update_cb;
|
||||
};
|
||||
|
||||
NearbySharingApi();
|
||||
explicit NearbySharingApi(std::string device_name_override);
|
||||
~NearbySharingApi();
|
||||
|
||||
NearbySharingApi(const NearbySharingApi&) = delete;
|
||||
NearbySharingApi& operator=(const NearbySharingApi&) = delete;
|
||||
NearbySharingApi(NearbySharingApi&&) noexcept;
|
||||
NearbySharingApi& operator=(NearbySharingApi&&) noexcept;
|
||||
|
||||
void SetListener(Listener listener);
|
||||
|
||||
void StartSendMode(std::function<void(StatusCode)> callback);
|
||||
void StopSendMode(std::function<void(StatusCode)> callback);
|
||||
|
||||
void StartReceiveMode(std::function<void(StatusCode)> callback);
|
||||
void StopReceiveMode(std::function<void(StatusCode)> callback);
|
||||
|
||||
void SendFile(int64_t share_target_id, const std::string& file_path,
|
||||
std::function<void(StatusCode)> callback);
|
||||
void Accept(int64_t share_target_id, std::function<void(StatusCode)> callback);
|
||||
void Reject(int64_t share_target_id, std::function<void(StatusCode)> callback);
|
||||
void Cancel(int64_t share_target_id, std::function<void(StatusCode)> callback);
|
||||
void Set5GhzHotspotEnabled(bool enabled);
|
||||
void SetDeviceName(const std::string& device_name);
|
||||
|
||||
void Shutdown(std::function<void(StatusCode)> callback);
|
||||
std::string GetQrCodeUrl() const;
|
||||
|
||||
static std::string StatusCodeToString(StatusCode status);
|
||||
static std::string TransferStatusToString(TransferStatus status);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
};
|
||||
|
||||
} // namespace sharing
|
||||
} // namespace nearby
|
||||
|
||||
#endif // SHARING_LINUX_NEARBY_SHARING_API_H_
|
||||
@@ -0,0 +1,102 @@
|
||||
// Copyright 2026 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 "sharing/linux/platform/linux_account_manager.h"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace nearby::sharing::linux::internal {
|
||||
namespace {
|
||||
|
||||
class FailedSigninAttempt final : public SigninAttempt {
|
||||
public:
|
||||
std::string Start(
|
||||
absl::AnyInvocable<void(AuthStatus, absl::string_view, absl::string_view,
|
||||
const AccountInfo&)>
|
||||
callback) override {
|
||||
if (callback) {
|
||||
std::move(callback)(UNSUPPORTED, "", "", AccountInfo{});
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void Close() override {}
|
||||
};
|
||||
|
||||
class LinuxAccountManager final : public AccountManager {
|
||||
public:
|
||||
std::optional<Account> GetCurrentAccount() override { return std::nullopt; }
|
||||
|
||||
std::unique_ptr<SigninAttempt> Login(absl::string_view client_id,
|
||||
absl::string_view client_secret)
|
||||
override {
|
||||
last_client_id_ = std::string(client_id);
|
||||
last_client_secret_ = std::string(client_secret);
|
||||
return std::make_unique<FailedSigninAttempt>();
|
||||
}
|
||||
|
||||
void Logout(absl::AnyInvocable<void(absl::Status)> logout_callback) override {
|
||||
if (logout_callback) {
|
||||
std::move(logout_callback)(absl::OkStatus());
|
||||
}
|
||||
}
|
||||
|
||||
bool GetAccessToken(
|
||||
absl::AnyInvocable<void(absl::StatusOr<std::string>)> callback)
|
||||
override {
|
||||
if (!callback) {
|
||||
return false;
|
||||
}
|
||||
std::move(callback)(
|
||||
absl::UnavailableError("Linux account integration is not available"));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> GetOAuthClientCredential() override {
|
||||
return {last_client_id_, last_client_secret_};
|
||||
}
|
||||
|
||||
void AddObserver(Observer* observer) override { observers_.insert(observer); }
|
||||
void RemoveObserver(Observer* observer) override {
|
||||
observers_.erase(observer);
|
||||
}
|
||||
|
||||
void SaveAccountPrefs(absl::string_view user_id, absl::string_view client_id,
|
||||
absl::string_view client_secret) override {
|
||||
static_cast<void>(user_id);
|
||||
last_client_id_ = std::string(client_id);
|
||||
last_client_secret_ = std::string(client_secret);
|
||||
}
|
||||
|
||||
private:
|
||||
absl::flat_hash_set<Observer*> observers_;
|
||||
std::string last_client_id_;
|
||||
std::string last_client_secret_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<AccountManager> CreateLinuxAccountManager() {
|
||||
return std::make_unique<LinuxAccountManager>();
|
||||
}
|
||||
|
||||
} // namespace nearby::sharing::linux::internal
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2026 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 SHARING_LINUX_PLATFORM_LINUX_ACCOUNT_MANAGER_H_
|
||||
#define SHARING_LINUX_PLATFORM_LINUX_ACCOUNT_MANAGER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "location/nearby/sharing/lib/account/account_manager.h"
|
||||
|
||||
namespace nearby::sharing::linux::internal {
|
||||
|
||||
std::unique_ptr<AccountManager> CreateLinuxAccountManager();
|
||||
|
||||
} // namespace nearby::sharing::linux::internal
|
||||
|
||||
#endif // SHARING_LINUX_PLATFORM_LINUX_ACCOUNT_MANAGER_H_
|
||||
@@ -0,0 +1,381 @@
|
||||
// Copyright 2026 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 "sharing/linux/platform/linux_platform_components.h"
|
||||
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/base/file_path.h"
|
||||
#include "internal/platform/mac_address.h"
|
||||
#include "sharing/internal/api/private_certificate_data.h"
|
||||
#include "sharing/linux/platform/platform_util.h"
|
||||
#include "sharing/proto/rpc_resources.pb.h"
|
||||
|
||||
namespace nearby::sharing::linux::internal {
|
||||
namespace {
|
||||
|
||||
using ::nearby::sharing::api::PreferenceManager;
|
||||
using ::nearby::sharing::api::PublicCertificateDatabase;
|
||||
using ::nearby::sharing::proto::PublicCertificate;
|
||||
|
||||
constexpr absl::string_view kAppFirstRunPref = "nearby_sharing.app.first_run";
|
||||
constexpr absl::string_view kAppActivePref = "nearby_sharing.app.active";
|
||||
|
||||
class LinuxNetworkMonitor final : public nearby::api::NetworkMonitor {
|
||||
public:
|
||||
LinuxNetworkMonitor(std::function<void(bool)> lan_connected_callback,
|
||||
std::function<void(bool)> internet_connected_callback)
|
||||
: nearby::api::NetworkMonitor(std::move(lan_connected_callback),
|
||||
std::move(internet_connected_callback)) {
|
||||
if (lan_connected_callback_) {
|
||||
lan_connected_callback_(IsLanConnected());
|
||||
}
|
||||
if (internet_connected_callback_) {
|
||||
internet_connected_callback_(IsInternetConnected());
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLanConnected() override { return HasNonLoopbackInterface(); }
|
||||
bool IsInternetConnected() override { return HasNonLoopbackInterface(); }
|
||||
};
|
||||
|
||||
class LinuxSystemInfo final : public nearby::api::SystemInfo {
|
||||
public:
|
||||
std::string GetComputerManufacturer() override { return "Unknown"; }
|
||||
std::string GetComputerModel() override { return "Unknown"; }
|
||||
int64_t GetComputerPhysicalMemory() override {
|
||||
struct sysinfo info;
|
||||
if (sysinfo(&info) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int64_t>(info.totalram) * info.mem_unit;
|
||||
}
|
||||
int GetComputerProcessorCount() override {
|
||||
long processors = sysconf(_SC_NPROCESSORS_CONF);
|
||||
return processors > 0 ? static_cast<int>(processors) : 1;
|
||||
}
|
||||
int GetComputerLogicProcessorCount() override {
|
||||
long processors = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return processors > 0 ? static_cast<int>(processors) : 1;
|
||||
}
|
||||
int GetProcessorMemoryInfo() override { return 0; }
|
||||
BatteryChargeStatus QueryBatteryInfo(int& seconds, int& percent,
|
||||
bool& battery_saver) override {
|
||||
seconds = 0;
|
||||
percent = 0;
|
||||
battery_saver = false;
|
||||
return BatteryChargeStatus::UNKNOWN;
|
||||
}
|
||||
std::string GetOsManufacturer() override { return "Linux"; }
|
||||
std::string GetOsName() override { return "Linux"; }
|
||||
std::string GetOsVersion() override {
|
||||
struct utsname info;
|
||||
return uname(&info) == 0 ? std::string(info.release) : std::string();
|
||||
}
|
||||
std::string GetOsArchitecture() override {
|
||||
struct utsname info;
|
||||
return uname(&info) == 0 ? std::string(info.machine) : std::string();
|
||||
}
|
||||
std::string GetOsLanguage() override {
|
||||
return GetLanguageCode().value_or("en");
|
||||
}
|
||||
std::string GetProcessorManufacturer() override { return "Unknown"; }
|
||||
std::string GetProcessorName() override { return "Unknown"; }
|
||||
std::list<DriverInfo> GetBluetoothDriverInfos() override { return {}; }
|
||||
std::list<DriverInfo> GetNetworkDriverInfos() override { return {}; }
|
||||
void GetBatteryUsageReport(const FilePath& save_path) override {
|
||||
static_cast<void>(save_path);
|
||||
}
|
||||
};
|
||||
|
||||
class LinuxAppInfo final : public nearby::api::AppInfo {
|
||||
public:
|
||||
explicit LinuxAppInfo(PreferenceManager& preference_manager)
|
||||
: preference_manager_(preference_manager) {}
|
||||
|
||||
std::optional<std::string> GetAppVersion() override {
|
||||
return std::string("linux");
|
||||
}
|
||||
std::optional<std::string> GetAppLanguage() override {
|
||||
return GetLanguageCode();
|
||||
}
|
||||
std::optional<std::string> GetUpdateTrack() override { return std::nullopt; }
|
||||
std::optional<std::string> GetAppInstallSource() override {
|
||||
return std::string("manual");
|
||||
}
|
||||
bool GetFirstRunDone() override {
|
||||
return preference_manager_.GetBoolean(kAppFirstRunPref, false);
|
||||
}
|
||||
bool SetFirstRunDone(bool value) override {
|
||||
preference_manager_.SetBoolean(kAppFirstRunPref, value);
|
||||
return true;
|
||||
}
|
||||
bool SetActiveFlag() override {
|
||||
preference_manager_.SetBoolean(kAppActivePref, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
PreferenceManager& preference_manager_;
|
||||
};
|
||||
|
||||
class LinuxDeviceInfo final : public nearby::api::DeviceInfo {
|
||||
public:
|
||||
std::optional<std::string> GetOsDeviceName() const override {
|
||||
char hostname[256] = {};
|
||||
if (gethostname(hostname, sizeof(hostname)) == 0 && hostname[0] != '\0') {
|
||||
return std::string(hostname);
|
||||
}
|
||||
return std::string("Linux");
|
||||
}
|
||||
DeviceType GetDeviceType() const override { return DeviceType::kLaptop; }
|
||||
OsType GetOsType() const override { return OsType::kUnknown; }
|
||||
FilePath GetDownloadPath() const override {
|
||||
const char* xdg_download_dir = std::getenv("XDG_DOWNLOAD_DIR");
|
||||
if (xdg_download_dir != nullptr && *xdg_download_dir != '\0') {
|
||||
return FilePath(std::string(xdg_download_dir));
|
||||
}
|
||||
return BuildPathFromBase(GetHomeDirectory(), {"Downloads"});
|
||||
}
|
||||
FilePath GetLocalAppDataPath(FilePath sub_path) const override {
|
||||
std::string config_home = GetEnvOrDefault(
|
||||
"XDG_CONFIG_HOME",
|
||||
BuildPathFromBase(GetHomeDirectory(), {".config"}).ToString());
|
||||
FilePath path = BuildPathFromBase(config_home, {"Google Nearby"});
|
||||
if (!sub_path.IsEmpty()) {
|
||||
path.append(sub_path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
FilePath GetTemporaryPath() const override {
|
||||
const char* runtime_dir = std::getenv("XDG_RUNTIME_DIR");
|
||||
if (runtime_dir != nullptr && *runtime_dir != '\0') {
|
||||
return BuildPathFromBase(runtime_dir, {"Google Nearby"});
|
||||
}
|
||||
return BuildPathFromBase("/tmp", {"Google Nearby"});
|
||||
}
|
||||
FilePath GetLogPath() const override {
|
||||
return GetLocalAppDataPath(FilePath("logs"));
|
||||
}
|
||||
bool IsScreenLocked() const override { return false; }
|
||||
void RegisterScreenLockedListener(
|
||||
absl::string_view listener_name,
|
||||
std::function<void(ScreenStatus)> callback) override {
|
||||
screen_locked_listeners_[std::string(listener_name)] = std::move(callback);
|
||||
}
|
||||
void UnregisterScreenLockedListener(
|
||||
absl::string_view listener_name) override {
|
||||
screen_locked_listeners_.erase(std::string(listener_name));
|
||||
}
|
||||
bool PreventSleep() override { return true; }
|
||||
bool AllowSleep() override { return true; }
|
||||
|
||||
private:
|
||||
mutable absl::flat_hash_map<std::string, std::function<void(ScreenStatus)>>
|
||||
screen_locked_listeners_;
|
||||
};
|
||||
|
||||
class LinuxBluetoothAdapter final : public api::BluetoothAdapter {
|
||||
public:
|
||||
explicit LinuxBluetoothAdapter(
|
||||
std::shared_ptr<::nearby::linux::BluetoothAdapter> adapter)
|
||||
: adapter_(std::move(adapter)) {}
|
||||
|
||||
bool IsPresent() const override { return GetAddress().IsSet(); }
|
||||
bool IsPowered() const override {
|
||||
return adapter_ != nullptr && adapter_->IsEnabled();
|
||||
}
|
||||
bool IsLowEnergySupported() const override { return adapter_ != nullptr; }
|
||||
bool IsScanOffloadSupported() const override { return false; }
|
||||
bool IsAdvertisementOffloadSupported() const override { return false; }
|
||||
bool IsExtendedAdvertisingSupported() const override { return false; }
|
||||
bool IsPeripheralRoleSupported() const override { return adapter_ != nullptr; }
|
||||
PermissionStatus GetOsPermissionStatus() const override {
|
||||
return adapter_ != nullptr ? PermissionStatus::kAllowed
|
||||
: PermissionStatus::kSystemDenied;
|
||||
}
|
||||
void SetPowered(bool powered, std::function<void()> success_callback,
|
||||
std::function<void()> error_callback) override {
|
||||
if (adapter_ == nullptr) {
|
||||
if (error_callback) {
|
||||
error_callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
bool success = adapter_->SetStatus(
|
||||
powered ? nearby::api::BluetoothAdapter::Status::kEnabled
|
||||
: nearby::api::BluetoothAdapter::Status::kDisabled);
|
||||
if (success) {
|
||||
if (success_callback) {
|
||||
success_callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (error_callback) {
|
||||
error_callback();
|
||||
}
|
||||
}
|
||||
std::optional<std::string> GetAdapterId() const override {
|
||||
if (adapter_ == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::string name = adapter_->GetName();
|
||||
return name.empty() ? std::nullopt : std::make_optional(name);
|
||||
}
|
||||
MacAddress GetAddress() const override {
|
||||
return adapter_ != nullptr ? adapter_->GetMacAddress() : MacAddress();
|
||||
}
|
||||
void AddObserver(Observer* observer) override { observers_.insert(observer); }
|
||||
void RemoveObserver(Observer* observer) override {
|
||||
observers_.erase(observer);
|
||||
}
|
||||
bool HasObserver(Observer* observer) override {
|
||||
return observers_.contains(observer);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<::nearby::linux::BluetoothAdapter> adapter_;
|
||||
absl::flat_hash_set<Observer*> observers_;
|
||||
};
|
||||
|
||||
class LinuxPublicCertificateDatabase final : public PublicCertificateDatabase {
|
||||
public:
|
||||
void Initialize(absl::AnyInvocable<void(InitStatus) &&> callback) override {
|
||||
if (callback) {
|
||||
std::move(callback)(InitStatus::kOk);
|
||||
}
|
||||
}
|
||||
void LoadEntries(
|
||||
absl::AnyInvocable<void(bool, std::unique_ptr<std::vector<
|
||||
PublicCertificate>>) &&>
|
||||
callback) override {
|
||||
auto certificates = std::make_unique<std::vector<PublicCertificate>>();
|
||||
{
|
||||
absl::MutexLock lock(mutex_);
|
||||
for (const auto& [id, certificate] : entries_) {
|
||||
static_cast<void>(id);
|
||||
certificates->push_back(certificate);
|
||||
}
|
||||
}
|
||||
if (callback) {
|
||||
std::move(callback)(true, std::move(certificates));
|
||||
}
|
||||
}
|
||||
void LoadCertificate(
|
||||
absl::string_view id,
|
||||
absl::AnyInvocable<void(bool, std::unique_ptr<PublicCertificate>) &&>
|
||||
callback) override {
|
||||
auto certificate = std::make_unique<PublicCertificate>();
|
||||
bool found = false;
|
||||
{
|
||||
absl::MutexLock lock(mutex_);
|
||||
auto it = entries_.find(std::string(id));
|
||||
if (it != entries_.end()) {
|
||||
*certificate = it->second;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (callback) {
|
||||
std::move(callback)(found, found ? std::move(certificate) : nullptr);
|
||||
}
|
||||
}
|
||||
void AddCertificates(absl::Span<const PublicCertificate> certificates,
|
||||
absl::AnyInvocable<void(bool) &&> callback) override {
|
||||
{
|
||||
absl::MutexLock lock(mutex_);
|
||||
for (const PublicCertificate& certificate : certificates) {
|
||||
entries_[certificate.secret_id()] = certificate;
|
||||
}
|
||||
}
|
||||
if (callback) {
|
||||
std::move(callback)(true);
|
||||
}
|
||||
}
|
||||
void RemoveCertificatesById(
|
||||
std::vector<std::string> ids_to_remove,
|
||||
absl::AnyInvocable<void(bool) &&> callback) override {
|
||||
{
|
||||
absl::MutexLock lock(mutex_);
|
||||
for (const std::string& id : ids_to_remove) {
|
||||
entries_.erase(id);
|
||||
}
|
||||
}
|
||||
if (callback) {
|
||||
std::move(callback)(true);
|
||||
}
|
||||
}
|
||||
void Destroy(absl::AnyInvocable<void(bool) &&> callback) override {
|
||||
{
|
||||
absl::MutexLock lock(mutex_);
|
||||
entries_.clear();
|
||||
}
|
||||
if (callback) {
|
||||
std::move(callback)(true);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
absl::Mutex mutex_;
|
||||
std::map<std::string, PublicCertificate> entries_ ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<nearby::api::NetworkMonitor> CreateLinuxNetworkMonitor(
|
||||
std::function<void(bool)> lan_connected_callback,
|
||||
std::function<void(bool)> internet_connected_callback) {
|
||||
return std::make_unique<LinuxNetworkMonitor>(
|
||||
std::move(lan_connected_callback), std::move(internet_connected_callback));
|
||||
}
|
||||
|
||||
std::unique_ptr<nearby::api::SystemInfo> CreateLinuxSystemInfo() {
|
||||
return std::make_unique<LinuxSystemInfo>();
|
||||
}
|
||||
|
||||
std::unique_ptr<nearby::api::AppInfo> CreateLinuxAppInfo(
|
||||
api::PreferenceManager& preference_manager) {
|
||||
return std::make_unique<LinuxAppInfo>(preference_manager);
|
||||
}
|
||||
|
||||
std::unique_ptr<nearby::api::DeviceInfo> CreateLinuxDeviceInfo() {
|
||||
return std::make_unique<LinuxDeviceInfo>();
|
||||
}
|
||||
|
||||
std::unique_ptr<api::BluetoothAdapter> CreateLinuxBluetoothAdapter(
|
||||
std::shared_ptr<::nearby::linux::BluetoothAdapter> adapter) {
|
||||
return std::make_unique<LinuxBluetoothAdapter>(std::move(adapter));
|
||||
}
|
||||
|
||||
std::unique_ptr<api::PublicCertificateDatabase>
|
||||
CreateLinuxPublicCertificateDatabase() {
|
||||
return std::make_unique<LinuxPublicCertificateDatabase>();
|
||||
}
|
||||
|
||||
} // namespace nearby::sharing::linux::internal
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2026 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 SHARING_LINUX_PLATFORM_LINUX_PLATFORM_COMPONENTS_H_
|
||||
#define SHARING_LINUX_PLATFORM_LINUX_PLATFORM_COMPONENTS_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "internal/platform/implementation/device_info.h"
|
||||
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
|
||||
#include "sharing/internal/api/app_info.h"
|
||||
#include "sharing/internal/api/bluetooth_adapter.h"
|
||||
#include "sharing/internal/api/network_monitor.h"
|
||||
#include "sharing/internal/api/preference_manager.h"
|
||||
#include "sharing/internal/api/public_certificate_database.h"
|
||||
#include "sharing/internal/api/system_info.h"
|
||||
|
||||
namespace nearby::sharing::linux::internal {
|
||||
|
||||
std::unique_ptr<nearby::api::NetworkMonitor> CreateLinuxNetworkMonitor(
|
||||
std::function<void(bool)> lan_connected_callback,
|
||||
std::function<void(bool)> internet_connected_callback);
|
||||
std::unique_ptr<nearby::api::SystemInfo> CreateLinuxSystemInfo();
|
||||
std::unique_ptr<nearby::api::AppInfo> CreateLinuxAppInfo(
|
||||
api::PreferenceManager& preference_manager);
|
||||
std::unique_ptr<nearby::api::DeviceInfo> CreateLinuxDeviceInfo();
|
||||
std::unique_ptr<api::BluetoothAdapter> CreateLinuxBluetoothAdapter(
|
||||
std::shared_ptr<::nearby::linux::BluetoothAdapter> adapter);
|
||||
std::unique_ptr<api::PublicCertificateDatabase>
|
||||
CreateLinuxPublicCertificateDatabase();
|
||||
|
||||
} // namespace nearby::sharing::linux::internal
|
||||
|
||||
#endif // SHARING_LINUX_PLATFORM_LINUX_PLATFORM_COMPONENTS_H_
|
||||
@@ -0,0 +1,410 @@
|
||||
// Copyright 2026 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 "sharing/linux/platform/linux_preference_manager.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/implementation/platform.h"
|
||||
#include "location/nearby/sharing/lib/sync/sync_binding_prefs.pb.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "sharing/internal/api/private_certificate_data.h"
|
||||
#include "sharing/internal/public/pref_names.h"
|
||||
|
||||
namespace nearby::sharing::linux::internal {
|
||||
namespace {
|
||||
|
||||
using Json = nlohmann::json;
|
||||
using ::nearby::sharing::api::PreferenceManager;
|
||||
using ::nearby::sharing::api::PrivateCertificateData;
|
||||
|
||||
constexpr absl::string_view kPreferencesFile = "nearby_sharing_linux.json";
|
||||
constexpr absl::string_view kFileSyncBindingName = "FileSync";
|
||||
|
||||
Json ToJson(const PrivateCertificateData& certificate) {
|
||||
return Json{
|
||||
{PrivateCertificateData::kVisibility, certificate.visibility},
|
||||
{PrivateCertificateData::kNotBefore, certificate.not_before},
|
||||
{PrivateCertificateData::kNotAfter, certificate.not_after},
|
||||
{PrivateCertificateData::kKeyPair, certificate.key_pair},
|
||||
{PrivateCertificateData::kSecretKey, certificate.secret_key},
|
||||
{PrivateCertificateData::kMetadataEncryptionKey,
|
||||
certificate.metadata_encryption_key},
|
||||
{PrivateCertificateData::kId, certificate.id},
|
||||
{PrivateCertificateData::kUnencryptedMetadata,
|
||||
certificate.unencrypted_metadata_proto},
|
||||
{PrivateCertificateData::kConsumedSalts, certificate.consumed_salts},
|
||||
};
|
||||
}
|
||||
|
||||
std::optional<PrivateCertificateData> FromJson(const Json& value) {
|
||||
if (!value.is_object()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
PrivateCertificateData certificate;
|
||||
try {
|
||||
certificate.visibility = value.at(PrivateCertificateData::kVisibility);
|
||||
certificate.not_before = value.at(PrivateCertificateData::kNotBefore);
|
||||
certificate.not_after = value.at(PrivateCertificateData::kNotAfter);
|
||||
certificate.key_pair = value.at(PrivateCertificateData::kKeyPair);
|
||||
certificate.secret_key = value.at(PrivateCertificateData::kSecretKey);
|
||||
certificate.metadata_encryption_key =
|
||||
value.at(PrivateCertificateData::kMetadataEncryptionKey);
|
||||
certificate.id = value.at(PrivateCertificateData::kId);
|
||||
certificate.unencrypted_metadata_proto =
|
||||
value.at(PrivateCertificateData::kUnencryptedMetadata);
|
||||
certificate.consumed_salts =
|
||||
value.at(PrivateCertificateData::kConsumedSalts);
|
||||
return certificate;
|
||||
} catch (const Json::exception&) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
class LinuxPreferenceManager final : public PreferenceManager {
|
||||
public:
|
||||
LinuxPreferenceManager()
|
||||
: storage_(nearby::api::ImplementationPlatform::CreatePreferencesManager(
|
||||
kPreferencesFile)) {}
|
||||
|
||||
void SetBoolean(absl::string_view key, bool value) override {
|
||||
if (storage_ != nullptr && storage_->SetBoolean(key, value)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetInteger(absl::string_view key, int value) override {
|
||||
if (storage_ != nullptr && storage_->SetInteger(key, value)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetInt64(absl::string_view key, int64_t value) override {
|
||||
if (storage_ != nullptr && storage_->SetInt64(key, value)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetString(absl::string_view key, absl::string_view value) override {
|
||||
if (storage_ != nullptr && storage_->SetString(key, value)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetTime(absl::string_view key, absl::Time value) override {
|
||||
if (storage_ != nullptr && storage_->SetTime(key, value)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetBooleanArray(absl::string_view key,
|
||||
absl::Span<const bool> value) override {
|
||||
if (storage_ != nullptr && storage_->SetBooleanArray(key, value)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetIntegerArray(absl::string_view key,
|
||||
absl::Span<const int> value) override {
|
||||
if (storage_ != nullptr && storage_->SetIntegerArray(key, value)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetInt64Array(absl::string_view key,
|
||||
absl::Span<const int64_t> value) override {
|
||||
if (storage_ != nullptr && storage_->SetInt64Array(key, value)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetStringArray(absl::string_view key,
|
||||
absl::Span<const std::string> value) override {
|
||||
if (storage_ != nullptr && storage_->SetStringArray(key, value)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetPrivateCertificateArray(
|
||||
absl::string_view key, absl::Span<const PrivateCertificateData> value)
|
||||
override {
|
||||
Json certificates = Json::array();
|
||||
for (const PrivateCertificateData& certificate : value) {
|
||||
certificates.push_back(ToJson(certificate));
|
||||
}
|
||||
if (storage_ != nullptr && storage_->Set(key, certificates)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetCertificateExpirationArray(
|
||||
absl::string_view key,
|
||||
absl::Span<const std::pair<std::string, int64_t>> value) override {
|
||||
Json expirations = Json::array();
|
||||
for (const auto& [id, expiration] : value) {
|
||||
expirations.push_back(Json{{"id", id}, {"expiration", expiration}});
|
||||
}
|
||||
if (storage_ != nullptr && storage_->Set(key, expirations)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetDictionaryBooleanValue(absl::string_view key,
|
||||
absl::string_view dictionary_item,
|
||||
bool value) override {
|
||||
SetDictionaryValue(key, dictionary_item, value);
|
||||
}
|
||||
void SetDictionaryIntegerValue(absl::string_view key,
|
||||
absl::string_view dictionary_item,
|
||||
int value) override {
|
||||
SetDictionaryValue(key, dictionary_item, value);
|
||||
}
|
||||
void SetDictionaryInt64Value(absl::string_view key,
|
||||
absl::string_view dictionary_item,
|
||||
int64_t value) override {
|
||||
SetDictionaryValue(key, dictionary_item, value);
|
||||
}
|
||||
void SetDictionaryStringValue(absl::string_view key,
|
||||
absl::string_view dictionary_item,
|
||||
std::string value) override {
|
||||
SetDictionaryValue(key, dictionary_item, std::move(value));
|
||||
}
|
||||
void RemoveDictionaryItem(absl::string_view key,
|
||||
absl::string_view dictionary_item) override {
|
||||
if (storage_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
Json dictionary = storage_->Get(key, Json::object());
|
||||
if (!dictionary.is_object()) {
|
||||
return;
|
||||
}
|
||||
dictionary.erase(std::string(dictionary_item));
|
||||
if (storage_->Set(key, dictionary)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void SetSyncBindingValue(
|
||||
const nearby::sharing::sync::SyncBindingPrefs& value) override {
|
||||
std::string serialized;
|
||||
if (value.SerializeToString(&serialized)) {
|
||||
SetString(absl::StrCat(PrefNames::kBindingConfigPrefix,
|
||||
kFileSyncBindingName),
|
||||
serialized);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetBoolean(absl::string_view key, bool default_value) const override {
|
||||
return storage_ != nullptr ? storage_->GetBoolean(key, default_value)
|
||||
: default_value;
|
||||
}
|
||||
int GetInteger(absl::string_view key, int default_value) const override {
|
||||
return storage_ != nullptr ? storage_->GetInteger(key, default_value)
|
||||
: default_value;
|
||||
}
|
||||
int64_t GetInt64(absl::string_view key,
|
||||
int64_t default_value) const override {
|
||||
return storage_ != nullptr ? storage_->GetInt64(key, default_value)
|
||||
: default_value;
|
||||
}
|
||||
std::string GetString(absl::string_view key,
|
||||
const std::string& default_value) const override {
|
||||
return storage_ != nullptr ? storage_->GetString(key, default_value)
|
||||
: default_value;
|
||||
}
|
||||
absl::Time GetTime(absl::string_view key,
|
||||
absl::Time default_value) const override {
|
||||
return storage_ != nullptr ? storage_->GetTime(key, default_value)
|
||||
: default_value;
|
||||
}
|
||||
std::vector<bool> GetBooleanArray(
|
||||
absl::string_view key,
|
||||
absl::Span<const bool> default_value) const override {
|
||||
return storage_ != nullptr ? storage_->GetBooleanArray(key, default_value)
|
||||
: std::vector<bool>(default_value.begin(),
|
||||
default_value.end());
|
||||
}
|
||||
std::vector<int> GetIntegerArray(
|
||||
absl::string_view key,
|
||||
absl::Span<const int> default_value) const override {
|
||||
return storage_ != nullptr ? storage_->GetIntegerArray(key, default_value)
|
||||
: std::vector<int>(default_value.begin(),
|
||||
default_value.end());
|
||||
}
|
||||
std::vector<int64_t> GetInt64Array(
|
||||
absl::string_view key,
|
||||
absl::Span<const int64_t> default_value) const override {
|
||||
return storage_ != nullptr ? storage_->GetInt64Array(key, default_value)
|
||||
: std::vector<int64_t>(default_value.begin(),
|
||||
default_value.end());
|
||||
}
|
||||
std::vector<std::string> GetStringArray(
|
||||
absl::string_view key,
|
||||
absl::Span<const std::string> default_value) const override {
|
||||
return storage_ != nullptr ? storage_->GetStringArray(key, default_value)
|
||||
: std::vector<std::string>(default_value.begin(),
|
||||
default_value.end());
|
||||
}
|
||||
std::vector<PrivateCertificateData> GetPrivateCertificateArray(
|
||||
absl::string_view key) const override {
|
||||
std::vector<PrivateCertificateData> result;
|
||||
if (storage_ == nullptr) {
|
||||
return result;
|
||||
}
|
||||
Json certificates = storage_->Get(key, Json::array());
|
||||
if (!certificates.is_array()) {
|
||||
return result;
|
||||
}
|
||||
for (const Json& certificate_json : certificates) {
|
||||
std::optional<PrivateCertificateData> certificate =
|
||||
FromJson(certificate_json);
|
||||
if (certificate.has_value()) {
|
||||
result.push_back(*certificate);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
std::vector<std::pair<std::string, int64_t>>
|
||||
GetCertificateExpirationArray(absl::string_view key) const override {
|
||||
std::vector<std::pair<std::string, int64_t>> result;
|
||||
if (storage_ == nullptr) {
|
||||
return result;
|
||||
}
|
||||
Json expirations = storage_->Get(key, Json::array());
|
||||
if (!expirations.is_array()) {
|
||||
return result;
|
||||
}
|
||||
for (const Json& item : expirations) {
|
||||
if (!item.is_object()) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
result.emplace_back(item.at("id").get<std::string>(),
|
||||
item.at("expiration").get<int64_t>());
|
||||
} catch (const Json::exception&) {
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
std::optional<bool> GetDictionaryBooleanValue(
|
||||
absl::string_view key, absl::string_view dictionary_item) const override {
|
||||
return GetDictionaryValue<bool>(key, dictionary_item);
|
||||
}
|
||||
std::optional<int> GetDictionaryIntegerValue(
|
||||
absl::string_view key, absl::string_view dictionary_item) const override {
|
||||
return GetDictionaryValue<int>(key, dictionary_item);
|
||||
}
|
||||
std::optional<int64_t> GetDictionaryInt64Value(
|
||||
absl::string_view key, absl::string_view dictionary_item) const override {
|
||||
return GetDictionaryValue<int64_t>(key, dictionary_item);
|
||||
}
|
||||
std::optional<std::string> GetDictionaryStringValue(
|
||||
absl::string_view key, absl::string_view dictionary_item) const override {
|
||||
return GetDictionaryValue<std::string>(key, dictionary_item);
|
||||
}
|
||||
std::optional<nearby::sharing::sync::SyncBindingPrefs> GetSyncBindingValue()
|
||||
const override {
|
||||
std::string serialized =
|
||||
GetString(absl::StrCat(PrefNames::kBindingConfigPrefix,
|
||||
kFileSyncBindingName),
|
||||
"");
|
||||
if (serialized.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
nearby::sharing::sync::SyncBindingPrefs value;
|
||||
if (!value.ParseFromString(serialized)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
void Remove(absl::string_view key) override {
|
||||
if (storage_ != nullptr) {
|
||||
storage_->Remove(key);
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
void RemoveAllBindingConfigs() override {
|
||||
if (storage_ != nullptr &&
|
||||
storage_->RemoveKeyPrefix(PrefNames::kBindingConfigPrefix)) {
|
||||
NotifyPreferenceChanged(PrefNames::kBindingConfigPrefix);
|
||||
}
|
||||
}
|
||||
void AddObserver(
|
||||
absl::string_view name,
|
||||
std::function<void(absl::string_view pref_name)> observer) override {
|
||||
observers_[std::string(name)] = std::move(observer);
|
||||
}
|
||||
void RemoveObserver(absl::string_view name) override {
|
||||
observers_.erase(std::string(name));
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void SetDictionaryValue(absl::string_view key,
|
||||
absl::string_view dictionary_item, T value) {
|
||||
if (storage_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
Json dictionary = storage_->Get(key, Json::object());
|
||||
if (!dictionary.is_object()) {
|
||||
dictionary = Json::object();
|
||||
}
|
||||
dictionary[std::string(dictionary_item)] = std::move(value);
|
||||
if (storage_->Set(key, dictionary)) {
|
||||
NotifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::optional<T> GetDictionaryValue(
|
||||
absl::string_view key, absl::string_view dictionary_item) const {
|
||||
if (storage_ == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
Json dictionary = storage_->Get(key, Json::object());
|
||||
if (!dictionary.is_object()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto it = dictionary.find(std::string(dictionary_item));
|
||||
if (it == dictionary.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
try {
|
||||
return it->get<T>();
|
||||
} catch (const Json::exception&) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyPreferenceChanged(absl::string_view key) {
|
||||
for (const auto& [name, observer] : observers_) {
|
||||
static_cast<void>(name);
|
||||
if (observer) {
|
||||
observer(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<nearby::api::PreferencesManager> storage_;
|
||||
absl::flat_hash_map<std::string,
|
||||
std::function<void(absl::string_view pref_name)>>
|
||||
observers_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<api::PreferenceManager> CreateLinuxPreferenceManager() {
|
||||
return std::make_unique<LinuxPreferenceManager>();
|
||||
}
|
||||
|
||||
} // namespace nearby::sharing::linux::internal
|
||||
+8
-11
@@ -12,20 +12,17 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef THIRD_PARTY_NEARBY_SHARING_LINUX_STUBS_HIGHWAY_FINGERPRINT_H_
|
||||
#define THIRD_PARTY_NEARBY_SHARING_LINUX_STUBS_HIGHWAY_FINGERPRINT_H_
|
||||
#ifndef SHARING_LINUX_PLATFORM_LINUX_PREFERENCE_MANAGER_H_
|
||||
#define SHARING_LINUX_PLATFORM_LINUX_PREFERENCE_MANAGER_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "absl/hash/hash.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "sharing/internal/api/preference_manager.h"
|
||||
|
||||
namespace util_hash {
|
||||
namespace nearby::sharing::linux::internal {
|
||||
|
||||
inline uint64_t HighwayFingerprint64(absl::string_view input) {
|
||||
return absl::Hash<absl::string_view>{}(input);
|
||||
}
|
||||
std::unique_ptr<api::PreferenceManager> CreateLinuxPreferenceManager();
|
||||
|
||||
} // namespace util_hash
|
||||
} // namespace nearby::sharing::linux::internal
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_SHARING_LINUX_STUBS_HIGHWAY_FINGERPRINT_H_
|
||||
#endif // SHARING_LINUX_PLATFORM_LINUX_PREFERENCE_MANAGER_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,30 @@
|
||||
// Copyright 2026
|
||||
// Copyright 2026 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_SHARING_LINUX_PLATFORM_LINUX_SHARING_PLATFORM_H_
|
||||
#define THIRD_PARTY_NEARBY_SHARING_LINUX_PLATFORM_LINUX_SHARING_PLATFORM_H_
|
||||
#ifndef SHARING_LINUX_PLATFORM_LINUX_SHARING_PLATFORM_H_
|
||||
#define SHARING_LINUX_PLATFORM_LINUX_SHARING_PLATFORM_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/base/file_path.h"
|
||||
#include "internal/platform/device_info.h"
|
||||
#include "internal/platform/implementation/account_manager.h"
|
||||
#include "internal/platform/task_runner.h"
|
||||
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
|
||||
#include "location/nearby/sharing/lib/account/account_manager.h"
|
||||
#include "sharing/internal/api/sharing_platform.h"
|
||||
|
||||
namespace nearby::sharing {
|
||||
namespace nearby::sharing::linux {
|
||||
|
||||
class LinuxSharingPlatform final : public nearby::sharing::api::SharingPlatform {
|
||||
class LinuxSharingPlatform final : public api::SharingPlatform {
|
||||
public:
|
||||
LinuxSharingPlatform();
|
||||
explicit LinuxSharingPlatform(std::string device_name_override);
|
||||
@@ -33,32 +40,33 @@ class LinuxSharingPlatform final : public nearby::sharing::api::SharingPlatform
|
||||
std::function<void(bool)> lan_connected_callback,
|
||||
std::function<void(bool)> internet_connected_callback) override;
|
||||
|
||||
nearby::sharing::api::BluetoothAdapter& GetBluetoothAdapter() override;
|
||||
api::BluetoothAdapter& GetBluetoothAdapter() override;
|
||||
nearby::api::FastInitBleBeacon& GetFastInitBleBeacon() override;
|
||||
nearby::api::FastInitiationManager& GetFastInitiationManager() override;
|
||||
std::unique_ptr<nearby::api::SystemInfo> CreateSystemInfo() override;
|
||||
std::unique_ptr<nearby::api::AppInfo> CreateAppInfo() override;
|
||||
nearby::sharing::api::PreferenceManager& GetPreferenceManager() override;
|
||||
api::PreferenceManager& GetPreferenceManager() override;
|
||||
AccountManager& GetAccountManager() override;
|
||||
TaskRunner& GetDefaultTaskRunner() override;
|
||||
nearby::DeviceInfo& GetDeviceInfo() override;
|
||||
std::unique_ptr<nearby::sharing::api::PublicCertificateDatabase>
|
||||
nearby::api::DeviceInfo& GetDeviceInfo() override;
|
||||
std::unique_ptr<api::PublicCertificateDatabase>
|
||||
CreatePublicCertificateDatabase(const FilePath& database_path) override;
|
||||
bool UpdateFileOriginMetadata(std::vector<FilePath>& file_paths) override;
|
||||
|
||||
private:
|
||||
void Initialize(std::string device_name_override);
|
||||
|
||||
std::unique_ptr<nearby::sharing::api::PreferenceManager> preference_manager_;
|
||||
std::shared_ptr<::nearby::linux::BluetoothAdapter> fast_init_adapter_;
|
||||
std::unique_ptr<api::PreferenceManager> preference_manager_;
|
||||
std::unique_ptr<AccountManager> account_manager_;
|
||||
std::unique_ptr<nearby::sharing::api::BluetoothAdapter> bluetooth_adapter_;
|
||||
std::unique_ptr<api::BluetoothAdapter> bluetooth_adapter_;
|
||||
std::unique_ptr<nearby::api::FastInitBleBeacon> fast_init_ble_beacon_;
|
||||
std::unique_ptr<nearby::api::FastInitiationManager> fast_initiation_manager_;
|
||||
std::unique_ptr<TaskRunner> default_task_runner_;
|
||||
std::unique_ptr<nearby::DeviceInfo> device_info_;
|
||||
std::unique_ptr<nearby::api::FastInitiationManager>
|
||||
fast_initiation_manager_;
|
||||
std::unique_ptr<nearby::api::DeviceInfo> device_info_;
|
||||
absl::string_view (*product_id_getter_)() = nullptr;
|
||||
};
|
||||
|
||||
} // namespace nearby::sharing::linux
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_SHARING_LINUX_PLATFORM_LINUX_SHARING_PLATFORM_H_
|
||||
#endif // SHARING_LINUX_PLATFORM_LINUX_SHARING_PLATFORM_H_
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright 2026 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 "sharing/linux/platform/platform_util.h"
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <sdbus-c++/Error.h>
|
||||
|
||||
#include "internal/platform/implementation/linux/bluez.h"
|
||||
#include "internal/platform/implementation/linux/dbus.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby::sharing::linux::internal {
|
||||
|
||||
std::string GetEnvOrDefault(const char* key, std::string fallback) {
|
||||
const char* value = std::getenv(key);
|
||||
if (value == nullptr || *value == '\0') {
|
||||
return fallback;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string GetHomeDirectory() { return GetEnvOrDefault("HOME", "/tmp"); }
|
||||
|
||||
FilePath BuildPathFromBase(const std::string& base,
|
||||
std::initializer_list<std::string> components) {
|
||||
std::filesystem::path path(base);
|
||||
for (const std::string& component : components) {
|
||||
path /= component;
|
||||
}
|
||||
return FilePath(path.string());
|
||||
}
|
||||
|
||||
std::optional<std::string> GetLanguageCode() {
|
||||
const char* lang = std::getenv("LANG");
|
||||
if (lang == nullptr || *lang == '\0') {
|
||||
return std::string("en");
|
||||
}
|
||||
std::string value(lang);
|
||||
size_t dot = value.find('.');
|
||||
if (dot != std::string::npos) {
|
||||
value.resize(dot);
|
||||
}
|
||||
size_t underscore = value.find('_');
|
||||
if (underscore != std::string::npos) {
|
||||
value.resize(underscore);
|
||||
}
|
||||
if (value.empty()) {
|
||||
return std::string("en");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool HasNonLoopbackInterface() {
|
||||
struct ifaddrs* interfaces = nullptr;
|
||||
if (getifaddrs(&interfaces) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool connected = false;
|
||||
for (struct ifaddrs* current = interfaces; current != nullptr;
|
||||
current = current->ifa_next) {
|
||||
if (current->ifa_name == nullptr || current->ifa_flags == 0) {
|
||||
continue;
|
||||
}
|
||||
if ((current->ifa_flags & IFF_UP) == 0 ||
|
||||
(current->ifa_flags & IFF_LOOPBACK) != 0) {
|
||||
continue;
|
||||
}
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
|
||||
freeifaddrs(interfaces);
|
||||
return connected;
|
||||
}
|
||||
|
||||
std::shared_ptr<::nearby::linux::BluetoothAdapter>
|
||||
CreateFastInitBluetoothAdapter() {
|
||||
auto system_bus = ::nearby::linux::getSystemBusConnection();
|
||||
auto manager = ::nearby::linux::bluez::BluezObjectManager(*system_bus);
|
||||
try {
|
||||
auto interfaces = manager.GetManagedObjects();
|
||||
for (auto& [object, properties] : interfaces) {
|
||||
if (properties.count(sdbus::InterfaceName(
|
||||
org::bluez::Adapter1_proxy::INTERFACE_NAME)) == 1) {
|
||||
LOG(INFO) << __func__ << ": found bluetooth adapter " << object;
|
||||
return std::make_shared<::nearby::linux::BluetoothAdapter>(system_bus,
|
||||
object);
|
||||
}
|
||||
}
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(&manager, "GetManagedObjects", e);
|
||||
}
|
||||
|
||||
LOG(WARNING) << __func__
|
||||
<< ": couldn't find a bluetooth adapter on this system";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace nearby::sharing::linux::internal
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright 2026 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 SHARING_LINUX_PLATFORM_PLATFORM_UTIL_H_
|
||||
#define SHARING_LINUX_PLATFORM_PLATFORM_UTIL_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "internal/base/file_path.h"
|
||||
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
|
||||
|
||||
namespace nearby::sharing::linux::internal {
|
||||
|
||||
std::string GetEnvOrDefault(const char* key, std::string fallback);
|
||||
std::string GetHomeDirectory();
|
||||
FilePath BuildPathFromBase(const std::string& base,
|
||||
std::initializer_list<std::string> components);
|
||||
std::optional<std::string> GetLanguageCode();
|
||||
bool HasNonLoopbackInterface();
|
||||
|
||||
std::shared_ptr<::nearby::linux::BluetoothAdapter>
|
||||
CreateFastInitBluetoothAdapter();
|
||||
|
||||
} // namespace nearby::sharing::linux::internal
|
||||
|
||||
#endif // SHARING_LINUX_PLATFORM_PLATFORM_UTIL_H_
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright 2026
|
||||
|
||||
#include "internal/platform/system_clock.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace nearby {
|
||||
|
||||
void SystemClock::Init() {}
|
||||
|
||||
absl::Time SystemClock::ElapsedRealtime() {
|
||||
return absl::FromUnixNanos(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch())
|
||||
.count());
|
||||
}
|
||||
|
||||
Exception SystemClock::Sleep(absl::Duration duration) {
|
||||
absl::SleepFor(duration);
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
@@ -1,41 +0,0 @@
|
||||
load("@rules_cc//cc:cc_library.bzl", "cc_library")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
cc_library(
|
||||
name = "rpc",
|
||||
hdrs = [
|
||||
"grpc_async_client_factory.h",
|
||||
"identity_rpc_types.h",
|
||||
"sharing_rpc_client.h",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//internal/platform/implementation:account_manager",
|
||||
"//sharing/analytics",
|
||||
"//sharing/proto:share_cc_proto",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_protobuf//:protobuf",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "sync",
|
||||
hdrs = ["sync_manager.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//sharing/internal/api:platform",
|
||||
"@com_google_absl//absl/strings:string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "highway_fingerprint",
|
||||
hdrs = ["highway_fingerprint.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"@com_google_absl//absl/hash",
|
||||
"@com_google_absl//absl/strings:string_view",
|
||||
],
|
||||
)
|
||||
@@ -1,86 +0,0 @@
|
||||
// Copyright 2026 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_SHARING_LINUX_STUBS_GRPC_ASYNC_CLIENT_FACTORY_H_
|
||||
#define THIRD_PARTY_NEARBY_SHARING_LINUX_STUBS_GRPC_ASYNC_CLIENT_FACTORY_H_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "internal/platform/clock.h"
|
||||
#include "internal/platform/implementation/account_manager.h"
|
||||
#include "sharing/analytics/analytics_recorder.h"
|
||||
#include "sharing/linux/stubs/sharing_rpc_client.h"
|
||||
|
||||
namespace nearby::sharing::platform::common {
|
||||
namespace internal {
|
||||
|
||||
class NoOpSharingRpcClient : public nearby::sharing::api::SharingRpcClient {
|
||||
public:
|
||||
void ListContactPeople(
|
||||
nearby::sharing::proto::ListContactPeopleRequest request,
|
||||
ListContactPeopleCallback callback) override {
|
||||
static_cast<void>(request);
|
||||
callback(nearby::sharing::proto::ListContactPeopleResponse());
|
||||
}
|
||||
};
|
||||
|
||||
class NoOpIdentityRpcClient : public nearby::sharing::api::IdentityRpcClient {
|
||||
public:
|
||||
void QuerySharedCredentials(
|
||||
google::nearby::identity::v1::QuerySharedCredentialsRequest request,
|
||||
QuerySharedCredentialsCallback callback) override {
|
||||
static_cast<void>(request);
|
||||
callback(google::nearby::identity::v1::QuerySharedCredentialsResponse());
|
||||
}
|
||||
|
||||
void PublishDevice(
|
||||
google::nearby::identity::v1::PublishDeviceRequest request,
|
||||
PublishDeviceCallback callback) override {
|
||||
static_cast<void>(request);
|
||||
callback(google::nearby::identity::v1::PublishDeviceResponse());
|
||||
}
|
||||
|
||||
void GetAccountInfo(
|
||||
google::nearby::identity::v1::GetAccountInfoRequest request,
|
||||
GetAccountInfoCallback callback) override {
|
||||
static_cast<void>(request);
|
||||
callback(google::nearby::identity::v1::GetAccountInfoResponse());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
class GrpcAsyncClientFactory {
|
||||
public:
|
||||
GrpcAsyncClientFactory(AccountManager* account_manager, Clock* clock,
|
||||
analytics::AnalyticsRecorder* analytics_recorder) {
|
||||
static_cast<void>(account_manager);
|
||||
static_cast<void>(clock);
|
||||
static_cast<void>(analytics_recorder);
|
||||
}
|
||||
|
||||
std::unique_ptr<nearby::sharing::api::SharingRpcClient> CreateInstance() {
|
||||
return std::make_unique<internal::NoOpSharingRpcClient>();
|
||||
}
|
||||
|
||||
std::unique_ptr<nearby::sharing::api::IdentityRpcClient>
|
||||
CreateIdentityInstance() {
|
||||
return std::make_unique<internal::NoOpIdentityRpcClient>();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nearby::sharing::platform::common
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_SHARING_LINUX_STUBS_GRPC_ASYNC_CLIENT_FACTORY_H_
|
||||
@@ -1,208 +0,0 @@
|
||||
// Copyright 2026 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_SHARING_LINUX_STUBS_IDENTITY_RPC_TYPES_H_
|
||||
#define THIRD_PARTY_NEARBY_SHARING_LINUX_STUBS_IDENTITY_RPC_TYPES_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "google/protobuf/timestamp.pb.h"
|
||||
|
||||
namespace google::nearby::identity::v1 {
|
||||
|
||||
class SharedCredential {
|
||||
public:
|
||||
enum DataType {
|
||||
DATA_TYPE_UNKNOWN = 0,
|
||||
DATA_TYPE_PUBLIC_CERTIFICATE = 1,
|
||||
};
|
||||
|
||||
void set_id(uint64_t id) { id_ = id; }
|
||||
uint64_t id() const { return id_; }
|
||||
|
||||
void set_data(std::string data) { data_ = std::move(data); }
|
||||
const std::string& data() const { return data_; }
|
||||
|
||||
void set_data_type(DataType data_type) { data_type_ = data_type; }
|
||||
DataType data_type() const { return data_type_; }
|
||||
|
||||
google::protobuf::Timestamp* mutable_expiration_time() {
|
||||
return &expiration_time_;
|
||||
}
|
||||
const google::protobuf::Timestamp& expiration_time() const {
|
||||
return expiration_time_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t id_ = 0;
|
||||
std::string data_;
|
||||
DataType data_type_ = DATA_TYPE_UNKNOWN;
|
||||
google::protobuf::Timestamp expiration_time_;
|
||||
};
|
||||
|
||||
class PerVisibilitySharedCredentials {
|
||||
public:
|
||||
enum Visibility {
|
||||
VISIBILITY_UNKNOWN = 0,
|
||||
VISIBILITY_SELF = 1,
|
||||
VISIBILITY_CONTACTS = 2,
|
||||
};
|
||||
|
||||
void set_visibility(Visibility visibility) { visibility_ = visibility; }
|
||||
Visibility visibility() const { return visibility_; }
|
||||
|
||||
SharedCredential* add_shared_credentials() {
|
||||
shared_credentials_.emplace_back();
|
||||
return &shared_credentials_.back();
|
||||
}
|
||||
const std::vector<SharedCredential>& shared_credentials() const {
|
||||
return shared_credentials_;
|
||||
}
|
||||
|
||||
private:
|
||||
Visibility visibility_ = VISIBILITY_UNKNOWN;
|
||||
std::vector<SharedCredential> shared_credentials_;
|
||||
};
|
||||
|
||||
class Device {
|
||||
public:
|
||||
enum Contact {
|
||||
CONTACT_UNKNOWN = 0,
|
||||
CONTACT_GOOGLE_CONTACT = 1,
|
||||
CONTACT_GOOGLE_CONTACT_LATEST = 2,
|
||||
};
|
||||
|
||||
void set_name(std::string name) { name_ = std::move(name); }
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
void set_display_name(std::string display_name) {
|
||||
display_name_ = std::move(display_name);
|
||||
}
|
||||
const std::string& display_name() const { return display_name_; }
|
||||
|
||||
void set_contact(Contact contact) { contact_ = contact; }
|
||||
Contact contact() const { return contact_; }
|
||||
|
||||
PerVisibilitySharedCredentials* add_per_visibility_shared_credentials() {
|
||||
per_visibility_shared_credentials_.emplace_back();
|
||||
return &per_visibility_shared_credentials_.back();
|
||||
}
|
||||
const std::vector<PerVisibilitySharedCredentials>&
|
||||
per_visibility_shared_credentials() const {
|
||||
return per_visibility_shared_credentials_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::string display_name_;
|
||||
Contact contact_ = CONTACT_UNKNOWN;
|
||||
std::vector<PerVisibilitySharedCredentials> per_visibility_shared_credentials_;
|
||||
};
|
||||
|
||||
class QuerySharedCredentialsRequest {
|
||||
public:
|
||||
void set_name(std::string name) { name_ = std::move(name); }
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
void set_page_token(std::string page_token) {
|
||||
page_token_ = std::move(page_token);
|
||||
}
|
||||
const std::string& page_token() const { return page_token_; }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::string page_token_;
|
||||
};
|
||||
|
||||
class QuerySharedCredentialsResponse {
|
||||
public:
|
||||
SharedCredential* add_shared_credentials() {
|
||||
shared_credentials_.emplace_back();
|
||||
return &shared_credentials_.back();
|
||||
}
|
||||
const std::vector<SharedCredential>& shared_credentials() const {
|
||||
return shared_credentials_;
|
||||
}
|
||||
|
||||
void set_next_page_token(std::string next_page_token) {
|
||||
next_page_token_ = std::move(next_page_token);
|
||||
}
|
||||
const std::string& next_page_token() const { return next_page_token_; }
|
||||
|
||||
private:
|
||||
std::vector<SharedCredential> shared_credentials_;
|
||||
std::string next_page_token_;
|
||||
};
|
||||
|
||||
class PublishDeviceRequest {
|
||||
public:
|
||||
Device* mutable_device() { return &device_; }
|
||||
const Device& device() const { return device_; }
|
||||
|
||||
private:
|
||||
Device device_;
|
||||
};
|
||||
|
||||
class PublishDeviceResponse {
|
||||
public:
|
||||
enum ContactUpdate {
|
||||
CONTACT_UPDATE_UNKNOWN = 0,
|
||||
CONTACT_UPDATE_REMOVED = 1,
|
||||
};
|
||||
|
||||
void add_contact_updates(ContactUpdate contact_update) {
|
||||
contact_updates_.push_back(contact_update);
|
||||
}
|
||||
const std::vector<ContactUpdate>& contact_updates() const {
|
||||
return contact_updates_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<ContactUpdate> contact_updates_;
|
||||
};
|
||||
|
||||
class GetAccountInfoRequest {};
|
||||
|
||||
class AccountInfo {
|
||||
public:
|
||||
enum Capability {
|
||||
CAPABILITY_UNKNOWN = 0,
|
||||
CAPABILITY_TITANIUM = 1,
|
||||
};
|
||||
|
||||
void add_capabilities(Capability capability) {
|
||||
capabilities_.push_back(capability);
|
||||
}
|
||||
const std::vector<Capability>& capabilities() const { return capabilities_; }
|
||||
|
||||
private:
|
||||
std::vector<Capability> capabilities_;
|
||||
};
|
||||
|
||||
class GetAccountInfoResponse {
|
||||
public:
|
||||
AccountInfo* mutable_account_info() { return &account_info_; }
|
||||
const AccountInfo& account_info() const { return account_info_; }
|
||||
|
||||
private:
|
||||
AccountInfo account_info_;
|
||||
};
|
||||
|
||||
} // namespace google::nearby::identity::v1
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_SHARING_LINUX_STUBS_IDENTITY_RPC_TYPES_H_
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright 2026 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_SHARING_LINUX_STUBS_SHARING_RPC_CLIENT_H_
|
||||
#define THIRD_PARTY_NEARBY_SHARING_LINUX_STUBS_SHARING_RPC_CLIENT_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "absl/status/statusor.h"
|
||||
#include "sharing/linux/stubs/identity_rpc_types.h"
|
||||
#include "sharing/proto/contact_rpc.pb.h"
|
||||
|
||||
namespace nearby::sharing::api {
|
||||
|
||||
class SharingRpcClient {
|
||||
public:
|
||||
using ListContactPeopleCallback = std::function<void(
|
||||
const absl::StatusOr<nearby::sharing::proto::ListContactPeopleResponse>&)>;
|
||||
|
||||
virtual ~SharingRpcClient() = default;
|
||||
|
||||
virtual void ListContactPeople(
|
||||
nearby::sharing::proto::ListContactPeopleRequest request,
|
||||
ListContactPeopleCallback callback) = 0;
|
||||
};
|
||||
|
||||
class IdentityRpcClient {
|
||||
public:
|
||||
using QuerySharedCredentialsCallback = std::function<void(
|
||||
const absl::StatusOr<
|
||||
google::nearby::identity::v1::QuerySharedCredentialsResponse>&)>;
|
||||
using PublishDeviceCallback = std::function<void(
|
||||
const absl::StatusOr<google::nearby::identity::v1::PublishDeviceResponse>&)>;
|
||||
using GetAccountInfoCallback = std::function<void(
|
||||
const absl::StatusOr<
|
||||
google::nearby::identity::v1::GetAccountInfoResponse>&)>;
|
||||
|
||||
virtual ~IdentityRpcClient() = default;
|
||||
|
||||
virtual void QuerySharedCredentials(
|
||||
google::nearby::identity::v1::QuerySharedCredentialsRequest request,
|
||||
QuerySharedCredentialsCallback callback) = 0;
|
||||
|
||||
virtual void PublishDevice(
|
||||
google::nearby::identity::v1::PublishDeviceRequest request,
|
||||
PublishDeviceCallback callback) = 0;
|
||||
|
||||
virtual void GetAccountInfo(
|
||||
google::nearby::identity::v1::GetAccountInfoRequest request,
|
||||
GetAccountInfoCallback callback) = 0;
|
||||
};
|
||||
|
||||
} // namespace nearby::sharing::api
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_SHARING_LINUX_STUBS_SHARING_RPC_CLIENT_H_
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright 2026 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_SHARING_LINUX_STUBS_SYNC_MANAGER_H_
|
||||
#define THIRD_PARTY_NEARBY_SHARING_LINUX_STUBS_SYNC_MANAGER_H_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "sharing/internal/api/preference_manager.h"
|
||||
|
||||
namespace nearby::sharing {
|
||||
|
||||
class SyncManager {
|
||||
public:
|
||||
explicit SyncManager(api::PreferenceManager* preference_manager)
|
||||
: preference_manager_(preference_manager) {}
|
||||
|
||||
bool IsFileSyncBinding(absl::string_view binding_id) const {
|
||||
static_cast<void>(binding_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<nearby::sharing::sync::SyncConfigPrefs> GetSyncConfig(
|
||||
absl::string_view binding_id) const {
|
||||
static_cast<void>(binding_id);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
api::PreferenceManager* preference_manager_;
|
||||
};
|
||||
|
||||
} // namespace nearby::sharing
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_SHARING_LINUX_STUBS_SYNC_MANAGER_H_
|
||||
Reference in New Issue
Block a user