Peripherals Integration Guide


Printing

To print, the application must first bind to the print service, then once bound, can use the APIs from the print service.

 @startuml
 !include uml_styles.iuml
 hide footbox

 participant POS order 10
 participant "Print Service" as PrintService order 20
 activate POS
 |||
 POS ->> PrintService: Bind to service
 activate PrintService
 POS <<- PrintService: Service connected
 ...
 POS ->> PrintService: Print
 POS <<- PrintService: Print started
 POS <<- PrintService: Print complete
 ...
 POS ->> PrintService: Unbind
 deactivate PrintService
 |||
 @enduml

/** Manages the connection to the service. */
private final ServiceConnection mServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        // We must use this to expose the service methods.
        mPrintService = IDirectPrintService.Stub.asInterface(iBinder);
        Log.d("PrintConnection", "Print service connected.");
    }
    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        Log.d("PrintConnection", "Print service disconnected.");
        mPrintService = null;
    }
};

/** Binds to the direct print service by dynamically locating it in the system. */
private static boolean bindToDirectPrintService(Context context, ServiceConnection serviceConnection) {
    Intent directPrintImplicitIntent = new Intent("com.verifone.intent.action.DIRECT_PRINT");
    directPrintImplicitIntent.addCategory("com.verifone.intent.category.DIRECT_PRINT");
    Intent directPrintIntent = createExplicitFromImplicitIntent(context, directPrintImplicitIntent);
    return directPrintIntent != null && context.bindService(directPrintIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}

/** Used when binding to the print service to turn a dynamic intent into an explicit intent. */
@Nullable
private static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
    //Retrieve all services that can match the given intent
    PackageManager pm = context.getPackageManager();
    List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);

    //Make sure only one match was found
    if (resolveInfo == null || resolveInfo.size() != 1) {
        Log.e(TAG, "Could not find service for intent with action " + implicitIntent.getAction() + ".");
        return null;
    }

    //Get component info and create ComponentName
    ResolveInfo serviceInfo = resolveInfo.get(0);
    String packageName = serviceInfo.serviceInfo.packageName;
    String className = serviceInfo.serviceInfo.name;
    ComponentName component = new ComponentName(packageName, className);

    //Create a new intent. Use the old one for extras and such reuse
    Intent explicitIntent = new Intent(implicitIntent);
    //Set the component to be explicit
    explicitIntent.setComponent(component);
    return explicitIntent;
}

Here’s a sample print listener that receives back the different events for printing.

/**
 * The listener which receives the callbacks from the print service for print job status
 * updates.
 */
private final IDirectPrintListener mPrintListener = new IDirectPrintListener.Stub() {
    /** Called when a print job has moved from the queue and is being processed. */
    @Override
    public void started(String printId) throws RemoteException {

    }

    /** Called when the print job cannot continue, but could be resumed later. */
    @Override
    public void block(String printId, String errorMessage) throws RemoteException {

    }

    /** Called when the print job has finished being cancelled. This is the final message. */
    @Override
    public void cancel(String printId) throws RemoteException {

    }

    /** Called when the print job has failed, and cannot be resumed. This is the final message. */
    @Override
    public void failed(String printId, String errorMessage) throws RemoteException {

    }

    /** Called when the print job is complete. */
    @Override
    public void complete(String printId) throws RemoteException {

    }
};

An example of printing a receipt once the service is bound and the listener is set up.

try {
    mPrintService.printString(mPrintListener, receipt.getAsHtml(), null, Printer.PRINTER_FULL_CUT);
} catch (RemoteException e) {
    e.printStackTrace();
}

Barcode Scanning

First use PeripheralManager.getManager(context, null) to get the manager. Then add a listener for the scanner using PeripheralManager.addListener(listener, Scanner.TYPE) to receive the scan results. Finally, get the Scanner itself using PeripheralManager.getPeripheralsByType(Scanner.TYPE), and start a scan Scanner.initiateScan(attributes). The listener will receive the results as they are scanned. The attributes must contain an Activity or Fragment under the Scanner.ATTRIBUTE_DISPLAY_FEED_PARENT key to work. It uses this to present the scan view to the cashier.

HashMap<String, Object> attributes = new HashMap<>();
attributes.put(Scanner.ATTRIBUTE_DISPLAY_FEED_PARENT, activity);
// Optionally limit the barcode formats. Leaving this empty
// will search for the default list of barcodes.
int[] barcodeFormats = new int[] {
    ScannerBarcodeFormat.QRCODE
};
attributes.put(Scanner.ATTRIBUTE_SCANNING_FORMATS, barcodeFormats);
scanner.initiateScan(attributes);

Note

The scanner will not scan until the PeripheralManager is successfully bound, which means there must be some time between first retrieving the PeripheralManager and starting the first scan. Subsequent calls to get the manager after the first binding do not require a delay.


Cash Drawer

First use PeripheralManager.getManager(context, null) to get the manager. Then add a listener for the cash drawer using PeripheralManager.addListener(listener, CashDrawer.TYPE) to receive the scan results. Finally, get the CashDrawer itself using PeripheralManager.getPeripheralsByType(CashDrawer.TYPE). At this point, the current status can be queried using CashDrawer.getStatus(), and the drawer can be opened using CashDrawer.open().

In some cases, the difference between an open drawer and a disconnected drawer cannot be detected by the system. In this case, the status will be Peripheral.STATUS_UNKNOWN. The ability to detect the difference can be determined through the CashDrawer.isCapable(CashDrawer.CAPABILITY_OPEN_QUERY). In all cases, if the drawer is closed and connected, the status is CashDrawer.STATUS_CLOSED, and in some cases, the system can detect CashDrawer.STATUS_OPEN after it has detected a closed drawer. The listener should consider either unknown or open as successful statuses when opening the cash drawer, as the status will Peripheral.STATUS_ERROR or one of the other defined statuses if the open command fails.

Note

The cash drawer will not open until the PeripheralManager is successfully bound, which means there must be some time between first retrieving the PeripheralManager and opening the drawer. Subsequent calls to get the manager after the first binding do not require a delay.

Note

The cash drawer can only be operated while docked. If the tablet is removed from the dock while a listener is registered, it will receive Peripheral.STATUS_DISCONNECTED_BY_UNDOCK.



Warning

Verifone Confidential

This documentation is protected by law from any form of duplication unless prior permission is obtained from the officers of Verifone.