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);
}
});
}
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){
}
}
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
surfaceChanged: 540 x 573 method parametrosCamera: 640 x 480
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.
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.