summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2011-03-02 15:38:55 -0800
committerAndroid Git Automerger <android-git-automerger@android.com>2011-03-02 15:38:55 -0800
commitb13581a9dab07ccd1841890e0443b9cfe0805679 (patch)
treee416e1773015582c0221dc146574905afa3942ff /libs
parent7866be2b76e421ca28e5dcbd3e7d362baf279dd9 (diff)
parent1110748b2df664f9c5066819c1f0616eae3394a7 (diff)
downloadframeworks_base-b13581a9dab07ccd1841890e0443b9cfe0805679.zip
frameworks_base-b13581a9dab07ccd1841890e0443b9cfe0805679.tar.gz
frameworks_base-b13581a9dab07ccd1841890e0443b9cfe0805679.tar.bz2
am 1110748b: DO NOT MERGE: USB accessory support library
* commit '1110748b2df664f9c5066819c1f0616eae3394a7': DO NOT MERGE: USB accessory support library
Diffstat (limited to 'libs')
-rw-r--r--libs/usb/Android.mk27
-rw-r--r--libs/usb/src/com/android/future/usb/UsbAccessory.java (renamed from libs/usb/src/com/google/android/usb/UsbAccessory.java)2
-rw-r--r--libs/usb/src/com/android/future/usb/UsbManager.java (renamed from libs/usb/src/com/google/android/usb/UsbManager.java)2
-rw-r--r--libs/usb/tests/AccessoryChat/Android.mk31
-rw-r--r--libs/usb/tests/AccessoryChat/AndroidManifest.xml39
-rw-r--r--libs/usb/tests/AccessoryChat/README.txt10
-rw-r--r--libs/usb/tests/AccessoryChat/accessorychat/Android.mk21
-rw-r--r--libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c174
-rw-r--r--libs/usb/tests/AccessoryChat/accessorychat/usbhost.c574
-rw-r--r--libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h219
-rw-r--r--libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml47
-rw-r--r--libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml18
-rw-r--r--libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java153
13 files changed, 1315 insertions, 2 deletions
diff --git a/libs/usb/Android.mk b/libs/usb/Android.mk
new file mode 100644
index 0000000..129828f
--- /dev/null
+++ b/libs/usb/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE:= com.android.future.usb.accessory
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/libs/usb/src/com/google/android/usb/UsbAccessory.java b/libs/usb/src/com/android/future/usb/UsbAccessory.java
index 931f42e..cdd2b73 100644
--- a/libs/usb/src/com/google/android/usb/UsbAccessory.java
+++ b/libs/usb/src/com/android/future/usb/UsbAccessory.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.google.android.usb;
+package com.android.future.usb;
/**
* A class representing a USB accessory.
diff --git a/libs/usb/src/com/google/android/usb/UsbManager.java b/libs/usb/src/com/android/future/usb/UsbManager.java
index d7afb95..f74b291 100644
--- a/libs/usb/src/com/google/android/usb/UsbManager.java
+++ b/libs/usb/src/com/android/future/usb/UsbManager.java
@@ -15,7 +15,7 @@
*/
-package com.google.android.usb;
+package com.android.future.usb;
import android.content.Context;
import android.content.Intent;
diff --git a/libs/usb/tests/AccessoryChat/Android.mk b/libs/usb/tests/AccessoryChat/Android.mk
new file mode 100644
index 0000000..d555961
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := AccessoryChatGB
+
+LOCAL_JAVA_LIBRARIES := com.android.future.usb.accessory
+
+# Force an old SDK version to make sure we aren't using newer UsbManager APIs
+LOCAL_SDK_VERSION := 8
+
+include $(BUILD_PACKAGE)
diff --git a/libs/usb/tests/AccessoryChat/AndroidManifest.xml b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
new file mode 100644
index 0000000..d6093ae
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.accessorychat">
+
+ <application>
+ <uses-library android:name="com.android.future.usb.accessory" />
+
+ <activity android:name="AccessoryChat" android:label="Accessory Chat GB">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <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>
+ </application>
+ <uses-sdk android:minSdkVersion="10" />
+</manifest>
diff --git a/libs/usb/tests/AccessoryChat/README.txt b/libs/usb/tests/AccessoryChat/README.txt
new file mode 100644
index 0000000..d2ce11e
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/README.txt
@@ -0,0 +1,10 @@
+This is a test app for the USB accessory APIs. It consists of two parts:
+
+AccessoryChat - A Java app with a chat-like UI that sends and receives strings
+ via the UsbAccessory class.
+
+accessorychat - A C command-line program that communicates with AccessoryChat.
+ This program behaves as if it were a USB accessory.
+ It builds both for the host (Linux PC) and as an android
+ command line program, which will work if run as root on an
+ android device with USB host support
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/Android.mk b/libs/usb/tests/AccessoryChat/accessorychat/Android.mk
new file mode 100644
index 0000000..5a7b30e
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/accessorychat/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+
+# Build for Linux (desktop) host
+ifeq ($(HOST_OS),linux)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := accessorychat.c usbhost.c
+
+LOCAL_MODULE := accessorychat
+
+LOCAL_C_INCLUDES += bionic/libc/kernel/common
+LOCAL_STATIC_LIBRARIES := libcutils
+LOCAL_LDLIBS += -lpthread
+LOCAL_CFLAGS := -g -O0
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
new file mode 100644
index 0000000..94cc0ce
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include <usbhost/usbhost.h>
+#include <linux/usb/f_accessory.h>
+
+struct usb_device *sDevice = NULL;
+
+static void* read_thread(void* arg) {
+ int endpoint = (int)arg;
+ int ret = 0;
+
+ while (sDevice && ret >= 0) {
+ char buffer[16384];
+
+ ret = usb_device_bulk_transfer(sDevice, endpoint, buffer, sizeof(buffer), 1000);
+ if (ret < 0 && errno == ETIMEDOUT)
+ ret = 0;
+ if (ret > 0) {
+ fwrite(buffer, 1, ret, stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+ }
+
+ return NULL;
+}
+
+static void* write_thread(void* arg) {
+ int endpoint = (int)arg;
+ int ret = 0;
+
+ while (ret >= 0) {
+ char buffer[16384];
+ char *line = fgets(buffer, sizeof(buffer), stdin);
+ if (!line || !sDevice)
+ break;
+ ret = usb_device_bulk_transfer(sDevice, endpoint, line, strlen(line), 1000);
+ }
+
+ return NULL;
+}
+
+static void send_string(struct usb_device *device, int index, const char* string) {
+ int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
+ ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 0);
+}
+
+static int usb_device_added(const char *devname, void* client_data) {
+ struct usb_descriptor_header* desc;
+ struct usb_descriptor_iter iter;
+ uint16_t vendorId, productId;
+ int ret;
+ pthread_t th;
+
+ struct usb_device *device = usb_device_open(devname);
+ if (!device) {
+ fprintf(stderr, "usb_device_open failed\n");
+ return 0;
+ }
+
+ vendorId = usb_device_get_vendor_id(device);
+ productId = usb_device_get_product_id(device);
+
+ if (vendorId == 0x18D1 || vendorId == 0x22B8) {
+ if (!sDevice && (productId == 0x2D00 || productId == 0x2D01)) {
+ struct usb_descriptor_header* desc;
+ struct usb_descriptor_iter iter;
+ struct usb_interface_descriptor *intf = NULL;
+ struct usb_endpoint_descriptor *ep1 = NULL;
+ struct usb_endpoint_descriptor *ep2 = NULL;
+
+ printf("Found android device in accessory mode\n");
+ sDevice = device;
+
+ usb_descriptor_iter_init(device, &iter);
+ while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) {
+ if (desc->bDescriptorType == USB_DT_INTERFACE) {
+ intf = (struct usb_interface_descriptor *)desc;
+ } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
+ if (ep1)
+ ep2 = (struct usb_endpoint_descriptor *)desc;
+ else
+ ep1 = (struct usb_endpoint_descriptor *)desc;
+ }
+ }
+
+ if (!intf) {
+ fprintf(stderr, "interface not found\n");
+ exit(1);
+ }
+ if (!ep1 || !ep2) {
+ fprintf(stderr, "endpoints not found\n");
+ exit(1);
+ }
+
+ if (usb_device_claim_interface(device, intf->bInterfaceNumber)) {
+ fprintf(stderr, "usb_device_claim_interface failed errno: %d\n", errno);
+ exit(1);
+ }
+
+ if ((ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ pthread_create(&th, NULL, read_thread, (void *)ep1->bEndpointAddress);
+ pthread_create(&th, NULL, write_thread, (void *)ep2->bEndpointAddress);
+ } else {
+ pthread_create(&th, NULL, read_thread, (void *)ep2->bEndpointAddress);
+ pthread_create(&th, NULL, write_thread, (void *)ep1->bEndpointAddress);
+ }
+ } else {
+ printf("Found possible android device - attempting to switch to accessory mode\n");
+
+ send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc.");
+ send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat");
+ send_string(device, ACCESSORY_STRING_TYPE, "Sample Program");
+ send_string(device, ACCESSORY_STRING_VERSION, "1.0");
+
+ ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
+ ACCESSORY_START, 0, 0, 0, 0, 0);
+ return 0;
+ }
+ }
+
+ if (device != sDevice)
+ usb_device_close(device);
+
+ return 0;
+}
+
+static int usb_device_removed(const char *devname, void* client_data) {
+ if (sDevice && !strcmp(usb_device_get_name(sDevice), devname)) {
+ usb_device_close(sDevice);
+ sDevice = NULL;
+ // exit when we are disconnected
+ return 1;
+ }
+ return 0;
+}
+
+
+int main(int argc, char* argv[]) {
+ struct usb_host_context* context = usb_host_init();
+ if (!context) {
+ fprintf(stderr, "usb_host_init failed");
+ return 1;
+ }
+
+ // this will never return so it is safe to pass thiz directly
+ usb_host_run(context, usb_device_added, usb_device_removed, NULL, NULL);
+ return 0;
+}
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/usbhost.c b/libs/usb/tests/AccessoryChat/accessorychat/usbhost.c
new file mode 100644
index 0000000..f5a7c3f
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/accessorychat/usbhost.c
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define DEBUG 1
+#if DEBUG
+
+#ifdef USE_LIBLOG
+#define LOG_TAG "usbhost"
+#include "utils/Log.h"
+#define D LOGD
+#else
+#define D printf
+#endif
+
+#else
+#define D(...)
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/inotify.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pthread.h>
+
+#include <linux/usbdevice_fs.h>
+#include <asm/byteorder.h>
+
+#include "usbhost/usbhost.h"
+
+#define USB_FS_DIR "/dev/bus/usb"
+#define USB_FS_ID_SCANNER "/dev/bus/usb/%d/%d"
+#define USB_FS_ID_FORMAT "/dev/bus/usb/%03d/%03d"
+
+
+struct usb_host_context {
+ int fd;
+};
+
+struct usb_device {
+ char dev_name[64];
+ unsigned char desc[4096];
+ int desc_length;
+ int fd;
+ int writeable;
+};
+
+static inline int badname(const char *name)
+{
+ while(*name) {
+ if(!isdigit(*name++)) return 1;
+ }
+ return 0;
+}
+
+/* returns true if one of the callbacks indicates we are done */
+static int find_existing_devices(usb_device_added_cb added_cb,
+ usb_device_removed_cb removed_cb,
+ void *client_data)
+{
+ char busname[32], devname[32];
+ DIR *busdir , *devdir ;
+ struct dirent *de;
+ int done = 0;
+
+ busdir = opendir(USB_FS_DIR);
+ if(busdir == 0) return 1;
+
+ while ((de = readdir(busdir)) != 0 && !done) {
+ if(badname(de->d_name)) continue;
+
+ snprintf(busname, sizeof busname, "%s/%s", USB_FS_DIR, de->d_name);
+ devdir = opendir(busname);
+ if(devdir == 0) continue;
+
+ while ((de = readdir(devdir)) && !done) {
+ if(badname(de->d_name)) continue;
+
+ snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
+ done = added_cb(devname, client_data);
+ } // end of devdir while
+ closedir(devdir);
+ } //end of busdir while
+ closedir(busdir);
+
+ return done;
+}
+
+struct usb_host_context *usb_host_init()
+{
+ struct usb_host_context *context = calloc(1, sizeof(struct usb_host_context));
+ if (!context) {
+ fprintf(stderr, "out of memory in usb_host_context\n");
+ return NULL;
+ }
+ context->fd = inotify_init();
+ if (context->fd < 0) {
+ fprintf(stderr, "inotify_init failed\n");
+ free(context);
+ return NULL;
+ }
+ return context;
+}
+
+void usb_host_cleanup(struct usb_host_context *context)
+{
+ close(context->fd);
+ free(context);
+}
+
+void usb_host_run(struct usb_host_context *context,
+ usb_device_added_cb added_cb,
+ usb_device_removed_cb removed_cb,
+ usb_discovery_done_cb discovery_done_cb,
+ void *client_data)
+{
+ struct inotify_event* event;
+ char event_buf[512];
+ char path[100];
+ int i, ret, done = 0;
+ int wd, wds[10];
+ int wd_count = sizeof(wds) / sizeof(wds[0]);
+
+ D("Created device discovery thread\n");
+
+ /* watch for files added and deleted within USB_FS_DIR */
+ memset(wds, 0, sizeof(wds));
+ /* watch the root for new subdirectories */
+ wds[0] = inotify_add_watch(context->fd, USB_FS_DIR, IN_CREATE | IN_DELETE);
+ if (wds[0] < 0) {
+ fprintf(stderr, "inotify_add_watch failed\n");
+ if (discovery_done_cb)
+ discovery_done_cb(client_data);
+ return;
+ }
+
+ /* watch existing subdirectories of USB_FS_DIR */
+ for (i = 1; i < wd_count; i++) {
+ snprintf(path, sizeof(path), "%s/%03d", USB_FS_DIR, i);
+ ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);
+ if (ret > 0)
+ wds[i] = ret;
+ }
+
+ /* check for existing devices first, after we have inotify set up */
+ done = find_existing_devices(added_cb, removed_cb, client_data);
+ if (discovery_done_cb)
+ done |= discovery_done_cb(client_data);
+
+ while (!done) {
+ ret = read(context->fd, event_buf, sizeof(event_buf));
+ if (ret >= (int)sizeof(struct inotify_event)) {
+ event = (struct inotify_event *)event_buf;
+ wd = event->wd;
+ if (wd == wds[0]) {
+ i = atoi(event->name);
+ snprintf(path, sizeof(path), "%s/%s", USB_FS_DIR, event->name);
+ D("new subdirectory %s: index: %d\n", path, i);
+ if (i > 0 && i < wd_count) {
+ ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);
+ if (ret > 0)
+ wds[i] = ret;
+ }
+ } else {
+ for (i = 1; i < wd_count && !done; i++) {
+ if (wd == wds[i]) {
+ snprintf(path, sizeof(path), "%s/%03d/%s", USB_FS_DIR, i, event->name);
+ if (event->mask == IN_CREATE) {
+ D("new device %s\n", path);
+ done = added_cb(path, client_data);
+ } else if (event->mask == IN_DELETE) {
+ D("gone device %s\n", path);
+ done = removed_cb(path, client_data);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+struct usb_device *usb_device_open(const char *dev_name)
+{
+ int fd, did_retry = 0, writeable = 1;
+
+ D("usb_device_open %s\n", dev_name);
+
+retry:
+ fd = open(dev_name, O_RDWR);
+ if (fd < 0) {
+ /* if we fail, see if have read-only access */
+ fd = open(dev_name, O_RDONLY);
+ D("usb_device_open open returned %d errno %d\n", fd, errno);
+ if (fd < 0 && (errno == EACCES || errno == ENOENT) && !did_retry) {
+ /* work around race condition between inotify and permissions management */
+ sleep(1);
+ did_retry = 1;
+ goto retry;
+ }
+
+ if (fd < 0)
+ return NULL;
+ writeable = 0;
+ D("[ usb open read-only %s fd = %d]\n", dev_name, fd);
+ }
+
+ struct usb_device* result = usb_device_new(dev_name, fd);
+ if (result)
+ result->writeable = writeable;
+ return result;
+}
+
+void usb_device_close(struct usb_device *device)
+{
+ close(device->fd);
+ free(device);
+}
+
+struct usb_device *usb_device_new(const char *dev_name, int fd)
+{
+ struct usb_device *device = calloc(1, sizeof(struct usb_device));
+ int length;
+
+ D("usb_device_new %s fd: %d\n", dev_name, fd);
+
+ if (lseek(fd, 0, SEEK_SET) != 0)
+ goto failed;
+ length = read(fd, device->desc, sizeof(device->desc));
+ D("usb_device_new read returned %d errno %d\n", length, errno);
+ if (length < 0)
+ goto failed;
+
+ strncpy(device->dev_name, dev_name, sizeof(device->dev_name) - 1);
+ device->fd = fd;
+ device->desc_length = length;
+ // assume we are writeable, since usb_device_get_fd will only return writeable fds
+ device->writeable = 1;
+ return device;
+
+failed:
+ close(fd);
+ free(device);
+ return NULL;
+}
+
+static int usb_device_reopen_writeable(struct usb_device *device)
+{
+ if (device->writeable)
+ return 1;
+
+ int fd = open(device->dev_name, O_RDWR);
+ if (fd >= 0) {
+ close(device->fd);
+ device->fd = fd;
+ device->writeable = 1;
+ return 1;
+ }
+ D("usb_device_reopen_writeable failed errno %d\n", errno);
+ return 0;
+}
+
+int usb_device_get_fd(struct usb_device *device)
+{
+ if (!usb_device_reopen_writeable(device))
+ return -1;
+ return device->fd;
+}
+
+const char* usb_device_get_name(struct usb_device *device)
+{
+ return device->dev_name;
+}
+
+int usb_device_get_unique_id(struct usb_device *device)
+{
+ int bus = 0, dev = 0;
+ sscanf(device->dev_name, USB_FS_ID_SCANNER, &bus, &dev);
+ return bus * 1000 + dev;
+}
+
+int usb_device_get_unique_id_from_name(const char* name)
+{
+ int bus = 0, dev = 0;
+ sscanf(name, USB_FS_ID_SCANNER, &bus, &dev);
+ return bus * 1000 + dev;
+}
+
+char* usb_device_get_name_from_unique_id(int id)
+{
+ int bus = id / 1000;
+ int dev = id % 1000;
+ char* result = (char *)calloc(1, strlen(USB_FS_ID_FORMAT));
+ snprintf(result, strlen(USB_FS_ID_FORMAT) - 1, USB_FS_ID_FORMAT, bus, dev);
+ return result;
+}
+
+uint16_t usb_device_get_vendor_id(struct usb_device *device)
+{
+ struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc;
+ return __le16_to_cpu(desc->idVendor);
+}
+
+uint16_t usb_device_get_product_id(struct usb_device *device)
+{
+ struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc;
+ return __le16_to_cpu(desc->idProduct);
+}
+
+const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device)
+{
+ return (struct usb_device_descriptor*)device->desc;
+}
+
+char* usb_device_get_string(struct usb_device *device, int id)
+{
+ char string[256];
+ __u16 buffer[128];
+ __u16 languages[128];
+ int i, result;
+ int languageCount = 0;
+
+ string[0] = 0;
+ memset(languages, 0, sizeof(languages));
+
+ // read list of supported languages
+ result = usb_device_control_transfer(device,
+ USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages), 0);
+ if (result > 0)
+ languageCount = (result - 2) / 2;
+
+ for (i = 1; i <= languageCount; i++) {
+ memset(buffer, 0, sizeof(buffer));
+
+ result = usb_device_control_transfer(device,
+ USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer), 0);
+ if (result > 0) {
+ int i;
+ // skip first word, and copy the rest to the string, changing shorts to bytes.
+ result /= 2;
+ for (i = 1; i < result; i++)
+ string[i - 1] = buffer[i];
+ string[i - 1] = 0;
+ return strdup(string);
+ }
+ }
+
+ return NULL;
+}
+
+char* usb_device_get_manufacturer_name(struct usb_device *device)
+{
+ struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
+
+ if (desc->iManufacturer)
+ return usb_device_get_string(device, desc->iManufacturer);
+ else
+ return NULL;
+}
+
+char* usb_device_get_product_name(struct usb_device *device)
+{
+ struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
+
+ if (desc->iProduct)
+ return usb_device_get_string(device, desc->iProduct);
+ else
+ return NULL;
+}
+
+char* usb_device_get_serial(struct usb_device *device)
+{
+ struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
+
+ if (desc->iSerialNumber)
+ return usb_device_get_string(device, desc->iSerialNumber);
+ else
+ return NULL;
+}
+
+int usb_device_is_writeable(struct usb_device *device)
+{
+ return device->writeable;
+}
+
+void usb_descriptor_iter_init(struct usb_device *device, struct usb_descriptor_iter *iter)
+{
+ iter->config = device->desc;
+ iter->config_end = device->desc + device->desc_length;
+ iter->curr_desc = device->desc;
+}
+
+struct usb_descriptor_header *usb_descriptor_iter_next(struct usb_descriptor_iter *iter)
+{
+ struct usb_descriptor_header* next;
+ if (iter->curr_desc >= iter->config_end)
+ return NULL;
+ next = (struct usb_descriptor_header*)iter->curr_desc;
+ iter->curr_desc += next->bLength;
+ return next;
+}
+
+int usb_device_claim_interface(struct usb_device *device, unsigned int interface)
+{
+ return ioctl(device->fd, USBDEVFS_CLAIMINTERFACE, &interface);
+}
+
+int usb_device_release_interface(struct usb_device *device, unsigned int interface)
+{
+ return ioctl(device->fd, USBDEVFS_RELEASEINTERFACE, &interface);
+}
+
+int usb_device_connect_kernel_driver(struct usb_device *device,
+ unsigned int interface, int connect)
+{
+ struct usbdevfs_ioctl ctl;
+
+ ctl.ifno = interface;
+ ctl.ioctl_code = (connect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT);
+ ctl.data = NULL;
+ return ioctl(device->fd, USBDEVFS_IOCTL, &ctl);
+}
+
+int usb_device_control_transfer(struct usb_device *device,
+ int requestType,
+ int request,
+ int value,
+ int index,
+ void* buffer,
+ int length,
+ unsigned int timeout)
+{
+ struct usbdevfs_ctrltransfer ctrl;
+
+ // this usually requires read/write permission
+ if (!usb_device_reopen_writeable(device))
+ return -1;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.bRequestType = requestType;
+ ctrl.bRequest = request;
+ ctrl.wValue = value;
+ ctrl.wIndex = index;
+ ctrl.wLength = length;
+ ctrl.data = buffer;
+ ctrl.timeout = timeout;
+ return ioctl(device->fd, USBDEVFS_CONTROL, &ctrl);
+}
+
+int usb_device_bulk_transfer(struct usb_device *device,
+ int endpoint,
+ void* buffer,
+ int length,
+ unsigned int timeout)
+{
+ struct usbdevfs_bulktransfer ctrl;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.ep = endpoint;
+ ctrl.len = length;
+ ctrl.data = buffer;
+ ctrl.timeout = timeout;
+ return ioctl(device->fd, USBDEVFS_BULK, &ctrl);
+}
+
+struct usb_request *usb_request_new(struct usb_device *dev,
+ const struct usb_endpoint_descriptor *ep_desc)
+{
+ struct usbdevfs_urb *urb = calloc(1, sizeof(struct usbdevfs_urb));
+ if (!urb)
+ return NULL;
+
+ if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
+ urb->type = USBDEVFS_URB_TYPE_BULK;
+ else if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+ urb->type = USBDEVFS_URB_TYPE_INTERRUPT;
+ else {
+ D("Unsupported endpoint type %d", ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+ free(urb);
+ return NULL;
+ }
+ urb->endpoint = ep_desc->bEndpointAddress;
+
+ struct usb_request *req = calloc(1, sizeof(struct usb_request));
+ if (!req) {
+ free(urb);
+ return NULL;
+ }
+
+ req->dev = dev;
+ req->max_packet_size = __le16_to_cpu(ep_desc->wMaxPacketSize);
+ req->private_data = urb;
+ req->endpoint = urb->endpoint;
+ urb->usercontext = req;
+
+ return req;
+}
+
+void usb_request_free(struct usb_request *req)
+{
+ free(req->private_data);
+ free(req);
+}
+
+int usb_request_queue(struct usb_request *req)
+{
+ struct usbdevfs_urb *urb = (struct usbdevfs_urb*)req->private_data;
+ int res;
+
+ urb->status = -1;
+ urb->buffer = req->buffer;
+ urb->buffer_length = req->buffer_length;
+
+ do {
+ res = ioctl(req->dev->fd, USBDEVFS_SUBMITURB, urb);
+ } while((res < 0) && (errno == EINTR));
+
+ return res;
+}
+
+struct usb_request *usb_request_wait(struct usb_device *dev)
+{
+ struct usbdevfs_urb *urb = NULL;
+ struct usb_request *req = NULL;
+ int res;
+
+ while (1) {
+ int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb);
+ D("USBDEVFS_REAPURB returned %d\n", res);
+ if (res < 0) {
+ if(errno == EINTR) {
+ continue;
+ }
+ D("[ reap urb - error ]\n");
+ return NULL;
+ } else {
+ D("[ urb @%p status = %d, actual = %d ]\n",
+ urb, urb->status, urb->actual_length);
+ req = (struct usb_request*)urb->usercontext;
+ req->actual_length = urb->actual_length;
+ }
+ break;
+ }
+ return req;
+}
+
+int usb_request_cancel(struct usb_request *req)
+{
+ struct usbdevfs_urb *urb = ((struct usbdevfs_urb*)req->private_data);
+ return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, &urb);
+}
+
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h b/libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h
new file mode 100644
index 0000000..9a6b59c
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __USB_HOST_H
+#define __USB_HOST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
+#include <linux/usb/ch9.h>
+#else
+#include <linux/usb_ch9.h>
+#endif
+
+struct usb_host_context;
+struct usb_endpoint_descriptor;
+
+struct usb_descriptor_iter {
+ unsigned char* config;
+ unsigned char* config_end;
+ unsigned char* curr_desc;
+};
+
+struct usb_request
+{
+ struct usb_device *dev;
+ void* buffer;
+ int buffer_length;
+ int actual_length;
+ int max_packet_size;
+ void *private_data; /* struct usbdevfs_urb* */
+ int endpoint;
+ void *client_data; /* free for use by client */
+};
+
+/* Callback for notification when new USB devices are attached.
+ * Return true to exit from usb_host_run.
+ */
+typedef int (* usb_device_added_cb)(const char *dev_name, void *client_data);
+
+/* Callback for notification when USB devices are removed.
+ * Return true to exit from usb_host_run.
+ */
+typedef int (* usb_device_removed_cb)(const char *dev_name, void *client_data);
+
+/* Callback indicating that initial device discovery is done.
+ * Return true to exit from usb_host_run.
+ */
+typedef int (* usb_discovery_done_cb)(void *client_data);
+
+/* Call this to initialize the USB host library. */
+struct usb_host_context *usb_host_init(void);
+
+/* Call this to cleanup the USB host library. */
+void usb_host_cleanup(struct usb_host_context *context);
+
+/* Call this to monitor the USB bus for new and removed devices.
+ * This is intended to be called from a dedicated thread,
+ * as it will not return until one of the callbacks returns true.
+ * added_cb will be called immediately for each existing USB device,
+ * and subsequently each time a new device is added.
+ * removed_cb is called when USB devices are removed from the bus.
+ * discovery_done_cb is called after the initial discovery of already
+ * connected devices is complete.
+ */
+void usb_host_run(struct usb_host_context *context,
+ usb_device_added_cb added_cb,
+ usb_device_removed_cb removed_cb,
+ usb_discovery_done_cb discovery_done_cb,
+ void *client_data);
+
+/* Creates a usb_device object for a USB device */
+struct usb_device *usb_device_open(const char *dev_name);
+
+/* Releases all resources associated with the USB device */
+void usb_device_close(struct usb_device *device);
+
+/* Creates a usb_device object for already open USB device */
+struct usb_device *usb_device_new(const char *dev_name, int fd);
+
+/* Returns the file descriptor for the usb_device */
+int usb_device_get_fd(struct usb_device *device);
+
+/* Returns the name for the USB device, which is the same as
+ * the dev_name passed to usb_device_open()
+ */
+const char* usb_device_get_name(struct usb_device *device);
+
+/* Returns a unique ID for the device.
+ *Currently this is generated from the dev_name path.
+ */
+int usb_device_get_unique_id(struct usb_device *device);
+
+/* Returns a unique ID for the device name.
+ * Currently this is generated from the device path.
+ */
+int usb_device_get_unique_id_from_name(const char* name);
+
+/* Returns the device name for the unique ID.
+ * Call free() to deallocate the returned string */
+char* usb_device_get_name_from_unique_id(int id);
+
+/* Returns the USB vendor ID from the device descriptor for the USB device */
+uint16_t usb_device_get_vendor_id(struct usb_device *device);
+
+/* Returns the USB product ID from the device descriptor for the USB device */
+uint16_t usb_device_get_product_id(struct usb_device *device);
+
+const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device);
+
+/* Returns a USB descriptor string for the given string ID.
+ * Used to implement usb_device_get_manufacturer_name,
+ * usb_device_get_product_name and usb_device_get_serial.
+ * Call free() to free the result when you are done with it.
+ */
+char* usb_device_get_string(struct usb_device *device, int id);
+
+/* Returns the manufacturer name for the USB device.
+ * Call free() to free the result when you are done with it.
+ */
+char* usb_device_get_manufacturer_name(struct usb_device *device);
+
+/* Returns the product name for the USB device.
+ * Call free() to free the result when you are done with it.
+ */
+char* usb_device_get_product_name(struct usb_device *device);
+
+/* Returns the USB serial number for the USB device.
+ * Call free() to free the result when you are done with it.
+ */
+char* usb_device_get_serial(struct usb_device *device);
+
+/* Returns true if we have write access to the USB device,
+ * and false if we only have access to the USB device configuration.
+ */
+int usb_device_is_writeable(struct usb_device *device);
+
+/* Initializes a usb_descriptor_iter, which can be used to iterate through all
+ * the USB descriptors for a USB device.
+ */
+void usb_descriptor_iter_init(struct usb_device *device, struct usb_descriptor_iter *iter);
+
+/* Returns the next USB descriptor for a device, or NULL if we have reached the
+ * end of the list.
+ */
+struct usb_descriptor_header *usb_descriptor_iter_next(struct usb_descriptor_iter *iter);
+
+/* Claims the specified interface of a USB device */
+int usb_device_claim_interface(struct usb_device *device, unsigned int interface);
+
+/* Releases the specified interface of a USB device */
+int usb_device_release_interface(struct usb_device *device, unsigned int interface);
+
+/* Requests the kernel to connect or disconnect its driver for the specified interface.
+ * This can be used to ask the kernel to disconnect its driver for a device
+ * so usb_device_claim_interface can claim it instead.
+ */
+int usb_device_connect_kernel_driver(struct usb_device *device,
+ unsigned int interface, int connect);
+
+/* Sends a control message to the specified device on endpoint zero */
+int usb_device_control_transfer(struct usb_device *device,
+ int requestType,
+ int request,
+ int value,
+ int index,
+ void* buffer,
+ int length,
+ unsigned int timeout);
+
+/* Reads or writes on a bulk endpoint.
+ * Returns number of bytes transferred, or negative value for error.
+ */
+int usb_device_bulk_transfer(struct usb_device *device,
+ int endpoint,
+ void* buffer,
+ int length,
+ unsigned int timeout);
+
+/* Creates a new usb_request. */
+struct usb_request *usb_request_new(struct usb_device *dev,
+ const struct usb_endpoint_descriptor *ep_desc);
+
+/* Releases all resources associated with the request */
+void usb_request_free(struct usb_request *req);
+
+/* Submits a read or write request on the specified device */
+int usb_request_queue(struct usb_request *req);
+
+ /* Waits for the results of a previous usb_request_queue operation.
+ * Returns a usb_request, or NULL for error.
+ */
+struct usb_request *usb_request_wait(struct usb_device *dev);
+
+/* Cancels a pending usb_request_queue() operation. */
+int usb_request_cancel(struct usb_request *req);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __USB_HOST_H */
diff --git a/libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml b/libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml
new file mode 100644
index 0000000..596ecbf
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+
+ <ScrollView android:id="@+id/scroll"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ >
+ <TextView android:id="@+id/log"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="25dp"
+ android:textSize="12sp"
+ android:textColor="#ffffffff"
+ />
+ </ScrollView>
+
+ <EditText android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:capitalize="sentences"
+ android:autoText="true"
+ android:singleLine="true"
+ />
+
+</LinearLayout>
+
+
diff --git a/libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml b/libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml
new file mode 100644
index 0000000..588946f
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <usb-accessory manufacturer="Google, Inc." model="AccessoryChat" type="Sample Program" version="1.0" />
+</resources>
diff --git a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
new file mode 100644
index 0000000..5cf02c7
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.accessorychat;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.util.Log;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import com.android.future.usb.UsbAccessory;
+import com.android.future.usb.UsbManager;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class AccessoryChat extends Activity implements Runnable, TextView.OnEditorActionListener {
+
+ private static final String TAG = "AccessoryChat";
+ TextView mLog;
+ EditText mEditText;
+ ParcelFileDescriptor mFileDescriptor;
+ FileInputStream mInputStream;
+ FileOutputStream mOutputStream;
+
+ private static final int MESSAGE_LOG = 1;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.accessory_chat);
+ mLog = (TextView)findViewById(R.id.log);
+ mEditText = (EditText)findViewById(R.id.message);
+ mEditText.setOnEditorActionListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ Intent intent = getIntent();
+ Log.d(TAG, "intent: " + intent);
+ UsbManager manager = UsbManager.getInstance();
+ UsbAccessory[] accessories = manager.getAccessoryList();
+ UsbAccessory accessory = (accessories == null ? null : accessories[0]);
+ if (accessory != null) {
+ mFileDescriptor = manager.openAccessory(accessory);
+ if (mFileDescriptor != null) {
+ FileDescriptor fd = mFileDescriptor.getFileDescriptor();
+ mInputStream = new FileInputStream(fd);
+ mOutputStream = new FileOutputStream(fd);
+ Thread thread = new Thread(null, this, "AccessoryChat");
+ thread.start();
+ } else {
+ Log.d(TAG, "openAccessory fail");
+ }
+ } else {
+ Log.d(TAG, "mAccessory is null");
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (mFileDescriptor != null) {
+ try {
+ mFileDescriptor.close();
+ } catch (IOException e) {
+ } finally {
+ mFileDescriptor = null;
+ }
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (actionId == EditorInfo.IME_ACTION_DONE && mOutputStream != null) {
+ try {
+ mOutputStream.write(v.getText().toString().getBytes());
+ } catch (IOException e) {
+ Log.e(TAG, "write failed", e);
+ }
+ v.setText("");
+ return true;
+ }
+ Log.d(TAG, "onEditorAction " + actionId + " event: " + event);
+ return false;
+ }
+
+ public void run() {
+ int ret = 0;
+ byte[] buffer = new byte[16384];
+ while (ret >= 0) {
+ try {
+ ret = mInputStream.read(buffer);
+ } catch (IOException e) {
+ break;
+ }
+
+ if (ret > 0) {
+ Message m = Message.obtain(mHandler, MESSAGE_LOG);
+ String text = new String(buffer, 0, ret);
+ Log.d(TAG, "chat: " + text);
+ m.obj = text;
+ mHandler.sendMessage(m);
+ }
+ }
+ Log.d(TAG, "thread out");
+ }
+
+ Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_LOG:
+ mLog.setText(mLog.getText() + "\n" + (String)msg.obj);
+ break;
+ }
+ }
+ };
+}
+
+