// Path: IOIO/iOIOLibAndroid/src/main/java/ioio/lib/api/IOIOConnection.java
// public interface IOIOConnection {
//     void waitForConnect() throws ConnectionLostException;
// 
//     void disconnect();
// 
//     InputStream getInputStream() throws ConnectionLostException;
// 
//     OutputStream getOutputStream() throws ConnectionLostException;
// 
//     /**
//      * Can this connection be closed. Normally the answer would be "true", but
//      * some weird connections cannot be closed and need the higher layer to do
//      * a "soft close" instead.
//      *
//      * @return true This connection can be closed.
//      */
//     boolean canClose();
// }
// 
// Path: IOIO/iOIOLibAndroid/src/main/java/ioio/lib/impl/FixedReadBufferedInputStream.java
// public class FixedReadBufferedInputStream extends InputStream {
//     private int bufferIndex_ = 0;
//     private int validData_ = 0;
//     private final byte[] buffer_;
//     private final InputStream source_;
// 
//     public FixedReadBufferedInputStream(InputStream source, int size) {
//         buffer_ = new byte[size];
//         source_ = source;
//     }
// 
//     @Override
//     public int available() throws IOException {
//         return validData_ - bufferIndex_;
//     }
// 
//     @Override
//     public void close() throws IOException {
//         source_.close();
//     }
// 
//     @Override
//     public int read(byte[] buffer, int offset, int length) throws IOException {
//         fillIfEmpty();
//         if (validData_ == -1) {
//             return -1;
//         }
//         length = Math.min(length, validData_ - bufferIndex_);
//         System.arraycopy(buffer_, bufferIndex_, buffer, offset, length);
//         bufferIndex_ += length;
//         return length;
//     }
// 
//     @Override
//     public int read(byte[] buffer) throws IOException {
//         return read(buffer, 0, buffer.length);
//     }
// 
//     @Override
//     public int read() throws IOException {
//         fillIfEmpty();
//         if (validData_ == -1) {
//             return -1;
//         }
//         return buffer_[bufferIndex_++] & 0xFF;
//     }
// 
//     @Override
//     public long skip(long byteCount) throws IOException {
//         long skipped = 0;
//         while (byteCount > 0) {
//             fillIfEmpty();
//             if (validData_ == -1) {
//                 return skipped;
//             }
//             int count = (int) Math.min(available(), byteCount);
//             byteCount -= count;
//             bufferIndex_ += count;
//             skipped += count;
//         }
//         return skipped;
//     }
// 
//     private void fillIfEmpty() throws IOException {
//         while (available() == 0 && validData_ != -1) {
//             fill();
//         }
//     }
// 
//     private void fill() throws IOException {
//         bufferIndex_ = 0;
//         validData_ = source_.read(buffer_);
//     }
// }
// 
// Path: IOIO/iOIOLibAndroid/src/main/java/ioio/lib/spi/IOIOConnectionBootstrap.java
// public interface IOIOConnectionBootstrap {
//     public void getFactories(Collection<IOIOConnectionFactory> result);
// }
// 
// Path: IOIO/iOIOLibAndroid/src/main/java/ioio/lib/spi/IOIOConnectionFactory.java
// public interface IOIOConnectionFactory {
//     /**
//      * A unique name of the connection type. Typically a fully-qualified
//      * name of the connection class.
//      */
//     public String getType();
// 
//     /**
//      * Extra information on the connection. This is specific to the
//      * connection type. For example, for a Bluetooth connection, this is an
//      * array containing the name and the Bluetooth address of the remote
//      * IOIO.
//      */
//     public Object getExtra();
// 
//     public IOIOConnection createConnection();
// }
// 
// Path: IOIO/iOIOLibAndroid/src/main/java/ioio/lib/util/android/ContextWrapperDependent.java
// public interface ContextWrapperDependent {
//     public void onCreate(ContextWrapper wrapper);
// 
//     public void onDestroy();
// 
//     public void open();
// 
//     public void reopen();
// 
//     public void close();
// }


import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import ioio.lib.api.IOIOConnection;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.impl.FixedReadBufferedInputStream;
import ioio.lib.spi.IOIOConnectionBootstrap;
import ioio.lib.spi.IOIOConnectionFactory;
import ioio.lib.spi.NoRuntimeSupportException;
import ioio.lib.util.android.ContextWrapperDependent;
            epIn_ = ep0;
            epOut_ = ep1;
        } else if (ep0.getDirection() == UsbConstants.USB_DIR_OUT
                && ep1.getDirection() == UsbConstants.USB_DIR_IN) {
            epIn_ = ep1;
            epOut_ = ep0;
        } else {
            Log.e(TAG, "Endpoints directions are not compatible.");
            return false;
        }
        return true;
    }

    /**
     * Claim interfaces and create the I/O streams.
     * <p/>
     * If the call succeeds it returns {@code true} and the caller is responsible to call
     * {@link #closeStreams()}. If the call fails, it returns (@code false} and no clean-up is
     * required from the caller.
     *
     * @precondition The device is attached, permission has been granted to connect to it, and the
     * descriptor has been processed.
     */
    private boolean openStreams() {
        // Claim interfaces.
        if (connection_.claimInterface(controlInterface_, true)) {
            if (connection_.claimInterface(dataInterface_, true)) {
                // Raise DTR.
                if (setDTR(true)) {
                    // Create streams. Buffer them with a reasonable buffer sizes.
// Path: IOIO/iOIOLibAndroid/src/main/java/ioio/lib/api/IOIOConnection.java
// public interface IOIOConnection {
//     void waitForConnect() throws ConnectionLostException;
// 
//     void disconnect();
// 
//     InputStream getInputStream() throws ConnectionLostException;
// 
//     OutputStream getOutputStream() throws ConnectionLostException;
// 
//     /**
//      * Can this connection be closed. Normally the answer would be "true", but
//      * some weird connections cannot be closed and need the higher layer to do
//      * a "soft close" instead.
//      *
//      * @return true This connection can be closed.
//      */
//     boolean canClose();
// }
// 
// Path: IOIO/iOIOLibAndroid/src/main/java/ioio/lib/impl/FixedReadBufferedInputStream.java
// public class FixedReadBufferedInputStream extends InputStream {
//     private int bufferIndex_ = 0;
//     private int validData_ = 0;
//     private final byte[] buffer_;
//     private final InputStream source_;
// 
//     public FixedReadBufferedInputStream(InputStream source, int size) {
//         buffer_ = new byte[size];
//         source_ = source;
//     }
// 
//     @Override
//     public int available() throws IOException {
//         return validData_ - bufferIndex_;
//     }
// 
//     @Override
//     public void close() throws IOException {
//         source_.close();
//     }
// 
//     @Override
//     public int read(byte[] buffer, int offset, int length) throws IOException {
//         fillIfEmpty();
//         if (validData_ == -1) {
//             return -1;
//         }
//         length = Math.min(length, validData_ - bufferIndex_);
//         System.arraycopy(buffer_, bufferIndex_, buffer, offset, length);
//         bufferIndex_ += length;
//         return length;
//     }
// 
//     @Override
//     public int read(byte[] buffer) throws IOException {
//         return read(buffer, 0, buffer.length);
//     }
// 
//     @Override
//     public int read() throws IOException {
//         fillIfEmpty();
//         if (validData_ == -1) {
//             return -1;
//         }
//         return buffer_[bufferIndex_++] & 0xFF;
//     }
// 
//     @Override
//     public long skip(long byteCount) throws IOException {
//         long skipped = 0;
//         while (byteCount > 0) {
//             fillIfEmpty();
//             if (validData_ == -1) {
//                 return skipped;
//             }
//             int count = (int) Math.min(available(), byteCount);
//             byteCount -= count;
//             bufferIndex_ += count;
//             skipped += count;
//         }
//         return skipped;
//     }
// 
//     private void fillIfEmpty() throws IOException {
//         while (available() == 0 && validData_ != -1) {
//             fill();
//         }
//     }
// 
//     private void fill() throws IOException {
//         bufferIndex_ = 0;
//         validData_ = source_.read(buffer_);
//     }
// }
// 
// Path: IOIO/iOIOLibAndroid/src/main/java/ioio/lib/spi/IOIOConnectionBootstrap.java
// public interface IOIOConnectionBootstrap {
//     public void getFactories(Collection<IOIOConnectionFactory> result);
// }
// 
// Path: IOIO/iOIOLibAndroid/src/main/java/ioio/lib/spi/IOIOConnectionFactory.java
// public interface IOIOConnectionFactory {
//     /**
//      * A unique name of the connection type. Typically a fully-qualified
//      * name of the connection class.
//      */
//     public String getType();
// 
//     /**
//      * Extra information on the connection. This is specific to the
//      * connection type. For example, for a Bluetooth connection, this is an
//      * array containing the name and the Bluetooth address of the remote
//      * IOIO.
//      */
//     public Object getExtra();
// 
//     public IOIOConnection createConnection();
// }
// 
// Path: IOIO/iOIOLibAndroid/src/main/java/ioio/lib/util/android/ContextWrapperDependent.java
// public interface ContextWrapperDependent {
//     public void onCreate(ContextWrapper wrapper);
// 
//     public void onDestroy();
// 
//     public void open();
// 
//     public void reopen();
// 
//     public void close();
// }


// Path: IOIO/iOIOLibAndroidDevice/src/main/java/ioio/lib/android/device/DeviceConnectionBootstrap.java
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import ioio.lib.api.IOIOConnection;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.impl.FixedReadBufferedInputStream;
import ioio.lib.spi.IOIOConnectionBootstrap;
import ioio.lib.spi.IOIOConnectionFactory;
import ioio.lib.spi.NoRuntimeSupportException;
import ioio.lib.util.android.ContextWrapperDependent;

            epIn_ = ep0;
            epOut_ = ep1;
        } else if (ep0.getDirection() == UsbConstants.USB_DIR_OUT
                && ep1.getDirection() == UsbConstants.USB_DIR_IN) {
            epIn_ = ep1;
            epOut_ = ep0;
        } else {
            Log.e(TAG, "Endpoints directions are not compatible.");
            return false;
        }
        return true;
    }

    /**
     * Claim interfaces and create the I/O streams.
     * <p/>
     * If the call succeeds it returns {@code true} and the caller is responsible to call
     * {@link #closeStreams()}. If the call fails, it returns (@code false} and no clean-up is
     * required from the caller.
     *
     * @precondition The device is attached, permission has been granted to connect to it, and the
     * descriptor has been processed.
     */
    private boolean openStreams() {
        // Claim interfaces.
        if (connection_.claimInterface(controlInterface_, true)) {
            if (connection_.claimInterface(dataInterface_, true)) {
                // Raise DTR.
                if (setDTR(true)) {
                    // Create streams. Buffer them with a reasonable buffer sizes.
                    inputStream_ = new FixedReadBufferedInputStream(new Streams.DeviceInputStream(