package anywheresoftware.b4a.objects;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import android.hardware.Camera;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.ActivityObject;
import anywheresoftware.b4a.BA.Events;
import anywheresoftware.b4a.BA.Permissions;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;
/**
* The camera object allows you to use the device back facing camera to take pictures and show preview images.
*Currently the camera orientation is always landscape. Usually you will want to force the application to also be in landscape mode (Project - Supported Orientations).
*Only one process can access the camera at any time. Therefore it is highly recommended to initialize the camera object in Activity_Resume and release it in Activity_Pause.
*A working example with explanations is available <link>here|http://www.b4x.com/forum/basic4android-getting-started-tutorials/6891-take-pictures-internal-camera.html</link>.
*/
@ActivityObject
@Permissions(values={"android.permission.CAMERA"})
@ShortName("Camera")
@Version(1.10f)
@Events(values={"Ready (Success As Boolean)", "PictureTaken (Data() As Byte)",
"Preview (Data() As Byte)"})
public class CameraW {
private static Camera c;
private SurfaceView sv;
private String eventName;
private BA ba;
private AtomicInteger readyCount = new AtomicInteger();
/**
* Initializes the camera.
*Panel - The preview images will be displayed on the panel.
*EventName - Events subs prefix.
*The Ready event will be raised when the camera has finished opening.
*/
public void Initialize(final BA ba, ViewGroup Panel, String EventName) {
this.ba = ba;
readyCount.set(0);
this.eventName = EventName.toLowerCase(BA.cul);
sv = new SurfaceView(ba.context);
anywheresoftware.b4a.BALayout.LayoutParams lp = new anywheresoftware.b4a.BALayout.LayoutParams(0, 0,
Panel.getLayoutParams().width, Panel.getLayoutParams().height);
Panel.addView(sv, lp);
if (c != null) {
readyCount.set(1);
}
sv.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
sv.getHolder().setFixedSize(Panel.getLayoutParams().width, Panel.getLayoutParams().height);
sv.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (readyCount.addAndGet(1) == 2) {
ba.raiseEvent(null, eventName + "_ready", true);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
if (c == null) {
ba.submitRunnable(new Runnable() {
@Override
public void run() {
try {
c = Camera.open();
if (readyCount.addAndGet(1) == 2) {
ba.raiseEventFromDifferentThread(null, CameraW.this, -1,eventName + "_ready", false, new Object[] {true});
}
if (ba.subExists(eventName + "_preview")) {
c.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data,
Camera camera) {
ba.raiseEvent(null, eventName + "_preview", data);
}
});
}
}
catch (Exception e) {
e.printStackTrace();
Release();
ba.raiseEventFromDifferentThread(null, CameraW.this, -1,eventName + "_ready", false, new Object[] {false});
}
}
}, this, -1);
}
}
/**
* Starts displaying the preview images.
*/
public void StartPreview() throws IOException {
c.setPreviewDisplay(sv.getHolder());
c.startPreview();
}
/**
* Stops displaying the preview images.
*/
public void StopPreview() {
if (c != null)
c.stopPreview();
}
/**
* Releases the camera object and allows other processes to access the camera.
*/
public void Release() {
if (sv != null) {
ViewGroup vg = (ViewGroup) sv.getParent();
vg.removeView(sv);
sv = null;
}
if (c != null) {
c.release();
c = null;
}
}
/**
* Takes a picture. When the picture is ready, the PictureTaken event will be raised.
*You should not call TakePicture while another picture is currently taken.
*The preview images are stopped after calling this method. You can call StartPreview to restart the preview images.
*/
public void TakePicture() {
c.takePicture(null , null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
ba.raiseEvent(null, eventName + "_picturetaken", data);
}
});
}
}