Skip to main content

Quick Start: Zero to Print

This guide gets you from nothing to printing a label in the shortest time possible. We'll cover the most important use case: scan a barcode, look up product information, and print a label.

By the end of this guide, you'll have working code that:

  1. Connects to a Pathfinder Edge device
  2. Scans a product barcode
  3. Looks up product information
  4. Prints a price label

Prerequisites

Before you begin, ensure you have:

  • ✅ Android Studio installed
  • ✅ An Android device (7.1+) with Bluetooth enabled
  • ✅ A Pathfinder Edge device powered on
  • ✅ The SDK files: addevicemanager.aar and edge.aar

Step 1: Project Setup (2 minutes)

Add the SDK Libraries

  1. Copy addevicemanager.aar and edge.aar into your project's app/libs/ folder
  2. Open app/build.gradle and add:
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'

// ... your other dependencies
}
  1. Click Sync Now in Android Studio

Add Bluetooth Permissions

Open app/src/main/AndroidManifest.xml and add 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" />

Step 2: Create the Layout (1 minute)

Create or update app/src/main/res/layout/activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:padding="16dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<RadioButton
android:id="@+id/bleRadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="BLE" />

<RadioButton
android:id="@+id/serialRadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Serial" />

</RadioGroup>

<TextView
android:id="@+id/statusText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="Ready to connect"
android:textSize="18sp" />

<Button
android:id="@+id/searchButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Scan for Devices" />

<Button
android:id="@+id/serialConnectButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Connect via Serial"
android:visibility="gone" />

<Button
android:id="@+id/disconnectButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Disconnect"
android:visibility="gone" />

<Button
android:id="@+id/scanButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
android:text="Scan Barcode" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false">

<EditText
android:id="@+id/inputField"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Text to Print" />

<Button
android:id="@+id/printButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:text="Print" />

</LinearLayout>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="4dp"
android:text="Available Devices:"
android:textStyle="bold" />

<ListView
android:id="@+id/deviceList"
android:layout_width="match_parent"
android:layout_height="200dp" />
</LinearLayout>

</ScrollView>

Step 3: Create the Activity (5 minutes)

Create a new Activity or modify your MainActivity.java. Here's the complete, working code:

package com.averydennison.pfquickstart;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

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.callbacks.ScanCallback;
import com.averydennison.addevicemanager.connection.DeviceConnection;
import com.averydennison.addevicemanager.connection.SerialConnection;
import com.averydennison.addevicemanager.models.ScannedData;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";

// SDK Components
private DeviceManager deviceManager;
private DeviceAdapter deviceAdapter;
private PrinterAdapter printerAdapter;
private ScannerAdapter scannerAdapter;

// UI Components
private RadioButton bleRadioButton, serialRadioButton;
private TextView statusText;
private Button bleSearchButton, serialConnectButton, disconnectButton, scanButton, printButton;
private EditText inputField;
private ListView deviceListView;

// Discovered devices
private final List<DeviceConnection> discoveredDevices = new ArrayList<>();
private ArrayAdapter<String> deviceListAdapter;

// Permission launcher
private final ActivityResultLauncher<String[]> permissionLauncher =
registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(),
result -> {
if (!result.containsValue(false)) startDeviceDiscovery();
else showToast("Bluetooth permissions required");
});

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Initialize UI
statusText = findViewById(R.id.statusText);
bleSearchButton = findViewById(R.id.searchButton);
serialConnectButton = findViewById(R.id.serialConnectButton);
disconnectButton = findViewById(R.id.disconnectButton);
scanButton = findViewById(R.id.scanButton);
printButton = findViewById(R.id.printButton);
inputField = findViewById(R.id.inputField);
deviceListView = findViewById(R.id.deviceList);

bleRadioButton = findViewById(R.id.bleRadioButton);
serialRadioButton = findViewById(R.id.serialRadioButton);
bleRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
bleSearchButton.setVisibility(isChecked ? Button.VISIBLE : Button.GONE);
deviceListView.setVisibility(isChecked ? ListView.VISIBLE : ListView.GONE);
serialConnectButton.setVisibility(!isChecked ? Button.VISIBLE : Button.GONE);
});

// Check if device supports BLE, if not allow serial only (and hide radio buttons)
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
serialRadioButton.setChecked(true);
bleRadioButton.setVisibility(RadioButton.GONE);
serialRadioButton.setVisibility(RadioButton.GONE);
showToast("BLE not supported, defaulting to Serial connection");
}

// Initialize device list adapter
deviceListAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new ArrayList<>());
deviceListView.setAdapter(deviceListAdapter);

// Tap a device in the list to connect
deviceListView.setOnItemClickListener((parent, view, position, id) -> {
DeviceConnection device = discoveredDevices.get(position);
deviceManager.stopBluetoothDiscovery();
connectToDevice(device);
});

// Initialize SDK
deviceManager = new DeviceManager(this);

// Button handlers
bleSearchButton.setOnClickListener(v -> checkPermissionsAndSearch());
serialConnectButton.setOnClickListener(v -> connectViaSerial());
disconnectButton.setOnClickListener(v -> disconnect());
scanButton.setOnClickListener(v -> triggerScan());
printButton.setOnClickListener(v -> onClickPrint());
}

@Override
protected void onDestroy() {
super.onDestroy();
if (deviceAdapter == null) return;
deviceAdapter.disconnect();
}

// ============================================
// STEP 1: Request Permissions & Discover, Or connect via Serial
// ============================================
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()) {
startDeviceDiscovery();
} else {
permissionLauncher.launch(needed.toArray(new String[0]));
}
}

private void startDeviceDiscovery() {
// Clear previous results
discoveredDevices.clear();
deviceListAdapter.clear();
updateStatus("Scanning for devices...");

deviceManager.startBluetoothDiscovery(new DiscoveryCallback() {
@Override
public void onDeviceFound(DeviceConnection device) {
Log.i(TAG, "Found device: " + device.getName());
runOnUiThread(() -> {
discoveredDevices.add(device);
deviceListAdapter.add(device.getName());
deviceListAdapter.notifyDataSetChanged();
});
}

@Override
public void onDiscoveryFinished() {
if (discoveredDevices.isEmpty()) {
updateStatus("No devices found");
} else {
updateStatus("Found " + discoveredDevices.size() + " device(s). Tap to connect.");
}
}

@Override
public void onDiscoveryFailed(Exception error) {
updateStatus("Discovery failed: " + error.getMessage());
}
});
}

private void connectViaSerial() {
DeviceConnection deviceConnection = new SerialConnection(DeviceConnection.PrinterType.EDGE,
"PF Edge Printer");
connectToDevice(deviceConnection);
}

// ============================================
// STEP 2: Connect and Create Print Template
// ============================================
private void connectToDevice(DeviceConnection device) {
updateStatus("Connecting to " + device.getName() + "...");

deviceAdapter = deviceManager.getAdapterForDevice(device);
deviceAdapter.connect()
.thenRunAsync(this::createPrintTemplate)
.thenAccept(avoid -> {
updateUiState("Connected to " + device.getName(), true);
setupSdkComponents();
})
.exceptionally(error -> {
updateStatus("Connection failed: " + error.getMessage());
return null;
});
}

private void createPrintTemplate() {
String template = "SIZE 2,1\n" +
"CLS\n" +
"DIRECTION 0\n" +
"TEXT 160,20,\"Roboto-Bold.TTF\",0,0,10,\"{PRICE}\"\n" +
"BARCODE 200,60,\"128\",50,2,0,2,2,2,\"{SERIAL}\"\n";
deviceAdapter.createResource("ProductLabel.ngt", template.getBytes(), true, null)
.exceptionally(error -> {
showToast("Failed to create template: " + error.getMessage());
return null;
});
}

private void setupSdkComponents() {
try {
printerAdapter = deviceAdapter.getPrinterAdapter();
scannerAdapter = deviceAdapter.getScannerAdapter();

scannerAdapter.setScanCallback(new ScanCallback() {
@Override
public void onScanSuccess(ScannedData scannedData) {
runOnUiThread(() -> handleScannedBarcode(scannedData.data));
}

@Override
public void onScanFailure(String errorMessage) {
showToast("Scan failed: " + errorMessage);
}
});

Log.i(TAG, "Adapters initialized successfully");
} catch (Exception e) {
Log.e(TAG, "Failed to initialize adapters", e);
}
}

private void disconnect() {
if (deviceAdapter != null) {
deviceAdapter.disconnect();
deviceAdapter = null;
printerAdapter = null;
scannerAdapter = null;
}
discoveredDevices.clear();
deviceListAdapter.clear();
updateUiState("Disconnected. Ready to connect.", false);
}

// ============================================
// STEP 3: Scan Barcode
// ============================================
private void triggerScan() {
if (scannerAdapter == null) {
showToast("Scanner not available");
return;
}

updateStatus("Scanning...");
scannerAdapter.triggerScan()
.exceptionally(error -> {
runOnUiThread(() -> showToast("Scan failed: " + error.getMessage()));
return null;
});
}

private void handleScannedBarcode(String barcode) {
Log.i(TAG, "Scanned barcode: " + barcode);

updateStatus("Scanned: " + barcode);
showToast("Scanned: " + barcode);
inputField.setText(barcode);
}

// ============================================
// STEP 4: Print
// ============================================
private void onClickPrint() {
String input = inputField.getText().toString().trim();
if (input.isEmpty()) {
showToast("Please enter a barcode");
return;
}

String productPrice = "$1.99";
String data = "SERIAL=" + input + ";PRICE=" + productPrice;

printerAdapter.print("ProductLabel.ngt", data, 1)
.thenAccept(unused -> {
updateStatus("Printed: " + input);
showToast("Label printed!");
})
.exceptionally(error -> {
updateStatus("Print failed");
showToast("Print failed: " + error.getMessage());
return null;
});
}

// ============================================
// Helper Methods
// ============================================
private void updateStatus(String message) {
Log.i(TAG, message);
runOnUiThread(() -> statusText.setText(message));
}

private void updateUiState(String statusMessage, boolean connected) {
runOnUiThread(() -> {
boolean bleMode = ((RadioButton) findViewById(R.id.bleRadioButton)).isChecked();
bleSearchButton.setVisibility(bleMode && !connected ? Button.VISIBLE : Button.GONE);
serialConnectButton.setVisibility(connected || bleMode ? Button.GONE : Button.VISIBLE);
disconnectButton.setVisibility(connected ? Button.VISIBLE : Button.GONE);

bleRadioButton.setEnabled(!connected);
serialRadioButton.setEnabled(!connected);

scanButton.setEnabled(connected);
inputField.setEnabled(connected);
printButton.setEnabled(connected);
updateStatus(statusMessage);
});
}

private void showToast(String message) {
runOnUiThread(() -> Toast.makeText(this, message, Toast.LENGTH_SHORT).show());
}
}

Step 4: Run and Test

  1. Power on your Pathfinder Edge device
  2. Run the app on your Android device
  3. Choose connection mode:
    • BLE (Companion Device): Select "BLE" radio button, then tap Scan for Devices
    • Serial (Integrated Device): Select "Serial" radio button, then tap Connect via Serial
  4. Grant Bluetooth permissions when prompted (for BLE mode)
  5. For BLE mode: Click the device to connect
  6. Once connected, tap Scan Barcode
  7. The scanned barcode will appear in the input field
  8. Tap Print to print a label with the scanned barcode
  9. Watch the label print! 🎉

What Just Happened?

Here's the workflow:

┌─────────────────────────────────────────────────────────────────┐
│ 1. User selects connection mode (BLE or Serial) │
│ │
│ 2. User taps "Scan for Devices" (BLE) or "Connect" (Serial) │
│ └── BLE Mode: │
│ └── App requests Bluetooth permissions │
│ └── App discovers Pathfinder Edge devices │
│ └── App connects to selected device │
│ └── Serial Mode: │
│ └── App connects directly via Serial connection │
│ │
│ 3. User taps "Scan" (or presses device button) │
│ └── Scanner reads barcode │
│ └── ScanCallback.onScanSuccess() fires with barcode │
│ │
│ 4. User taps "Print" button │
│ └── Builds template data string: "PRICE=...;SERIAL=...;" │
│ └── Calls printerAdapter.print() │
│ └── Label prints! ✓ │
└─────────────────────────────────────────────────────────────────┘

Troubleshooting

ProblemSolution
"No devices found"Ensure Pathfinder Edge is powered on and Bluetooth is enabled
Permission dialog doesn't appearCheck that permissions are in AndroidManifest.xml
Scan doesn't triggerEnsure device has scanning capability

Next Steps

You've got the basics working! Now dive deeper:

GuideLearn About
Getting StartedComplete SDK setup and configuration
Resource ManagementUploading templates and fonts
PrintingAdvanced printing techniques
ScanningSymbology configuration
CallbacksReal-time status updates
Error HandlingHandling failures gracefully