Java 使用Android USB主机API读取我的USB游戏控制器/或其他USB设备数据

Java 使用Android USB主机API读取我的USB游戏控制器/或其他USB设备数据,java,android,android-intent,usb,Java,Android,Android Intent,Usb,我正在尝试使用安卓USB主机API读取我的USB游戏控制器数据,一旦我让它工作,我将连接其他设备进行测试。 我的游戏控制器使用OTG电缆连接到我的Android手机。我现在能够获取设备、端点信息,但我不知道如何读取原始数据并显示它 有人能帮我吗?将欣赏一些示例代码 TextView countDisplay; ArrayList<String> listItems = new ArrayList<String>(); ArrayAdapter<Str

我正在尝试使用安卓USB主机API读取我的USB游戏控制器数据,一旦我让它工作,我将连接其他设备进行测试。 我的游戏控制器使用OTG电缆连接到我的Android手机。我现在能够获取设备、端点信息,但我不知道如何读取原始数据并显示它

有人能帮我吗?将欣赏一些示例代码

TextView countDisplay;
    ArrayList<String> listItems = new ArrayList<String>();
    ArrayAdapter<String> adapter;
    String values = "";
    UsbManager mManager;
    UsbDevice device = null;
    private byte[] bytes;
    private static int TIMEOUT = 0;
    private boolean forceClaim = true;
    static PendingIntent mPermissionIntent;
    UsbDeviceConnection connection = null;
    UsbEndpoint InputEndpoint = null;
    UsbEndpoint OutputEndpoint = null;
    private Handler mHandler = new Handler();


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mManager = (UsbManager) getSystemService(Context.USB_SERVICE);
    mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(
            "com.android.example.USB_PERMISSION"), 0);
    IntentFilter filter = new IntentFilter();
    filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
    filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
    registerReceiver(mUsbReceiver, filter);

    HashMap<String, UsbDevice> deviceList = mManager.getDeviceList();
    values = values + "deviceListSize:" + deviceList.size() + ",tostring:"
            + deviceList.toString();
    Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
    while (deviceIterator.hasNext()) {
        device = deviceIterator.next();
        values = values + ",device id:" + device.getDeviceId()
                + ",device name:" + device.getDeviceName();
        values = values + ",Protocol:" + device.getDeviceProtocol()
                + ",ProductId:" + device.getProductId();
        values = values + ",DeviceClass:" + device.getDeviceClass()
                + ",VendorId:" + device.getVendorId();
    }
    if (device != null) {
        values = values + ",getInterfaceCount:"
                + device.getInterfaceCount();
        UsbInterface intf = device.getInterface(0);
        values = values + ",intf.getEndpointCount():"
                + intf.getEndpointCount();
        UsbEndpoint endpoint1 = intf.getEndpoint(0);
        UsbEndpoint endpoint2 = intf.getEndpoint(1);

        mManager.requestPermission(device, mPermissionIntent);
        if (mManager.hasPermission(device)) {
            values = values + ",has permission over device!";
            connection = mManager.openDevice(device);
            if (connection == null) {
                values = values + ",connection null";
            } else {
                values = values + ",getFileDescriptor:"
                        + connection.getFileDescriptor();
                if (endpoint1.getDirection() == UsbConstants.USB_DIR_IN) {
                    InputEndpoint = endpoint1;
                } else {
                    OutputEndpoint = endpoint1;
                }
                if (endpoint2.getDirection() == UsbConstants.USB_DIR_IN) {
                    InputEndpoint = endpoint2;
                } else {
                    OutputEndpoint = endpoint2;
                }
            }
            if (InputEndpoint == null) {
                countDisplay.setText(values + ",InputEndpoint is null");
            }
            if (OutputEndpoint == null) {
                countDisplay.setText(values + ",OutputEndPoint is null");
            }
            connection.claimInterface(intf, forceClaim);
            mHandler.postDelayed(runnable, 1);
        } else {
            values = values + ",Do not have permission over device!";
        }

    }

    setContentView(R.layout.activity_main);
    LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    View v = inflater.inflate(R.layout.activity_main, null);
    LinearLayout ll = new LinearLayout(this);
    ll.setOrientation(LinearLayout.VERTICAL);
    int counter = 1;
    countDisplay = new TextView(this);
    ll.addView(countDisplay);

    countDisplay.setText(values + ",counter here");
    final Button button = new Button(this);
    button.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            if (device != null && mManager.hasPermission(device)) {
                values = values + ",device id:" + device.getDeviceId()
                        + ",device name:" + device.getDeviceName();
                values = values + ",Protocol:" + device.getDeviceProtocol()
                        + ",ProductId:" + device.getProductId();
                values = values + ",DeviceClass:" + device.getDeviceClass()
                        + ",VendorId:" + device.getVendorId();

                countDisplay.setText(values + ",okok");

            } else {
                if (device != null)
                    mManager.requestPermission(device, mPermissionIntent);
            }
        }

    });
    ll.addView(button);
    setContentView(ll);
}

此程序作为以下USB主机功能的示例:

  • 基于接口类、子类和协议匹配设备(参见device_filter.xml)

  • 批量端点上的异步IO

所有代码版权:

    /*
     * Copyright (C) 2011 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 com.android.adb;

    import android.hardware.usb.UsbConstants;
    import android.hardware.usb.UsbDeviceConnection;
    import android.hardware.usb.UsbEndpoint;
    import android.hardware.usb.UsbInterface;
    import android.hardware.usb.UsbRequest;
    import android.util.SparseArray;

    import java.util.LinkedList;

    /* This class represents a USB device that supports the adb protocol. */
    public class AdbDevice {

        private final AdbTestActivity mActivity;
        private final UsbDeviceConnection mDeviceConnection;
        private final UsbEndpoint mEndpointOut;
        private final UsbEndpoint mEndpointIn;

        private String mSerial;

        // pool of requests for the OUT endpoint
        private final LinkedList<UsbRequest> mOutRequestPool = new LinkedList<UsbRequest>();
        // pool of requests for the IN endpoint
        private final LinkedList<UsbRequest> mInRequestPool = new LinkedList<UsbRequest>();
        // list of currently opened sockets
        private final SparseArray<AdbSocket> mSockets = new SparseArray<AdbSocket>();
        private int mNextSocketId = 1;

        private final WaiterThread mWaiterThread = new WaiterThread();

        public AdbDevice(AdbTestActivity activity, UsbDeviceConnection connection,
                UsbInterface intf) {
            mActivity = activity;
            mDeviceConnection = connection;
            mSerial = connection.getSerial();

            UsbEndpoint epOut = null;
            UsbEndpoint epIn = null;
            // look for our bulk endpoints
            for (int i = 0; i < intf.getEndpointCount(); i++) {
                UsbEndpoint ep = intf.getEndpoint(i);
                if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                        epOut = ep;
                    } else {
                        epIn = ep;
                    }
                }
            }
            if (epOut == null || epIn == null) {
                throw new IllegalArgumentException("not all endpoints found");
            }
            mEndpointOut = epOut;
            mEndpointIn = epIn;
        }

        // return device serial number
        public String getSerial() {
            return mSerial;
        }

        // get an OUT request from our pool
        public UsbRequest getOutRequest() {
            synchronized(mOutRequestPool) {
                if (mOutRequestPool.isEmpty()) {
                    UsbRequest request = new UsbRequest();
                    request.initialize(mDeviceConnection, mEndpointOut);
                    return request;
                } else {
                    return mOutRequestPool.removeFirst();
                }
            }
        }

        // return an OUT request to the pool
        public void releaseOutRequest(UsbRequest request) {
            synchronized (mOutRequestPool) {
                mOutRequestPool.add(request);
            }
        }

        // get an IN request from the pool
        public UsbRequest getInRequest() {
            synchronized(mInRequestPool) {
                if (mInRequestPool.isEmpty()) {
                    UsbRequest request = new UsbRequest();
                    request.initialize(mDeviceConnection, mEndpointIn);
                    return request;
                } else {
                    return mInRequestPool.removeFirst();
                }
            }
        }

        public void start() {
            mWaiterThread.start();
            connect();
        }

        public AdbSocket openSocket(String destination) {
            AdbSocket socket;
            synchronized (mSockets) {
                int id = mNextSocketId++;
                socket = new AdbSocket(this, id);
                mSockets.put(id, socket);
            }
            if (socket.open(destination)) {
                return socket;
            } else {
                return null;
            }
        }

        private AdbSocket getSocket(int id) {
            synchronized (mSockets) {
                return mSockets.get(id);
            }
        }

        public void socketClosed(AdbSocket socket) {
            synchronized (mSockets) {
                mSockets.remove(socket.getId());
            }
        }

        // send a connect command
        private void connect() {
            AdbMessage message = new AdbMessage();
            message.set(AdbMessage.A_CNXN, AdbMessage.A_VERSION, AdbMessage.MAX_PAYLOAD, "host::\0");
            message.write(this);
        }

        // handle connect response
        private void handleConnect(AdbMessage message) {
            if (message.getDataString().startsWith("device:")) {
                log("connected");
                mActivity.deviceOnline(this);
            }
        }

        public void stop() {
            synchronized (mWaiterThread) {
                mWaiterThread.mStop = true;
            }
        }

        // dispatch a message from the device
        void dispatchMessage(AdbMessage message) {
            int command = message.getCommand();
            switch (command) {
                case AdbMessage.A_SYNC:
                    log("got A_SYNC");
                    break;
                case AdbMessage.A_CNXN:
                    handleConnect(message);
                    break;
                case AdbMessage.A_OPEN:
                case AdbMessage.A_OKAY:
                case AdbMessage.A_CLSE:
                case AdbMessage.A_WRTE:
                    AdbSocket socket = getSocket(message.getArg1());
                    if (socket == null) {
                        log("ERROR socket not found");
                    } else {
                        socket.handleMessage(message);
                    }
                    break;
            }
        }

        void log(String s) {
            mActivity.log(s);
        }


        private class WaiterThread extends Thread {
            public boolean mStop;

            public void run() {
                // start out with a command read
                AdbMessage currentCommand = new AdbMessage();
                AdbMessage currentData = null;
                // FIXME error checking
                currentCommand.readCommand(getInRequest());

                while (true) {
                    synchronized (this) {
                        if (mStop) {
                            return;
                        }
                    }
                    UsbRequest request = mDeviceConnection.requestWait();
                    if (request == null) {
                        break;
                    }

                    AdbMessage message = (AdbMessage)request.getClientData();
                    request.setClientData(null);
                    AdbMessage messageToDispatch = null;

                    if (message == currentCommand) {
                        int dataLength = message.getDataLength();
                        // read data if length > 0
                        if (dataLength > 0) {
                            message.readData(getInRequest(), dataLength);
                            currentData = message;
                        } else {
                            messageToDispatch = message;
                        }
                        currentCommand = null;
                    } else if (message == currentData) {
                        messageToDispatch = message;
                        currentData = null;
                    }

                    if (messageToDispatch != null) {
                        // queue another read first
                        currentCommand = new AdbMessage();
                        currentCommand.readCommand(getInRequest());

                        // then dispatch the current message
                        dispatchMessage(messageToDispatch);
                    }

                    // put request back into the appropriate pool
                    if (request.getEndpoint() == mEndpointOut) {
                        releaseOutRequest(request);
                    } else {
                        synchronized (mInRequestPool) {
                            mInRequestPool.add(request);
                        }
                    }
                }
            }
        }
    }

有关usb和连接的更多信息,请参阅下面的文章

最后一段解释了您可能面临的一些问题。他们提供的示例还可能向您展示如何读取数据以及如何格式化消息

看起来你面临两个问题。一个是设置你的代码来读取消息,这是Puspendu的答案,第二个问题是“如何”沟通,你需要发送什么消息来建立连接、握手,并确定好的东西,即你想要的数据


Puspendu展示了一个读取和写入设备的示例。但是,我可以想象,根据您连接的设备,握手和消息结构将发生变化,因此您必须查找这些部分(恐怕我不知道其他任何示例)。

您是否阅读过此内容:@mico您是否编写过此程序?没有关于如何从USB读取数据的代码devices@PuspenduBanerjee你看过他的问题了吗?在他问的58个问题中,18个未被接受的问题要么没有任何答案,要么没有任何可接受的答案。谢谢你的回答,我已经看到了这一点,这是API sdk中的一个Andriod示例。我需要一些可以与游戏机和其他适当的usb设备工作please@leon不确定,你所说的“合适的usb设备”是什么意思?哦,是的,一般来说,你需要创建一个消息并将其写入一个缓冲区,让设备传输数据。同样,我会想象创建一个阅读器来捕获设备接收到的消息。我会在例子中寻找这些。
    package com.android.adb;

    import android.hardware.usb.UsbConstants;
    import android.hardware.usb.UsbDeviceConnection;
    import android.hardware.usb.UsbEndpoint;
    import android.hardware.usb.UsbInterface;
    import android.hardware.usb.UsbRequest;
    import android.util.SparseArray;

    import java.util.LinkedList;

    /* This class represents a USB device that supports the adb protocol. */
    public class AdbDevice {

        private final AdbTestActivity mActivity;
        private final UsbDeviceConnection mDeviceConnection;
        private final UsbEndpoint mEndpointOut;
        private final UsbEndpoint mEndpointIn;

        private String mSerial;

        // pool of requests for the OUT endpoint
        private final LinkedList<UsbRequest> mOutRequestPool = new LinkedList<UsbRequest>();
        // pool of requests for the IN endpoint
        private final LinkedList<UsbRequest> mInRequestPool = new LinkedList<UsbRequest>();
        // list of currently opened sockets
        private final SparseArray<AdbSocket> mSockets = new SparseArray<AdbSocket>();
        private int mNextSocketId = 1;

        private final WaiterThread mWaiterThread = new WaiterThread();

        public AdbDevice(AdbTestActivity activity, UsbDeviceConnection connection,
                UsbInterface intf) {
            mActivity = activity;
            mDeviceConnection = connection;
            mSerial = connection.getSerial();

            UsbEndpoint epOut = null;
            UsbEndpoint epIn = null;
            // look for our bulk endpoints
            for (int i = 0; i < intf.getEndpointCount(); i++) {
                UsbEndpoint ep = intf.getEndpoint(i);
                if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                        epOut = ep;
                    } else {
                        epIn = ep;
                    }
                }
            }
            if (epOut == null || epIn == null) {
                throw new IllegalArgumentException("not all endpoints found");
            }
            mEndpointOut = epOut;
            mEndpointIn = epIn;
        }

        // return device serial number
        public String getSerial() {
            return mSerial;
        }

        // get an OUT request from our pool
        public UsbRequest getOutRequest() {
            synchronized(mOutRequestPool) {
                if (mOutRequestPool.isEmpty()) {
                    UsbRequest request = new UsbRequest();
                    request.initialize(mDeviceConnection, mEndpointOut);
                    return request;
                } else {
                    return mOutRequestPool.removeFirst();
                }
            }
        }

        // return an OUT request to the pool
        public void releaseOutRequest(UsbRequest request) {
            synchronized (mOutRequestPool) {
                mOutRequestPool.add(request);
            }
        }

        // get an IN request from the pool
        public UsbRequest getInRequest() {
            synchronized(mInRequestPool) {
                if (mInRequestPool.isEmpty()) {
                    UsbRequest request = new UsbRequest();
                    request.initialize(mDeviceConnection, mEndpointIn);
                    return request;
                } else {
                    return mInRequestPool.removeFirst();
                }
            }
        }

        public void start() {
            mWaiterThread.start();
            connect();
        }

        public AdbSocket openSocket(String destination) {
            AdbSocket socket;
            synchronized (mSockets) {
                int id = mNextSocketId++;
                socket = new AdbSocket(this, id);
                mSockets.put(id, socket);
            }
            if (socket.open(destination)) {
                return socket;
            } else {
                return null;
            }
        }

        private AdbSocket getSocket(int id) {
            synchronized (mSockets) {
                return mSockets.get(id);
            }
        }

        public void socketClosed(AdbSocket socket) {
            synchronized (mSockets) {
                mSockets.remove(socket.getId());
            }
        }

        // send a connect command
        private void connect() {
            AdbMessage message = new AdbMessage();
            message.set(AdbMessage.A_CNXN, AdbMessage.A_VERSION, AdbMessage.MAX_PAYLOAD, "host::\0");
            message.write(this);
        }

        // handle connect response
        private void handleConnect(AdbMessage message) {
            if (message.getDataString().startsWith("device:")) {
                log("connected");
                mActivity.deviceOnline(this);
            }
        }

        public void stop() {
            synchronized (mWaiterThread) {
                mWaiterThread.mStop = true;
            }
        }

        // dispatch a message from the device
        void dispatchMessage(AdbMessage message) {
            int command = message.getCommand();
            switch (command) {
                case AdbMessage.A_SYNC:
                    log("got A_SYNC");
                    break;
                case AdbMessage.A_CNXN:
                    handleConnect(message);
                    break;
                case AdbMessage.A_OPEN:
                case AdbMessage.A_OKAY:
                case AdbMessage.A_CLSE:
                case AdbMessage.A_WRTE:
                    AdbSocket socket = getSocket(message.getArg1());
                    if (socket == null) {
                        log("ERROR socket not found");
                    } else {
                        socket.handleMessage(message);
                    }
                    break;
            }
        }

        void log(String s) {
            mActivity.log(s);
        }


        private class WaiterThread extends Thread {
            public boolean mStop;

            public void run() {
                // start out with a command read
                AdbMessage currentCommand = new AdbMessage();
                AdbMessage currentData = null;
                // FIXME error checking
                currentCommand.readCommand(getInRequest());

                while (true) {
                    synchronized (this) {
                        if (mStop) {
                            return;
                        }
                    }
                    UsbRequest request = mDeviceConnection.requestWait();
                    if (request == null) {
                        break;
                    }

                    AdbMessage message = (AdbMessage)request.getClientData();
                    request.setClientData(null);
                    AdbMessage messageToDispatch = null;

                    if (message == currentCommand) {
                        int dataLength = message.getDataLength();
                        // read data if length > 0
                        if (dataLength > 0) {
                            message.readData(getInRequest(), dataLength);
                            currentData = message;
                        } else {
                            messageToDispatch = message;
                        }
                        currentCommand = null;
                    } else if (message == currentData) {
                        messageToDispatch = message;
                        currentData = null;
                    }

                    if (messageToDispatch != null) {
                        // queue another read first
                        currentCommand = new AdbMessage();
                        currentCommand.readCommand(getInRequest());

                        // then dispatch the current message
                        dispatchMessage(messageToDispatch);
                    }

                    // put request back into the appropriate pool
                    if (request.getEndpoint() == mEndpointOut) {
                        releaseOutRequest(request);
                    } else {
                        synchronized (mInRequestPool) {
                            mInRequestPool.add(request);
                        }
                    }
                }
            }
        }
    }
    package com.android.adb;

    import android.hardware.usb.UsbRequest;

    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;

    /* This class encapsulates and adb command packet */
    public class AdbMessage {

        // command names
        public static final int A_SYNC = 0x434e5953;
        public static final int A_CNXN = 0x4e584e43;
        public static final int A_OPEN = 0x4e45504f;
        public static final int A_OKAY = 0x59414b4f;
        public static final int A_CLSE = 0x45534c43;
        public static final int A_WRTE = 0x45545257;

        // ADB protocol version
        public static final int A_VERSION = 0x01000000;

        public static final int MAX_PAYLOAD = 4096;

        private final ByteBuffer mMessageBuffer;
        private final ByteBuffer mDataBuffer;

        public AdbMessage() {
            mMessageBuffer = ByteBuffer.allocate(24);
            mDataBuffer = ByteBuffer.allocate(MAX_PAYLOAD);
            mMessageBuffer.order(ByteOrder.LITTLE_ENDIAN);
            mDataBuffer.order(ByteOrder.LITTLE_ENDIAN);
        }

        // sets the fields in the command header
        public void set(int command, int arg0, int arg1, byte[] data) {
            mMessageBuffer.putInt(0, command);
            mMessageBuffer.putInt(4, arg0);
            mMessageBuffer.putInt(8, arg1);
            mMessageBuffer.putInt(12, (data == null ? 0 : data.length));
            mMessageBuffer.putInt(16, (data == null ? 0 : checksum(data)));
            mMessageBuffer.putInt(20, command ^ 0xFFFFFFFF);
            if (data != null) {
                mDataBuffer.put(data, 0, data.length);
            }
        }

        public void set(int command, int arg0, int arg1) {
            set(command, arg0, arg1, (byte[])null);
        }
        public void set(int command, int arg0, int arg1, String data) {
            // add trailing zero
            data += "\0";
            set(command, arg0, arg1, data.getBytes());
        }

        // returns the command's message ID
        public int getCommand() {
            return mMessageBuffer.getInt(0);
        }

        // returns command's first argument
        public int getArg0() {
            return mMessageBuffer.getInt(4);
        }

        // returns command's second argument
        public int getArg1() {
            return mMessageBuffer.getInt(8);
        }

        // returns command's data buffer
        public ByteBuffer getData() {
            return mDataBuffer;
        }

        // returns command's data length
        public int getDataLength() {
            return mMessageBuffer.getInt(12);
        }

        // returns command's data as a string
        public String getDataString() {
            int length = getDataLength();
            if (length == 0) return null;
            // trim trailing zero
            return new String(mDataBuffer.array(), 0, length - 1);
        }


        public boolean write(AdbDevice device) {
            synchronized (device) {
                UsbRequest request = device.getOutRequest();
                request.setClientData(this);
                if (request.queue(mMessageBuffer, 24)) {
                    int length = getDataLength();
                    if (length > 0) {
                        request = device.getOutRequest();
                        request.setClientData(this);
                        if (request.queue(mDataBuffer, length)) {
                            return true;
                        } else {
                            device.releaseOutRequest(request);
                            return false;
                        }
                    }
                    return true;
                } else {
                    device.releaseOutRequest(request);
                    return false;
                }
            }
        }

        public boolean readCommand(UsbRequest request) {
            request.setClientData(this);
            return request.queue(mMessageBuffer, 24);
        }

        public boolean readData(UsbRequest request, int length) {
            request.setClientData(this);
            return request.queue(mDataBuffer, length);
        }

        private static String extractString(ByteBuffer buffer, int offset, int length) {
            byte[] bytes = new byte[length];
            for (int i = 0; i < length; i++) {
                bytes[i] = buffer.get(offset++);
            }
            return new String(bytes);
        }

        @Override
        public String toString() {
            String commandName = extractString(mMessageBuffer, 0, 4);
            int dataLength = getDataLength();
            String result = "Adb Message: " + commandName + " arg0: " + getArg0() +
                 " arg1: " + getArg1() + " dataLength: " + dataLength;
            if (dataLength > 0) {
                result += (" data: \"" + getDataString() + "\"");
            }
            return result;
        }

        private static int checksum(byte[] data) {
            int result = 0;
            for (int i = 0; i < data.length; i++) {
                int x = data[i];
                // dang, no unsigned ints in java
                if (x < 0) x += 256;
                result += x;
            }
            return result;
        }
    }
    package com.android.adb;

    /* This class represents an adb socket.  adb supports multiple independent
     * socket connections to a single device.  Typically a socket is created
     * for each adb command that is executed.
     */
    public class AdbSocket {

        private final AdbDevice mDevice;
        private final int mId;
        private int mPeerId;

        public AdbSocket(AdbDevice device, int id) {
            mDevice = device;
            mId = id;
        }

        public int getId() {
            return mId;
        }

        public boolean open(String destination) {
            AdbMessage message = new AdbMessage();
            message.set(AdbMessage.A_OPEN, mId, 0, destination);
            if (! message.write(mDevice)) {
                return false;
            }

            synchronized (this) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    return false;
                }
            }
            return true;
        }

        public void handleMessage(AdbMessage message) {
            switch (message.getCommand()) {
                case AdbMessage.A_OKAY:
                    mPeerId = message.getArg0();
                    synchronized (this) {
                        notify();
                    }
                    break;
                case AdbMessage.A_WRTE:
                    mDevice.log(message.getDataString());
                    sendReady();
                    break;
            }
        }

        private void sendReady() {
            AdbMessage message = new AdbMessage();
            message.set(AdbMessage.A_OKAY, mId, mPeerId);
            message.write(mDevice);
        }
    }