18f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown/* 28f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Copyright (C) 2013 The Android Open Source Project 38f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 48f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 58f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * you may not use this file except in compliance with the License. 68f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * You may obtain a copy of the License at 78f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 88f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 98f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Unless required by applicable law or agreed to in writing, software 118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * See the License for the specific language governing permissions and 148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * limitations under the License. 158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownpackage com.android.accessorydisplay.sink; 188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport com.android.accessorydisplay.common.Logger; 208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.app.Activity; 228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.app.PendingIntent; 238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.content.BroadcastReceiver; 248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.content.Context; 258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.content.Intent; 268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.content.IntentFilter; 278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.hardware.usb.UsbConstants; 288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.hardware.usb.UsbDevice; 298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.hardware.usb.UsbDeviceConnection; 308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.hardware.usb.UsbEndpoint; 318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.hardware.usb.UsbInterface; 328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.hardware.usb.UsbManager; 338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.media.MediaCodec; 348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.media.MediaCodec.BufferInfo; 358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.media.MediaFormat; 368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.os.Bundle; 378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.text.method.ScrollingMovementMethod; 388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.util.Log; 398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.view.MotionEvent; 408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.view.Surface; 418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.view.SurfaceHolder; 428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.view.SurfaceView; 438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.view.View; 448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.widget.TextView; 458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport java.nio.ByteBuffer; 478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport java.util.LinkedList; 488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport java.util.Map; 498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownpublic class SinkActivity extends Activity { 518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final String TAG = "SinkActivity"; 528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final String ACTION_USB_DEVICE_PERMISSION = 548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown "com.android.accessorydisplay.sink.ACTION_USB_DEVICE_PERMISSION"; 558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final String MANUFACTURER = "Android"; 578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final String MODEL = "Accessory Display"; 588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final String DESCRIPTION = "Accessory Display Sink Test Application"; 598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final String VERSION = "1.0"; 608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final String URI = "http://www.android.com/"; 618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final String SERIAL = "0000000012345678"; 628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final int MULTITOUCH_DEVICE_ID = 0; 648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final int MULTITOUCH_REPORT_ID = 1; 658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final int MULTITOUCH_MAX_CONTACTS = 1; 668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private UsbManager mUsbManager; 688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private DeviceReceiver mReceiver; 698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private TextView mLogTextView; 708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private TextView mFpsTextView; 718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private SurfaceView mSurfaceView; 728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private Logger mLogger; 738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private boolean mConnected; 758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private int mProtocolVersion; 768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private UsbDevice mDevice; 778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private UsbInterface mAccessoryInterface; 788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private UsbDeviceConnection mAccessoryConnection; 798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private UsbEndpoint mControlEndpoint; 808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private UsbAccessoryBulkTransport mTransport; 818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private boolean mAttached; 838f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private DisplaySinkService mDisplaySinkService; 848f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 858f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final ByteBuffer mHidBuffer = ByteBuffer.allocate(4096); 868f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private UsbHid.Multitouch mMultitouch; 878f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private boolean mMultitouchEnabled; 888f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private UsbHid.Multitouch.Contact[] mMultitouchContacts; 898f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 908f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 918f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown protected void onCreate(Bundle savedInstanceState) { 928f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown super.onCreate(savedInstanceState); 938f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 948f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE); 958f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 968f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown setContentView(R.layout.sink_activity); 978f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 988f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogTextView = (TextView) findViewById(R.id.logTextView); 998f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogTextView.setMovementMethod(ScrollingMovementMethod.getInstance()); 1008f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger = new TextLogger(); 1018f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1028f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mFpsTextView = (TextView) findViewById(R.id.fpsTextView); 1038f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1048f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView); 1058f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSurfaceView.setOnTouchListener(new View.OnTouchListener() { 1068f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 1078f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public boolean onTouch(View v, MotionEvent event) { 1088f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown sendHidTouch(event); 1098f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return true; 1108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown }); 1128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Waiting for accessory display source to be attached to USB..."); 1148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown IntentFilter filter = new IntentFilter(); 1168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); 1178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); 1188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown filter.addAction(ACTION_USB_DEVICE_PERMISSION); 1198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mReceiver = new DeviceReceiver(); 1208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown registerReceiver(mReceiver, filter); 1218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown Intent intent = getIntent(); 1238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) { 1248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE); 1258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (device != null) { 1268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown onDeviceAttached(device); 1278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else { 1298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown Map<String, UsbDevice> devices = mUsbManager.getDeviceList(); 1308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (devices != null) { 1318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown for (UsbDevice device : devices.values()) { 1328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown onDeviceAttached(device); 1338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 1398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown protected void onDestroy() { 1408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown super.onDestroy(); 1418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown unregisterReceiver(mReceiver); 1438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void onDeviceAttached(UsbDevice device) { 1468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("USB device attached: " + device); 1478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (!mConnected) { 1488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown connect(device); 1498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void onDeviceDetached(UsbDevice device) { 1538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("USB device detached: " + device); 1548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mConnected && device.equals(mDevice)) { 1558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown disconnect(); 1568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void connect(UsbDevice device) { 1608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mConnected) { 1618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown disconnect(); 1628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Check whether we have permission to access the device. 1658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (!mUsbManager.hasPermission(device)) { 1668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Prompting the user for access to the device."); 1678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown Intent intent = new Intent(ACTION_USB_DEVICE_PERMISSION); 1688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown intent.setPackage(getPackageName()); 1698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown PendingIntent pendingIntent = PendingIntent.getBroadcast( 1708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown this, 0, intent, PendingIntent.FLAG_ONE_SHOT); 1718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mUsbManager.requestPermission(device, pendingIntent); 1728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 1738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Claim the device. 1768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbDeviceConnection conn = mUsbManager.openDevice(device); 1778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (conn == null) { 1788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Could not obtain device connection."); 1798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 1808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbInterface iface = device.getInterface(0); 1828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbEndpoint controlEndpoint = iface.getEndpoint(0); 1838f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (!conn.claimInterface(iface, true)) { 1848f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Could not claim interface."); 1858f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 1868f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1878f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown try { 1888f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // If already in accessory mode, then connect to the device. 1898f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (isAccessory(device)) { 1908f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Connecting to accessory..."); 1918f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1928f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int protocolVersion = getProtocol(conn); 1938f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (protocolVersion < 1) { 1948f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Device does not support accessory protocol."); 1958f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 1968f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1978f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Protocol version: " + protocolVersion); 1988f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1998f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Setup bulk endpoints. 2008f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbEndpoint bulkIn = null; 2018f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbEndpoint bulkOut = null; 2028f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown for (int i = 0; i < iface.getEndpointCount(); i++) { 2038f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbEndpoint ep = iface.getEndpoint(i); 2048f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (ep.getDirection() == UsbConstants.USB_DIR_IN) { 2058f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (bulkIn == null) { 2068f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log(String.format("Bulk IN endpoint: %d", i)); 2078f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown bulkIn = ep; 2088f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2098f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else { 2108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (bulkOut == null) { 2118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log(String.format("Bulk OUT endpoint: %d", i)); 2128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown bulkOut = ep; 2138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (bulkIn == null || bulkOut == null) { 2178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Unable to find bulk endpoints"); 2188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 2198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Connected"); 2228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mConnected = true; 2238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mDevice = device; 2248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mProtocolVersion = protocolVersion; 2258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mAccessoryInterface = iface; 2268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mAccessoryConnection = conn; 2278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mControlEndpoint = controlEndpoint; 2288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mTransport = new UsbAccessoryBulkTransport(mLogger, conn, bulkIn, bulkOut); 2298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mProtocolVersion >= 2) { 2308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown registerHid(); 2318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown startServices(); 2338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mTransport.startReading(); 2348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 2358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Do accessory negotiation. 2388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Attempting to switch device to accessory mode..."); 2398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Send get protocol. 2418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int protocolVersion = getProtocol(conn); 2428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (protocolVersion < 1) { 2438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Device does not support accessory protocol."); 2448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 2458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Protocol version: " + protocolVersion); 2478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Send identifying strings. 2498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_MANUFACTURER, MANUFACTURER); 2508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_MODEL, MODEL); 2518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_DESCRIPTION, DESCRIPTION); 2528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_VERSION, VERSION); 2538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_URI, URI); 2548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_SERIAL, SERIAL); 2558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Send start. 2578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // The device should re-enumerate as an accessory. 2588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Sending accessory start request."); 2598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int len = conn.controlTransfer(UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR, 2608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbAccessoryConstants.ACCESSORY_START, 0, 0, null, 0, 10000); 2618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (len != 0) { 2628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Device refused to switch to accessory mode."); 2638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else { 2648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Waiting for device to re-enumerate..."); 2658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } finally { 2678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (!mConnected) { 2688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown conn.releaseInterface(iface); 2698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void disconnect() { 2748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Disconnecting from device: " + mDevice); 2758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown stopServices(); 2768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown unregisterHid(); 2778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Disconnected."); 2798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mConnected = false; 2808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mDevice = null; 2818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mAccessoryConnection = null; 2828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mAccessoryInterface = null; 2838f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mControlEndpoint = null; 2848f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mTransport != null) { 2858f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mTransport.close(); 2868f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mTransport = null; 2878f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2888f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2898f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2908f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void registerHid() { 2918f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Registering HID multitouch device."); 2928f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2938f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouch = new UsbHid.Multitouch(MULTITOUCH_REPORT_ID, MULTITOUCH_MAX_CONTACTS, 2948f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSurfaceView.getWidth(), mSurfaceView.getHeight()); 2958f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2968f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHidBuffer.clear(); 2978f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouch.generateDescriptor(mHidBuffer); 2988f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHidBuffer.flip(); 2998f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3008f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("HID descriptor size: " + mHidBuffer.limit()); 3018f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("HID report size: " + mMultitouch.getReportSize()); 3028f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3038f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int maxPacketSize = mControlEndpoint.getMaxPacketSize(); 3048f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Control endpoint max packet size: " + maxPacketSize); 3058f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mMultitouch.getReportSize() > maxPacketSize) { 3068f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("HID report is too big for this accessory."); 3078f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 3088f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3098f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int len = mAccessoryConnection.controlTransfer( 3118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR, 3128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbAccessoryConstants.ACCESSORY_REGISTER_HID, 3138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown MULTITOUCH_DEVICE_ID, mHidBuffer.limit(), null, 0, 10000); 3148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (len != 0) { 3158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Device rejected ACCESSORY_REGISTER_HID request."); 3168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 3178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown while (mHidBuffer.hasRemaining()) { 3208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int position = mHidBuffer.position(); 3218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int count = Math.min(mHidBuffer.remaining(), maxPacketSize); 3228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown len = mAccessoryConnection.controlTransfer( 3238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR, 3248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbAccessoryConstants.ACCESSORY_SET_HID_REPORT_DESC, 3258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown MULTITOUCH_DEVICE_ID, 0, 3268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHidBuffer.array(), position, count, 10000); 3278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (len != count) { 3288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Device rejected ACCESSORY_SET_HID_REPORT_DESC request."); 3298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 3308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHidBuffer.position(position + count); 3328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("HID device registered."); 3358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouchEnabled = true; 3378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mMultitouchContacts == null) { 3388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouchContacts = new UsbHid.Multitouch.Contact[MULTITOUCH_MAX_CONTACTS]; 3398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown for (int i = 0; i < MULTITOUCH_MAX_CONTACTS; i++) { 3408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouchContacts[i] = new UsbHid.Multitouch.Contact(); 3418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void unregisterHid() { 3468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouch = null; 3478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouchContacts = null; 3488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouchEnabled = false; 3498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void sendHidTouch(MotionEvent event) { 3528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mMultitouchEnabled) { 3538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Sending touch event: " + event); 3548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown switch (event.getActionMasked()) { 3568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown case MotionEvent.ACTION_DOWN: 3578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown case MotionEvent.ACTION_MOVE: { 3588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int pointerCount = 3598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown Math.min(MULTITOUCH_MAX_CONTACTS, event.getPointerCount()); 3608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int historySize = event.getHistorySize(); 3618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown for (int p = 0; p < pointerCount; p++) { 3628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouchContacts[p].id = event.getPointerId(p); 3638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown for (int h = 0; h < historySize; h++) { 3658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown for (int p = 0; p < pointerCount; p++) { 3668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouchContacts[p].x = (int)event.getHistoricalX(p, h); 3678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouchContacts[p].y = (int)event.getHistoricalY(p, h); 3688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown sendHidTouchReport(pointerCount); 3708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown for (int p = 0; p < pointerCount; p++) { 3728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouchContacts[p].x = (int)event.getX(p); 3738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouchContacts[p].y = (int)event.getY(p); 3748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown sendHidTouchReport(pointerCount); 3768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; 3778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown case MotionEvent.ACTION_CANCEL: 3808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown case MotionEvent.ACTION_UP: 3818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown sendHidTouchReport(0); 3828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; 3838f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3848f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3858f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3868f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3878f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void sendHidTouchReport(int contactCount) { 3888f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHidBuffer.clear(); 3898f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mMultitouch.generateReport(mHidBuffer, mMultitouchContacts, contactCount); 3908f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHidBuffer.flip(); 3918f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3928f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int count = mHidBuffer.limit(); 3938f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int len = mAccessoryConnection.controlTransfer( 3948f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR, 3958f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbAccessoryConstants.ACCESSORY_SEND_HID_EVENT, 3968f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown MULTITOUCH_DEVICE_ID, 0, 3978f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHidBuffer.array(), 0, count, 10000); 3988f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (len != count) { 3998f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Device rejected ACCESSORY_SEND_HID_EVENT request."); 4008f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 4018f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4028f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4038f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4048f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void startServices() { 4058f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mDisplaySinkService = new DisplaySinkService(this, mTransport, 4068f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown getResources().getConfiguration().densityDpi); 4078f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mDisplaySinkService.start(); 4088f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4098f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mAttached) { 4108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mDisplaySinkService.setSurfaceView(mSurfaceView); 4118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void stopServices() { 4158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mDisplaySinkService != null) { 4168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mDisplaySinkService.stop(); 4178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mDisplaySinkService = null; 4188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 4228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void onAttachedToWindow() { 4238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown super.onAttachedToWindow(); 4248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mAttached = true; 4268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mDisplaySinkService != null) { 4278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mDisplaySinkService.setSurfaceView(mSurfaceView); 4288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 4328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void onDetachedFromWindow() { 4338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown super.onDetachedFromWindow(); 4348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mAttached = false; 4368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mDisplaySinkService != null) { 4378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mDisplaySinkService.setSurfaceView(null); 4388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private int getProtocol(UsbDeviceConnection conn) { 4428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown byte buffer[] = new byte[2]; 4438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int len = conn.controlTransfer( 4448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR, 4458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbAccessoryConstants.ACCESSORY_GET_PROTOCOL, 0, 0, buffer, 2, 10000); 4468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (len != 2) { 4478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return -1; 4488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return (buffer[1] << 8) | buffer[0]; 4508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void sendString(UsbDeviceConnection conn, int index, String string) { 4538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown byte[] buffer = (string + "\0").getBytes(); 4548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int len = conn.controlTransfer(UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR, 4558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbAccessoryConstants.ACCESSORY_SEND_STRING, 0, index, 4568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer, buffer.length, 10000); 4578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (len != buffer.length) { 4588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Failed to send string " + index + ": \"" + string + "\""); 4598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else { 4608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Sent string " + index + ": \"" + string + "\""); 4618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static boolean isAccessory(UsbDevice device) { 4658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int vid = device.getVendorId(); 4668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int pid = device.getProductId(); 4678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return vid == UsbAccessoryConstants.USB_ACCESSORY_VENDOR_ID 4688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown && (pid == UsbAccessoryConstants.USB_ACCESSORY_PRODUCT_ID 4698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown || pid == UsbAccessoryConstants.USB_ACCESSORY_ADB_PRODUCT_ID); 4708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown class TextLogger extends Logger { 4738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 4748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void log(final String message) { 4758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown Log.d(TAG, message); 4768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogTextView.post(new Runnable() { 4788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 4798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void run() { 4808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogTextView.append(message); 4818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogTextView.append("\n"); 4828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4838f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown }); 4848f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4858f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 4868f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 4878f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown class DeviceReceiver extends BroadcastReceiver { 4888f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 4898f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void onReceive(Context context, Intent intent) { 4908f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE); 4918f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (device != null) { 4928f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown String action = intent.getAction(); 4938f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) { 4948f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown onDeviceAttached(device); 4958f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else if (action.equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) { 4968f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown onDeviceDetached(device); 4978f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else if (action.equals(ACTION_USB_DEVICE_PERMISSION)) { 4988f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { 4998f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Device permission granted: " + device); 5008f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown onDeviceAttached(device); 5018f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else { 5028f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Device permission denied: " + device); 5038f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 5048f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 5058f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 5068f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 5078f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 5088f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown} 509