SinkActivitypublic class SinkActivity extends android.app.Activity
Fields Summary |
---|
private static final String | TAG | private static final String | ACTION_USB_DEVICE_PERMISSION | private static final String | MANUFACTURER | private static final String | MODEL | private static final String | DESCRIPTION | private static final String | VERSION | private static final String | URI | private static final String | SERIAL | private static final int | MULTITOUCH_DEVICE_ID | private static final int | MULTITOUCH_REPORT_ID | private static final int | MULTITOUCH_MAX_CONTACTS | private android.hardware.usb.UsbManager | mUsbManager | private DeviceReceiver | mReceiver | private android.widget.TextView | mLogTextView | private android.widget.TextView | mFpsTextView | private android.view.SurfaceView | mSurfaceView | private com.android.accessorydisplay.common.Logger | mLogger | private boolean | mConnected | private int | mProtocolVersion | private android.hardware.usb.UsbDevice | mDevice | private android.hardware.usb.UsbInterface | mAccessoryInterface | private android.hardware.usb.UsbDeviceConnection | mAccessoryConnection | private android.hardware.usb.UsbEndpoint | mControlEndpoint | private UsbAccessoryBulkTransport | mTransport | private boolean | mAttached | private DisplaySinkService | mDisplaySinkService | private final ByteBuffer | mHidBuffer | private UsbHid.Multitouch | mMultitouch | private boolean | mMultitouchEnabled | private UsbHid.Multitouch.Contact[] | mMultitouchContacts |
Methods Summary |
---|
private void | connect(android.hardware.usb.UsbDevice device)
if (mConnected) {
disconnect();
}
// Check whether we have permission to access the device.
if (!mUsbManager.hasPermission(device)) {
mLogger.log("Prompting the user for access to the device.");
Intent intent = new Intent(ACTION_USB_DEVICE_PERMISSION);
intent.setPackage(getPackageName());
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
mUsbManager.requestPermission(device, pendingIntent);
return;
}
// Claim the device.
UsbDeviceConnection conn = mUsbManager.openDevice(device);
if (conn == null) {
mLogger.logError("Could not obtain device connection.");
return;
}
UsbInterface iface = device.getInterface(0);
UsbEndpoint controlEndpoint = iface.getEndpoint(0);
if (!conn.claimInterface(iface, true)) {
mLogger.logError("Could not claim interface.");
return;
}
try {
// If already in accessory mode, then connect to the device.
if (isAccessory(device)) {
mLogger.log("Connecting to accessory...");
int protocolVersion = getProtocol(conn);
if (protocolVersion < 1) {
mLogger.logError("Device does not support accessory protocol.");
return;
}
mLogger.log("Protocol version: " + protocolVersion);
// Setup bulk endpoints.
UsbEndpoint bulkIn = null;
UsbEndpoint bulkOut = null;
for (int i = 0; i < iface.getEndpointCount(); i++) {
UsbEndpoint ep = iface.getEndpoint(i);
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
if (bulkIn == null) {
mLogger.log(String.format("Bulk IN endpoint: %d", i));
bulkIn = ep;
}
} else {
if (bulkOut == null) {
mLogger.log(String.format("Bulk OUT endpoint: %d", i));
bulkOut = ep;
}
}
}
if (bulkIn == null || bulkOut == null) {
mLogger.logError("Unable to find bulk endpoints");
return;
}
mLogger.log("Connected");
mConnected = true;
mDevice = device;
mProtocolVersion = protocolVersion;
mAccessoryInterface = iface;
mAccessoryConnection = conn;
mControlEndpoint = controlEndpoint;
mTransport = new UsbAccessoryBulkTransport(mLogger, conn, bulkIn, bulkOut);
if (mProtocolVersion >= 2) {
registerHid();
}
startServices();
mTransport.startReading();
return;
}
// Do accessory negotiation.
mLogger.log("Attempting to switch device to accessory mode...");
// Send get protocol.
int protocolVersion = getProtocol(conn);
if (protocolVersion < 1) {
mLogger.logError("Device does not support accessory protocol.");
return;
}
mLogger.log("Protocol version: " + protocolVersion);
// Send identifying strings.
sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_MANUFACTURER, MANUFACTURER);
sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_MODEL, MODEL);
sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_DESCRIPTION, DESCRIPTION);
sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_VERSION, VERSION);
sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_URI, URI);
sendString(conn, UsbAccessoryConstants.ACCESSORY_STRING_SERIAL, SERIAL);
// Send start.
// The device should re-enumerate as an accessory.
mLogger.log("Sending accessory start request.");
int len = conn.controlTransfer(UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
UsbAccessoryConstants.ACCESSORY_START, 0, 0, null, 0, 10000);
if (len != 0) {
mLogger.logError("Device refused to switch to accessory mode.");
} else {
mLogger.log("Waiting for device to re-enumerate...");
}
} finally {
if (!mConnected) {
conn.releaseInterface(iface);
}
}
| private void | disconnect()
mLogger.log("Disconnecting from device: " + mDevice);
stopServices();
unregisterHid();
mLogger.log("Disconnected.");
mConnected = false;
mDevice = null;
mAccessoryConnection = null;
mAccessoryInterface = null;
mControlEndpoint = null;
if (mTransport != null) {
mTransport.close();
mTransport = null;
}
| private int | getProtocol(android.hardware.usb.UsbDeviceConnection conn)
byte buffer[] = new byte[2];
int len = conn.controlTransfer(
UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR,
UsbAccessoryConstants.ACCESSORY_GET_PROTOCOL, 0, 0, buffer, 2, 10000);
if (len != 2) {
return -1;
}
return (buffer[1] << 8) | buffer[0];
| private static boolean | isAccessory(android.hardware.usb.UsbDevice device)
final int vid = device.getVendorId();
final int pid = device.getProductId();
return vid == UsbAccessoryConstants.USB_ACCESSORY_VENDOR_ID
&& (pid == UsbAccessoryConstants.USB_ACCESSORY_PRODUCT_ID
|| pid == UsbAccessoryConstants.USB_ACCESSORY_ADB_PRODUCT_ID);
| public void | onAttachedToWindow()
super.onAttachedToWindow();
mAttached = true;
if (mDisplaySinkService != null) {
mDisplaySinkService.setSurfaceView(mSurfaceView);
}
| protected void | onCreate(android.os.Bundle savedInstanceState)
super.onCreate(savedInstanceState);
mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
setContentView(R.layout.sink_activity);
mLogTextView = (TextView) findViewById(R.id.logTextView);
mLogTextView.setMovementMethod(ScrollingMovementMethod.getInstance());
mLogger = new TextLogger();
mFpsTextView = (TextView) findViewById(R.id.fpsTextView);
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
mSurfaceView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
sendHidTouch(event);
return true;
}
});
mLogger.log("Waiting for accessory display source to be attached to USB...");
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(ACTION_USB_DEVICE_PERMISSION);
mReceiver = new DeviceReceiver();
registerReceiver(mReceiver, filter);
Intent intent = getIntent();
if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
onDeviceAttached(device);
}
} else {
Map<String, UsbDevice> devices = mUsbManager.getDeviceList();
if (devices != null) {
for (UsbDevice device : devices.values()) {
onDeviceAttached(device);
}
}
}
| protected void | onDestroy()
super.onDestroy();
unregisterReceiver(mReceiver);
| public void | onDetachedFromWindow()
super.onDetachedFromWindow();
mAttached = false;
if (mDisplaySinkService != null) {
mDisplaySinkService.setSurfaceView(null);
}
| private void | onDeviceAttached(android.hardware.usb.UsbDevice device)
mLogger.log("USB device attached: " + device);
if (!mConnected) {
connect(device);
}
| private void | onDeviceDetached(android.hardware.usb.UsbDevice device)
mLogger.log("USB device detached: " + device);
if (mConnected && device.equals(mDevice)) {
disconnect();
}
| private void | registerHid()
mLogger.log("Registering HID multitouch device.");
mMultitouch = new UsbHid.Multitouch(MULTITOUCH_REPORT_ID, MULTITOUCH_MAX_CONTACTS,
mSurfaceView.getWidth(), mSurfaceView.getHeight());
mHidBuffer.clear();
mMultitouch.generateDescriptor(mHidBuffer);
mHidBuffer.flip();
mLogger.log("HID descriptor size: " + mHidBuffer.limit());
mLogger.log("HID report size: " + mMultitouch.getReportSize());
final int maxPacketSize = mControlEndpoint.getMaxPacketSize();
mLogger.log("Control endpoint max packet size: " + maxPacketSize);
if (mMultitouch.getReportSize() > maxPacketSize) {
mLogger.logError("HID report is too big for this accessory.");
return;
}
int len = mAccessoryConnection.controlTransfer(
UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
UsbAccessoryConstants.ACCESSORY_REGISTER_HID,
MULTITOUCH_DEVICE_ID, mHidBuffer.limit(), null, 0, 10000);
if (len != 0) {
mLogger.logError("Device rejected ACCESSORY_REGISTER_HID request.");
return;
}
while (mHidBuffer.hasRemaining()) {
int position = mHidBuffer.position();
int count = Math.min(mHidBuffer.remaining(), maxPacketSize);
len = mAccessoryConnection.controlTransfer(
UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
UsbAccessoryConstants.ACCESSORY_SET_HID_REPORT_DESC,
MULTITOUCH_DEVICE_ID, 0,
mHidBuffer.array(), position, count, 10000);
if (len != count) {
mLogger.logError("Device rejected ACCESSORY_SET_HID_REPORT_DESC request.");
return;
}
mHidBuffer.position(position + count);
}
mLogger.log("HID device registered.");
mMultitouchEnabled = true;
if (mMultitouchContacts == null) {
mMultitouchContacts = new UsbHid.Multitouch.Contact[MULTITOUCH_MAX_CONTACTS];
for (int i = 0; i < MULTITOUCH_MAX_CONTACTS; i++) {
mMultitouchContacts[i] = new UsbHid.Multitouch.Contact();
}
}
| private void | sendHidTouch(android.view.MotionEvent event)
if (mMultitouchEnabled) {
mLogger.log("Sending touch event: " + event);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE: {
final int pointerCount =
Math.min(MULTITOUCH_MAX_CONTACTS, event.getPointerCount());
final int historySize = event.getHistorySize();
for (int p = 0; p < pointerCount; p++) {
mMultitouchContacts[p].id = event.getPointerId(p);
}
for (int h = 0; h < historySize; h++) {
for (int p = 0; p < pointerCount; p++) {
mMultitouchContacts[p].x = (int)event.getHistoricalX(p, h);
mMultitouchContacts[p].y = (int)event.getHistoricalY(p, h);
}
sendHidTouchReport(pointerCount);
}
for (int p = 0; p < pointerCount; p++) {
mMultitouchContacts[p].x = (int)event.getX(p);
mMultitouchContacts[p].y = (int)event.getY(p);
}
sendHidTouchReport(pointerCount);
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
sendHidTouchReport(0);
break;
}
}
| private void | sendHidTouchReport(int contactCount)
mHidBuffer.clear();
mMultitouch.generateReport(mHidBuffer, mMultitouchContacts, contactCount);
mHidBuffer.flip();
int count = mHidBuffer.limit();
int len = mAccessoryConnection.controlTransfer(
UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
UsbAccessoryConstants.ACCESSORY_SEND_HID_EVENT,
MULTITOUCH_DEVICE_ID, 0,
mHidBuffer.array(), 0, count, 10000);
if (len != count) {
mLogger.logError("Device rejected ACCESSORY_SEND_HID_EVENT request.");
return;
}
| private void | sendString(android.hardware.usb.UsbDeviceConnection conn, int index, java.lang.String string)
byte[] buffer = (string + "\0").getBytes();
int len = conn.controlTransfer(UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
UsbAccessoryConstants.ACCESSORY_SEND_STRING, 0, index,
buffer, buffer.length, 10000);
if (len != buffer.length) {
mLogger.logError("Failed to send string " + index + ": \"" + string + "\"");
} else {
mLogger.log("Sent string " + index + ": \"" + string + "\"");
}
| private void | startServices()
mDisplaySinkService = new DisplaySinkService(this, mTransport,
getResources().getConfiguration().densityDpi);
mDisplaySinkService.start();
if (mAttached) {
mDisplaySinkService.setSurfaceView(mSurfaceView);
}
| private void | stopServices()
if (mDisplaySinkService != null) {
mDisplaySinkService.stop();
mDisplaySinkService = null;
}
| private void | unregisterHid()
mMultitouch = null;
mMultitouchContacts = null;
mMultitouchEnabled = false;
|
|