startPreview failed but not all devices

groff07 picture groff07 · Jun 17, 2013 · Viewed 8.1k times · Source

I'm getting an error startPreview failed but not all devices. In Motorola RAZR and Samsung Galaxy S3, it's working very well. Some people told me they got the same problem in other devices (Galaxy SII Lite, Galaxy Ace Duos, Samsung Galaxy Y, etc) I'm trying to test in a Samsung Galaxy Y and here's what I got in Logcat

java.lang.RuntimeException: startPreview failed
    at android.hardware.Camera.startPreview(Native Method)
    at br.com.timo.tubagram.CameraSurfaceView.surfaceCreated(CameraSurfaceView.java:47)
    at android.view.SurfaceView.updateWindow(SurfaceView.java:601)
    at android.view.SurfaceView.updateWindow(SurfaceView.java:413)
    at android.view.SurfaceView.dispatchDraw(SurfaceView.java:358)
    at android.view.View.draw(View.java:7083)
    at android.view.SurfaceView.draw(SurfaceView.java:344)
    at android.view.View.buildDrawingCache(View.java:6842)
    at android.view.View.getDrawingCache(View.java:6628)
    at android.view.ViewGroup.drawChild(ViewGroup.java:1571)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
    at android.view.View.draw(View.java:7083)
    at android.widget.FrameLayout.draw(FrameLayout.java:357)
    at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
    at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
    at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
    at android.view.View.draw(View.java:7083)
    at android.widget.FrameLayout.draw(FrameLayout.java:357)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2108)
    at android.view.ViewRoot.draw(ViewRoot.java:1540)
    at android.view.ViewRoot.performTraversals(ViewRoot.java:1276)
    at android.view.ViewRoot.handleMessage(ViewRoot.java:1878)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3770)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:670)
    at dalvik.system.NativeStart.main(Native Method)

And here is my code

public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, PreviewCallback{

    private SurfaceHolder holder;
    private Camera camera;
    private Camera.Parameters parameters;
    boolean front = false;

    public CameraSurfaceView(Context context) {
        super(context);

        this.holder = this.getHolder();
        this.holder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            this.holder = holder;
            camera = Camera.open();
            camera.setPreviewDisplay(holder);
            parameters = parametrosCamera();
            camera.setParameters(parameters);
            camera.setDisplayOrientation(90);
            camera.startPreview();
        } catch (IOException ioe) {
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.stopPreview();
        camera.release();   
        camera = null;
    }

    private Parameters parametrosCamera(){
        Parameters parameters = camera.getParameters();
        List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
        if (sizes != null){
            Size min = sizes.get(0);
            for (Size size : sizes){
                if (size.width < min.width){ 
                    min = size;
                }else{
                    parameters.setPreviewSize(min.width, min.height);
                    parameters.setPictureSize(min.width, min.height);
                }
            }
            parameters.set("orientation", "portrait");
            parameters.setRotation(90);
        }
        if (parameters.getFlashMode() != null){
            parameters.setFlashMode(Parameters.FLASH_MODE_AUTO);
        }
        return parameters;
    }
}

And my PrincipalActivity

public class PrincipalActivity extends Activity{

Camera camera;
File sdImageMainDirectory;
CameraSurfaceView cameraSurfaceView;
Button principalActivity_bt_TirarFoto;
Button principalActivity_bt_VirarFoto;
Button principalActivity_bt_Aceitar;
Button principalActivity_bt_Cancelar;
FrameLayout preview;
ImageView principalActivity_iv_UltimaFoto;

HandlePictureStorage hps;
int wid = 0;
boolean imageSelected = false;
boolean front = false;
String caminhoImagens;
String url;

//  File storagePath = new File(Environment.getExternalStorageDirectory() + "/Tubagram/");

@SuppressWarnings("deprecation")
@SuppressLint("NewApi") 
public void onCreate(Bundle savedInstanceState) {
    Log.i("PrincipalActivity","onCreate");
    super.onCreate(savedInstanceState);

    setContentView(R.layout.principal_activity);
    principalActivity_bt_TirarFoto = (Button) findViewById(R.id.principalActivity_bt_TirarFoto);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    cameraSurfaceView = new CameraSurfaceView(principalActivity_bt_TirarFoto.getContext());
    cameraSurfaceView.setSoundEffectsEnabled(true);
    cameraSurfaceView.setDrawingCacheEnabled(true);
    preview = (FrameLayout) findViewById(R.id.principalActivity_fl_Camera);

    preview.addView(cameraSurfaceView);

    principalActivity_bt_TirarFoto.setSoundEffectsEnabled(true);
    principalActivity_bt_TirarFoto.setOnClickListener(new OnClickListener() {

        @SuppressLint("NewApi") 
        @Override
        public void onClick(View v) {
            Log.i("PrincipalActivity","onClick - TirarFoto");
            camera = cameraSurfaceView.getCamera();
            camera.takePicture(new ShutterCallback() {

                @Override
                public void onShutter() {
                    AudioManager mgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
                    mgr.playSoundEffect(AudioManager.FLAG_PLAY_SOUND);

                }
            }, null, hps = new HandlePictureStorage());

            imageSelected = false;

            mostrarBotoesConfirma();

        }
    });

    principalActivity_bt_Aceitar = (Button) findViewById(R.id.principalActivity_bt_Aceitar);
    principalActivity_bt_Aceitar.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Log.i("PrincipalActivity","onClick - Aceitar");
            if (verificaInstagram()){

                ByteArrayOutputStream stream = new ByteArrayOutputStream();

                if (imageSelected){
                    Bitmap bitmap = ((BitmapDrawable)cameraSurfaceView.getBackground()).getBitmap();
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
                }else{
                    hps.getBitmap().compress(Bitmap.CompressFormat.PNG, 100, stream);
                }

                salvarImagemSelecionada(stream.toByteArray());

                Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
                shareIntent.setType("image/*");

                caminhoImagens = getRealPathFromURI(Uri.parse(url));

                Log.i("Caminho imagem: ", caminhoImagens);

                shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + caminhoImagens));
                shareIntent.setPackage("com.instagram.android");

                startActivity(shareIntent);
                //                  }
            }else{
                Toast.makeText(v.getContext(), "Você não possui o Instagram no seu smartphone!", Toast.LENGTH_SHORT).show();
            }

        }
    });

    principalActivity_bt_Cancelar = (Button) findViewById(R.id.principalActivity_bt_Cancelar);
    principalActivity_bt_Cancelar.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Log.i("PrincipalActivity","onClick - Cancelar");

            esconderBotoesConfirma();

            cameraSurfaceView.setBackgroundColor(Color.TRANSPARENT);

            cameraSurfaceView.voltarCamera();
        }
    });

    int qtdCameras = Camera.getNumberOfCameras();
    principalActivity_bt_VirarFoto = (Button) findViewById(R.id.principalActivity_bt_VirarFoto);
    if(qtdCameras > 1){
        principalActivity_bt_VirarFoto.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                Log.i("PrincipalActivity","onClick - VirarCamera");
                Thread t = new Thread(){
                    @Override
                    public void run() {
                        cameraSurfaceView.flipit();
                        front = cameraSurfaceView.getFront();
                    }
                };
                t.start();
            }
        });
    }else{
        principalActivity_bt_VirarFoto.setVisibility(View.INVISIBLE);
    }

    LinearLayout principalActivity_ll_Molduras = (LinearLayout) findViewById(R.id.principalActivity_ll_Molduras);
    principalActivity_ll_Molduras.setVisibility(View.VISIBLE);

    List<Integer> listaMoldurasMenores = new ArrayList<Integer>();
    final List<Integer> listaMoldurasMaiores = new ArrayList<Integer>();

    //      listaMoldurasMenores.add(R.drawable.moldura_menor0);
    listaMoldurasMenores.add(R.drawable.moldura_menor1);
    listaMoldurasMenores.add(R.drawable.moldura_menor2);
    listaMoldurasMenores.add(R.drawable.moldura_menor3);
    listaMoldurasMenores.add(R.drawable.moldura_menor4);
    listaMoldurasMenores.add(R.drawable.moldura_menor5);
    listaMoldurasMenores.add(R.drawable.moldura_menor6);

    listaMoldurasMaiores.add(R.drawable.moldura_maior1);
    listaMoldurasMaiores.add(R.drawable.moldura_maior2);
    listaMoldurasMaiores.add(R.drawable.moldura_maior3);
    listaMoldurasMaiores.add(R.drawable.moldura_maior4);
    listaMoldurasMaiores.add(R.drawable.moldura_maior5);
    listaMoldurasMaiores.add(R.drawable.moldura_maior6);

    for (int i = 0; i < listaMoldurasMenores.size(); i++) {
        final ImageView imagem_moldura = new ImageView(this);
        imagem_moldura.setScaleType(ScaleType.FIT_XY);
        imagem_moldura.setId(i);
        imagem_moldura.setImageResource(listaMoldurasMenores.get(i));
        imagem_moldura.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.i("PrincipalActivity","onClick - Molduras");
                ImageView imagem_moldura_maior = new ImageView(v.getContext());
                imagem_moldura_maior.setImageResource(listaMoldurasMaiores.get(imagem_moldura.getId()));
                preview.setForeground(imagem_moldura_maior.getDrawable());
            }
        });
        principalActivity_ll_Molduras.addView(imagem_moldura,i);
    }

    principalActivity_iv_UltimaFoto = (ImageView) findViewById(R.id.principalActivity_iv_UltimaFoto);
    principalActivity_iv_UltimaFoto.setAdjustViewBounds(false);

    Uri uri = buscaUltimaFotoAlbum();
    Drawable backgroundGaleria;

    if (uri != null){
        String caminhosImagensGaleria = getRealPathFromURI(uri);
        backgroundGaleria = Drawable.createFromPath(caminhosImagensGaleria);
        principalActivity_iv_UltimaFoto.setBackgroundDrawable(backgroundGaleria);
    }else{
        principalActivity_iv_UltimaFoto.setBackgroundResource(R.drawable.box_imagem_album);
    }

    principalActivity_iv_UltimaFoto.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI);
            final int ACTION_SELECT_IMAGE = 1;
            intent.putExtra("crop", "true");
            intent.putExtra("aspectX", 10);
            intent.putExtra("aspectY", 10);
            intent.putExtra("outputX", 256);
            intent.putExtra("outputY", 256);
            intent.putExtra("scale", true);
            intent.putExtra("return-data", true);
            startActivityForResult(intent,ACTION_SELECT_IMAGE);
        }
    });
}

EDIT 1 - 06/20/2013

I change a little my code and now runs in my Galaxy Y but my FrameLayout with the camera isn't working. I getting a black screen on FrameLayout. Anyone knows why?

What I change:

I added this line in my constructor

this.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

I changed my surfaceCreated and surfaceChanged to this

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    try {
        camera.stopPreview();
        parameters = parametrosCamera();
        camera.setParameters(parameters);
        camera.setDisplayOrientation(90);
        camera.setPreviewDisplay(holder);
        camera.startPreview();
    } 
    catch (IOException e) {
    } 
    catch (Exception e){
    }
}

@SuppressLint("NewApi") 
@Override
public void surfaceCreated(SurfaceHolder holder) {
    try {
        camera = Camera.open(0);
        camera.setPreviewDisplay(this.holder);
        camera.startPreview();
    } catch (IOException ioe) {
    } catch (Exception e){
    }
}

P.S.

I added some Log's to get the size my setPreviewSize is getting with my method

private Parameters parametersCamera(){
    Parameters parameters = camera.getParameters();
    List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
    if (sizes != null){
        Size min = sizes.get(0);
        for (Size size : sizes){
            if (size.width < min.width){
                min = size;
            }else{
                parameters.setPreviewSize(min.width, min.height);
                parameters.setPictureSize(min.width, min.height);
                Log.i("Ultima Camera Width: " + min.width, "Ultima Camera Height: " + min.height);
            }
        }
        parameters.set("orientation", "portrait");
        parameters.setRotation(90);
    }
    if (parameters.getFlashMode() != null){
        parameters.setFlashMode(Parameters.FLASH_MODE_AUTO);
    }
    return parameters;
}

and I added a Log in surfaceChanged to get the width and height (I don't use this width and height) and see if is the same and I get this result's

Motorola RAZR HD (works verywell)

surfaceChanged: 540 x 573 method parametrosCamera: 640 x 480

Samsung Galaxy Y (don't show my preview)

surfaceChanged: 240 x 162 (W x H) method parametrosCamera: 320 x 240

and in my method parametersCamera I use these two lines

parameters.set("orientation", "portrait");
parameters.setRotation(90);

I think the answer to my question is in this part of my code.

Answer

Alex Cohn picture Alex Cohn · May 26, 2014

You seem to be looking for the minimal supported preview size. But if this size is not supported as picture size, your code will initialize the camera into an unsupported state. Some devices may choose to fail to open preview in such state.

I am not sure you really need picture size to be equal to preview frame size. If you don't, you can simply iterate separately on the values from parameters.getSupportedPictureSizes().

Another common mistake (not necessarily applicable to your use case) is rooted in that the sizes for rear-facing camera do not match those of the front-facing camera. Therefore, the size must always be recalculated when you switch the camera.