1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.hardware.usb.aoaphosttest;
17
18import android.app.Activity;
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.hardware.usb.UsbAccessory;
24import android.hardware.usb.UsbConstants;
25import android.hardware.usb.UsbDevice;
26import android.hardware.usb.UsbDeviceConnection;
27import android.hardware.usb.UsbEndpoint;
28import android.hardware.usb.UsbInterface;
29import android.hardware.usb.UsbManager;
30import android.os.Bundle;
31import android.os.Handler;
32import android.os.HandlerThread;
33import android.os.Process;
34import android.text.TextUtils;
35import android.util.Log;
36
37import libcore.io.IoUtils;
38
39public class UsbAoapHostTestActivity extends Activity {
40
41    private static final String TAG = UsbAoapHostTestActivity.class.getSimpleName();
42
43    private UsbManager mUsbManager;
44    private UsbStateReceiver mReceiver;
45    private UsbDevice mUsbDevice;
46    private UsbDeviceConnection mUsbConnection;
47    private ReaderThread mReaderThread;
48
49    @Override
50    protected void onCreate(Bundle savedInstanceState) {
51        super.onCreate(savedInstanceState);
52
53        setContentView(R.layout.host);
54
55        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
56        IntentFilter filter = new IntentFilter();
57        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
58        mReceiver = new UsbStateReceiver();
59        registerReceiver(mReceiver, filter);
60
61        Intent intent = getIntent();
62        if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
63            mUsbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
64            mUsbConnection = mUsbManager.openDevice(mUsbDevice);
65            mReaderThread = new ReaderThread(mUsbDevice, mUsbConnection);
66            mReaderThread.start();
67        } else {
68            finish();
69        }
70    }
71
72    @Override
73    protected void onDestroy() {
74        super.onDestroy();
75        unregisterReceiver(mReceiver);
76        if (mUsbConnection != null) {
77            mUsbConnection.close();
78        }
79        if (mReaderThread != null) {
80            mReaderThread.requestToQuit();
81            try {
82                mReaderThread.join(1000);
83            } catch (InterruptedException e) {
84            }
85            if (mReaderThread.isAlive()) { // reader thread stuck
86                throw new RuntimeException("ReaderThread still alive");
87            }
88        }
89    }
90
91    private static boolean isDevicesMatching(UsbDevice l, UsbDevice r) {
92        if (l.getVendorId() == r.getVendorId() && l.getProductId() == r.getProductId() &&
93                TextUtils.equals(l.getSerialNumber(), r.getSerialNumber())) {
94            return true;
95        }
96        return false;
97    }
98
99    private class ReaderThread extends Thread {
100        private boolean mShouldQuit = false;
101        private final UsbDevice mDevice;
102        private final UsbDeviceConnection mUsbConnection;
103        private final UsbEndpoint mBulkIn;
104        private final UsbEndpoint mBulkOut;
105        private final byte[] mBuffer = new byte[16384];
106
107        private ReaderThread(UsbDevice device, UsbDeviceConnection conn) {
108            super("AOAP");
109            mDevice = device;
110            mUsbConnection = conn;
111            UsbInterface iface = mDevice.getInterface(0);
112            // Setup bulk endpoints.
113            UsbEndpoint bulkIn = null;
114            UsbEndpoint bulkOut = null;
115            for (int i = 0; i < iface.getEndpointCount(); i++) {
116                UsbEndpoint ep = iface.getEndpoint(i);
117                if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
118                    if (bulkIn == null) {
119                        bulkIn = ep;
120                    }
121                } else {
122                    if (bulkOut == null) {
123                        bulkOut = ep;
124                    }
125                }
126            }
127            if (bulkIn == null || bulkOut == null) {
128                throw new IllegalStateException("Unable to find bulk endpoints");
129            }
130            mBulkIn = bulkIn;
131            mBulkOut = bulkOut;
132        }
133
134        private synchronized void requestToQuit() {
135            mShouldQuit = true;
136        }
137
138        private synchronized boolean shouldQuit() {
139            return mShouldQuit;
140        }
141
142        @Override
143        public void run() {
144            while (!shouldQuit()) {
145                int read = mUsbConnection.bulkTransfer(mBulkIn, mBuffer, mBuffer.length,
146                        Integer.MAX_VALUE);
147                if (read < 0) {
148                    throw new RuntimeException("bulkTransfer failed, read = " + read);
149                }
150            }
151        }
152    }
153
154    private class UsbStateReceiver extends BroadcastReceiver {
155        @Override
156        public void onReceive(Context context, Intent intent) {
157            if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
158                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
159                if (isDevicesMatching(mUsbDevice, device)) {
160                    finish();
161                }
162            }
163        }
164    }
165}
166