# Printer Android SDK Development Guide

> **Document Version**: V5.7.4  
> **Applicable SDK**: `printersdkv5.7.4.jar`  
> **Document Purpose**: For customers/integrators to reference for secondary development  
> **Target Platform**: Android 5.0 (API 21) and above

---

## Table of Contents

1. [Overview](#1-overview)
2. [Environment Requirements & SDK Integration](#2-environment-requirements--sdk-integration)
3. [Project Structure](#3-project-structure)
4. [Quick Start](#4-quick-start)
5. [Printer Connection Details](#5-printer-connection-details)
   - 5.1 [Bluetooth Connection](#51-bluetooth-connection)
   - 5.2 [USB Connection](#52-usb-connection)
   - 5.3 [WiFi Connection](#53-wifi-connection)
   - 5.4 [Serial Port Connection](#54-serial-port-connection)
   - 5.5 [Connection State Management](#55-connection-state-management)
6. [Print Function Development](#6-print-function-development)
   - 6.1 [Text Printing](#61-text-printing)
   - 6.2 [Image Printing](#62-image-printing)
   - 6.3 [Barcode / QR Code Printing](#63-barcode--qr-code-printing)
   - 6.4 [Label Printing (CPCL/TSPL)](#64-label-printing-cpcltspl)
   - 6.5 [Table Printing](#65-table-printing)
   - 6.6 [PDF Printing](#66-pdf-printing)
   - 6.7 [Canvas Drawing Print (PageMode)](#67-canvas-drawing-print-pagemode)
   - 6.8 [Soft Flow Control Printing (Large Data)](#68-soft-flow-control-printing-large-data)
7. [Core API Reference](#7-core-api-reference)
8. [AndroidManifest Permission Configuration](#8-androidmanifest-permission-configuration)
9. [FAQs & Notes](#9-faqs--notes)
10. [Appendix](#10-appendix)

---

## 1. Overview

This SDK is an Android development kit for thermal/thermal transfer printers, supporting the following features:

| Feature | Description |
|--------|------|
| **Connection Methods** | Bluetooth (Classic Bluetooth), USB Host, WiFi (Socket), Serial Port (RS232/TTL) |
| **Print Content** | Plain text, images (camera/gallery/Bitmap), 1D barcodes, QR codes, PDF, labels |
| **Instruction Sets** | ESC/POS, CPCL, TSPL |
| **Advanced Features** | PageMode canvas drawing, image binarization, soft flow control chunked sending, table-to-Bitmap, multi-language mixed layout |
| **Paper Width Support** | 58mm (384px), 80mm (576px), 100mm (724px) |

---

## 2. Environment Requirements & SDK Integration

### 2.1 Development Environment

| Item | Requirement |
|------|------|
| Android Studio | 4.0 and above |
| Gradle Plugin | 7.0 and above |
| compileSdk | 32 |
| minSdkVersion | 21 (Android 5.0) |
| targetSdkVersion | 31 |

### 2.2 SDK Integration

1. Copy `printersdkv5.7.4.jar` to your project's `libs/` directory.
2. **Important**: If you do not need serial port communication and PDF printing features, you do not need to migrate SO library files. Only when serial port communication or PDF printing is required should you copy the corresponding SO library files into the project.
3. Add dependencies in module-level `build.gradle`:

```groovy
android {
    compileSdk 32
    defaultConfig {
        minSdk 21
        targetSdk 31
    }
}

dependencies {
    implementation files('libs/printersdkv5.7.4.jar')
    // Other AndroidX dependencies please add as needed
}
```

3. Sync Project with Gradle Files.

---

## 3. Project Structure

The Demo project uses a classic Android project structure. Key directories are explained below:

```
PrintDemoV5.7.1/
├── src/main/java/com/printer/demo/
│   ├── MainActivity.java              # Main entry, feature navigation
│   ├── SettingActivity.java           # [Core] Printer connection configuration
│   ├── TextPrintActivity.java         # Text printing example
│   ├── PicturePrintActivity.java      # Image printing example
│   ├── BarcoePrintActivity.java       # Barcode/QR code printing example
│   ├── LablePrintActivity.java        # Label printing example (CPCL/TSPL)
│   ├── PdfPrintActivity.java          # PDF printing example
│   ├── BaseActivity.java              # Activity base class (title bar, status display)
│   ├── BluetoothDeviceList.java       # Bluetooth device search list
│   ├── UsbDeviceList.java             # USB device search list
│   ├── SerialsDeviceList.java         # Serial port device search list
│   ├── IpEditActivity.java            # WiFi IP input interface
│   └── utils/                         # Utility class collection
│       ├── XTUtils.java               # Core printing utilities (receipt, table, test page)
│       ├── CanvasUtils.java           # Canvas printing utilities
│       ├── PrinterUtils.java          # Advanced table-to-Bitmap implementation
│       ├── PrinterBlockSender.java    # Soft flow control chunked sender
│       ├── ImageBinarizationUtils.java# Image binarization (Otsu/Floyd)
│       ├── Table2Bitmap.java          # Table drawing to Bitmap
│       ├── AlignedTable.java          # Aligned table data structure
│       └── PrintLabel58/80/100/*.java # Preset label templates
├── src/main/res/layout/               # Layout files
├── src/main/assets/                   # Font files (kaiti.ttf, songti.ttf, heiti.ttf)
└── libs/printersdkv5.7.4.jar          # SDK core package
```

**Recommendation**: When developing, focus on referencing `SettingActivity.java` (connection logic) and `XTUtils.java` (printing logic).

---

## 4. Quick Start

The following code demonstrates the simplest integration flow: **Initialize → Connect Bluetooth printer → Print text → Disconnect**.

```java
import com.printer.sdk.PrinterInstance;
import com.printer.sdk.PrinterConstants.Connect;
import com.printer.sdk.PrinterConstants.Command;

public class QuickStartActivity extends AppCompatActivity {

    private PrinterInstance mPrinter;
    private Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case Connect.SUCCESS:
                    Toast.makeText(context, "Connection successful", Toast.LENGTH_SHORT).show();
                    // Execute print after successful connection
                    printText();
                    break;
                case Connect.FAILED:
                    Toast.makeText(context, "Connection failed", Toast.LENGTH_SHORT).show();
                    break;
                case Connect.CLOSED:
                    Toast.makeText(context, "Connection closed", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };

    // 1. Connect via Bluetooth MAC address
    private void connectBluetooth(String macAddress) {
        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(macAddress);
        mPrinter = PrinterInstance.getPrinterInstance(this, device, mHandler);
        mPrinter.openConnection();
    }

    // 2. Print text (must be executed in a sub-thread)
    private void printText() {
        new Thread(() -> {
            mPrinter.initPrinter();
            mPrinter.setFont(0, 0, 0, 0, 0);
            mPrinter.setPrinter(Command.ALIGN, Command.ALIGN_CENTER);
            mPrinter.printText("Welcome to Printer SDK\n");
            mPrinter.setPrinter(Command.PRINT_AND_WAKE_PAPER_BY_LINE, 3); // Feed 3 lines
        }).start();
    }

    // 3. Disconnect
    private void disconnect() {
        if (mPrinter != null) {
            mPrinter.closeConnection();
            mPrinter = null;
        }
    }
}
```

---

## 5. Printer Connection Details

The SDK supports **4 connection methods**, implemented through different overloaded methods of `PrinterInstance.getPrinterInstance(...)`.

### 5.1 Bluetooth Connection

#### 5.1.1 Classic Bluetooth Search and Connection

```java
// Connect after returning MAC address from Bluetooth device list
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(macAddress);
PrinterInstance myPrinter = PrinterInstance.getPrinterInstance(context, device, handler);
myPrinter.openConnection();
```

#### 5.1.2 Scan QR Code to Connect (scan MAC address)

The Demo provides `MipcaActivityCapture.java`, which automatically parses and connects after scanning a QR code containing a MAC address.

```java
// Parse scan result, extract 12-digit hexadecimal MAC
String rawAddress = input.replaceAll("[^0-9A-Fa-f]", "");
if (rawAddress.length() >= 12) {
    String mac = rawAddress.substring(0, 12);
    // Format to standard MAC address 00:12:5B:01:F6:D2
    mac = mac.replaceAll("(.{2})(?=.)", "$1:").substring(0, 17);
}
```

#### 5.1.3 Scan Name + Password to Connect

Applicable to scenarios with pairing passwords. Refer to `MipcaActivityCapture_GetBtName.java` in the Demo.

#### 5.1.4 Bluetooth Disconnect Listener

Register a broadcast after successful connection to listen for Bluetooth disconnect events:

```java
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
context.registerReceiver(disconnectReceiver, filter);
```

### 5.2 USB Connection

#### 5.2.1 Search USB Devices

The Demo `UsbDeviceList.java` has encapsulated the search logic, filtering VID/PID:
- VID: `0x0483`, PID: `0x5720`
- VID: `0x067B`, PID: `0x2305`
- VID: `0x6868`, PID: `0x0200`

#### 5.2.2 Request Permission and Connect

```java
UsbDevice usbDevice = ...; // Returned from UsbDeviceList
PrinterInstance myPrinter = PrinterInstance.getPrinterInstance(context, usbDevice, handler);

UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
if (usbManager.hasPermission(usbDevice)) {
    myPrinter.openConnection();
} else {
    PendingIntent pendingIntent = PendingIntent.getBroadcast(
        context, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);
    usbManager.requestPermission(usbDevice, pendingIntent);
}
```

#### 5.2.3 USB Plug/Unplug Listener

```java
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
context.registerReceiver(usbDetachReceiver, filter);
```

### 5.3 WiFi Connection

WiFi printers connect via Socket, default port **9100**.

```java
String ipAddress = "192.168.0.100"; // Printer IP
PrinterInstance myPrinter = PrinterInstance.getPrinterInstance(ipAddress, 9100, handler);

// WiFi connection must be executed in a sub-thread
new Thread(() -> myPrinter.openConnection()).start();
```

### 5.4 Serial Port Connection

Supports `/dev/tty*` device nodes, configurable baud rate and flow control.

```java
String path = "/dev/ttyS1";      // Serial port device path
int baudrate = 9600;              // Baud rate
int flags = 0;                    // Flags
int flowControl = 1;              // Flow control: 0=XON/XOFF, 1=RTS/CTS, 2=NONE

PrinterInstance myPrinter = PrinterInstance.getPrinterInstance(
    new File(path), baudrate, flags, flowControl, handler);
myPrinter.openConnection();
```

### 5.5 Connection State Management

Receive connection state callbacks via `Handler`:

| State Constant | Value | Description |
|----------|-----|------|
| `Connect.SUCCESS` | 0 | Connection successful |
| `Connect.FAILED` | 1 | Connection failed |
| `Connect.CLOSED` | 2 | Connection closed |
| `Connect.NODEVICE` | 3 | No device |

```java
private Handler mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case Connect.SUCCESS:
                // Save connection state, update UI
                break;
            case Connect.FAILED:
                // Prompt user connection failed
                break;
            case Connect.CLOSED:
                // Clean up resources, update UI
                break;
        }
    }
};
```

---

## 6. Print Function Development

**Important**: Except for WiFi connection which is strongly recommended to execute in a sub-thread, all print operations are recommended to be executed in a sub-thread to avoid blocking the UI.

### 6.1 Text Printing

#### Basic Text Printing

```java
mPrinter.initPrinter();                                   // Initialize printer
mPrinter.setFont(0, 0, 0, 0, 0);                         // Restore default font
mPrinter.setPrinter(Command.ALIGN, Command.ALIGN_CENTER); // Center alignment
mPrinter.printText("Welcome\n");
mPrinter.setPrinter(Command.PRINT_AND_WAKE_PAPER_BY_LINE, 2); // Feed 2 lines
```

#### Font Settings

```java
// setFont(charset, doubleWidth, doubleHeight, bold, underline)
mPrinter.setFont(0, 1, 1, 0, 0);  // Double width and height
mPrinter.setFont(0, 0, 0, 1, 0);  // Bold
mPrinter.setFont(0, 0, 0, 0, 1);  // Underline
```

#### Receipt Template Printing

Refer to `XTUtils.printNote(...)` method, which encapsulates a complete receipt format (title, items, price, footer, etc.).

```java
XTUtils.printNote(getResources(), mPrinter);
```

#### Code Page Settings

To print special languages (e.g., Lao, Thai), set the character set first:

```java
mPrinter.setCharsetName("UTF-8");
```

### 6.2 Image Printing

#### Direct Bitmap Printing

```java
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test_image);

// If image width exceeds paper width, scale first
if (bitmap.getWidth() > PrinterConstants.paperWidth) {
    bitmap = Utils.zoomImage(bitmap, PrinterConstants.paperWidth, printerType);
}

// Print image
mPrinter.printImage(bitmap, PAlign.NONE, 0, false);
```

Parameter description:
- `PAlign`: Alignment (`NONE`, `START`, `CENTER`, `END`)
- `leftMargin`: Left margin (pixels)
- `isCompressed`: Whether to compress (usually pass `false`)

#### Binarize Image Before Printing (Recommended)

For color/grayscale images, it is recommended to binarize first for better print quality:

```java
// Otsu binarization
Bitmap otsu = ImageBinarizationUtils.binarizeImage(bitmap, "otsu", 0);
mPrinter.printImage(otsu, PAlign.NONE, 0, false);

// Floyd-Steinberg dithering binarization
Bitmap floyd = ImageBinarizationUtils.binarizeImage(bitmap, "floyd", 0);
mPrinter.printImage(floyd, PAlign.NONE, 0, false);
```

#### Dot Matrix Printer Image

```java
mPrinter.printImageStylus(bitmap, 1);
```

### 6.3 Barcode / QR Code Printing

#### 1D Barcode

```java
Barcode barcode = new Barcode(
    BarcodeType.CODE128,  // Type: CODE128/CODE39/CODABAR/ITF/CODE93/UPC_A/UPC_E/JAN13/JAN8
    2,                    // Width (2~6)
    162,                  // Height (1~255)
    2,                    // Text position (0=none, 1=above, 2=below, 3=both)
    "1234567890"          // Content
);
mPrinter.printBarCode(barcode);
```

#### QR Code

```java
Barcode qrCode = new Barcode(
    BarcodeType.QRCODE,   // Or PDF417 / DATAMATRIX
    2,                    // Version/char count (meaning varies by type)
    3,                    // Error correction level/height
    6,                    // Magnification
    "https://www.example.com"
);
mPrinter.printBarCode(qrCode);
```

#### Scan and Print

The Demo `MipcaActivityCapture.java` encapsulates the ZXing scanning module; scan results can be directly passed to print.

### 6.4 Label Printing (CPCL/TSPL)

#### CPCL Instruction Label Printing

```java
// Example with 80mm label paper
iPrinter.pageSetup(LablePaperType.Size_80mm, pageWidth, pageHeight);
iPrinter.drawBorder(3, x1, y1, x2, y2);
iPrinter.drawLine(width, x1, y1, x2, y2, true);
iPrinter.drawText(x1, y1, x2, y2, PAlign.CENTER, PAlign.CENTER,
    "Label Content", LableFontSize.Size_64, 0, 0, 0);
iPrinter.drawBarCode(...);
iPrinter.print(PRotate.Rotate_0, copies); // Print copies
```

The Demo provides multiple preset templates:
- `PrintLabel58.java` — 58mm label
- `PrintLabel80.java` — 80mm label
- `PrintLabel100.java` — 100mm label
- `PrintLabelDrink.java` — Drink label
- `PrintLabelExpress.java` — Express label

#### TSPL Instruction Settings

```java
mPrinter.setPrinterTSPL(CommandTSPL.SPEED, 12);      // Print speed
mPrinter.setPrinterTSPL(CommandTSPL.DENSITY, 7);     // Print density
mPrinter.setGAPTSPL(gapWidth, gapOffset);            // Label gap
```

### 6.5 Table Printing

#### Simple Table (SDK Native)

```java
String column = "Name;Price;Qty;Total";
Table table = new Table(column, ";", new int[]{18, 10, 10, 12});
table.addRow("Apple;5.00;2;10.00");
table.addRow("Banana;3.00;5;15.00");
mPrinter.printTable(table);
```

#### Advanced Aligned Table (Convert to Bitmap for Printing)

Supports Chinese, Lao mixed layout,超长 automatic line wrapping, left/center/right alignment:

```java
String header = "Item|Qty|Price|Subtotal";
int[] widths = {10, 4, 4, 4};  // Column width (char count)
AlignedTable table = new AlignedTable(header, "\\|", widths, 0, 1);

table.setColumnAlign(0, AlignedTable.Align.LEFT);
table.setColumnAlign(1, AlignedTable.Align.CENTER);
table.setColumnAlign(2, AlignedTable.Align.RIGHT);
table.setColumnAlign(3, AlignedTable.Align.RIGHT);

table.addRow("Mineral Water|2|5,000|10,000");
table.addRow("Lao product name long text test|3|2,800|8,400");

// Convert to Bitmap then print
Bitmap bmp = Table2Bitmap.get().draw(table);
Bitmap bin = ImageBinarizationUtils.binarizeImage(bmp, "otsu", 0);
mPrinter.printImage(bin, PrinterConstants.PAlign.NONE, 0, false);
```

#### Weighted Column Width

```java
// Automatically distribute column width ratios based on paper width
int[] widths = ColWidthUtil.weight(PrinterConstants.paperWidth, 16, 5, 2, 2, 2);
```

### 6.6 PDF Printing

Refer to `PdfPrintActivity.java`, which parses PDF pages and converts them to Bitmap, then calls `printImage` to print.

### 6.7 Canvas Drawing Print (PageMode)

Applicable to complex layout scenarios, supporting free combination of text, lines, barcodes, QR codes, and images.

```java
CanvasDrawPrint cd = new CanvasDrawPrint();
cd.SetPageMode(576, 800);  // Set canvas size: width 576px, height 800px

// Draw text
cd.PrintText(10, 10, 0, 24, 1, 0, 1, "Title Text", context);

// Draw line
cd.PrintLine(0, 50, 576, 50, 2);

// Draw QR code
cd.PrintQRCode(200, 100, 150, 150, 3, 0, 0, "https://example.com");

// Draw 1D barcode
cd.PrintCode(BarcodeType.CODE128, 50, 300, 300, 100, true, "123456");

// Get Bitmap and print
Bitmap canvasBitmap = cd.getCanvasImage();
mPrinter.printImage(canvasBitmap, PAlign.NONE, 0, false);
```

**Callback Listener**: Set `CanvasDrawBack` to listen for drawing errors.

```java
cd.setCanvasDrawBack(new CanvasDrawPrint.CanvasDrawBack() {
    @Override
    public void resultsBack(int type) {
        switch (type) {
            case CanvasDrawPrint.TEXT: Log.e("TAG", "Text drawing error"); break;
            case CanvasDrawPrint.QRCODE_ORDINARY: Log.e("TAG", "QR code drawing error"); break;
            // ... other types
        }
    }
});
```

### 6.8 Soft Flow Control Printing (Large Data)

When printing large amounts of text + images, use `PrinterBlockSender` to send in chunks, automatically querying the printer buffer status to prevent data loss.

```java
// 1. Prepare Bitmap (convert to print instruction bytes first)
byte[] printBytes = Utils.originalBmpToPrintByte(bitmap, PAlign.NONE, 0, 128);

// 2. Encapsulate printer read/write interface
PrinterBlockSender.PrinterSendRead io = new PrinterBlockSender.PrinterSendRead() {
    public int sendBytesData(byte[] data) {
        return mPrinter.sendBytesData(data);
    }
    public int read(byte[] buffer) {
        return mPrinter.read(buffer);
    }
};

// 3. Create sender
PrinterBlockSender sender = new PrinterBlockSender(io);
sender.setTimeoutByCharCount(text.length()); // Dynamically set timeout based on char count

// 4. Execute print
int initCode = sender.initPrinter();
if (initCode == 0) {
    sender.printText(text);           // Soft flow control print text
    sender.lineFeed();
    sender.sendChunkWithCode(printBytes); // Soft flow control print image
}
```

Error code description:
| Error Code | Meaning |
|--------|------|
| 0 | Print completed |
| 2 | Out of paper |
| 3 | Cover open |
| 4 | Overheating |
| 6 | Timeout |

---

## 7. Core API Reference

### 7.1 PrinterInstance (Printer Instance)

| Method | Description |
|------|------|
| `getPrinterInstance(Context, BluetoothDevice, Handler)` | Bluetooth connection |
| `getPrinterInstance(Context, UsbDevice, Handler)` | USB connection |
| `getPrinterInstance(String ip, int port, Handler)` | WiFi connection |
| `getPrinterInstance(File path, int baudrate, int flags, int flow, Handler)` | Serial port connection |
| `openConnection()` | Open connection |
| `closeConnection()` | Close connection |
| `initPrinter()` | Initialize printer |
| `printText(String text)` | Print text |
| `printImage(Bitmap bitmap, PAlign align, int leftMargin, boolean isCompressed)` | Print image |
| `printImage(Bitmap bitmap, PAlign align, int leftMargin, int threshold)` | Print image (with threshold) |
| `printImageStylus(Bitmap bitmap, int mode)` | Dot matrix printer image |
| `printBarCode(Barcode barcode)` | Print barcode |
| `printTable(Table table)` | Print table |
| `printSelfCheckingPage()` | Print self-test page |
| `cutPaper(int mode, int distance)` | Cut paper |
| `getCurrentStatus()` | Get printer status |
| `sendBytesData(byte[] data)` | Send raw byte data |
| `read(byte[] buffer)` | Read printer return data |
| `setFont(int charset, int width, int height, int bold, int underline)` | Set font |
| `setPrinter(Command cmd, int value)` | Set printer parameters |
| `setPrinterTSPL(CommandTSPL cmd, int value)` | TSPL parameter settings |
| `setCharsetName(String charset)` | Set character encoding |
| `setPaperWidth(int width)` | Set paper width |

### 7.2 Key Constants

#### Command (ESC/POS Instructions)

| Constant | Description |
|------|------|
| `Command.ALIGN` | Alignment |
| `Command.ALIGN_LEFT` | Left align |
| `Command.ALIGN_CENTER` | Center align |
| `Command.ALIGN_RIGHT` | Right align |
| `Command.PRINT_AND_WAKE_PAPER_BY_LINE` | Feed paper by line |

#### BarcodeType (Barcode Types)

| Constant | Type |
|------|------|
| `BarcodeType.CODE128` | CODE128 1D barcode |
| `BarcodeType.CODE39` | CODE39 1D barcode |
| `BarcodeType.CODABAR` | CODABAR 1D barcode |
| `BarcodeType.ITF` | ITF 1D barcode |
| `BarcodeType.CODE93` | CODE93 1D barcode |
| `BarcodeType.UPC_A` | UPC-A 1D barcode |
| `BarcodeType.UPC_E` | UPC-E 1D barcode |
| `BarcodeType.JAN13` | EAN13/JAN13 1D barcode |
| `BarcodeType.JAN8` | EAN8/JAN8 1D barcode |
| `BarcodeType.QRCODE` | QR code |
| `BarcodeType.PDF417` | PDF417 code |
| `BarcodeType.DATAMATRIX` | DataMatrix code |

#### PAlign (Image Alignment)

| Constant | Description |
|------|------|
| `PAlign.NONE` | No alignment, offset by leftMargin |
| `PAlign.START` | Left align |
| `PAlign.CENTER` | Center align |
| `PAlign.END` | Right align |

---

## 8. AndroidManifest Permission Configuration

The following permissions must be declared in `AndroidManifest.xml`:

```xml
<!-- Bluetooth permissions -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Android 12+ requires the following permissions -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

<!-- WiFi/Network permissions -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<!-- USB permission -->
<uses-permission android:name="android.hardware.usb.host" />

<!-- Storage permissions -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Android 11+ if you need to access all files -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

<!-- Camera/Scan permissions -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

<!-- Location permissions (required for Bluetooth scanning) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
```

**Android 6.0+ Dynamic Permissions**:
- `BLUETOOTH_SCAN`, `BLUETOOTH_CONNECT`, `ACCESS_FINE_LOCATION`, `CAMERA`, `WRITE_EXTERNAL_STORAGE`, etc. need to be requested at runtime.

---

## 9. FAQs & Notes

### 9.1 Connection Related

| Issue | Solution |
|------|----------|
| Bluetooth cannot find device | Confirm printer is powered on and in discoverable mode; Android 6.0+ requires location permission |
| USB connection no response | Confirm OTG cable is normal; confirm USB permission is granted; check if VID/PID matches |
| WiFi connection timeout | Confirm phone and printer are on the same LAN; confirm IP address and port 9100 are correct |
| Serial port connection failed | Confirm device node path is correct (e.g., `/dev/ttyS1`); confirm baud rate matches |

### 9.2 Printing Related

| Issue | Solution |
|------|----------|
| Print garbled text | Confirm character encoding is set correctly (`setCharsetName`); confirm printer code page matches |
| Image print blurry | Recommended to use `ImageBinarizationUtils.binarizeImage` for binarization first |
| Table not aligned | Use `AlignedTable` + `Table2Bitmap` method to convert to Bitmap for printing |
| Lao/Thai text display abnormal | Use UTF-8 encoding, and render as Bitmap via `Table2Bitmap` for printing |
| Large data print missing content | Use `PrinterBlockSender` soft flow control chunked sending |
| Print content offset | Adjust `PrinterConstants.paperWidth` to match actual paper width (384/576/724) |

### 9.3 Development Notes

1. **Thread Safety**: WiFi connection and print operations must be executed in a sub-thread; Bluetooth/USB/serial port printing is also recommended to execute in a sub-thread.
2. **Connection State Maintenance**: It is recommended to save `PrinterInstance` reference and connection state globally to avoid repeated connections.
3. **Resource Release**: Close connections and unregister broadcast receivers when Activity is destroyed to avoid memory leaks.
4. **Paper Width Setting**: Before printing, ensure `PrinterConstants.paperWidth` is consistent with actual paper width, otherwise layout will be disordered.
5. **Font Files**: If you need to use custom fonts (e.g., Kaiti, Songti), place `.ttf` files in the `assets/` directory and specify the font path via `CanvasDrawPrint`.

---

## 10. Appendix

### 10.1 Paper Width and Pixel Comparison Table

| Paper Width | Pixel Width | Applicable Scenario |
|------|----------|----------|
| 58mm | 384px | Portable receipt |
| 80mm | 576px | Standard receipt |
| 100mm | 724px | Large label/waybill |

### 10.2 Printer Status Codes

```java
int status = mPrinter.getCurrentStatus();
```

| Return Value | Status Description |
|--------|----------|
| 0 | Normal |
| -1 | Read error |
| -2 | Out of paper |
| -3 | Paper near end |
| -4 | Cover open |
| -5 | Write error |

### 10.3 Serial Port Flow Control Types

| Value | Type | Description |
|-----|------|------|
| 0 | XON/XOFF | Software flow control |
| 1 | RTS/CTS | Hardware flow control |
| 2 | NONE | No flow control |

### 10.4 Contact and Support

If you encounter problems that cannot be solved during SDK usage, please contact the manufacturer technical support and provide the following information:
- SDK version number (e.g., V5.7.4)
- Printer model
- Connection method (Bluetooth/USB/WiFi/Serial)
- Android device model and system version
- Problem reproduction steps and relevant logs (Logcat)

---

> **End of Document**