Question

I'm having trouble invoking the built-in camera app on my Droid Razr M using an ACTION_IMAGE_CAPTURE Intent on ICS and was hoping someone else has seen this and knows how to solve/work-around the issue. My app launches the Camera, waits for the user to capture and accept the image, then processes it upon return. But note that there is NO processing of the image in the sample app, below, and the problem still happens. The key element here is that we immediately re-invoke the camera upon the return from the Intent, to allow the user to continue taking pictures, one after another. This has been working fine on many devices (more than a dozen different devices) but fails on the Droid Razr M running 4.1.2 (as well as earlier versions of ICS). The failure manifests after taking the second photo -- all of the buttons on the camera become disabled and only the back button works. The problem does not happen if we put in a delay of 5 or more seconds in our app before relaunching the Intent -- but that is unacceptable. Here's a simple repro app that demonstrates the problem (note that you will need to enable the WRITE_EXTERNAL_STORAGE permission for this to work):

public class MainActivity extends Activity {

private static final int RESPONSE_SINGLE_SHOT = 45;
private static final String TAG = "CameraTest";

private String mCameraFilePath = null;

@Override
protected void onCreate( Bundle savedInstanceState ) {
    super.onCreate( savedInstanceState );
    setContentView( R.layout.activity_main );
    onLaunchCamera( true );  //The launch is here only for simplification - it also fails in onStart()
}

@Override
protected void onActivityResult( final int requestCode, final int resultCode, final Intent intent )
{
    super.onActivityResult(requestCode, resultCode, intent);
    processImage( requestCode, resultCode, intent );
}

public void onLaunchCamera( boolean fromUserAction )
{
    final String storageState = Environment.getExternalStorageState();
    if (storageState.equals(Environment.MEDIA_MOUNTED))
    {
        final Intent cameraIntent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE );
        cameraIntent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET );

        final List<ResolveInfo> list = getPackageManager().queryIntentActivities( cameraIntent, 0 );
        //Grab the first camera in the list, this should be the camera app that came with the device:
        final String packageName = list.get(0).activityInfo.packageName;
        final String name = list.get(0).activityInfo.name;

        final File publicDir = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_DCIM );
        final Time t = new Time();
        t.setToNow();

        File cameraFile = new File( publicDir, "/Camera/" + makePhotoFileName( t )  );
        mCameraFilePath = cameraFile.getAbsolutePath();
        Log.i( TAG, "creating camera file: " +  mCameraFilePath );

        try
        {
            if ( cameraFile.exists() == false )
            {
                cameraFile.getParentFile().mkdirs();
                if ( cameraFile.createNewFile() )
                {
                    cameraIntent.putExtra( MediaStore.EXTRA_OUTPUT, Uri.fromFile( cameraFile ) );
                } else {
                    Log.e( TAG, "failed to create file:" + cameraFile.getAbsolutePath() );
                    return;
                }
            }

        } catch ( IOException e )
        {
            Log.e( TAG, "Could not create file.", e );
            return;
        }

        cameraIntent.setComponent( new ComponentName( packageName, name ) );
        startActivityForResult( cameraIntent, RESPONSE_SINGLE_SHOT );

    } else {
        Log.e(TAG, "SD card not present");
    }
}

private void processImage( final int requestCode, final int resultCode, final Intent intent ) {
    switch (requestCode)
    {
        case RESPONSE_SINGLE_SHOT:
            if ( resultCode == RESULT_OK )
            {       
                runOnUiThread( new Runnable() {
                    @Override
                    public void run() {
                        onLaunchCamera( false );    //Immediately re-run camera
                    }
                });
            }
            else {
                // delete the placeholder file we created
                if ( mCameraFilePath != null ) {
                    final File cameraFile = new File( mCameraFilePath );
                    cameraFile.delete();
                    mCameraFilePath = null;
                }
            }
            break;
        default:
            break;
    }
}

private String makePhotoFileName( final Time t ) {
    final String fileName = t.format("IMG_%Y%m%d_%H%M%S") + ".jpg";
    return fileName;
}
}

Any help is greatly appreciated.

Was it helpful?

Solution

The only solution that we've been able to come up with for the default camera on the Razr M is to not immediately return to the camera after capturing an image. We did this by inserting the following code just before the try-catch block in onLaunchCamera():

if ( !fromUserAction && name.equals( "com.motorola.camera.Camera" ) && Build.MODEL.equals( "XT907" ) )
    return;

This is just a work-around, but does keep the camera from hanging up.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top