org.chromium.latency.walt.BaseUsbConnection.java Source code

Java tutorial

Introduction

Here is the source code for org.chromium.latency.walt.BaseUsbConnection.java

Source

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.chromium.latency.walt;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.support.v4.content.LocalBroadcastManager;

import java.util.HashMap;
import java.util.Locale;

public abstract class BaseUsbConnection {
    private static final String USB_PERMISSION_RESPONSE_INTENT = "usb-permission-response";
    private static final String CONNECT_INTENT = "org.chromium.latency.walt.CONNECT";

    protected SimpleLogger logger;
    protected Context context;
    private LocalBroadcastManager broadcastManager;
    private BroadcastReceiver currentConnectReceiver;
    private WaltConnection.ConnectionStateListener connectionStateListener;

    private UsbManager usbManager;
    protected UsbDevice usbDevice = null;
    protected UsbDeviceConnection usbConnection;

    public BaseUsbConnection(Context context) {
        this.context = context;
        usbManager = (UsbManager) this.context.getSystemService(Context.USB_SERVICE);
        logger = SimpleLogger.getInstance(context);
        broadcastManager = LocalBroadcastManager.getInstance(context);
    }

    public abstract int getVid();

    public abstract int getPid();

    // Used to distinguish between bootloader and normal mode that differ by PID
    // TODO: change intent strings to reduce dependence on PID
    protected abstract boolean isCompatibleUsbDevice(UsbDevice usbDevice);

    public void onDisconnect() {
        if (connectionStateListener != null) {
            connectionStateListener.onDisconnect();
        }
    }

    public void onConnect() {
        if (connectionStateListener != null) {
            connectionStateListener.onConnect();
        }
    }

    private String getConnectIntent() {
        return CONNECT_INTENT + getVid() + ":" + getPid();
    }

    private String getUsbPermissionResponseIntent() {
        return USB_PERMISSION_RESPONSE_INTENT + getVid() + ":" + getPid();
    }

    public boolean isConnected() {
        return usbConnection != null;
    }

    public void registerConnectCallback(final Runnable r) {
        if (currentConnectReceiver != null) {
            broadcastManager.unregisterReceiver(currentConnectReceiver);
            currentConnectReceiver = null;
        }

        if (isConnected()) {
            r.run();
            return;
        }

        currentConnectReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                broadcastManager.unregisterReceiver(this);
                r.run();
            }
        };
        broadcastManager.registerReceiver(currentConnectReceiver, new IntentFilter(getConnectIntent()));
    }

    public void connect() {
        UsbDevice usbDevice = findUsbDevice();
        connect(usbDevice);
    }

    public void connect(UsbDevice usbDevice) {
        if (usbDevice == null) {
            logger.log("Device not found.");
            return;
        }

        if (!isCompatibleUsbDevice(usbDevice)) {
            logger.log("Not a valid device");
            return;
        }

        this.usbDevice = usbDevice;

        // Request permission
        // This displays a dialog asking user for permission to use the device.
        // No dialog is displayed if the permission was already given before or the app started as a
        // result of intent filter when the device was plugged in.

        PendingIntent permissionIntent = PendingIntent.getBroadcast(context, 0,
                new Intent(getUsbPermissionResponseIntent()), 0);
        context.registerReceiver(respondToUsbPermission, new IntentFilter(getUsbPermissionResponseIntent()));
        logger.log("Requesting permission for USB device.");
        usbManager.requestPermission(this.usbDevice, permissionIntent);
    }

    public void disconnect() {
        onDisconnect();

        usbConnection.close();
        usbConnection = null;
        usbDevice = null;

        context.unregisterReceiver(disconnectReceiver);
    }

    private BroadcastReceiver disconnectReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
            if (isConnected() && BaseUsbConnection.this.usbDevice.equals(usbDevice)) {
                logger.log("WALT was detached");
                disconnect();
            }
        }
    };

    private BroadcastReceiver respondToUsbPermission = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {

            if (usbDevice == null) {
                logger.log("USB device was not properly opened");
                return;
            }

            if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
                    && usbDevice.equals(intent.getParcelableExtra(UsbManager.EXTRA_DEVICE))) {
                usbConnection = usbManager.openDevice(usbDevice);

                BaseUsbConnection.this.context.registerReceiver(disconnectReceiver,
                        new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED));

                onConnect();

                broadcastManager.sendBroadcast(new Intent(getConnectIntent()));
            } else {
                logger.log("Could not get permission to open the USB device");
            }
            BaseUsbConnection.this.context.unregisterReceiver(respondToUsbPermission);
        }
    };

    public UsbDevice findUsbDevice() {

        logger.log(String.format("Looking for TeensyUSB VID=0x%x PID=0x%x", getVid(), getPid()));

        HashMap<String, UsbDevice> deviceHash = usbManager.getDeviceList();
        if (deviceHash.size() == 0) {
            logger.log("No connected USB devices found");
            return null;
        }

        logger.log("Found " + deviceHash.size() + " connected USB devices:");

        UsbDevice usbDevice = null;

        for (String key : deviceHash.keySet()) {

            UsbDevice dev = deviceHash.get(key);

            String msg = String.format(Locale.US, "USB Device: %s, VID:PID - %x:%x, %d interfaces", key,
                    dev.getVendorId(), dev.getProductId(), dev.getInterfaceCount());

            if (isCompatibleUsbDevice(dev)) {
                usbDevice = dev;
                msg = "Using " + msg;
            } else {
                msg = "Skipping " + msg;
            }

            logger.log(msg);
        }
        return usbDevice;
    }

    public void setConnectionStateListener(WaltConnection.ConnectionStateListener connectionStateListener) {
        this.connectionStateListener = connectionStateListener;
    }
}