AndroidTalerUsbTransport.kt

/*
 * This file is part of GNU Taler
 * (C) 2026 Taler Systems S.A.
 *
 * GNU Taler is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3, or (at your option) any later version.
 *
 * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */

package net.taler.merchantpos.devices

import android.hardware.usb.UsbConstants
import android.hardware.usb.UsbManager

/** The vendor-control protocol from the device's Android example; not USB serial. */
internal class AndroidTalerUsbTransport(
    private val manager: UsbManager,
) : TalerUsbTransport
{
    override fun devices() =
        manager.deviceList.values
            .filter { TalerUsbSession.supports(it.vendorId, it.productId) }
            .sortedBy { it.deviceName }
            .map { TalerUsbDevice(it.deviceName, manager.hasPermission(it)) }

    override fun write(
        device: TalerUsbDevice,
        payload: ByteArray,
    ): Boolean
    {
        val attached = manager.deviceList[device.id] ?: return false
        if (!TalerUsbSession.supports(attached.vendorId, attached.productId) ||
            !manager.hasPermission(attached))
        {
            return false
        }
        val connection = manager.openDevice(attached) ?: return false
        return try
        {
            connection.controlTransfer(
                UsbConstants.USB_DIR_OUT or UsbConstants.USB_TYPE_VENDOR,
                0,
                0,
                0,
                payload,
                payload.size,
                1000,
            ) == payload.size
        }
        finally
        {
            connection.close()
        }
    }
}