Skip to main content

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.aar and edge.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() and getScannerAdapter() 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
ComponentPurpose
DeviceManagerEntry point. Discovers BLE devices and creates adapters.
DeviceConnectionRepresents a device to connect to — either discovered via BLE or constructed for serial.
DeviceAdapterYour connected device. Use this for connection management and to get feature adapters.
PrinterAdapterPrint labels using templates.
ScannerAdapterScan 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:

GuideWhat You'll Learn
Resource ManagementUpload templates and fonts
PrintingPrint labels with templates
ScanningScan barcodes
CallbacksMonitor connection and printer status
LoggingSet up debugging and monitoring
Error HandlingHandle failures gracefully