I have an application that uses a barcode scanner to pass data to the next activity. I have managed to pass the data over to the next activity but when I return to the barcode scanner the app crashes. Im presuming it is because it is trying to open the Surfaceview again.
How would I continue with the surfaceview when going back to the barcode scanner
****Barcode Scanner ****
public class BarcodeScannerNew extends AppCompatActivity {
private Camera mCamera;
private CameraPreview mPreview;
private Handler autoFocusHandler;
private Button scanButton;
private ImageScanner scanner;
private boolean barcodeScanned = false;
private boolean previewing = true;
static {
System.loadLibrary("iconv");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.new_barcode_window);
initControls();
}
private void initControls() {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
autoFocusHandler = new Handler();
mCamera = getCameraInstance();
// Instance barcode scanner
scanner = new ImageScanner();
scanner.setConfig(0, Config.X_DENSITY, 10);
scanner.setConfig(0, Config.Y_DENSITY, 10);
mPreview = new CameraPreview(BarcodeScannerNew.this, mCamera, previewCb,
autoFocusCB);
FrameLayout preview = (FrameLayout) findViewById(R.id.cameraPreview);
preview.addView(mPreview);
scanButton = (Button) findViewById(R.id.ScanButton);
scanButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (barcodeScanned) {
barcodeScanned = false;
mCamera.setPreviewCallback(previewCb);
mCamera.startPreview();
previewing = true;
mCamera.autoFocus(autoFocusCB);
}
}
});
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
releaseCamera();
}
return super.onKeyDown(keyCode, event);
}
/**
* A safe way to get an instance of the Camera object.
*/
public static Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open();
} catch (Exception e) {
}
return c;
}
private void releaseCamera() {
if (mCamera != null) {
previewing = false;
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
private Runnable doAutoFocus = new Runnable() {
public void run() {
if (previewing)
mCamera.autoFocus(autoFocusCB);
}
};
Camera.PreviewCallback previewCb = new Camera.PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
Image barcode = new Image(size.width, size.height, "Y800");
barcode.setData(data);
int result = scanner.scanImage(barcode);
if (result != 0) {
previewing = false;
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
TextView labelScanResult = (TextView)findViewById(R.id.labelScanResult);
SymbolSet syms = scanner.getResults();
for (Symbol sym : syms) {
Log.i("<<<<<<Asset Code>>>>> ",
"<<<<Bar Code>>> " + sym.getData());
String scanResult = sym.getData().trim();
// shows dialog showAlertDialog(scanResult);
labelScanResult.setText(scanResult);
/* Toast.makeText(BarcodeScanner.this, scanResult,
Toast.LENGTH_SHORT).show();*/
Intent i = new Intent(BarcodeScannerNew.this, BarcodeScanner.class);
i.putExtra("" , labelScanResult.getText().toString());
startActivity(i);
finish();
barcodeScanned = true;
break;
}
}
}
};
// Mimic continuous auto-focusing
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
autoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
private void showAlertDialog(String message) {
new AlertDialog.Builder(this)
.setCancelable(false)
.setMessage(message)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
})
.show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_home, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
if (id == R.id.homebutton){
startActivity(new Intent(this,MainActivity.class));
}
return super.onOptionsItemSelected(item);
}
}
Camera activity
package com.example.dsouchon.myapplication;
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private Camera.PreviewCallback previewCallback;
private Camera.AutoFocusCallback autoFocusCallback;
public CameraPreview(Context context, Camera camera,
Camera.PreviewCallback previewCb,
Camera.AutoFocusCallback autoFocusCb) {
super(context);
mCamera = camera;
previewCallback = previewCb;
autoFocusCallback = autoFocusCb;
/*
* Set camera to continuous focus if supported, otherwise use
* software auto-focus. Only works for API level >=9.
*/
/*
Camera.Parameters parameters = camera.getParameters();
for (String f : parameters.getSupportedFocusModes()) {
if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
mCamera.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
autoFocusCallback = null;
break;
}
}
*/
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
}
catch (IOException e) {
Log.d("DBG", "Error setting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
/*
* If your preview can change or rotate, take care of those events here.
* Make sure to stop the preview before resizing or reformatting it.
*/
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
try {
// Hard code camera surface rotation 90 degs to match Activity view in portrait
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.setPreviewCallback(previewCallback);
mCamera.startPreview();
mCamera.autoFocus(autoFocusCallback);
} catch (Exception e) {
Log.d("DBG", "Error starting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
Logs
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.hardware.Camera.setPreviewDisplay(android.view.SurfaceHolder)' on a null object reference
at com.example.dsouchon.myapplication.CameraPreview.surfaceCreated(CameraPreview.java:56)
at android.view.SurfaceView.updateWindow(SurfaceView.java:607)
at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:184)
at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:921)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2164)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1191)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6642)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:777)
at android.view.Choreographer.doCallbacks(Choreographer.java:590)
at android.view.Choreographer.doFrame(Choreographer.java:560)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:763)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5951)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
Related
I need to show camera preview in live wallpaper.
I've already made for android < M versions. But can't understand how it working with new API. Oldest Camera is deprecated now
In google example they put it in xml and in TextureView but how I can change that for my needs, I can't understand.
Anyway Thanks!
Google example
https://github.com/googlesamples/android-Camera2Basic
Below my code.
Start wallpaper
Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, new ComponentName(this, TransparentWallpaperService.class));
startActivity(intent);
TransparentWallpaperService
public class TransparentWallpaperService extends WallpaperService {
#Override
public Engine onCreateEngine() {
return new GlowEngine();
}
private class GlowEngine extends Engine {
private final Handler handler = new Handler();
private final Runnable viewRunner = new Runnable() {
#Override
public void run() {
drawView();
}
};
private boolean visible = true;
private CameraView view;
public GlowEngine() {
super();
view = new CameraView(getBaseContext(), getSurfaceHolder());
handler.post(viewRunner);
}
#Override
public void onVisibilityChanged(boolean visible) {
this.visible = visible;
if (visible) {
handler.post(viewRunner);
}
else {
handler.removeCallbacks(viewRunner);
}
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
this.visible = false;
handler.removeCallbacks(viewRunner);
}
private void drawView() {
view.surfaceChanged(getSurfaceHolder(), OPAQUE, view.getWidth(), view.getHeight());
handler.removeCallbacks(viewRunner);
if (visible) {
handler.postDelayed(viewRunner, 4000);
}
}
}
}
CameraView class
public class CameraView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder;
private Camera camera;
public CameraView(Context context) {
super(context);
camera = getCameraInstance();
}
public CameraView(Context context, SurfaceHolder holder) {
this(context);
this.holder = holder;
holder.addCallback(this);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
if(camera == null) {
camera = getCameraInstance();
}
if(camera != null) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
}
catch (IOException e) {
Log.e("CameraView", "Error setting camera preview: " + e.getMessage());
}
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
boolean portrait = true;
if (width > 0 && height >0 && width < height){
portrait =true;
} else if (width > 0 && height >0 && width > height){
portrait = false;
}
Camera.Parameters parameters;
if (camera == null) {
camera = getCameraInstance();
}
if (camera != null){
parameters = camera.getParameters();
Camera.Size size = parameters.getPictureSize();
size = parameters.getPreviewSize();
parameters.setPreviewSize(size.width, size.height);
if (portrait) {
camera.setDisplayOrientation(90);
} else {
camera.setDisplayOrientation(180);
}
try {
camera.setParameters(parameters);
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if(camera != null) {
try {
camera.stopPreview();
camera.release();
}
catch (Exception e) {
Log.e("CameraView", "Error stopping camera preview: " + e.getMessage());
}
}
}
private Camera getCameraInstance() {
Context context = getContext();
Camera camera = null;
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
try {
camera = Camera.open();
}
catch (Exception e) {
Log.e("CameraView", "Error getting camera instance: " + e.getMessage());
}
}
else {
Log.i("CameraView", "No camera found!");
}
return camera;
}
}
You can just keep using the old API; it's fully functional even on new devices.
Otherwise, you can just replace the TextureView with a SurfaceView easily enough; instead of creating a Surface from TextureView's SurfaceTexture, get a Surface from SurfaceView's SurfaceHolder in surfaceChanged.
I understand how to capture an image using intents and launching the camera app using intents, however I would like to know how to do so in the following steps:
display surfaceview showing preview of camera to user
when user presses capture, display captured image on screen to user and hide surfaceview with camera preview (exact same behaviour as snapchat).
NP - I do not want the camera app to be launched at anytime during this process, I want it all to be done within my own app. The problem with my current code is that it launches the camera app when the capture button is pressed. Also, it does not display the taken photo properly, a white screen is shown instead. I currently have this code created:
ANDROID ACTIVITY:
public class CameraScreen extends Activity {
private Camera mCamera = null;
private SessionManager session;
private String rand_img;
private ImageView preview_pic;
private CameraPreview mCameraView = null;
static final int CAM_REQUEST = 1;
private RandomString randomString = new RandomString(10);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_screen);
session = new SessionManager(getApplicationContext());
try{
mCamera = Camera.open();//you can use open(int) to use different cameras
} catch (Exception e){
Log.d("ERROR", "Failed to get camera: " + e.getMessage());
}
if(mCamera != null) {
mCameraView = new CameraPreview(this, mCamera);//create a SurfaceView to show camera data
FrameLayout camera_view = (FrameLayout)findViewById(R.id.camera_view);
camera_view.addView(mCameraView);//add the SurfaceView to the layout
}
//btn to close the application
Button imgClose = (Button)findViewById(R.id.imgClose);
imgClose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
System.exit(0);
}
});
//btn to logout
Button logout = (Button)findViewById(R.id.imgOpen);
logout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
session.logOut();
Intent a = new Intent(CameraScreen.this, MainActivity.class);
startActivity(a);
finish();
}
});
//CAPTURE BUTTON
Button snap = (Button) findViewById(R.id.snap);
snap.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent capture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
capture.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getFile()));
startActivityForResult(capture,CAM_REQUEST);
}
});
}
#Override
protected void onPause() {
super.onPause();
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCameraView.getHolder().removeCallback(mCameraView);
mCamera.release();
}
}
#Override
public void onResume() {
super.onResume();
// Get the Camera instance as the activity achieves full user focus
if (mCamera == null) {
initializeCamera(); // Local method to handle camera initialization
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
String path = "sdcard/city_life_pic/" + rand_img;
preview_pic = (ImageView) findViewById(R.id.picturedisplay);
FrameLayout camera_view = (FrameLayout)findViewById(R.id.camera_view);
camera_view.setVisibility(View.GONE);
preview_pic.setVisibility(View.VISIBLE);
preview_pic.setImageDrawable(Drawable.createFromPath(path));
}
protected void initializeCamera(){
// Get an instance of Camera Object
try{
mCamera = Camera.open();//you can use open(int) to use different cameras
} catch (Exception e){
Log.d("ERROR", "Failed to get camera: " + e.getMessage());
}
if(mCamera != null) {
mCameraView = new CameraPreview(this, mCamera);//create a SurfaceView to show camera data
FrameLayout camera_view = (FrameLayout)findViewById(R.id.camera_view);
camera_view.addView(mCameraView);//add the SurfaceView to the layout
}
}
private File getFile() {
File folder = new File("sdcard/city_life_pic");
if (!folder.exists()) {
folder.mkdir();
}
rand_img = randomString.nextString() + ".jpg";
File image = new File(folder,rand_img);
return image;
}
}
CAMERA CLASS:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera){
super(context);
mCamera = camera;
mCamera.setDisplayOrientation(90);
//get the holder and set this class as the callback, so we can get camera data here
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);;
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try{
//when the surface is created, we can set the camera to draw images in this surfaceholder
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (IOException e) {
Log.d("ERROR", "Camera error on surfaceCreated " + e.getMessage());
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
//before changing the application orientation, you need to stop the preview, rotate and then start it again
if(mHolder.getSurface() == null)//check if the surface is ready to receive camera data
return;
try{
mCamera.stopPreview();
} catch (Exception e){
//this will happen when you are trying the camera if it's not running
}
//now, recreate the camera preview
try{
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (IOException e) {
Log.d("ERROR", "Camera error on surfaceChanged " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//our app has only one screen, so we'll destroy the camera in the surface
//if you are unsing with more screens, please move this code your activity
mCamera.stopPreview();
mCamera.release();
}
}
You are opening the device's camera app by using this code
Intent a = new Intent(CameraScreen.this, MainActivity.class);
startActivity(a);
finish();
Instead, to take a picture using your custom camera, use Camera#takePicture method instead
That would make your code
snap.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCamera.takePicture(....) //set parameters based on what you need
}
});
So my Manifest.xml is correct:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus"/>
<application>
...
I also release the camera in the onPause and onDestroy functions, using this function:
private void releaseCamera() {
// stop and release camera
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
//mPreview instance of CameraPreview (referenced below)
if (mPreview != null) {
mPreview.setCamera(null);
}
}
I call mCamera = Camera.open(); only once, during on onResume.
Even though I do everything exactly as specified by every example I have found on Stack Overflow and other sources, Camera.open() would occasionally fail.
Some use cases:
Open Camera Activity with WiFi enabled (Camera Works)
Open Camera Activity with no network connection (Camera Fails) //Bizarre
On catching RuntimeException, then calling mCamera.takePicture(), activity crashes and reloads. (Camera Works)
So I am completely stumped... Any ideas would be greatly appreciated :D
As requested, find the relevant code below:
CameraPreiview
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
// create the surface and start camera preview
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}
} catch (IOException e) {
Log.d(VIEW_LOG_TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void refreshCamera(Camera camera) {
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
setCamera(camera);
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
refreshCamera(mCamera);
}
public void setCamera(Camera camera) {
//method to set a camera instance
mCamera = camera;
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
}
}
}
SampleActivity
public class CameraActivity extends Activity {
private static final String TAG = "CameraActivity";
private Camera mCamera;
private CameraPreview mPreview;
private Camera.PictureCallback mPicture;
private ImageButton capture;
private Context myContext;
private LinearLayout cameraPreview;
// Required to remove the camera if onPause did not
#Override
public void onDestroy() {
releaseCamera();
super.onDestroy();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_test);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
myContext = this;
initialize();
}
//Code to find the id for the traditional back facing camera
private int findBackFacingCamera() {
int cameraId = -1;
//Search for the back facing camera
//get the number of cameras
int numberOfCameras = Camera.getNumberOfCameras();
//for every camera check
for (int i = 0; i < numberOfCameras; i++) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
cameraId = i;
cameraFront = false;
break;
}
}
return cameraId;
}
#Override
public void onResume() {
super.onResume();
//If there is no camera on the device, inform the user.
if (!hasCamera(myContext)) {
Toast toast = Toast.makeText(myContext, "Sorry, your phone does not have a camera!", Toast.LENGTH_LONG);
toast.show();
}
//release the camera if it's in use.
releaseCamera();
if (mCamera == null) {
//if the back facing camera does not exist
if (findBackFacingCamera() < 0) {
Toast.makeText(this, "No back facing camera found.", Toast.LENGTH_LONG).show();
} else {
try {
//Open the back facing camera, note that Camera.open() gives the same error.
mCamera = Camera.open(findBackFacingCamera());
mCamera.setDisplayOrientation(90); //Show in Portrait
mPicture = getPictureCallback();
mPreview.refreshCamera(mCamera);
} catch (RuntimeException e) {
e.printStackTrace();
Toast.makeText(this, "Could not connect to camera.", Toast.LENGTH_LONG).show();
}
}
}
}
public void initialize() {
cameraPreview = (LinearLayout) findViewById(R.id.camera_preview);
mPreview = new CameraPreview(myContext, mCamera);
cameraPreview.addView(mPreview);
capture = (ImageButton) findViewById(R.id.button_capture);
capture.setOnClickListener(captureListener);
}
#Override
protected void onPause() {
super.onPause();
//when on Pause, release camera in order to be used from other applications
releaseCamera();
}
private void captureComplete() {
//...
}
private Camera.PictureCallback getPictureCallback() {
Camera.PictureCallback picture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
//make a new picture file
mFile = ImageUtility.getOutputMediaFile(ImageUtility.MEDIA_TYPE_IMAGE);
Log.i(TAG, (mFile == null) + ": ");
if (mFile == null) {
return;
}
mPreview.refreshCamera(mCamera);
mBackgroundHandler.post(new ImageUtility.ImageSaver(getApplicationContext(), data, mFile, new Callable() {
#Override
public Object call() throws Exception {
captureComplete();
return null;
}
}));
}
};
return picture;
}
View.OnClickListener captureListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mCamera != null) {
mCamera.autoFocus(new Camera.AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
mPicture = getPictureCallback();
mPreview.refreshCamera(camera);
camera.takePicture(null, null, mPicture);
}
});
} else {
throw new NullPointerException();
}
}
};
private void releaseCamera() {
// stop and release camera
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
if (mPreview != null) {
mPreview.setCamera(null);
}
}
}
Some changes you can do, since i had also been working on Camera api since 3 months..
In your CameraPreview Constructor, add this line
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) // add this
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
In your surfaceDestroyed() method in CameraPreview you should remove the callback right after releasing camera resources:
this.getHolder().removeCallback(this);
Besides changing the above I couldn't figure much out of your CameraActivity since you've used AutoFocus and other features.... I used FrameLayout as the container to run the preview in.
I have a Glass application where I am trying to use a Live Card to start a Camera Preview activity from the menu options. The application seems to freeze when I move away from the Live Card (say, to the weather) and back, and then try to bring up the camera through the menu options. Sorry for all of the code, here are the following files:
Service.java
. . .
#Override
public IBinder onBind(Intent intent) { return mBinder; }
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mLiveCard == null) {
mLiveCard = new LiveCard(this, LIVE_CARD_TAG);
mRemoteViews = new RemoteViews(getPackageName(), R.layout.service_layout);
mLiveCard.setViews(mRemoteViews);
// Display the options menu when the live card is tapped.
Intent menuIntent = new Intent(this, MenuActivity.class);
menuIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TASK);
mLiveCard.setAction(PendingIntent.getActivity(this, 0, menuIntent, 0));
mLiveCard.attach(this);
mLiveCard.publish(PublishMode.REVEAL);
} else {
mLiveCard.navigate();
}
return START_STICKY;
}
#Override
public void onDestroy() {
if (mLiveCard != null && mLiveCard.isPublished()) {
mLiveCard.unpublish();
mLiveCard = null;
}
super.onDestroy();
}
}
MenuActivity.java
public class MenuActivity extends Activity {
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
// Open the options menu right away.
openOptionsMenu();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.layout, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_stop:
// Stop the service which will unpublish the live card.
stopService(new Intent(MenuActivity.this, Service.class));
return true;
case R.id.action_camera:
startActivity(new Intent(MenuActivity.this, Camera.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onOptionsMenuClosed(Menu menu) { finish(); }
}
Camera.java
public class Camera extends Activity {
private SurfaceView mPreview = null;
private SurfaceHolder mPreviewHolder = null;
private Camera mCamera = null;
private boolean inPreview = false;
private boolean cameraConfigured = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera);
mPreview = (SurfaceView) findViewById(R.id.camera_preview);
mPreviewHolder = mPreview.getHolder();
mPreviewHolder.addCallback(surfaceCallback);
}
#Override
public void onResume() {
super.onResume();
mCamera = Camera.open();
startPreview();
}
#Override
public void onPause() {
super.onPause();
if (inPreview) {
mCamera.stopPreview();
}
mCamera.release();
mCamera = null;
inPreview = false;
}
private Camera.Size getBestPreviewSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return (result);
}
private void initPreview(int width, int height) {
if (mCamera != null && mPreviewHolder.getSurface() != null) {
try {
mCamera.setPreviewDisplay(mPreviewHolder);
} catch (Throwable t) {
Log.e("PreviewDemo-surfaceCallback",
"Exception in setPreviewDisplay()", t);
}
if (!cameraConfigured) {
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size size = getBestPreviewSize(width, height,
parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
mCamera.setParameters(parameters);
cameraConfigured = true;
}
}
}
}
private void startPreview() {
if (cameraConfigured && mCamera != null) {
mCamera.startPreview();
inPreview = true;
}
}
I can't seem to figure out why the camera preview works initially but doesn't work when navigating away. I feel like there is something simple that I am just missing here. Any help would be greatly appreciated!
I'm not sure if this would fix your problem, but I would start and stop the camera this way:
private Camera getCameraInstance() {
Camera mCamera = null;
try {
/* attempt to get a Camera instance */
mCamera = Camera.open();
} catch (Exception e) {
/* Camera is not available (in use or does not exist) */
Log.e(TAG, "Error getting camera: " + e.getMessage());
// process null error here
// finish();
}
/* returns null if camera is unavailable */
return mCamera;
}
#Override
public void onResume() {
super.onResume();
if (mCamera == null) {
mCamera = getCameraInstance();
if (mCamera != null) {
startPreview();
} else {
// process null error here
}
}
}
#Override
public void onPause() {
super.onPause();
if (mCamera != null) {
/* stop preview */
if (inPreview) {
try {
mCamera.stopPreview();
} catch (Exception e) {
/* ignore: tried to stop a non-existent preview */
}
}
/* release the camera */
mCamera.release();
mCamera = null;
inPreview = false;
}
}
I would also check if mCamera or getSurface is null in initPreview.
private void initPreview(int width, int height) {
if (mCamera != null && mPreviewHolder.getSurface() != null) {
try {
mCamera.setPreviewDisplay(mPreviewHolder);
} catch (Throwable t) {
Log.e("PreviewDemo-surfaceCallback",
"Exception in setPreviewDisplay()", t);
}
if (!cameraConfigured) {
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size size = getBestPreviewSize(width, height,
parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
mCamera.setParameters(parameters);
cameraConfigured = true;
}
}
} else {
Log.e(TAG, "Camera or getSurface is null");
}
}
I am trying to create an flash light application which contains strobe function. I have successfully achieved flash light on/off effect but I am running into trouble with strobe effect. Whenever I try to create the strobe effect the application crashes. If I remove that, it works fine.
I have one activity with a seekbar at the top and the on/off switch at the center. What I want to achieve is that if the user clicks on/off button the flash light should toggle on/off if the seekbar at the top is at 0. If the user increase the value in seekbar the flash light should start to strobe accordingly and if the user move the value back to 0 flashlight should remain constant. Please help me fix the error.
LOG CAT
07-23 16:54:12.610: W/dalvikvm(21210): threadid=11: thread exiting with uncaught exception (group=0x40c15a68)
07-23 16:54:12.610: E/AndroidRuntime(21210): FATAL EXCEPTION: Thread-2373
07-23 16:54:12.610: E/AndroidRuntime(21210): java.lang.RuntimeException: Fail to connect to camera service
07-23 16:54:12.610: E/AndroidRuntime(21210): at android.hardware.Camera.native_setup(Native Method)
07-23 16:54:12.610: E/AndroidRuntime(21210): at android.hardware.Camera.<init>(Camera.java:365)
07-23 16:54:12.610: E/AndroidRuntime(21210): at android.hardware.Camera.open(Camera.java:340)
07-23 16:54:12.610: E/AndroidRuntime(21210): at com.shyam.flashlight.StrobeController.run(StrobeController.java:29)
07-23 16:54:12.610: E/AndroidRuntime(21210): at java.lang.Thread.run(Thread.java:856)
FlashLight.java
public class FlashLight extends Activity {
ImageButton btnSwitch;
private Camera camera;
private boolean isFlashOn;
private boolean hasFlash;
Parameters params;
MediaPlayer mp;
StrobeController runner;
Thread bw;
#SuppressWarnings("deprecation")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_flash_light);
btnSwitch = (ImageButton) findViewById(R.id.btnSwitch);
runner = StrobeController.getInstance();
bw = new Thread(runner);
bw.start();
hasFlash = getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (!hasFlash) {
AlertDialog alert = new AlertDialog.Builder(FlashLight.this).create();
alert.setTitle("Error");
alert.setMessage("Sorry, your device doesn't support flash light!");
alert.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
alert.show();
return;
}
getCamera();
toggleButtonImage();
btnSwitch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/*if (isFlashOn) {
turnOffFlash();
} else {
turnOnFlash();
}*/
if (isFlashOn) {
bw = new Thread(runner);
bw.start();
isFlashOn = false;
} else {
isFlashOn = true;
runner.requestStop = true;
}
}
});
final SeekBar skbar = (SeekBar) findViewById(R.id.volume_bar);
skbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) { }
#Override
public void onStartTrackingTouch(SeekBar seekBar) { }
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
runner.delay = 101 - progress;
runner.delayoff = 101 - progress;
}
});
}
private void getCamera() {
if (camera == null) {
try {
camera = Camera.open();
params = camera.getParameters();
} catch (RuntimeException e) {
Log.e("Camera Error. Failed to Open. Error: ", e.getMessage());
}
}
}
private void turnOnFlash() {
if (!isFlashOn) {
if (camera == null || params == null) {
return;
}
playSound();
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
isFlashOn = true;
toggleButtonImage();
}
}
private void turnOffFlash() {
if (isFlashOn) {
if (camera == null || params == null) {
return;
}
playSound();
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
isFlashOn = false;
toggleButtonImage();
}
}
private void playSound() {
if (isFlashOn) {
mp = MediaPlayer.create(FlashLight.this, R.raw.light_switch_off);
} else {
mp = MediaPlayer.create(FlashLight.this, R.raw.light_switch_on);
}
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
mp.start();
}
private void toggleButtonImage() {
if (isFlashOn) {
btnSwitch.setImageResource(R.drawable.btn_switch_on);
} else {
btnSwitch.setImageResource(R.drawable.btn_switch_off);
}
}
#Override
public void onBackPressed() {
super.onBackPressed();
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
isFlashOn = false;
if (camera != null) {
camera.release();
camera = null;
}
Log.d("Camera", "Back Pressed");
}
}
StrobeController.java
public class StrobeController implements Runnable {
protected StrobeController() { }
public static StrobeController getInstance() {
return (instance == null ? instance = new StrobeController() : instance);
}
private static StrobeController instance;
public volatile boolean requestStop = false;
public volatile boolean isRunning = false;
public volatile int delay = 10;
public volatile int delayoff = 500;
public volatile String errorMessage = "";
#Override
public void run() {
if (isRunning)
return;
requestStop = false;
isRunning = true;
Camera cam = Camera.open();
Parameters pon = cam.getParameters(), poff = cam.getParameters();
pon.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
poff.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
while (!requestStop) {
try {
cam.setParameters(pon);
Thread.sleep(delay);
cam.setParameters(poff);
Thread.sleep(delayoff);
} catch (InterruptedException ex) {
} catch (RuntimeException ex) {
requestStop = true;
errorMessage = "Error setting camera flash status. Your device may be unsupported.";
}
}
cam.release();
isRunning = false;
requestStop = false;
}
}
I notice the exception is being thrown at line 29:
at com.shyam.flashlight.StrobeController.run(StrobeController.java:29)
Is line 29 Camera cam = Camera.open();?
You have the correct permissions as described here?
Also, are you trying to open a null camera? Look at what line 29 is in StrobeController class.