shithub: drawterm-fdroid

Download patch

ref: 207a95163f5a047e1f8ed8b77f1c4ab2b08edb64
parent: 6dbca8e2f85408be9486a3145f74bb0c3d2e46e1
author: glenda <[email protected]>
date: Thu Apr 14 22:45:58 EDT 2022

devandroid (#N) changes

--- a/gui-android/AndroidManifest.xml
+++ b/gui-android/AndroidManifest.xml
@@ -27,4 +27,6 @@
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.CAMERA"/>
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 </manifest>
--- a/gui-android/cpp/android.c
+++ b/gui-android/cpp/android.c
@@ -57,6 +57,30 @@
 	return 0;
 }
 
+long
+getlocation(char *a, long n)
+{
+	JNIEnv *env;
+	jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
+	if(rs != JNI_OK) {
+		__android_log_print(ANDROID_LOG_WARN, "drawterm", "AttachCurrentThread returned error: %d", rs);
+		return 0;
+	}
+	jclass clazz = (*env)->GetObjectClass(env, mainActivityObj);
+	jmethodID methodID = (*env)->GetMethodID(env, clazz, "getLocation", "()Ljava/lang/String;");
+	jstring str = (*env)->CallObjectMethod(env, mainActivityObj, methodID);
+	char *s = (*env)->GetStringUTFChars(env, str, NULL);
+	long ret = strlen(s);
+	if (ret > (n-1))
+		ret = n-1;
+	memcpy(a, s, ret);
+	a[ret] = '\n';
+	ret++;
+	(*env)->ReleaseStringUTFChars(env, str, s);
+	(*jvm)->DetachCurrentThread(jvm);
+	return ret;
+}
+
 void
 show_notification(char *buf)
 {
--- a/gui-android/cpp/devandroid.c
+++ b/gui-android/cpp/devandroid.c
@@ -4,17 +4,19 @@
 #include	"fns.h"
 #include	"error.h"
 
-#include <android/log.h>
+//#include <android/log.h>
 #include <android/sensor.h>
 
 void show_notification(char *buf);
 void take_picture(int id);
 int num_cameras();
+long getlocation(char *a, long n);
 
 int Ncameras = 0;
 
 uchar *cambuf = nil;
-int camlen;
+int camlen = 0;
+static char camopen = 0;
 
 ASensorManager *sensorManager = NULL;
 
@@ -21,10 +23,12 @@
 enum
 {
 	Qdir		= 0,
-	Qcam		= 1,
-	Qaccel		= 2,
-	Qcompass	= 4,
-	Qnotify		= 6,
+	Qaccel,
+	Qcompass,
+	Qnotify,
+	Qlocation,
+	Ntab,
+	Qcam		= 8,
 };
 
 Dirtab
@@ -31,10 +35,11 @@
 androiddir[] =
 {
 	".",		{Qdir, 0, QTDIR},	0,	DMDIR|0555,
-	"camNNNN.jpg",	{Qcam},			0,	0444,
 	"accel",	{Qaccel},		0,	0444,
 	"compass",	{Qcompass},		0,	0444,
 	"notify",	{Qnotify},		0,	0222,
+	"location",	{Qlocation},		0,	0444,
+	"camNNNN",	{Qcam},			0,	0444,
 };
 
 static void androidinit(void);
@@ -53,42 +58,53 @@
 	return devattach('N', param);
 }
 
-static int
-androidgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp)
+int
+androidgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
 {
 	Qid q;
 
-	if (s == DEVDOTDOT) {
-		devdir(c, d->qid, "#N", 0, eve, 0555, dp);
-		return 1;
+	if(tab == 0)
+		return -1;
+	if(i == DEVDOTDOT){
+		/* nothing */
+	}else if(name){
+//		__android_log_print(ANDROID_LOG_WARN, "drawterm", "androidgen name %s", name);
+		for(i=1; i<Ntab; i++)
+			if(strcmp(tab[i].name, name) == 0)
+				break;
+		if (i == Ntab) {
+			if (strncmp("cam", name, 3) == 0 &&
+			    name[3] >= '0' && name[3] <= '9' &&
+			    strspn(&name[3], "0123456789") == (strlen(name) - 3) &&
+			    (i = atoi(&name[3])) < Ncameras)
+				i += Ntab;
+			else
+				return -1;
+		}
+		if(i > Ntab)
+			tab += Ntab;
+		else
+			tab += i;
+	}else{
+//		__android_log_print(ANDROID_LOG_WARN, "drawterm", "androidgen i %d", i);
+		/* skip over the first element, that for . itself */
+		i++;
+		if(i >= ntab)
+			return -1;
+		if(i >= Ntab)
+			tab += Ntab;
+		else
+			tab += i;
 	}
-	if (s < Ncameras) {
-		d += 1;
-		q = d->qid;
-		q.path |= (s << 16);
-		sprintf(up->genbuf, "cam%d.jpg", s);
-		devdir(c, q, up->genbuf, 0, eve, 0444, dp);
+	if (i >= Ntab) {
+		q = tab->qid;
+		q.path |= ((i - Ntab) << 16);
+		sprintf(up->genbuf, "cam%d", i - Ntab);
+		devdir(c, q, up->genbuf, tab->length, eve, tab->perm, dp);
 		return 1;
 	}
-	if (s == Ncameras) {
-		d += 2;
-		sprintf(up->genbuf, "accel");
-		devdir(c, d->qid, up->genbuf, 0, eve, 0444, dp);
-		return 1;
-	}
-	if (s == (Ncameras+1)) {
-		d += 3;
-		sprintf(up->genbuf, "compass");
-		devdir(c, d->qid, up->genbuf, 0, eve, 0444, dp);
-		return 1;
-	}
-	if (s == (Ncameras+2)) {
-		d += 4;
-		sprintf(up->genbuf, "notify");
-		devdir(c, d->qid, up->genbuf, 0, eve, 0222, dp);
-		return 1;
-	}
-	return -1;
+	devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
+	return 1;
 }
 
 static Walkqid*
@@ -106,17 +122,18 @@
 static Chan*
 androidopen(Chan *c, int omode)
 {
-	p9_uvlong s;
+	int i;
 
-	c = devopen(c, omode, androiddir, nelem(androiddir) + Ncameras - 1, androidgen);
-
 	if (c->qid.path & Qcam) {
-		s = c->qid.path >> 16;
-		take_picture(s);
+		if (camopen != 0) {
+			error(Einuse);
+		} else {
+			camopen = 1;
+			i = c->qid.path >> 16;
+			take_picture(i);
+		}
 	}
-	c->mode = openmode(omode);
-	c->flag |= COPEN;
-	c->offset = 0;
+	c = devopen(c, omode, androiddir, nelem(androiddir) + Ncameras - 1, androidgen);
 
 	return c;
 }
@@ -124,20 +141,51 @@
 static void
 androidclose(Chan *c)
 {
-	if (c->qid.path & Qcam && cambuf != nil) {
+	if (c->qid.path & Qcam && camopen != 0) {
 		free(cambuf);
 		cambuf = nil;
+		camlen = 0;
+		camopen = 0;
 	}
 }
 
+long
+readsensor(char *a, long n, int type) {
+	long l;
+	const ASensor *sensor;
+	ASensorEventQueue *queue = NULL;
+	ASensorEvent data;
+
+	queue = ASensorManager_createEventQueue(sensorManager, ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS), 1, NULL, NULL);
+	if (queue == NULL)
+		return 0;
+	sensor = ASensorManager_getDefaultSensor(sensorManager, type);
+	if (sensor == NULL) {
+		ASensorManager_destroyEventQueue(sensorManager, queue);
+		return 0;
+	}
+	if (ASensorEventQueue_enableSensor(queue, sensor)) {
+		ASensorEventQueue_disableSensor(queue, sensor);
+		ASensorManager_destroyEventQueue(sensorManager, queue);
+		return 0;
+	}
+	l = 0;
+	if (ALooper_pollAll(1000, NULL, NULL, NULL) == 1) {
+		if (ASensorEventQueue_getEvents(queue, &data, 1)) {
+			l = snprint(a, n, "%11f %11f %11f\n", data.vector.x, data.vector.y, data.vector.z);
+		}
+	}
+	ASensorEventQueue_disableSensor(queue, sensor);
+	ASensorManager_destroyEventQueue(sensorManager, queue);
+
+	return l;
+}
+
 static long
 androidread(Chan *c, void *v, long n, vlong off)
 {
 	char *a = v;
 	long l;
-	const ASensor *sensor;
-	ASensorEventQueue *queue = NULL;
-	ASensorEvent data;
 
 	switch((ulong)c->qid.path & 0xF) {
 		default:
@@ -145,9 +193,14 @@
 			return -1;
 
 		case Qcam:
-			while(cambuf == nil)
+			while(camlen == 0)
 				usleep(10 * 1000);
 
+			if(camlen < 0) {
+				error(Eio);
+				return -1;
+			}
+
 			l = camlen - off;
 			if (l > n)
 				l = n;
@@ -157,51 +210,11 @@
 
 			return l;
 		case Qaccel:
-			queue = ASensorManager_createEventQueue(sensorManager, ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS), 1, NULL, NULL);
-			if (queue == NULL)
-				return 0;
-			sensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
-			if (sensor == NULL) {
-				ASensorManager_destroyEventQueue(sensorManager, queue);
-				return 0;
-			}
-			if (ASensorEventQueue_enableSensor(queue, sensor)) {
-				ASensorEventQueue_disableSensor(queue, sensor);
-				ASensorManager_destroyEventQueue(sensorManager, queue);
-				return 0;
-			}
-			l = 0;
-			if (ALooper_pollAll(1000, NULL, NULL, NULL) == 1) {
-				if (ASensorEventQueue_getEvents(queue, &data, 1)) {
-					l = snprint(a, n, "%11f %11f %11f\n", data.vector.x, data.vector.y, data.vector.z);
-				}
-			}
-			ASensorEventQueue_disableSensor(queue, sensor);
-			ASensorManager_destroyEventQueue(sensorManager, queue);
-			return l;
+			return readsensor(a, n, ASENSOR_TYPE_ACCELEROMETER);
 		case Qcompass:
-			queue = ASensorManager_createEventQueue(sensorManager, ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS), 1, NULL, NULL);
-			if (queue == NULL)
-				return 0;
-			sensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_MAGNETIC_FIELD);
-			if (sensor == NULL) {
-				ASensorManager_destroyEventQueue(sensorManager, queue);
-				return 0;
-			}
-			if (ASensorEventQueue_enableSensor(queue, sensor)) {
-				ASensorEventQueue_disableSensor(queue, sensor);
-				ASensorManager_destroyEventQueue(sensorManager, queue);
-				return 0;
-			}
-			l = 0;
-			if (ALooper_pollAll(1000, NULL, NULL, NULL) == 1) {
-				if (ASensorEventQueue_getEvents(queue, &data, 1)) {
-					l = snprint(a, n, "%11f %11f %11f\n", data.vector.x, data.vector.y, data.vector.z);
-				}
-			}
-			ASensorEventQueue_disableSensor(queue, sensor);
-			ASensorManager_destroyEventQueue(sensorManager, queue);
-			return l;
+			return readsensor(a, n, ASENSOR_TYPE_MAGNETIC_FIELD);
+		case Qlocation:
+			return getlocation(a, n);
 		case Qdir:
 			return devdirread(c, a, n, androiddir, nelem(androiddir) + Ncameras - 1, androidgen);
 	}
@@ -248,3 +261,4 @@
 	devremove,
 	devwstat,
 };
+
--- a/gui-android/cpp/native-lib.c
+++ b/gui-android/cpp/native-lib.c
@@ -163,11 +163,15 @@
 	JNIEnv* env,
 	jobject obj,
 	jbyteArray array) {
+    if ((*env)->IsSameObject(env, array, NULL)) {
+        camlen = -1;
+        return;
+    }
     jint len = (*env)->GetArrayLength(env, array);
     jbyte *bytes = (*env)->GetByteArrayElements(env, array, NULL);
-    camlen = len;
-    cambuf = malloc(camlen);
-    memcpy(cambuf, bytes, camlen);
+    cambuf = malloc(len);
+    memcpy(cambuf, bytes, len);
     (*env)->ReleaseByteArrayElements(env, array, bytes, 0);
+    camlen = len;
 }
 
--- a/gui-android/java/org/echoline/drawterm/MainActivity.java
+++ b/gui-android/java/org/echoline/drawterm/MainActivity.java
@@ -15,6 +15,8 @@
 
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.SparseIntArray;
+import android.util.Size;
 import android.view.Display;
 import android.view.MotionEvent;
 import android.view.View;
@@ -34,17 +36,22 @@
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.hardware.camera2.CameraManager;
-import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.Image;
 import android.media.ImageReader;
 import android.graphics.ImageFormat;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationListener;
 
 import java.io.File;
 import java.util.Map;
@@ -52,6 +59,8 @@
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
 
 public class MainActivity extends Activity {
 	private Map<String, ?> map;
@@ -59,13 +68,80 @@
 	private boolean dtrunning = false;
 	private DrawTermThread dthread;
 	private int notificationId;
-	private CameraDevice cameraDevice = null;
 	private byte []jpegBytes;
+	private String location;
 
 	static {
 		System.loadLibrary("drawterm");
 	}
 
+	private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
+
+	static {
+		ORIENTATIONS.append(Surface.ROTATION_0, 0);
+		ORIENTATIONS.append(Surface.ROTATION_90, 90);
+		ORIENTATIONS.append(Surface.ROTATION_180, 180);
+		ORIENTATIONS.append(Surface.ROTATION_270, 270);
+	}
+
+	static class CompareSizesByArea implements Comparator<Size> {
+		@Override
+		public int compare(Size lhs, Size rhs) {
+			return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
+		}
+	}
+
+
+	private static boolean contains(int[] modes, int mode) {
+		if (modes == null) {
+			return false;
+		}
+		for (int i : modes) {
+			if (i == mode) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public String getLocation() {
+		LocationManager locationManager = ((LocationManager)getSystemService(Context.LOCATION_SERVICE));
+
+		location = "";
+
+		HandlerThread mBackgroundThread = new HandlerThread("Location Background");
+		mBackgroundThread.start();
+
+		locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, new LocationListener() {
+			@Override
+			public void onLocationChanged(Location l) {
+				location = l.getLatitude() + "\t" + l.getLongitude() + "\t" + l.getAltitude();
+				mBackgroundThread.quitSafely();
+			}
+
+			@Override
+			public void onProviderDisabled(String p) {
+				mBackgroundThread.quitSafely();
+			}
+
+			@Override
+			public void onProviderEnabled(String p) {
+			}
+
+			@Override
+			public void onStatusChanged(String p, int i, Bundle b) {
+			}
+		}, mBackgroundThread.getLooper());
+
+		try {
+			mBackgroundThread.join();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+
+		return location;
+	}
+
 	public void showNotification(String text) {
 		Notification.Builder builder = new Notification.Builder(this)
 			.setDefaults(Notification.DEFAULT_SOUND)
@@ -81,86 +157,132 @@
 	public int numCameras() {
 		try {
 			return ((CameraManager)getSystemService(Context.CAMERA_SERVICE)).getCameraIdList().length;
-		} catch (CameraAccessException e) {
-			Log.w("drawterm", e.toString());
+		} catch (Exception e) {
+			e.printStackTrace();
 			return 0;
 		}
 	}
 
+	private static int sensorToDeviceRotation(CameraCharacteristics c, int deviceOrientation) {
+		int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);
+
+		deviceOrientation = ORIENTATIONS.get(deviceOrientation);
+
+		if (c.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) {
+			deviceOrientation = -deviceOrientation;
+		}
+
+		return (sensorOrientation - deviceOrientation + 360) % 360;
+	}
+
 	public void takePicture(int id) {
 		try {
+			jpegBytes = null;
 			HandlerThread mBackgroundThread = new HandlerThread("Camera Background");
 			mBackgroundThread.start();
 			Handler mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
 			CameraManager manager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
 			String []cameraIdList = manager.getCameraIdList();
+			CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraIdList[id]);
+			StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+			Size size = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new CompareSizesByArea());
+			ImageReader reader = ImageReader.newInstance(size.getWidth(), size.getHeight(), ImageFormat.JPEG, 1);
 			manager.openCamera(cameraIdList[id], new CameraDevice.StateCallback() {
 				public void onOpened(CameraDevice device) {
-					cameraDevice = device;
-				}
-				public void onDisconnected(CameraDevice device) {
-					if (cameraDevice != null)
-						cameraDevice.close();
-					cameraDevice = null;
-				}
-				public void onError(CameraDevice device, int error) {
-					if (cameraDevice != null)
-						cameraDevice.close();
-					cameraDevice = null;
-				}
-			}, mBackgroundHandler);
-			ImageReader reader = ImageReader.newInstance(640, 480, ImageFormat.JPEG, 1);
-			CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
-			captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
-			captureBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO);
-			captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON);
-			captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getWindowManager().getDefaultDisplay().getRotation());
-			captureBuilder.addTarget(reader.getSurface());
-			reader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
-				public void onImageAvailable(ImageReader reader) {
-					Image image = null;
 					try {
-						image = reader.acquireLatestImage();
-						ByteBuffer buffer = image.getPlanes()[0].getBuffer();
-						jpegBytes = new byte[buffer.capacity()];
-						buffer.get(jpegBytes);
-					} catch (Exception e) {
-						Log.w("drawterm", e.toString());
-					} finally {
-						if (image != null) {
-							image.close();
+						CaptureRequest.Builder captureBuilder = device.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
+						captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
+						Float minFocusDist = characteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
+						if (!(minFocusDist == null || minFocusDist == 0)) {
+							if (contains(characteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES), CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE))
+								captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+							else 
+								captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
 						}
-					}
-				}
-			}, mBackgroundHandler);
-			List<Surface> outputSurfaces = new ArrayList<Surface>(1);
-			outputSurfaces.add(reader.getSurface());
-			cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
-				public void onConfigured(CameraCaptureSession session) {
-					try {
-						List<CaptureRequest> captureRequests = new ArrayList<CaptureRequest>(10);
-						for (int i = 0; i < 10; i++)
-							captureRequests.add(captureBuilder.build());
-						session.captureBurst(captureRequests, new CameraCaptureSession.CaptureCallback() {
-							public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, long frameNumber) {
+						if (contains(characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES), CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH))
+							captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
+						else
+							captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
+						if (contains(characteristics.get(CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES), CaptureRequest.CONTROL_AWB_MODE_AUTO))
+							captureBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO);
+						captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, sensorToDeviceRotation(characteristics, getWindowManager().getDefaultDisplay().getRotation()));
+						captureBuilder.addTarget(reader.getSurface());
+						reader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
+							public void onImageAvailable(ImageReader reader) {
+								Image image = null;
 								try {
-									sendPicture(jpegBytes);
-									mBackgroundThread.quitSafely();
-									mBackgroundThread.join();
+									image = reader.acquireLatestImage();
+									ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+									jpegBytes = new byte[buffer.capacity()];
+									buffer.get(jpegBytes);
 								} catch (Exception e) {
-									Log.w("drawterm", e.toString());
+									e.printStackTrace();
+								} finally {
+									if (image != null) {
+										image.close();
+									}
 								}
 							}
 						}, mBackgroundHandler);
-					} catch (CameraAccessException e) {
+						List<Surface> outputSurfaces = new ArrayList<Surface>(1);
+						outputSurfaces.add(reader.getSurface());
+						device.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
+							public void onConfigured(CameraCaptureSession session) {
+								try {
+									List<CaptureRequest> captureRequests = new ArrayList<CaptureRequest>(10);
+										for (int i = 0; i < 10; i++)
+									captureRequests.add(captureBuilder.build());
+									session.captureBurst(captureRequests, new CameraCaptureSession.CaptureCallback() {
+										public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, long frameNumber) {
+											Log.w("drawterm", "CaptureSession capture sequence completed");
+											sendPicture(jpegBytes);
+											device.close();
+										}
+									}, mBackgroundHandler);
+								} catch (Exception e) {
+									Log.w("drawterm", "CaptureSession capture failed");
+									e.printStackTrace();
+									sendPicture(jpegBytes);
+								}
+							}
+							public void onConfigureFailed(CameraCaptureSession session) {
+								Log.w("drawterm", "createCaptureSession configure failed");
+								sendPicture(jpegBytes);
+							}
+						}, mBackgroundHandler);
+					} catch (Exception e) {
 						e.printStackTrace();
+						sendPicture(jpegBytes);
 					}
+				}	
+				public void onDisconnected(CameraDevice device) {
+					try {
+						device.close();
+					} catch (Exception e) {
+						e.printStackTrace();
+					}
+					Log.e("drawterm", "openCamera onDisconnected");
 				}
-				public void onConfigureFailed(CameraCaptureSession session) {
+				public void onError(CameraDevice device, int error) {
+					try {
+						device.close();
+					} catch (Exception e) {
+						e.printStackTrace();
+					}
+					Log.e("drawterm", "openCamera onError " + error);
 				}
+				public void onClosed(CameraDevice device) {
+					try {
+						mBackgroundThread.quitSafely();
+						mBackgroundThread.join();
+					} catch (Exception e) {
+						e.printStackTrace();
+					}
+				}
 			}, mBackgroundHandler);
 		} catch (Exception e) {
 			e.printStackTrace();
+			sendPicture(jpegBytes);
 		}
 	}