3

I want to create an app that has a button to record video and another separate toggle button to turn on the flah during recording the video.

I have built the camera app using camera2 API for recent androids which is accesssed by a image button. And i set torch mode access to a toggle button but this is not working at all. But the toggle button is able to access the flash separetly.

public class MainActivity extends AppCompatActivity {


    private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            setupCamera(width,height);
            connectCamera();
        }

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

        createFolder();

        mMediaRecorder = new MediaRecorder();

        mTextureView = (TextureView) findViewById(R.id.textureView);
        mRecordButtonimg = (ImageButton) findViewById(R.id.video_online_button);
                mRecordButtonimg.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                if (misRecording) {
                    misRecording = false;
                    mRecordButtonimg.setImageResource(R.mipmap.ic_launcher);
                    mMediaRecorder.stop();
                    mMediaRecorder.reset();
                    startPreview();
                } else {
                    checkWriteStoragePermission();
                    misRecording = true;
                    mRecordButtonimg.setImageResource(R.mipmap.ic_launcher_round);
                }
            }
        });

        mButtonLights = (ToggleButton) findViewById(R.id.buttonLights);
        mButtonLights.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try{
                    cameraManager.setTorchMode(mCameraId, mButtonLights.isChecked());
                }catch (CameraAccessException e){
                    e.printStackTrace();
                }
            }
            });
    }
}

I have just added the set torch mode to the onClickListenser. Should i add it elsewhere? Beacuse it doesn't make any to add it to the preview! And i am already checking for the back camera in the code(id is 0 with a flashlight), so i don't know why the code isn't working.

akshPhD
  • 31
  • 1
  • 6

4 Answers4

2

Figured out how to torch on and off while camera is previewing. On button click to on/off the light, use this code:

//at some other function where camera is initialised and start preview
//...
Camera camera = Camera.open();
camera.startPreview();
//...
boolean lightOn = false;
//...

buttonLight.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
                Camera.Parameters p = camera.getParameters();

                if (!lightOn) {
                    lightOn = true;
                    p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                    camera.setParameters(p);
                } else {
                    lightOn = false;
                    p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                    camera.setParameters(p);
                }
        }
    });

Happy Coding! :D

Cousin Roy
  • 191
  • 1
  • 6
  • @Psijic can you explain what do you mean by already opened camera? If based on my code above..the 3rd and 4th lines are the codes to open the camera. The already opened camera is hold by that variable 'camera' of type Camera. – Cousin Roy Nov 25 '20 at 09:34
  • 1
    already opened camera means you have no camera variable stored because camera was opened by 3rd party. – Psijic Nov 25 '20 at 09:46
  • @Psijic in that case, you can view this post on how to lookup for the already opened camera https://stackoverflow.com/questions/21559699/get-id-of-currently-open-camera as per what i know, there's no way to get the camera id without storing it in the first place...but one of the answer in the post shows how to do looping to get the camera info which holds the camera id that you want be it front or back etc. – Cousin Roy Nov 26 '20 at 08:14
2

Maybe it helps, My task was nearly the same - to turn on/off flashlight by a button while processing a camera preview. I stop repeating requests using session, make new object of capture request, turn on/off a flashlight in a builder, and start repeating requests.

NOTE: if your use camera api 2 this solution is a life saver for you.

Something like this:

private fun enableFlash() {

        //isTorchON = true
        session.stopRepeating()

        //camera is a DeviceCamera object
        //fragmentCameraBinding.viewFinder is a AutoSurfaceView
        //session is a CameraCaptureSession

        val captureRequest = camera.createCaptureRequest(
            CameraDevice.TEMPLATE_PREVIEW).apply { addTarget(fragmentCameraBinding.viewFinder.holder.surface) }

        captureRequest.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH)

        session.setRepeatingRequest(captureRequest.build(), null, cameraHandler)
    }

    private fun disableFlash() {
        //isTorchON = false

        session.stopRepeating()

        val captureRequest = camera.createCaptureRequest(
            CameraDevice.TEMPLATE_PREVIEW).apply { addTarget(fragmentCameraBinding.viewFinder.holder.surface) }

        session.setRepeatingRequest(captureRequest.build(), null, cameraHandler)
    }
1

Use below code

// write below line in Manifest file
 <uses-feature android:name="android.hardware.camera"
    android:required="true" />

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<permission android:name="android.permission.FLASHLIGHT"
    android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
    android:protectionLevel="normal" />
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />


// write below code in activity xml
 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
<LinearLayout
   android:orientation="horizontal"
   android:layout_width="match_parent"
   android:layout_height="match_parent">
  <FrameLayout
      android:id="@+id/videoview"
      android:layout_width="500px"
      android:layout_height="480px"/>
  <LinearLayout
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="match_parent">
     <Button
         android:id="@+id/mybutton"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="REC"
         android:textSize="12dp"/>
     <RadioGroup
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:id="@+id/radio_group"
         android:orientation="vertical">
        <RadioButton
            android:id="@+id/flashoff"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="OFF"
            android:textSize="8dp"
            android:checked="true"/>
        <RadioButton
            android:id="@+id/flashtorch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Torch"
            android:textSize="8dp"/>
     </RadioGroup>
    </LinearLayout>
   </LinearLayout>
  </LinearLayout>


 // Activity source code

 import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.Camera;
 import android.media.CamcorderProfile;
 import android.media.MediaRecorder;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
 import android.support.v4.app.ActivityCompat;
 import android.support.v4.content.ContextCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.util.Log;
 import android.view.MotionEvent;
  import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
 import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.RadioButton;
 import android.widget.Toast;

import java.io.IOException;

public class MainActivity extends AppCompatActivity {
private Camera myCamera;
private MyCameraSurfaceView myCameraSurfaceView;
private MediaRecorder mediaRecorder;
private Button myButton;
private RadioButton flashOff, flashTorch;
private SurfaceHolder surfaceHolder;
boolean recording;
private int PERMISSION_CODE=1021;
private static final String LOG_TAG=MainActivity.class.getName();
private String[] getDeviceIdPermissions = new String[]{
        Manifest.permission.CAMERA,
        android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
        android.Manifest.permission.READ_EXTERNAL_STORAGE,
        android.Manifest.permission.RECORD_AUDIO};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if(!checkPermission()) {
        askPermission();
    }else{
        init();
    }
}

private boolean checkPermission() {
    if(isPermitted(getDeviceIdPermissions)){
        return true;
    }
    return false;
}

private void askPermission(){
    ActivityCompat.requestPermissions(this,getDeviceIdPermissions,PERMISSION_CODE);
}

Button.OnTouchListener flashButtonOnTouchListener
        = new Button.OnTouchListener(){

    @Override
    public boolean onTouch(View arg0, MotionEvent arg1) {
        // TODO Auto-generated method stub

        if(myCamera != null){
            Camera.Parameters parameters = myCamera.getParameters();

            switch (arg1.getAction()){
                case MotionEvent.ACTION_DOWN:
                    parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                    myCamera.setParameters(parameters);
                    break;
                case MotionEvent.ACTION_UP:
                    parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                    myCamera.setParameters(parameters);
                    break;
            };
        }

        return true;
    }};

Button.OnClickListener flashModeButtonOnClickListener
        = new Button.OnClickListener(){

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub

    }
};

Button.OnClickListener myButtonOnClickListener
        = new Button.OnClickListener(){

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        if(recording){
            // stop recording and release camera
            mediaRecorder.stop();  // stop the recording
            releaseMediaRecorder(); // release the MediaRecorder object

            //Exit after saved
            finish();
        }else{

            //Release Camera before MediaRecorder start
            releaseCamera();

            if(!prepareMediaRecorder()){
                Toast.makeText(MainActivity.this,
                        "Fail in prepareMediaRecorder()!\n - Ended -",
                        Toast.LENGTH_LONG).show();
                finish();
            }

            mediaRecorder.start();
            recording = true;
            myButton.setText("STOP");
        }
    }};

private Camera getCameraInstance(){
    // TODO Auto-generated method stub
    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)
    }
    return c; // returns null if camera is unavailable
}


private void init(){
    myCamera = getCameraInstance();
    if(myCamera == null){
        Log.d(LOG_TAG,"Failed to get camera");
    }

    myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
    FrameLayout myCameraPreview = (FrameLayout)findViewById(R.id.videoview);
    myCameraPreview.addView(myCameraSurfaceView);

    myButton = (Button)findViewById(R.id.mybutton);
    myButton.setOnClickListener(myButtonOnClickListener);

    flashOff = (RadioButton)findViewById(R.id.flashoff);
    flashTorch = (RadioButton)findViewById(R.id.flashtorch);
}

private String getFlashModeSetting(){
    if(flashTorch.isChecked()){
        return Camera.Parameters.FLASH_MODE_TORCH;
    }else {
        return Camera.Parameters.FLASH_MODE_OFF;
    }
}

private boolean prepareMediaRecorder(){
    myCamera = getCameraInstance();

    Camera.Parameters parameters = myCamera.getParameters();
    parameters.setFlashMode(getFlashModeSetting());
    myCamera.setDisplayOrientation(90);
    myCamera.setParameters(parameters);

    mediaRecorder = new MediaRecorder();

    myCamera.unlock();
    mediaRecorder.setCamera(myCamera);

    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);

    mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

    mediaRecorder.setOutputFile("/sdcard/myvideo.mp4");
    mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec.
    mediaRecorder.setMaxFileSize(5000000); // Set max file size 5M

    mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder().getSurface());

    try {
        mediaRecorder.prepare();
    } catch (IllegalStateException e) {
        releaseMediaRecorder();
        return false;
    } catch (IOException e) {
        releaseMediaRecorder();
        return false;
    }
    return true;

}

@Override
protected void onPause() {
    super.onPause();
    releaseMediaRecorder();       // if you are using MediaRecorder, release it first
    releaseCamera();              // release the camera immediately on pause event
}

private void releaseMediaRecorder(){
    if (mediaRecorder != null) {
        mediaRecorder.reset();   // clear recorder configuration
        mediaRecorder.release(); // release the recorder object
        mediaRecorder = null;
        myCamera.lock();           // lock camera for later use
    }
}

private void releaseCamera(){
    if (myCamera != null){
        myCamera.release();        // release the camera for other applications
        myCamera = null;
    }
}

public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{

    private SurfaceHolder mHolder;
    private Camera mCamera;

    public MyCameraSurfaceView(Context context, Camera camera) {
        super(context);
        mCamera = camera;
        mCamera.setDisplayOrientation(90);
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int weight,
                               int height) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null){
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
            // ignore: tried to stop a non-existent preview
        }

        // make any resize, rotate or reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub

    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    boolean isPermitted =isPermitted(permissions);
    if(isPermitted){
        if(requestCode==PERMISSION_CODE){
            init();
        }
    }
}

public boolean isPermitted(String[] permissions) {
    boolean havePermission;
    for (String permission : permissions) {
        havePermission = (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED);
        if (!havePermission)
            return false;
    }
    return true;
}
}
Dharmender Manral
  • 1,504
  • 1
  • 6
  • 7
  • hey i am using camera2API and not the older version, so could you give me a idea to set my flash on timer while recording the video. – akshPhD May 29 '19 at 11:35
1

Maybe it helps you. I create an application that applies OpenGL EL shaders to a camera preview. And my task was nearly the same - to turn on/off flashlight by a button while processing a camera preview. I managed to do it quite easily: I stop repeating requests, turn on/off a flashlight in a builder, and start repeating requests. Something like this:

cameraSession.stopRepeating()
requestBuilder.set(CaptureRequest.FLASH_MODE, if(turnFlashOn) CaptureRequest.FLASH_MODE_TORCH else null)
cameraSession.setRepeatingRequest(requestBuilder!!.build(), null, null)
Alex Shevelev
  • 681
  • 7
  • 14