Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .idea/libraries/Flutter_Plugins.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result



/** FlutterUsbPrinterPlugin */
class FlutterUsbPrinterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
private var adapter: USBPrinterAdapter? = null
Expand All @@ -30,7 +28,7 @@ class FlutterUsbPrinterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_usb_printer")
channel.setMethodCallHandler(this)
context = flutterPluginBinding.getApplicationContext()
adapter = USBPrinterAdapter().getInstance()
adapter = USBPrinterAdapter.getInstance()
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
Expand Down Expand Up @@ -65,7 +63,6 @@ class FlutterUsbPrinterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
}

private fun getUSBDeviceList(result: Result) {

val usbDevices = adapter!!.getDeviceList()
val list = ArrayList<HashMap<String, String?>>()
for (usbDevice in usbDevices) {
Expand All @@ -81,11 +78,11 @@ class FlutterUsbPrinterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
}else{
deviceMap["productName"] = "unknown";
}
deviceMap["deviceId"] = Integer.toString(usbDevice.deviceId)
deviceMap["vendorId"] = Integer.toString(usbDevice.vendorId)
deviceMap["productId"] = Integer.toString(usbDevice.productId)
deviceMap["deviceId"] = usbDevice.deviceId.toString()
deviceMap["vendorId"] = usbDevice.vendorId.toString()
deviceMap["productId"] = usbDevice.productId.toString()
list.add(deviceMap)
print("usbDevice ${usbDevice}");
print("usbDevice $usbDevice");
}
result.success(list)
}
Expand Down Expand Up @@ -120,6 +117,7 @@ class FlutterUsbPrinterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
USBPrinterAdapter.dispose()
}

override fun onAttachedToActivity(binding: ActivityPluginBinding) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package app.mylekha.client.flutter_usb_printer.adapter

import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
Expand All @@ -14,49 +15,68 @@ import java.nio.charset.Charset
import java.util.*


class USBPrinterAdapter {
class USBPrinterAdapter private constructor(){
companion object {
private const val TAG = "Flutter USB Printer"

private var mInstance: USBPrinterAdapter? = null
private const val ACTION_USB_PERMISSION =
"app.mylekha.client.flutter_usb_printer.USB_PERMISSION"


private val LOG_TAG = "Flutter USB Printer"
@SuppressLint("StaticFieldLeak")
private var mInstance: USBPrinterAdapter? = null

fun getInstance(): USBPrinterAdapter {
if (mInstance == null) {
mInstance = USBPrinterAdapter()
}
return mInstance!!
}

fun dispose() {
mInstance = null
}
}

private var mContext: Context? = null
private var mUSBManager: UsbManager? = null
private var mPermissionIntent: PendingIntent? = null
private var mUsbDevice: UsbDevice? = null
private var mUsbDeviceConnection: UsbDeviceConnection? = null
private var mUsbInterface: UsbInterface? = null
private var mEndPoint: UsbEndpoint? = null

private val ACTION_USB_PERMISSION = "app.mylekha.client.flutter_usb_printer.USB_PERMISSION"

private val mUsbDeviceReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (ACTION_USB_PERMISSION == action) {
synchronized(this) {
var usbDevice = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE)

if (usbDevice == null) {
Log.d(TAG, "onReceive: Received null USB")

val vendorId = intent.getIntExtra("vendorId", -1)
val productId = intent.getIntExtra("productId", -1)

fun getInstance(): USBPrinterAdapter? {
if (mInstance == null) {
mInstance = this;
}
return mInstance
}
if (vendorId == -1 || productId == -1) {
Log.d(TAG, "onReceive: No vendor id or product id")
return
}

usbDevice = getDeviceByVendorAndProductId(vendorId, productId) ?: return
}

private val mUsbDeviceReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
var action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized(this) {
val usbDevice =
intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
Log.i(
LOG_TAG,
"Success to grant permission for device " + usbDevice!!.deviceId + ", vendor_id: " + usbDevice.vendorId + " product_id: " + usbDevice.productId
TAG,
"Success to grant permission for device " + usbDevice.deviceId + ", vendor_id: " + usbDevice.vendorId + " product_id: " + usbDevice.productId
)
mUsbDevice = usbDevice
} else {
Toast.makeText(
context,
"User refused to give USB device permissions" + usbDevice!!.deviceName,
"User refused to give USB device permissions" + usbDevice.deviceName,
Toast.LENGTH_LONG
).show()
}
Expand All @@ -74,17 +94,10 @@ class USBPrinterAdapter {
fun init(reactContext: Context?) {
mContext = reactContext
mUSBManager = mContext!!.getSystemService(Context.USB_SERVICE) as UsbManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
mPermissionIntent =
PendingIntent.getBroadcast(mContext, 0, Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
} else {
mPermissionIntent =
PendingIntent.getBroadcast(mContext, 0, Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_UPDATE_CURRENT)
}
val filter = IntentFilter(ACTION_USB_PERMISSION)
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
mContext!!.registerReceiver(mUsbDeviceReceiver, filter)
Log.v(LOG_TAG, "USB Printer initialized")
Log.v(TAG, "USB Printer initialized")
}


Expand All @@ -95,7 +108,7 @@ class USBPrinterAdapter {
mUsbInterface = null
mEndPoint = null
mUsbDeviceConnection = null
mUsbDevice=null
mUsbDevice = null
}
}

Expand All @@ -111,37 +124,52 @@ class USBPrinterAdapter {
return ArrayList(mUSBManager!!.deviceList.values)
}

private fun getDeviceByVendorAndProductId(vendorId: Int, productId: Int): UsbDevice? {
val usbDevices = getDeviceList()
for (usbDevice in usbDevices) {
if (usbDevice.vendorId == vendorId && usbDevice.productId == productId)
return usbDevice
}
return null
}

fun selectDevice(vendorId: Int, productId: Int): Boolean {
if (mUsbDevice == null || mUsbDevice!!.vendorId != vendorId || mUsbDevice!!.productId != productId) {
closeConnectionIfExists()
val usbDevices = getDeviceList()
for (usbDevice in usbDevices) {
if (usbDevice.vendorId == vendorId && usbDevice.productId == productId) {
Log.v(
LOG_TAG,
"Request for device: vendor_id: " + usbDevice.vendorId + ", product_id: " + usbDevice.productId
)
closeConnectionIfExists()
mUSBManager!!.requestPermission(usbDevice, mPermissionIntent)
return true
}
val usbDevice = getDeviceByVendorAndProductId(vendorId, productId) ?: return false

Log.v(TAG, "Request for device: vendor_id: " + usbDevice.vendorId + ", product_id: " + usbDevice.productId)
closeConnectionIfExists()

val flag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
else
PendingIntent.FLAG_UPDATE_CURRENT

val intent = Intent(ACTION_USB_PERMISSION).apply {
putExtra("vendorId", vendorId)
putExtra("productId", productId)
}
return false

val mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, intent, flag)

mUSBManager!!.requestPermission(usbDevice, mPermissionIntent)
return true
}
return true
}

private fun openConnection(): Boolean {
if (mUsbDevice == null) {
Log.e(LOG_TAG, "USB Device is not initialized")
Log.e(TAG, "USB Device is not initialized")
return false
}
if (mUSBManager == null) {
Log.e(LOG_TAG, "USB Manager is not initialized")
Log.e(TAG, "USB Manager is not initialized")
return false
}
if (mUsbDeviceConnection != null) {
Log.i(LOG_TAG, "USB Connection already connected")
Log.i(TAG, "USB Connection already connected")
return true
}
val usbInterface = mUsbDevice!!.getInterface(0)
Expand All @@ -151,7 +179,7 @@ class USBPrinterAdapter {
if (ep.direction == UsbConstants.USB_DIR_OUT) {
val usbDeviceConnection = mUSBManager!!.openDevice(mUsbDevice)
if (usbDeviceConnection == null) {
Log.e(LOG_TAG, "failed to open USB Connection")
Log.e(TAG, "failed to open USB Connection")
return false
}
Toast.makeText(mContext, "Device connected", Toast.LENGTH_SHORT).show()
Expand All @@ -162,7 +190,7 @@ class USBPrinterAdapter {
true
} else {
usbDeviceConnection.close()
Log.e(LOG_TAG, "failed to claim usb connection")
Log.e(TAG, "failed to claim usb connection")
false
}
}
Expand All @@ -172,51 +200,51 @@ class USBPrinterAdapter {
}

fun printText(text: String): Boolean {
Log.v(LOG_TAG, "start to print text")
Log.v(TAG, "start to print text")
val isConnected = openConnection()
return if (isConnected) {
Log.v(LOG_TAG, "Connected to device")
Log.v(TAG, "Connected to device")
Thread {
val bytes = text.toByteArray(Charset.forName("UTF-8"))
val b = mUsbDeviceConnection!!.bulkTransfer(mEndPoint, bytes, bytes.size, 100000)
Log.i(LOG_TAG, "Return Status: b-->$b")
Log.i(TAG, "Return Status: b-->$b")
}.start()
true
} else {
Log.v(LOG_TAG, "failed to connected to device")
Log.v(TAG, "failed to connected to device")
false
}
}

fun printRawText(data: String): Boolean {
Log.v(LOG_TAG, "start to print raw data $data")
Log.v(TAG, "start to print raw data $data")
val isConnected = openConnection()
return if (isConnected) {
Log.v(LOG_TAG, "Connected to device")
Log.v(TAG, "Connected to device")
Thread {
val bytes = Base64.decode(data, Base64.DEFAULT)
val b = mUsbDeviceConnection!!.bulkTransfer(mEndPoint, bytes, bytes.size, 100000)
Log.i(LOG_TAG, "Return Status: $b")
Log.i(TAG, "Return Status: $b")
}.start()
true
} else {
Log.v(LOG_TAG, "failed to connected to device")
Log.v(TAG, "failed to connected to device")
false
}
}

fun write(bytes: ByteArray): Boolean {
Log.v(LOG_TAG, "start to print raw data $bytes")
Log.v(TAG, "start to print raw data $bytes")
val isConnected = openConnection()
return if (isConnected) {
Log.v(LOG_TAG, "Connected to device")
Log.v(TAG, "Connected to device")
Thread {
val b = mUsbDeviceConnection!!.bulkTransfer(mEndPoint, bytes, bytes.size, 100000)
Log.i(LOG_TAG, "Return Status: $b")
Log.i(TAG, "Return Status: $b")
}.start()
true
} else {
Log.v(LOG_TAG, "failed to connected to device")
Log.v(TAG, "failed to connected to device")
false
}
}
Expand Down
2 changes: 1 addition & 1 deletion example/test/widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:flutter_usb_printer_example/main.dart';
import '../lib/main.dart';

void main() {
testWidgets('Verify Platform version', (WidgetTester tester) async {
Expand Down