1. 程式人生 > >Android USB通訊(完整版)

Android USB通訊(完整版)

這裡寫圖片描述

1.Host端程式碼:

package com.tcl.navigator.hostchart.activity;

import android.app.PendingIntent;
import android.content.Context;
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.Bundle; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import
android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import com.tcl.navigator.hostchart.R; import com.tcl.navigator.hostchart.base.MyApplication; import com.tcl.navigator.hostchart.receiver.OpenDevicesReceiver; import com.tcl.navigator.hostchart.receiver.UsbDetachedReceiver; import
java.util.Collection; import java.util.HashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * */ public class MainActivity extends AppCompatActivity implements UsbDetachedReceiver.UsbDetachedListener, OpenDevicesReceiver.OpenDevicesListener, View.OnClickListener { private static final int CONNECTED_SUCCESS = 0; private static final int RECEIVER_MESSAGE_SUCCESS = 1; private static final int SEND_MESSAGE_SUCCESS = 2; private static final String USB_ACTION = "com.tcl.navigator.hostchart"; private TextView mLog; private EditText mMessage; private UsbDetachedReceiver mUsbDetachedReceiver; private ExecutorService mThreadPool; private UsbManager mUsbManager; private OpenDevicesReceiver mOpenDevicesReceiver; private TextView mError; private UsbDeviceConnection mUsbDeviceConnection; private UsbEndpoint mUsbEndpointOut; private UsbEndpoint mUsbEndpointIn; private boolean mToggle = true; private Button mSendMessage; private boolean isDetached = false; private byte[] mBytes = new byte[1024]; private boolean isReceiverMessage = true; private UsbInterface mUsbInterface; private StringBuffer mStringBuffer = new StringBuffer(); private Context mContext; Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case CONNECTED_SUCCESS://車機和手機連線成功 mError.setText(""); mSendMessage.setEnabled(true); loopReceiverMessage(); break; case RECEIVER_MESSAGE_SUCCESS://成功接受到資料 mLog.setText(mStringBuffer.toString()); break; case SEND_MESSAGE_SUCCESS://成功傳送資料 mMessage.setText(""); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { initView(); initListener(); initData(); } private void initView() { mLog = (TextView) findViewById(R.id.log); mError = (TextView) findViewById(R.id.error); mMessage = (EditText) findViewById(R.id.message); mSendMessage = (Button) findViewById(R.id.sendmessage); } private void initListener() { mSendMessage.setOnClickListener(this); } private void initData() { mContext = getApplicationContext(); mSendMessage.setEnabled(false); mUsbDetachedReceiver = new UsbDetachedReceiver(this); IntentFilter intentFilter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED); registerReceiver(mUsbDetachedReceiver, intentFilter); mThreadPool = Executors.newFixedThreadPool(5); mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); openDevices(); } /** * 開啟裝置 , 讓車機和手機端連起來 */ private void openDevices() { PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(USB_ACTION), 0); IntentFilter intentFilter = new IntentFilter(USB_ACTION); mOpenDevicesReceiver = new OpenDevicesReceiver(this); registerReceiver(mOpenDevicesReceiver, intentFilter); //列舉裝置(手機) HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList(); if (deviceList != null) { for (UsbDevice usbDevice : deviceList.values()) { int productId = usbDevice.getProductId(); if (productId != 377 && productId != 7205) { //這裡說明下,這裡的377 , 7205是我這臺機子上獨有,因為我這上面有多臺裝置,所以我在這裡 //判斷了下.只有一臺裝置的無需這一步. if (mUsbManager.hasPermission(usbDevice)) { initAccessory(usbDevice); } else { mUsbManager.requestPermission(usbDevice, pendingIntent); } } } } else { mError.setText("請連線USB"); } } /** * 傳送命令 , 讓手機進入Accessory模式 * * @param usbDevice */ private void initAccessory(UsbDevice usbDevice) { UsbDeviceConnection usbDeviceConnection = mUsbManager.openDevice(usbDevice); if (usbDeviceConnection == null) { mError.setText("請連線USB"); return; } //根據AOA協議開啟Accessory模式 initStringControlTransfer(usbDeviceConnection, 0, "Google, Inc."); // MANUFACTURER initStringControlTransfer(usbDeviceConnection, 1, "AccessoryChat"); // MODEL initStringControlTransfer(usbDeviceConnection, 2, "Accessory Chat"); // DESCRIPTION initStringControlTransfer(usbDeviceConnection, 3, "1.0"); // VERSION initStringControlTransfer(usbDeviceConnection, 4, "http://www.android.com"); // URI initStringControlTransfer(usbDeviceConnection, 5, "0123456789"); // SERIAL usbDeviceConnection.controlTransfer(0x40, 53, 0, 0, new byte[]{}, 0, 100); usbDeviceConnection.close(); MyApplication.printLogDebug("initAccessory success"); initDevice(); } private void initStringControlTransfer(UsbDeviceConnection deviceConnection, int index, String string) { deviceConnection.controlTransfer(0x40, 52, 0, index, string.getBytes(), string.length(), 100); } /** * 初始化裝置(手機) , 當手機進入Accessory模式後 , 手機的PID會變為Google定義的2個常量值其中的一個 , */ private void initDevice() { mThreadPool.execute(new Runnable() { @Override public void run() { while (mToggle) { SystemClock.sleep(1000); HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList(); Collection<UsbDevice> values = deviceList.values(); if (!values.isEmpty()) { for (UsbDevice usbDevice : values) { int productId = usbDevice.getProductId(); if (productId == 0x2D00 || productId == 0x2D01) { if (mUsbManager.hasPermission(usbDevice)) { mUsbDeviceConnection = mUsbManager.openDevice(usbDevice); if (mUsbDeviceConnection != null) { mUsbInterface = usbDevice.getInterface(0); int endpointCount = mUsbInterface.getEndpointCount(); for (int i = 0; i < endpointCount; i++) { UsbEndpoint usbEndpoint = mUsbInterface.getEndpoint(i); if (usbEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) { if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_OUT) { mUsbEndpointOut = usbEndpoint; } else if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_IN) { mUsbEndpointIn = usbEndpoint; } } } if (mUsbEndpointOut != null && mUsbEndpointIn != null) { MyApplication.printLogDebug("connected success"); mHandler.sendEmptyMessage(CONNECTED_SUCCESS); mToggle = false; isDetached = true; } } } else { mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(""), 0)); } } } } else { finish(); } } } }); } /** * 接受訊息執行緒 , 此執行緒在裝置(手機)初始化完成後 , 就一直迴圈接受訊息 */ private void loopReceiverMessage() { mThreadPool.execute(new Runnable() { @Override public void run() { SystemClock.sleep(1000); while (isReceiverMessage) { /** * 迴圈接受資料的地方 , 只接受byte資料型別的資料 */ if (mUsbDeviceConnection != null && mUsbEndpointIn != null) { int i = mUsbDeviceConnection.bulkTransfer(mUsbEndpointIn, mBytes, mBytes.length, 3000); MyApplication.printLogDebug(i + ""); if (i > 0) { mStringBuffer.append(new String(mBytes, 0, i) + "\n"); mHandler.sendEmptyMessage(RECEIVER_MESSAGE_SUCCESS); } } } } }); } @Override public void usbDetached() { if (isDetached) { finish(); } } @Override public void openAccessoryModel(UsbDevice usbDevice) { initAccessory(usbDevice); } @Override public void openDevicesError() { mError.setText("USB連線錯誤"); } @Override public void onClick(View v) { final String messageContent = mMessage.getText().toString(); if (!TextUtils.isEmpty(messageContent)) { mThreadPool.execute(new Runnable() { @Override public void run() { /** * 傳送資料的地方 , 只接受byte資料型別的資料 */ int i = mUsbDeviceConnection.bulkTransfer(mUsbEndpointOut, messageContent.getBytes(), messageContent.getBytes().length, 3000); if (i > 0) { mHandler.sendEmptyMessage(SEND_MESSAGE_SUCCESS); } } }); } } @Override protected void onDestroy() { super.onDestroy(); if (mUsbDeviceConnection != null) { mUsbDeviceConnection.releaseInterface(mUsbInterface); mUsbDeviceConnection.close(); mUsbDeviceConnection = null; } mUsbEndpointIn = null; mUsbEndpointOut = null; mToggle = false; isReceiverMessage = false; mThreadPool.shutdownNow(); unregisterReceiver(mUsbDetachedReceiver); unregisterReceiver(mOpenDevicesReceiver); } }

OpenDevicesReceiver廣播程式碼:

package com.tcl.navigator.hostchart.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;

/**
 * Created by yaohui on 2017/3/3.
 */

public class OpenDevicesReceiver extends BroadcastReceiver {

    private OpenDevicesListener mOpenDevicesListener;

    public OpenDevicesReceiver(OpenDevicesListener openDevicesListener) {
        mOpenDevicesListener = openDevicesListener;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
            if (usbDevice != null) {
                mOpenDevicesListener.openAccessoryModel(usbDevice);
            } else {
                mOpenDevicesListener.openDevicesError();
            }
        } else {
            mOpenDevicesListener.openDevicesError();
        }
    }

    public interface OpenDevicesListener {
        /**
         * 開啟Accessory模式
         *
         * @param usbDevice
         */
        void openAccessoryModel(UsbDevice usbDevice);

        /**
         * 開啟裝置(手機)失敗
         */
        void openDevicesError();
    }
}

UsbDetachedReceiver廣播程式碼:

package com.tcl.navigator.hostchart.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class UsbDetachedReceiver extends BroadcastReceiver {

    private UsbDetachedListener mUsbDetachedListener;

    public UsbDetachedReceiver(UsbDetachedListener usbDetachedListener) {
        mUsbDetachedListener = usbDetachedListener;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        mUsbDetachedListener.usbDetached();
    }

    public interface UsbDetachedListener {
        /**
         * usb斷開連線
         */
        void usbDetached();
    }
}

以上就是Host端程式碼了.

2.Accessory端程式碼:

package com.tcl.navigator.accessorychart.activity;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.tcl.navigator.accessorychart.R;
import com.tcl.navigator.accessorychart.receiver.OpenAccessoryReceiver;
import com.tcl.navigator.accessorychart.receiver.UsbDetachedReceiver;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainActivity extends AppCompatActivity implements OpenAccessoryReceiver.OpenAccessoryListener, View.OnClickListener, UsbDetachedReceiver.UsbDetachedListener {

    private static final int    SEND_MESSAGE_SUCCESS     = 0;
    private static final int    RECEIVER_MESSAGE_SUCCESS = 1;
    private static final String USB_ACTION               = "com.tcl.navigator.accessorychart";
    private TextView              mLog;
    private EditText              mMessage;
    private Button                mSend;
    private UsbManager            mUsbManager;
    private OpenAccessoryReceiver mOpenAccessoryReceiver;
    private ParcelFileDescriptor  mParcelFileDescriptor;
    private FileInputStream       mFileInputStream;
    private FileOutputStream      mFileOutputStream;
    private ExecutorService       mThreadPool;
    private byte[]       mBytes        = new byte[1024];
    private StringBuffer mStringBuffer = new StringBuffer();
    private UsbDetachedReceiver mUsbDetachedReceiver;

    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SEND_MESSAGE_SUCCESS:
                    mMessage.setText("");
                    mMessage.clearComposingText();
                    break;

                case RECEIVER_MESSAGE_SUCCESS:
                    mLog.setText(mStringBuffer.toString());
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        init();
    }

    private void init() {
        initView();
        initListener();
        initData();
    }

    private void initView() {
        mLog = (TextView) findViewById(R.id.log);
        mMessage = (EditText) findViewById(R.id.message);
        mSend = (Button) findViewById(R.id.send);
    }

    private void initListener() {
        mSend.setOnClickListener(this);
    }

    private void initData() {
        mSend.setEnabled(false);
        mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
        mThreadPool = Executors.newFixedThreadPool(3);

        mUsbDetachedReceiver = new UsbDetachedReceiver(this);
        IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
        registerReceiver(mUsbDetachedReceiver, filter);

        mOpenAccessoryReceiver = new OpenAccessoryReceiver(this);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(USB_ACTION), 0);
        IntentFilter intentFilter = new IntentFilter(USB_ACTION);
        registerReceiver(mOpenAccessoryReceiver, intentFilter);

        UsbAccessory[] accessories = mUsbManager.getAccessoryList();
        UsbAccessory usbAccessory = (accessories == null ? null : accessories[0]);
        if (usbAccessory != null) {
            if (mUsbManager.hasPermission(usbAccessory)) {
                openAccessory(usbAccessory);
            } else {
                mUsbManager.requestPermission(usbAccessory, pendingIntent);
            }
        }
    }

    /**
     * 開啟Accessory模式
     *
     * @param usbAccessory
     */
    private void openAccessory(UsbAccessory usbAccessory) {
        mParcelFileDescriptor = mUsbManager.openAccessory(usbAccessory);
        if (mParcelFileDescriptor != null) {
            FileDescriptor fileDescriptor = mParcelFileDescriptor.getFileDescriptor();
            mFileInputStream = new FileInputStream(fileDescriptor);
            mFileOutputStream = new FileOutputStream(fileDescriptor);
            mSend.setEnabled(true);

            mThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    int i = 0;
                    while (i >= 0) {
                        try {
                            i = mFileInputStream.read(mBytes);
                        } catch (IOException e) {
                            e.printStackTrace();
                            break;
                        }
                        if (i > 0) {
                            mStringBuffer.append(new String(mBytes, 0, i) + "\n");
                            mHandler.sendEmptyMessage(RECEIVER_MESSAGE_SUCCESS);
                        }
                    }
                }
            });
        }
    }

    @Override
    public void openAccessoryModel(UsbAccessory usbAccessory) {
        openAccessory(usbAccessory);
    }

    @Override
    public void openAccessoryError() {

    }

    @Override
    public void onClick(View v) {
        final String mMessageContent = mMessage.getText().toString();
        if (!TextUtils.isEmpty(mMessageContent)) {
            mThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        mFileOutputStream.write(mMessageContent.getBytes());
                        mHandler.sendEmptyMessage(SEND_MESSAGE_SUCCESS);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    @Override
    public void usbDetached() {

        finish();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        unregisterReceiver(mOpenAccessoryReceiver);
        unregisterReceiver(mUsbDetachedReceiver);
        if (mParcelFileDescriptor != null) {
            try {
                mParcelFileDescriptor.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mFileInputStream != null) {
            try {
                mFileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mFileOutputStream != null) {
            try {
                mFileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

OpenAccessoryReceiver廣播程式碼:

package com.tcl.navigator.accessorychart.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;

public class OpenAccessoryReceiver extends BroadcastReceiver {

    private OpenAccessoryListener mOpenAccessoryListener;

    public OpenAccessoryReceiver(OpenAccessoryListener openAccessoryListener) {
        mOpenAccessoryListener = openAccessoryListener;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        UsbAccessory usbAccessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
            if (usbAccessory != null) {
                mOpenAccessoryListener.openAccessoryModel(usbAccessory);
            } else {
                mOpenAccessoryListener.openAccessoryError();
            }
        } else {
            mOpenAccessoryListener.openAccessoryError();
        }
    }

    public interface OpenAccessoryListener {
        /**
         * 開啟Accessory模式
         *
         * @param usbAccessory
         */
        void openAccessoryModel(UsbAccessory usbAccessory);

        /**
         * 開啟裝置(手機)失敗
         */
        void openAccessoryError();
    }
}

UsbDetachedReceiver廣播程式碼:

package com.tcl.navigator.accessorychart.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class UsbDetachedReceiver extends BroadcastReceiver {

    private UsbDetachedListener mUsbDetachedListener;

    public UsbDetachedReceiver(UsbDetachedListener usbDetachedListener) {
        mUsbDetachedListener = usbDetachedListener;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        mUsbDetachedListener.usbDetached();
    }

    public interface UsbDetachedListener {
        /**
         * usb斷開連線
         */
        void usbDetached();
    }
}

最後在AndroidManifest裡面有些小改動:

<activity android:name=".activity.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>

            <meta-data
                android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
                android:resource="@xml/accessory_filter"/>
        </activity>

其中USB通訊是需要使用者手動賦予許可權的,所以2個手機都會有提示的.
到此基本上就完了,我寫的這2個app執行在2個安卓手機上,通過資料線是可以進行聊天的.
不懂的請給我留言,我看到了都會回覆的,再見啦! ! !
原始碼下載地址:HostChart,AccessoryChart