M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
+27
View File
@@ -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)
@@ -0,0 +1,136 @@
/*
* 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.future.usb;
/**
* A class representing a USB accessory.
*/
public class UsbAccessory {
private final String mManufacturer;
private final String mModel;
private final String mDescription;
private final String mVersion;
private final String mUri;
private final String mSerial;
/* package */ UsbAccessory(android.hardware.usb.UsbAccessory accessory) {
mManufacturer = accessory.getManufacturer();
mModel = accessory.getModel();
mDescription = accessory.getDescription();
mVersion = accessory.getVersion();
mUri = accessory.getUri();
mSerial = accessory.getSerial();
}
/**
* Returns the manufacturer of the accessory.
*
* @return the accessory manufacturer
*/
public String getManufacturer() {
return mManufacturer;
}
/**
* Returns the model name of the accessory.
*
* @return the accessory model
*/
public String getModel() {
return mModel;
}
/**
* Returns a user visible description of the accessory.
*
* @return the accessory description
*/
public String getDescription() {
return mDescription;
}
/**
* Returns the version of the accessory.
*
* @return the accessory version
*/
public String getVersion() {
return mVersion;
}
/**
* Returns the URI for the accessory.
* This is an optional URI that might show information about the accessory
* or provide the option to download an application for the accessory
*
* @return the accessory URI
*/
public String getUri() {
return mUri;
}
/**
* Returns the unique serial number for the accessory.
* This is an optional serial number that can be used to differentiate
* between individual accessories of the same model and manufacturer
*
* @return the unique serial number
*/
public String getSerial() {
return mSerial;
}
private static boolean compare(String s1, String s2) {
if (s1 == null) return (s2 == null);
return s1.equals(s2);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof UsbAccessory) {
UsbAccessory accessory = (UsbAccessory)obj;
return (compare(mManufacturer, accessory.getManufacturer()) &&
compare(mModel, accessory.getModel()) &&
compare(mDescription, accessory.getDescription()) &&
compare(mVersion, accessory.getVersion()) &&
compare(mUri, accessory.getUri()) &&
compare(mSerial, accessory.getSerial()));
}
return false;
}
@Override
public int hashCode() {
return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
(mModel == null ? 0 : mModel.hashCode()) ^
(mDescription == null ? 0 : mDescription.hashCode()) ^
(mVersion == null ? 0 : mVersion.hashCode()) ^
(mUri == null ? 0 : mUri.hashCode()) ^
(mSerial == null ? 0 : mSerial.hashCode()));
}
@Override
public String toString() {
return "UsbAccessory[mManufacturer=" + mManufacturer +
", mModel=" + mModel +
", mDescription=" + mDescription +
", mVersion=" + mVersion +
", mUri=" + mUri +
", mSerial=" + mSerial + "]";
}
}
@@ -0,0 +1,186 @@
/*
* 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.future.usb;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.IUsbManager;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
/**
* This is a wrapper class for the USB Manager to support USB accessories.
*
* <p>You can obtain an instance of this class by calling {@link #getInstance}
*
*/
public class UsbManager {
private static final String TAG = "UsbManager";
/**
* Broadcast Action: A broadcast for USB accessory attached event.
*
* This intent is sent when a USB accessory is attached.
* Call {@link #getAccessory(android.content.Intent)} to retrieve the
* {@link com.google.android.usb.UsbAccessory} for the attached accessory.
*/
public static final String ACTION_USB_ACCESSORY_ATTACHED =
"android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
/**
* Broadcast Action: A broadcast for USB accessory detached event.
*
* This intent is sent when a USB accessory is detached.
* Call {@link #getAccessory(android.content.Intent)} to retrieve the
* {@link com.google.android.usb.UsbAccessory} for the attached accessory that was detached.
*/
public static final String ACTION_USB_ACCESSORY_DETACHED =
"android.hardware.usb.action.USB_ACCESSORY_DETACHED";
/**
* Name of extra added to the {@link android.app.PendingIntent}
* passed into {#requestPermission} or {#requestPermission}
* containing a boolean value indicating whether the user granted permission or not.
*/
public static final String EXTRA_PERMISSION_GRANTED = "permission";
private final Context mContext;
private final IUsbManager mService;
private UsbManager(Context context, IUsbManager service) {
mContext = context;
mService = service;
}
/**
* Returns a new instance of this class.
*
* @param context the caller's {@link android.content.Context}
* @return UsbManager instance.
*/
public static UsbManager getInstance(Context context) {
IBinder b = ServiceManager.getService(Context.USB_SERVICE);
return new UsbManager(context, IUsbManager.Stub.asInterface(b));
}
/**
* Returns the {@link com.google.android.usb.UsbAccessory} for
* a {@link #ACTION_USB_ACCESSORY_ATTACHED} or {@link #ACTION_USB_ACCESSORY_ATTACHED}
* broadcast Intent. This can also be used to retrieve the accessory from the result
* of a call to {#requestPermission}.
*
* @return UsbAccessory for the intent.
*/
public static UsbAccessory getAccessory(Intent intent) {
android.hardware.usb.UsbAccessory accessory =
intent.getParcelableExtra(android.hardware.usb.UsbManager.EXTRA_ACCESSORY);
if (accessory == null) {
return null;
} else {
return new UsbAccessory(accessory);
}
}
/**
* Returns a list of currently attached USB accessories.
* (in the current implementation there can be at most one)
*
* @return list of USB accessories, or null if none are attached.
*/
public UsbAccessory[] getAccessoryList() {
try {
android.hardware.usb.UsbAccessory accessory = mService.getCurrentAccessory();
if (accessory == null) {
return null;
} else {
return new UsbAccessory[] { new UsbAccessory(accessory) };
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in getAccessoryList" , e);
return null;
}
}
/**
* Opens a file descriptor for reading and writing data to the USB accessory.
*
* @param accessory the USB accessory to open
* @return file descriptor, or null if the accessor could not be opened.
*/
public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
try {
return mService.openAccessory(new android.hardware.usb.UsbAccessory(
accessory.getManufacturer(),accessory.getModel(),
accessory.getDescription(), accessory.getVersion(),
accessory.getUri(), accessory.getSerial()));
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in openAccessory" , e);
return null;
}
}
/**
* Returns true if the caller has permission to access the accessory.
* Permission might have been granted temporarily via
* {@link #requestPermission} or
* by the user choosing the caller as the default application for the accessory.
*
* @param accessory to check permissions for
* @return true if caller has permission
*/
public boolean hasPermission(UsbAccessory accessory) {
try {
return mService.hasAccessoryPermission(new android.hardware.usb.UsbAccessory(
accessory.getManufacturer(),accessory.getModel(),
accessory.getDescription(), accessory.getVersion(),
accessory.getUri(), accessory.getSerial()));
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in hasPermission", e);
return false;
}
}
/**
* Requests temporary permission for the given package to access the accessory.
* This may result in a system dialog being displayed to the user
* if permission had not already been granted.
* Success or failure is returned via the {@link android.app.PendingIntent} pi.
* The boolean extra {@link #EXTRA_PERMISSION_GRANTED} will be attached to the
* PendingIntent to indicate success or failure.
* If successful, this grants the caller permission to access the device only
* until the device is disconnected.
*
* @param accessory to request permissions for
* @param pi PendingIntent for returning result
*/
public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
try {
mService.requestAccessoryPermission(new android.hardware.usb.UsbAccessory(
accessory.getManufacturer(),accessory.getModel(),
accessory.getDescription(), accessory.getVersion(),
accessory.getUri(), accessory.getSerial()),
mContext.getPackageName(), pi);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in requestPermission", e);
}
}
}
@@ -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 := AccessoryChat
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)
@@ -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 android:label="Accessory Chat">
<uses-library android:name="com.android.future.usb.accessory" />
<activity android:name="AccessoryChat" android:label="Accessory Chat">
<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>
@@ -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
@@ -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
@@ -0,0 +1,196 @@
/*
* 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 <time.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 milli_sleep(int millis) {
struct timespec tm;
tm.tv_sec = 0;
tm.tv_nsec = millis * 1000000;
nanosleep(&tm, 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);
// some devices can't handle back-to-back requests, so delay a bit
milli_sleep(10);
}
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");
uint16_t protocol;
ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,
ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0);
if (ret == 2)
printf("device supports protocol version %d\n", protocol);
else
fprintf(stderr, "failed to read protocol version\n");
send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc.");
send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat");
send_string(device, ACCESSORY_STRING_DESCRIPTION, "Accessory Chat");
send_string(device, ACCESSORY_STRING_VERSION, "1.0");
send_string(device, ACCESSORY_STRING_URI, "http://www.android.com");
send_string(device, ACCESSORY_STRING_SERIAL, "1234567890");
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;
}
@@ -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);
}
@@ -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 */
@@ -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>
@@ -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>
@@ -0,0 +1,199 @@
/*
* 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.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
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";
private static final String ACTION_USB_PERMISSION =
"com.android.accessorychat.action.USB_PERMISSION";
private TextView mLog;
private EditText mEditText;
private ParcelFileDescriptor mFileDescriptor;
private FileInputStream mInputStream;
private FileOutputStream mOutputStream;
private UsbManager mUsbManager;
private PendingIntent mPermissionIntent;
private boolean mPermissionRequestPending;
private static final int MESSAGE_LOG = 1;
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
synchronized (this) {
UsbAccessory accessory = UsbManager.getAccessory(intent);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
openAccessory(accessory);
} else {
Log.d(TAG, "permission denied for accessory " + accessory);
}
mPermissionRequestPending = false;
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mUsbManager = UsbManager.getInstance(this);
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
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);
UsbAccessory[] accessories = mUsbManager.getAccessoryList();
UsbAccessory accessory = (accessories == null ? null : accessories[0]);
if (accessory != null) {
if (mUsbManager.hasPermission(accessory)) {
openAccessory(accessory);
} else {
synchronized (mUsbReceiver) {
if (!mPermissionRequestPending) {
mUsbManager.requestPermission(accessory, mPermissionIntent);
mPermissionRequestPending = true;
}
}
}
} 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() {
unregisterReceiver(mUsbReceiver);
super.onDestroy();
}
private void openAccessory(UsbAccessory accessory) {
Log.d(TAG, "openAccessory: " + accessory);
mFileDescriptor = mUsbManager.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();
Log.d(TAG, "openAccessory succeeded");
} else {
Log.d(TAG, "openAccessory fail");
}
}
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;
}
}
};
}