From 71bfafc84af4b820748b12e1a1010b0dfa7bdea6 Mon Sep 17 00:00:00 2001 From: zzy Date: Tue, 16 Apr 2013 17:17:37 -0700 Subject: [PATCH] Added flush() for bluetooth output stream Bug 8498784 Zebra QL420 Plus Bluetooth printer fails on Android 4.2.2 --- .../android/bluetooth/BluetoothOutputStream.java | 11 ++++++++++ core/java/android/bluetooth/BluetoothSocket.java | 12 +++++++++++ core/java/android/net/LocalSocketImpl.java | 20 +++++++++++++++++ core/jni/android_net_LocalSocketImpl.cpp | 25 ++++++++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/core/java/android/bluetooth/BluetoothOutputStream.java b/core/java/android/bluetooth/BluetoothOutputStream.java index 62242a2672ff..117dd47c1ab1 100644 --- a/core/java/android/bluetooth/BluetoothOutputStream.java +++ b/core/java/android/bluetooth/BluetoothOutputStream.java @@ -84,4 +84,15 @@ import java.io.OutputStream; } mSocket.write(b, offset, count); } + /** + * Wait until the data in sending queue is emptied. A polling version + * for flush implementation. Use it to ensure the writing data afterwards will + * be packed in the new RFCOMM frame. + * @throws IOException + * if an i/o error occurs. + * @since Android 4.2.3 + */ + public void flush() throws IOException { + mSocket.flush(); + } } diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java index 8029a1a25ce1..a19341c07da4 100644 --- a/core/java/android/bluetooth/BluetoothSocket.java +++ b/core/java/android/bluetooth/BluetoothSocket.java @@ -192,6 +192,7 @@ public final class BluetoothSocket implements Closeable { if (VDBG) Log.d(TAG, "socket fd passed by stack fds: " + fds); if(fds == null || fds.length != 1) { Log.e(TAG, "socket fd passed from stack failed, fds: " + fds); + as.close(); throw new IOException("bt socket acept failed"); } as.mSocket = new LocalSocket(fds[0]); @@ -407,6 +408,17 @@ public final class BluetoothSocket implements Closeable { if (VDBG) Log.d(TAG, "available: " + mSocketIS); return mSocketIS.available(); } + /** + * Wait until the data in sending queue is emptied. A polling version + * for flush implementation. Used to ensure the writing data afterwards will + * be packed in new RFCOMM frame. + * @throws IOException + * if an i/o error occurs. + */ + /*package*/ void flush() throws IOException { + if (VDBG) Log.d(TAG, "flush: " + mSocketOS); + mSocketOS.flush(); + } /*package*/ int read(byte[] b, int offset, int length) throws IOException { diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java index 6c36a7d62ff3..8e129cb53f60 100644 --- a/core/java/android/net/LocalSocketImpl.java +++ b/core/java/android/net/LocalSocketImpl.java @@ -136,8 +136,28 @@ class LocalSocketImpl write_native(b, myFd); } } + + /** + * Wait until the data in sending queue is emptied. A polling version + * for flush implementation. + * @throws IOException + * if an i/o error occurs. + */ + @Override + public void flush() throws IOException { + FileDescriptor myFd = fd; + if (myFd == null) throw new IOException("socket closed"); + while(pending_native(fd) > 0) { + try { + Thread.sleep(10); + } catch (InterruptedException ie) { + return; + } + } + } } + private native int pending_native(FileDescriptor fd) throws IOException; private native int available_native(FileDescriptor fd) throws IOException; private native void close_native(FileDescriptor fd) throws IOException; private native int read_native(FileDescriptor fd) throws IOException; diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp index 1426b2cd376b..f2b69c671bd4 100644 --- a/core/jni/android_net_LocalSocketImpl.cpp +++ b/core/jni/android_net_LocalSocketImpl.cpp @@ -371,7 +371,31 @@ static void socket_setOption( return; } } +static jint socket_pending (JNIEnv *env, jobject object, + jobject fileDescriptor) +{ + int fd; + + fd = jniGetFDFromFileDescriptor(env, fileDescriptor); + + if (env->ExceptionOccurred() != NULL) { + return (jint)-1; + } + + int pending; + int ret = ioctl(fd, TIOCOUTQ, &pending); + // If this were a non-socket fd, there would be other cases to worry + // about... + + //ALOGD("socket_pending, ioctl ret:%d, pending:%d", ret, pending); + if (ret < 0) { + jniThrowIOException(env, errno); + return (jint) 0; + } + + return (jint)pending; +} static jint socket_available (JNIEnv *env, jobject object, jobject fileDescriptor) { @@ -893,6 +917,7 @@ static JNINativeMethod gMethods[] = { {"accept", "(Ljava/io/FileDescriptor;Landroid/net/LocalSocketImpl;)Ljava/io/FileDescriptor;", (void*)socket_accept}, {"shutdown", "(Ljava/io/FileDescriptor;Z)V", (void*)socket_shutdown}, {"available_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_available}, + {"pending_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_pending}, {"close_native", "(Ljava/io/FileDescriptor;)V", (void*) socket_close}, {"read_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_read}, {"readba_native", "([BIILjava/io/FileDescriptor;)I", (void*) socket_readba}, -- 2.11.0