nnnnnnitters
nnnnnnitters

Reputation: 65

Android Camera Application: Capture button not working?

I've been working on this Camera app for a little while now. Basically what I want to do is take a picture(and store it internally), then display that image in the next Activity. The preview works perfectly, but when I hit the Capture button on MainActivity the error "Unfortunately, myApplication has stopped" shows up and the app crashes. AndroidStudio is not giving me any Event Log information either...

Here's the main activity(is something wrong with SendInfo?):

public class MainActivity extends ActionBarActivity {
public final static String EXTRA_MESSAGE = "File_name";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Create an instance of Camera
    Camera mCamera = getCameraInstance();

    // Create our Preview view and set it as the content of our activity.
    CameraPreview mPreview = new CameraPreview(this, mCamera);
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.addView(mPreview);

    // Add a listener to the Capture button
    Button captureButton = (Button) findViewById(R.id.button_capture);
    captureButton.setOnClickListener(new View.OnClickListener() {

       @Override
         public void onClick(View v) {
          Camera mCamera = getCameraInstance();
          // get an image from the camera
          mCamera.takePicture(null, null, mPicture);
         }
       }
    );
}
//////////////////////
public void sendInfo(View view)
{
    Intent intent = new Intent(this,show_image.class);
      Uri fileUri = getOutputMediaFileUri(1);
    intent.putExtra(EXTRA_MESSAGE, fileUri.toString());
    startActivity(intent);
}
/////////////////
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null){
            Log.d("Logtag:", "Error creating media file, check storage permissions: "
                   );
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d("Logtag:", "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d("Logtag:", "Error accessing file: " + e.getMessage());
        }
    }
};


@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_main, 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;
    }

    return super.onOptionsItemSelected(item);
}
/** A safe way to get an instance of the Camera object. */
public Camera getCameraInstance(){
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
        Toast.makeText(getApplicationContext(), "Camera is not available (in use or does not exist)",
                Toast.LENGTH_LONG).show();
    }
    return c; // returns null if camera is unavailable
}





public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;

/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
    return Uri.fromFile(getOutputMediaFile(type));
}


/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new     File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This locat ion works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            Log.d("Logtag", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                "IMG_"+ timeStamp + ".jpg");
    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                "VID_"+ timeStamp + ".mp4");
    } else {
        return null;
    }

    return mediaFile;
}
}

And here is the second Activity that should be displaying the image...

public class show_image extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Intent intent = getIntent();
    String stringURI = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
//    Uri uri = Uri.parse(stringURI);
   Bitmap bitmap = BitmapFactory.decodeFile(stringURI);
  ImageView imageView = new ImageView(this);
   imageView.setImageBitmap(bitmap);
    setContentView(imageView);


}

public static Bitmap decodeFile(File f, final int maxSize) {

    Bitmap b = null;
    // Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;

    FileInputStream fis = null;
    try {
        fis = new FileInputStream(f);
        BitmapFactory.decodeStream(fis, null, o);
        fis.close();

        int scale = 1;
        if (o.outHeight > maxSize || o.outWidth > maxSize) {
            scale = (int) Math.pow(2, (int) Math.round(Math.log(maxSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;

        fis = new FileInputStream(f);
        b = BitmapFactory.decodeStream(fis, null, o2);

    } catch (Exception e) {
        Log.e("Logtag", "Error processing bitmap", e);
    } finally {
        //FileUtil.closeQuietly(fis);
    }

    return b;
}




@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;
    }

    return super.onOptionsItemSelected(item);
    }
}

Output from Log Cat:

02-25 00:53:11.907  13191-13191/edu.ramapo.camer I/System.out﹕ debugger has settled (1480)

02-25 00:53:12.177  13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.view.ViewGroup.onNestedScrollAccepted, referenced from method android.support.v7.internal.widget.ActionBarOverlayLayout.onNestedScrollAccepted

02-25 00:53:12.177  13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 11357: Landroid/view/ViewGroup;.onNestedScrollAccepted (Landroid/view/View;Landroid/view/View;I)V

02-25 00:53:12.177  13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6f at 0x0000

02-25 00:53:12.177  13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.view.ViewGroup.onStopNestedScroll, referenced from method android.support.v7.internal.widget.ActionBarOverlayLayout.onStopNestedScroll

02-25 00:53:12.177  13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 11363: Landroid/view/ViewGroup;.onStopNestedScroll (Landroid/view/View;)V

02-25 00:53:12.177  13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6f at 0x0000

02-25 00:53:12.177  13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.support.v7.internal.widget.ActionBarOverlayLayout.stopNestedScroll, referenced from method android.support.v7.internal.widget.ActionBarOverlayLayout.setHideOnContentScrollEnabled

02-25 00:53:12.177  13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 9047: Landroid/support/v7/internal/widget/ActionBarOverlayLayout;.stopNestedScroll ()V

02-25 00:53:12.177  13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6e at 0x000e

02-25 00:53:12.207  13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.content.res.TypedArray.getChangingConfigurations, referenced from method android.support.v7.internal.widget.TintTypedArray.getChangingConfigurations

02-25 00:53:12.207  13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 365: Landroid/content/res/TypedArray;.getChangingConfigurations ()I

02-25 00:53:12.207  13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6e at 0x0002

02-25 00:53:12.207  13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.content.res.TypedArray.getType, referenced from method android.support.v7.internal.widget.TintTypedArray.getType

02-25 00:53:12.207  13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 387: Landroid/content/res/TypedArray;.getType (I)I

02-25 00:53:12.207  13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6e at 0x0002

02-25 00:53:13.068  13191-13191/edu.ramapo.camer D/libEGL﹕ loaded /system/lib/egl/libEGL_adreno200.so

02-25 00:53:13.068  13191-13191/edu.ramapo.camer D/libEGL﹕ loaded /system/lib/egl/libGLESv1_CM_adreno200.so

02-25 00:53:13.078  13191-13191/edu.ramapo.camer D/libEGL﹕ loaded /system/lib/egl/libGLESv2_adreno200.so

02-25 00:53:13.078  13191-13191/edu.ramapo.camer I/Adreno200-EGL﹕ <qeglDrvAPI_eglInitialize:265>: EGL 1.4 QUALCOMM build: HAREESHG_Nondeterministic_AU+PATCH[ES]_msm8960_JB_1.9.6_MR2_CL3219408_release_ENGG (CL3219408)
    Build Date: 09/28/13 Sat
    Local Branch: hhh
    Remote Branch: quic/jb_1.9.6_1
    Local Patches: 8d50ec23e42ef52b570aa6ff1650afac0b503d78 CL3219408: Fix in the Glreadpixels for negative offsets and larger dimensions.
    801859126f6ca69482b39a34ca61447e3f7cded8 rb: fix panel settings to clear undrawn/undefined buffers
    Reconstruct Branch: LOCAL_PATCH[ES]

02-25 00:53:13.118  13191-13191/edu.ramapo.camer D/OpenGLRenderer﹕ Enabling debug mode 0

02-25 00:53:27.353  13191-13191/edu.ramapo.camer D/Logtag﹕ failed to create directory

02-25 00:53:27.353  13191-13191/edu.ramapo.camer D/Logtag:﹕ Error creating media file, check storage permissions:

Upvotes: 0

Views: 1740

Answers (1)

ifeomaro
ifeomaro

Reputation: 2763

I think the reason for the crash is because you are trying to get the camera instance twice: when your activity is created and when button captureButton is pressed. When you try to get it the second time, it returns null because it is already in use by your activity.

You should get the camera instance once before the captureButton button is pressed and process the picture taken after that.

public class MainActivity extends ActionBarActivity {
  public final static String EXTRA_MESSAGE = "File_name";
  private Camera mCamera; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      // Create an instance of Camera
      mCamera = getCameraInstance();

      // Create our Preview view and set it as the content of our activity.
      CameraPreview mPreview = new CameraPreview(this, mCamera);
      FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
      preview.addView(mPreview);

      // Add a listener to the Capture button
      Button captureButton = (Button) findViewById(R.id.button_capture);
      captureButton.setOnClickListener(new View.OnClickListener() {

         @Override
           public void onClick(View v) {
            // get an image from the camera
            mCamera.takePicture(null, null, mPicture);
           }
         }
      );
  }

  ...

Edit

To move to the next activity when a picture is taken, you could call startActivity after the Camera.PictureCallback has saved the byte array to a file.

private Camera.PictureCallback mPicture = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null){
            Log.d("Logtag:", "Error creating media file, check storage permissions: "
                   );
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();

            Intent intent = new Intent(this,show_image.class);
            Uri fileUri = Uri.fromFile(pictureFile);
            intent.putExtra(EXTRA_MESSAGE, fileUri.toString());
            startActivity(intent);

        } catch (FileNotFoundException e) {
            Log.d("Logtag:", "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d("Logtag:", "Error accessing file: " + e.getMessage());
        }
    }
};

...

Edit 2

You need to add this permission to your manifest to store the photo on the device:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

I hope this helps.

Upvotes: 1

Related Questions