您的位置:首页 > 移动开发 > Android开发

两台android设备间通过OTG-USB连接,实现通信(android设备间的通信)

2017-12-02 14:09 856 查看
首先是一个简单的布局activity_chat.xml,就是后面进行通信的交互界面

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:padding="16dp"

    android:orientation="vertical"

    tools:context=".MainActivity">

    <ScrollView

        android:layout_width="match_parent"

        android:layout_height="0dip"

        android:layout_weight="1">

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_gravity="bottom"

            android:id="@+id/content_text"/>

        

    </ScrollView>

    

    <ImageView

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:id="@+id/screenshot"

        />

    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal">

        <EditText

            android:layout_width="0dip"

            android:layout_height="wrap_content"

            android:layout_weight="1"

            android:id="@+id/input_edittext"/>

        <Button

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="send"

            android:id="@+id/send_button"

            android:onClick="onButtonClick"

            />

    </LinearLayout>

</LinearLayout>

因为android设备之间的连接涉及到主从设备的问题,所以在这边有一个区分,device包下有BaseChatActivity,ChatAtivity,ConnectActivity

 
public class ConnectActivity extends AppCompatActivity {

    public static final String DEVICE_EXTRA_KEY = "device";

    private UsbManager mUsbManager;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_chat);

        mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

    }

    @Override

    protected void onResume() {

        super.onResume();

        final HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();

        if (deviceList == null || deviceList.size() == 0) {

            final Intent intent=new Intent(this, InfoActivity.class);

            startActivity(intent);

            finish();

            return;

        }

        if (searchForUsbAccessory(deviceList)) {

            return;

        }

        for (UsbDevice device:deviceList.values()) {

            initAccessory(device);

        }

        finish();

    }

    private boolean searchForUsbAccessory(final HashMap<String, UsbDevice> deviceList) {

        for (UsbDevice device:deviceList.values()) {

            if (isUsbAccessory(device)) {

                final Intent intent=new Intent(this,ChatActivity.class);

                intent.putExtra(DEVICE_EXTRA_KEY, device);

                startActivity(intent);

                finish();

                return true;

            }

        }

        return false;

    }

    private boolean isUsbAccessory(final UsbDevice device) {

        return (device.getProductId() == 0x2d00) || (device.getProductId() == 0x2d01);

    }

    private boolean initAccessory(final UsbDevice device) {

        final UsbDeviceConnection connection = mUsbManager.openDevice(device);

        if (connection == null) {

            return false;

        }

        initStringControlTransfer(connection, 0, "quandoo"); // MANUFACTURER

        initStringControlTransfer(connection
ec6e
, 1, "Android2AndroidAccessory"); // MODEL

        initStringControlTransfer(connection, 2, "showcasing android2android USB communication"); // DESCRIPTION

        initStringControlTransfer(connection, 3, "0.1"); // VERSION

        initStringControlTransfer(connection, 4, "http://quandoo.de"); // URI

        initStringControlTransfer(connection, 5, "42"); // SERIAL

        connection.controlTransfer(0x40, 53, 0, 0, new byte[]{}, 0, Constants.USB_TIMEOUT_IN_MS);

        connection.close();

        return true;

    }

    private void initStringControlTransfer(final UsbDeviceConnection deviceConnection,

                                           final int index,

                                           final String string) {

        deviceConnection.controlTransfer(0x40, 52, 0, index, string.getBytes(), string.length(), Constants.USB_TIMEOUT_IN_MS);

    }

}

然后

public class ChatActivity extends BaseChatActivity {

    private final AtomicBoolean keepThreadAlive = new AtomicBoolean(true);

    private final List<String> sendBuffer = new ArrayList<>();

    @Override

    public void sendString(final String string) {

        sendBuffer.add(string);

    }

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        new Thread(new CommunicationRunnable()).start();

    }

    private class CommunicationRunnable implements Runnable {

        @Override

        public void run() {

            final UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

            final UsbDevice device=getIntent().getParcelableExtra(ConnectActivity.DEVICE_EXTRA_KEY);

            UsbEndpoint endpointIn = null;

            UsbEndpoint endpointOut = null;

            final UsbInterface usbInterface = device.getInterface(0);

            for (int i = 0; i < device.getInterface(0).getEndpointCount(); i++) {

                final UsbEndpoint endpoint = device.getInterface(0).getEndpoint(i);

                if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {

                    endpointIn = endpoint;

                }

                if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {

                    endpointOut = endpoint;

                }

            }

            if (endpointIn == null) {

                printLineToUI("Input Endpoint not found");

                return;

            }

            if (endpointOut == null) {

                printLineToUI("Output Endpoint not found");

                return;

            }

            final UsbDeviceConnection connection = usbManager.openDevice(device);

            if (connection == null) {

                printLineToUI("Could not open device");

                return;

            }

            final boolean claimResult = connection.claimInterface(usbInterface, true);

            if (!claimResult) {

                printLineToUI("Could not claim device");

            } else {

                final byte buff[] = new byte[Constants.BUFFER_SIZE_IN_BYTES];

                printLineToUI("Claimed interface - ready to communicate");

                while (keepThreadAlive.get()) {

                    final int bytesTransferred = connection.bulkTransfer(endpointIn, buff, buff.length, Constants.USB_TIMEOUT_IN_MS);

                    if (bytesTransferred > 0) {

                        printLineToUI("host> "+new String(buff, 0, bytesTransferred));

                    }

                    synchronized (sendBuffer) {

                        if (sendBuffer.size()>0) {

                            final byte[] sendBuff=sendBuffer.get(0).toString().getBytes();

                            connection.bulkTransfer(endpointOut, sendBuff, sendBuff.length, Constants.USB_TIMEOUT_IN_MS);

                            sendBuffer.remove(0);

                        }

                    }

                }

            }

            connection.releaseInterface(usbInterface);

            connection.close();

        }

    }

    @Override

    protected void onStop() {

        super.onStop();

        keepThreadAlive.set(false);

    }

}

接着是

 public abstract class BaseChatActivity extends AppCompatActivity {

    TextView contentTextView;

    EditText inputMessage;

    Button input;

    public abstract void sendString(final String string);

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_chat);

        contentTextView= (TextView) findViewById(R.id.content_text);

        inputMessage= (EditText) findViewById(R.id.input_edittext);

        input= (Button)findViewById(R.id.send_button);

        //监听发送消息事件

        input.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View view) {

                final String inputString = inputMessage.getText().toString();

                if (inputString.length() == 0) {

                    return;

                }

                sendString(inputString);

                printLineToUI(getString(R.string.local_prompt2) + inputString);

                inputMessage.setText("");

            }

        });

    }

    public void printLineToUI(final String line) {

        runOnUiThread(new Runnable() {

            @Override

            public void run() {

                contentTextView.setText(contentTextView.getText() + "\n" + line);

            }

        });

    }

}

在host包下同样有BaseChatActivity,ChatAtivity,ConnectActivity三个类,方法和上面一样,就不重复写了

在main包下有

public abstract class AccessoryCommunicator {

    private UsbManager usbManager;

    private Context context;

    private Handler sendHandler;

    private ParcelFileDescriptor fileDescriptor;

    private FileInputStream inStream;

    private FileOutputStream outStream;

    private boolean running;

    public AccessoryCommunicator(final Context context) {

        this.context = context;

        usbManager = (UsbManager) this.context.getSystemService(Context.USB_SERVICE);

        final UsbAccessory[] accessoryList = usbManager.getAccessoryList();

        if (accessoryList == null || accessoryList.length == 0) {

            onError("no accessory found");

        } else {

            openAccessory(accessoryList[0]);

        }

    }

    public void send(byte[] payload) {

        if (sendHandler != null) {

            Message msg = sendHandler.obtainMessage();

            msg.obj = payload;

            sendHandler.sendMessage(msg);

        }

    }

    private void receive(final byte[] payload, final int length) {

        onReceive(payload, length);

    }

    public abstract void onReceive(final byte[] payload, final int length);

    public abstract void onError(String msg);

    public abstract void onConnected();

    public abstract void onDisconnected();

    private class CommunicationThread extends Thread {

        @Override

        public void run() {

            running = true;

            while (running) {

                byte[] msg = new byte[Constants.BUFFER_SIZE_IN_BYTES];

                try {

                    //Handle incoming messages

                    int len = inStream.read(msg);

                    while (inStream != null && len > 0 && running) {

                        receive(msg, len);

                        Thread.sleep(10);

                        len = inStream.read(msg);

                    }

                } catch (final Exception e) {

                    onError("USB Receive Failed " + e.toString() + "\n");

                    closeAccessory();

                }

            }

        }

    }

    private void openAccessory(UsbAccessory accessory) {

        fileDescriptor = usbManager.openAccessory(accessory);

        if (fileDescriptor != null) {

            FileDescriptor fd = fileDescriptor.getFileDescriptor();

            inStream = new FileInputStream(fd);

            outStream = new FileOutputStream(fd);

            new CommunicationThread().start();

            sendHandler = new Handler() {

                public void handleMessage(Message msg) {

                    try {

                        outStream.write((byte[]) msg.obj);

                    } catch (final Exception e) {

                        onError("USB Send Failed " + e.toString() + "\n");

                    }

                }

            };

            onConnected();

        } else {

            onError("could not connect");

        }

    }

    public void closeAccessory() {

        running = false;

        try {

            if (fileDescriptor != null) {

                fileDescriptor.close();

            }

        } catch (IOException e) {

        } finally {

            fileDescriptor = null;

        }

        onDisconnected();

    }

}

然后是

 public class Constants {

    public static final int USB_TIMEOUT_IN_MS = 100;

    public static final int BUFFER_SIZE_IN_BYTES = 256;

}

接着是InfoActivity ,InfoActivity 是整个整个程序的入口,对应的布局文件就一个textView,用于提示连接两台android设备。

public class InfoActivity extends AppCompatActivity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_info);

    }

}

最后就是在里配置一下就好了

    <application

        android:allowBackup="true"

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:supportsRtl="true"

        android:theme="@style/AppTheme">

        <activity android:name="InfoActivity">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

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

            </intent-filter>

        </activity>

        <activity android:name=".ChatActivity"

            android:screenOrientation="landscape">

            <intent-filter>

                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />

            </intent-filter>

            <meta-data

                android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"

                android:resource="@xml/accessory_filter" />

        </activity>

        <activity android:name=".ConnectActivity"

            android:screenOrientation="landscape">

        </activity>

        <activity android:name=".device.ChatActivity"

            android:screenOrientation="landscape">

            <intent-filter>

                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />

            </intent-filter>

            <meta-data

                android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"

                android:resource="@xml/accessory_filter" />

        </activity>

        <activity android:name=".device.ConnectActivity"

            android:screenOrientation="landscape">

            <intent-filter>

                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />

            </intent-filter>

            <meta-data

                android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"

                android:resource="@xml/device_filter" />

        </activity>

    </application>

 记录一下亲测好用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐