Search code examples
androidandroid-intentandroid-camerasurfaceview

Android Camera surface-view camera recreated when i press back button on archos tablet on jellybean


In my code i have camera preview and video recording on button click so my code works well for recording and preview.

but when i press back button then surfaceview create and surface view change method get called after that surfaceview destroy method called so i have to press back button again and at this time it directly call surface destroy ( second time surface create and surface change is not called)

Here is my code (based on vanevery's answer here):

public class VideoCapture extends Activity implements  SurfaceHolder.Callback {

public static final String LOGTAG = "VIDEOCAPTURE";
private static final int SELECT_PHOTO = 100;
private MediaRecorder recorder;
private SurfaceHolder holder;
private CamcorderProfile camcorderProfile;
private Camera camera;        

boolean recording = false;
boolean usecamera = true;
boolean previewRunning = false;
Button recorderButton,selectVideo;
long init,now,time;
Handler handler;
Runnable updater;
SimpleDateFormat df;
Camera.Parameters parameters;
String timeString, timeStamp,selectedVideoPath;


@Override
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                        
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                        WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        setContentView(R.layout.main);
         handler = new Handler();
       df = new SimpleDateFormat("mm:ss");
        
        camcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
        recorderButton = (Button)findViewById(R.id.button);
        selectVideo = (Button)findViewById(R.id.videoselect);
       
        final TextView timerText = (TextView)findViewById(R.id.time);
        File dir = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_DCIM), "/Filme");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        
        // Animation for blinking red dot while recording
        SurfaceView cameraView = (SurfaceView) findViewById(R.id.CameraView);

        holder = cameraView.getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);      
        
        cameraView.setClickable(true);
  

        cameraView.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v) {
                camera.autoFocus(new AutoFocusCallback(){
                    @Override
                    public void onAutoFocus(boolean arg0, Camera arg1) {
                        //camera.takePicture(shutterCallback, rawCallback, jpegCallback);
                    }
                });
            }
        });  
        
        selectVideo.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                
                  Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
                  photoPickerIntent.setType("video/*");
            
                  startActivityForResult(photoPickerIntent, SELECT_PHOTO);  
            }
        });
        
        recorderButton.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                 if (recording) {
                     recorderButton.setBackgroundResource(R.drawable.recordbutton_background_selector);
                        recorder.stop();
                        handler.removeCallbacks(updater); // stop handler
                       
                        
                     // to refresh media scan on storage 
                        sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse
                                ("file://" + Environment.getExternalStorageDirectory())));
                        
                        String filepath =Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)+File.separator+"Filme"+File.separator+"Filme_"+timeStamp+".mp4";
                        Intent i = new Intent(getBaseContext(),VideoCutActivity.class);
                          i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                         
                          i.putExtra("path", filepath);
                          getBaseContext().startActivity(i);
                          finish();
                         /*
                        if (usecamera) {
                                try {
                                        camera.reconnect();
                                } catch (IOException e) {
                                        e.printStackTrace();
                                        
                                }
                        }                        
                      */
                        recording = false;
                        Log.v(LOGTAG, "Recording Stopped");
                        // Let's prepareRecorder so we can record again
                       // prepareRecorder();
                } else {
                    recorderButton.setBackgroundResource(R.drawable.stopbutton_background_selector);
                    
              
                     
                        recording = true;
                        prepareRecorder();
                     //   recorder.start();
                        Log.v(LOGTAG, "Recording Started");
                }
            }
        });
        
        // Recording timmer 
         updater = new Runnable() {
            @Override
            public void run() {
                
                    now=System.currentTimeMillis();
                    time=now-init;
                    timeString  = df.format(new Date(time));
                    timerText.setText(timeString);
                    handler.postDelayed(this, 30);
              
            }
        };
          
}
   @Override
  protected void onResume() {
       super.onResume();
  Log.e("onresume", "on resume");
    // Open the default i.e. the first rear facing camera. 
}



@Override
protected void onPause() {
    super.onPause();

    // Because the Camera object is a shared resource, it's very
    // important to release it when the activity is paused.
    if (recording) {
     recorder.stop();
        recording = false;
        recorder.release();
        camera.stopPreview();
        camera.setPreviewCallback(null);
        camera.release();
        camera = null;
}
else
{
    if (camera != null) {      
        previewRunning = false;
        camera.release();
        camera = null;
    }
}}


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) { 
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent); 

    switch(requestCode) { 
    case SELECT_PHOTO:
        if(resultCode == RESULT_OK){  
            Uri selectedImage = imageReturnedIntent.getData();
            selectedVideoPath  = getPath(selectedImage);
             
          Intent i = new Intent(getBaseContext(),VideoCutActivity.class);
          i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        
          i.putExtra("path", selectedVideoPath);
          VideoCapture.this.startActivity(i);
          finish();
   
        }
    }
}

public String getPath(Uri uri) {
     String[] proj = { MediaStore.Images.Media.DATA };
        CursorLoader loader = new CursorLoader(getBaseContext(), uri, proj, null, null, null);
        Cursor cursor = loader.loadInBackground();
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    }


private void prepareRecorder() {
recorder = new MediaRecorder();
        recorder.setPreviewDisplay(holder.getSurface());
        
        if (usecamera) {
                camera.unlock();
                recorder.setCamera(camera);
        }
        
        recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
        recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
        recorder.setProfile(camcorderProfile);

       
        timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        recorder.setOutputFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)+File.separator+"Filme"+File.separator+"Filme_"+timeStamp+".mp4");
        Log.v(LOGTAG, "camcorderProfile");
       
     
        try {
                recorder.prepare();
                recorder.start();
                init = System.currentTimeMillis();
                handler.post(updater);
                
        } catch (IllegalStateException e) {
                e.printStackTrace();
                finish();
        } catch (IOException e) {
                e.printStackTrace();
                finish();
        }
}



public void surfaceCreated(SurfaceHolder holder) {
        Log.v(LOGTAG, "surfaceCreated");
        
        if (usecamera) {
                camera = Camera.open();
                parameters = camera.getParameters();
                try {
                    Log.i("Capture","surface created");
                     parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                     camera.setParameters(parameters);
                        camera.setPreviewDisplay(holder);
                        camera.startPreview();
                        previewRunning = true;
                }
                catch (IOException e) {
                        Log.e(LOGTAG,e.getMessage());
                        e.printStackTrace();
                }        
        }                
        
}


public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.v(LOGTAG, "surfaceChanged");

        if (!recording && usecamera) {
            
                if (previewRunning){
                    Log.e("Capture","preview is running");
                        camera.stopPreview();
                }

                try {
                    Log.e("Capture","inside try of surface changed");
                    parameters = camera.getParameters();
                    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                    parameters.setPreviewSize(camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight);
                    parameters.setPreviewFrameRate(camcorderProfile.videoFrameRate);
                        
                        camera.setParameters(parameters);
                        camera.setPreviewDisplay(holder);
                        camera.startPreview();
                        previewRunning = true;
                }
                catch (IOException e) {
                    
                        Log.e(LOGTAG,e.getMessage());
                        e.printStackTrace();
                }        
                
               // prepareRecorder();        
        }
}


public void surfaceDestroyed(SurfaceHolder holder) {
        Log.v(LOGTAG, "surfaceDestroyed");
        
        if (camera != null) {
            camera.stopPreview();
        }
        
        if (recording) {
            try{
            Log.e("Capture","inside recording  of surface destory");
                recorder.stop();
                recording = false;
                recorder.release();
                camera.stopPreview();
                camera.setPreviewCallback(null);
                camera.release();
                camera = null;
            }
            catch (RuntimeException e) {
                Log.d("surface destroyed", "Problem in surfaceDestroyed"); 
                e.printStackTrace();
            } 
        }

Solution

  • Based on debugging/discussion on chat:

    • the first time back is being hit, the existing Camera activity gets destroyed and another one is created. Used the following to follow the changes in the back stack:

      adb shell dumpsys activity | grep -i run

    • No new task is required, so this is useless: i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

      Apparently, using i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) helps!

    I'm not sure why exactly this is helping though. (Especially, because IIUC, with *CLEAR_TOP, the existing instance of the activity on the stack would be used (with onNewIntent), but here (based on the output from dumpsys, a new activity gets created :|). But it works on archos.