Getting Started
You'll go from zero to connected device in about 15 minutes. This guide covers everything you need to set up the SDK and establish your first connection.
Requirements
Before you begin, ensure you have:
- Android Studio (latest version recommended)
- Android device or emulator running Android 7.1 (API Level 25) or higher
- Bluetooth support on your device
- Pathfinder Edge device powered on and in pairing mode
- SDK files:
addevicemanager.aarandedge.aar
Step 1: Add the SDK to Your Project
Copy the Library Files
Place both AAR files in your app's libs/ folder:
your-app/
└── app/
└── libs/
├── addevicemanager.aar
└── edge.aar
Configure Gradle
Open app/build.gradle and add the dependencies:
dependencies {
// AD Device Manager SDK
implementation(files("libs/addevicemanager.aar"))
// Required dependencies for AD Device Manager SDK
implementation(files("libs/edge.aar"))
implementation 'org.slf4j:slf4j-api:2.0.17'
// Logback for logging (optional but recommended)
implementation 'com.github.tony19:logback-android:3.0.0'
// ... your other dependencies
}
Click Sync Now in Android Studio to apply the changes.
Step 2: Handle Android Permissions
Android requires runtime permissions for Bluetooth operations. Your app must declare permissions in the manifest and request them from the user at runtime.
Declare Permissions in AndroidManifest.xml
Add these inside the <manifest> tag:
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Request Permissions at Runtime
Here's a complete, production-ready example using ActivityResultLauncher:
import android.Manifest;
import android.content.pm.PackageManager;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class ConnectionFragment extends Fragment {
private final ActivityResultLauncher<String[]> permissionLauncher =
registerForActivityResult(
new ActivityResultContracts.RequestMultiplePermissions(),
result -> {
if (!result.containsValue(false)) {
// All permissions granted — proceed with Bluetooth operations
startDeviceDiscovery();
} else {
// Some permissions denied
Toast.makeText(getContext(),
"Bluetooth permissions are required to connect.",
Toast.LENGTH_LONG).show();
}
}
);
private void checkPermissionsAndSearch() {
List<String> permissions = new ArrayList<>();
permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
permissions.add(Manifest.permission.BLUETOOTH_SCAN);
permissions.add(Manifest.permission.BLUETOOTH_CONNECT);
}
List<String> needed = new ArrayList<>();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED) {
needed.add(permission);
}
}
if (needed.isEmpty()) {
// Already have all permissions
startDeviceDiscovery();
} else {
// Request missing permissions
permissionLauncher.launch(needed.toArray(new String[0]));
}
}
private void startDeviceDiscovery() {
// Implemented in next section
}
}
Step 3: Connect to a Device
The SDK supports two connection methods: BLE (wireless, for companion devices) and Serial (for integrated or USB-connected devices). Choose the one that matches your hardware setup.
Import SDK Classes
import com.averydennison.addevicemanager.DeviceManager;
import com.averydennison.addevicemanager.adapters.DeviceAdapter;
import com.averydennison.addevicemanager.adapters.PrinterAdapter;
import com.averydennison.addevicemanager.adapters.ScannerAdapter;
import com.averydennison.addevicemanager.callbacks.DiscoveryCallback;
import com.averydennison.addevicemanager.connection.DeviceConnection;
import com.averydennison.addevicemanager.connection.SerialConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Initialize DeviceManager
private DeviceManager deviceManager;
private List<DeviceConnection> discoveredDevices = new ArrayList<>();
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Pass activity or application context
deviceManager = new DeviceManager(requireContext());
}
Option A: Connect via BLE
BLE is the recommended method for companion (wireless) devices. After permissions are granted (see Step 2), start scanning for nearby devices:
private void startDeviceDiscovery() {
discoveredDevices.clear();
updateStatus("Scanning for devices...");
deviceManager.startBluetoothDiscovery(new DiscoveryCallback() {
@Override
public void onDeviceFound(DeviceConnection device) {
logger.info("Found device: {}", device.getName());
discoveredDevices.add(device);
// Update your UI — show device in a list
updateDeviceList();
}
@Override
public void onDiscoveryFinished() {
logger.info("Discovery complete. Found {} devices.", discoveredDevices.size());
// Let user pick which device to connect to
showDeviceSelectionUI();
}
@Override
public void onDiscoveryFailed(Exception error) {
logger.error("Discovery failed: {}", error.getMessage());
showError("Failed to scan for devices: " + error.getMessage());
}
});
}
Tip: Discovery typically takes 10–15 seconds. Show a progress indicator so users know something's happening.
You can stop discovery early (e.g. when the user taps a device in the list):
deviceManager.stopBluetoothDiscovery();
Option B: Connect via Serial
For integrated or USB-connected devices, skip discovery entirely and connect directly using a SerialConnection:
private void connectViaSerial() {
DeviceConnection deviceConnection = new SerialConnection(
DeviceConnection.PrinterType.EDGE, "PF Edge Printer");
connectToDevice(deviceConnection);
}
Note: Serial connections do not require Bluetooth permissions.
Step 4: Connect to a Device
Once you have a DeviceConnection — either selected from BLE discovery or constructed for serial — connect to it:
private DeviceAdapter deviceAdapter;
private void connectToDevice(DeviceConnection device) {
deviceAdapter = deviceManager.getAdapterForDevice(device);
deviceAdapter.connect()
.thenAccept(unused -> {
logger.info("Connected to {}", device.getName());
runOnUiThread(() -> {
showStatus("Connected");
setupAdapters();
});
})
.exceptionally(error -> {
logger.error("Connection failed: {}", error.getMessage());
runOnUiThread(() -> showError("Connection failed: " + error.getMessage()));
return null;
});
}
If you need to upload a template or resource immediately after connecting, chain it with .thenRunAsync() before proceeding:
deviceAdapter.connect()
.thenRunAsync(this::uploadPrintTemplate)
.thenAccept(unused -> {
setupAdapters();
})
.exceptionally(error -> {
showError("Setup failed: " + error.getMessage());
return null;
});
Step 5: Get Feature Adapters
Once connected, retrieve the printer and scanner adapters and wire up any callbacks:
private PrinterAdapter printerAdapter;
private ScannerAdapter scannerAdapter;
private void setupAdapters() {
try {
printerAdapter = deviceAdapter.getPrinterAdapter();
scannerAdapter = deviceAdapter.getScannerAdapter();
// Register a persistent scan callback for hardware button presses
scannerAdapter.setScanCallback(new ScanCallback() {
@Override
public void onScanSuccess(ScannedData scannedData) {
runOnUiThread(() -> handleScannedBarcode(scannedData.data));
}
@Override
public void onScanFailure(String errorMessage) {
logger.warn("Scan failed: {}", errorMessage);
}
});
logger.info("Adapters initialized");
} catch (Exception e) {
logger.error("Failed to initialize adapters: {}", e.getMessage());
}
}
Note: Both
getPrinterAdapter()andgetScannerAdapter()will throw if the connected device does not support that feature. Wrap them in a try/catch as shown above, or check device capabilities before calling.
Understanding the Object Model
Here's how the SDK components fit together:
DeviceManager
│
├── startBluetoothDiscovery() → DeviceConnection (one per found BLE device)
│
├── new SerialConnection(...) → DeviceConnection (for serial/USB devices)
│
└── getAdapterForDevice(connection) → DeviceAdapter
│
├── getPrinterAdapter() → PrinterAdapter
│
└── getScannerAdapter() → ScannerAdapter
| Component | Purpose |
|---|---|
| DeviceManager | Entry point. Discovers BLE devices and creates adapters. |
| DeviceConnection | Represents a device to connect to — either discovered via BLE or constructed for serial. |
| DeviceAdapter | Your connected device. Use this for connection management and to get feature adapters. |
| PrinterAdapter | Print labels using templates. |
| ScannerAdapter | Scan barcodes and configure symbologies. |
Error Handling
The SDK uses CompletableFuture for async operations. Handle errors with .exceptionally():
deviceAdapter.connect()
.thenAccept(unused -> {
// Success path
logger.info("Connected!");
})
.exceptionally(error -> {
// Error path
logger.error("Something went wrong: {}", error.getMessage());
return null; // Required to complete the future
});
Chaining Operations
Chain multiple operations together. A single .exceptionally() at the end catches errors from any step:
deviceAdapter.connect()
.thenCompose(unused -> {
// Connection succeeded, now register resources
return deviceAdapter.registerResources("PrintResources", true, progressCallback);
})
.thenCompose(unused -> {
// Resources registered, now print
return deviceAdapter.getPrinterAdapter().print("Label.ngt", "DATA=test", 1);
})
.thenAccept(unused -> {
logger.info("Connected, registered resources, and printed!");
})
.exceptionally(error -> {
// Catches errors from connect(), registerResources(), OR print()
logger.error("Operation failed: {}", error.getMessage());
return null;
});
Disconnecting
Always clean up all adapter references when disconnecting:
private void disconnect() {
if (deviceAdapter != null) {
deviceAdapter.disconnect();
deviceAdapter = null;
printerAdapter = null;
scannerAdapter = null;
}
}
Lifecycle Integration
Disconnect in onDestroy() to avoid resource leaks:
@Override
protected void onDestroy() {
super.onDestroy();
if (deviceAdapter != null) {
deviceAdapter.disconnect();
}
}
Common Issues
Discovery finds nothing
- Is Bluetooth enabled on your Android device?
- Is the Pathfinder Edge powered on and in range?
- Did you grant all required permissions?
Connection fails immediately
- Ensure you're not already connected from another app
- Try power-cycling the Pathfinder Edge
- Check that the device is within Bluetooth range
Permission dialog never appears
- Verify permissions are declared in
AndroidManifest.xml - On Android 12+, you need all three permissions listed above
- Try uninstalling and reinstalling the app
Next Steps
You're connected! Now explore the SDK features:
| Guide | What You'll Learn |
|---|---|
| Resource Management | Upload templates and fonts |
| Printing | Print labels with templates |
| Scanning | Scan barcodes |
| Callbacks | Monitor connection and printer status |
| Logging | Set up debugging and monitoring |
| Error Handling | Handle failures gracefully |