Flashlight in Android fragment - SurfaceView

2019-02-19 12:46发布

问题:

I'm trying to develop a flashlight application for a local concert. This is part of a bigger application so it is in a fragment. This is the code:

First I declared the class together with its variables:

public class ConcertFragment extends Fragment {

    ToggleButton btnFlashlight;
    View rootView;

    private Camera cam;
    private boolean hasFlash;
    boolean hasCamera;
    boolean isFlashOn;
    Parameters params;

    public ConcertFragment() {
    }

Next is the onActivityCreated method which returns the getCamera method (declared further down):

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getCamera();
    }

Then I create the onCreateView method which builds the layout:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        rootView = inflater.inflate(R.layout.fragment_concert, container, false);

        hasFlash = getActivity().getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);

        if (!hasFlash) {
            // device doesn't support flash
            // Show alert message and close the application
            AlertDialog alert = new AlertDialog.Builder(getActivity()).create();

            alert.setTitle("No Flash");
            alert.setMessage("Sorry, device is not flash supported.");
            alert.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new android.content.DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {

                }
            });
            alert.show();
        }

        btnFlashlight = (ToggleButton) rootView.findViewById(R.id.toggleButton);
        btnFlashlight.setOnCheckedChangeListener(new OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton buttonView,
                    boolean isChecked) {
                if (isFlashOn) {
                    // turn off flash
                    turnOffFlash();
                } else {
                    // turn on flash
                    turnOnFlash();
                }
            }
        });

        return rootView;
    }

Method to turn on the flash:

    private void turnOnFlash() {
        if (!isFlashOn) {
            if (cam == null || params == null) {
                return;
            }

            params = cam.getParameters();
            params.setFlashMode(Parameters.FLASH_MODE_TORCH);
            cam.setParameters(params);
            cam.startPreview();
            isFlashOn = true;

            // changing button/switch image
            toggleButtonImage();
        }
    }

Method to turn off the flash:

    private void turnOffFlash() {
        if (isFlashOn) {
            if (cam == null || params == null) {
                return;
            }

            params = cam.getParameters();
            params.setFlashMode(Parameters.FLASH_MODE_OFF);
            cam.setParameters(params);
            cam.stopPreview();
            isFlashOn = false;

            // changing button/switch image
            toggleButtonImage();
        }
    }

Method to set the camera parameters:

       private void getCamera() {
            if (cam != null) {
                try {
                    cam = Camera.open();
                    params = cam.getParameters();
                    cam.startPreview();
                    hasCamera = true;

                } catch (RuntimeException e) {
                    Log.e("Camera Error. Failed to Open. Error: ", e.getMessage());
                }
            }
       }        

       private void toggleButtonImage(){
            if(isFlashOn){
                btnFlashlight.setBackgroundResource(R.drawable.btn_switch_on);
            }else{
                btnFlashlight.setBackgroundResource(R.drawable.btn_switch_off);
            }
        }
   }
}

The togglebutton switching on the flashlight switches on and off, but the flashlight never switches on at the back of my Nexus 5.

The related permissions I am using are as follows:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.VIBRATE" />

Can anyone help please?

回答1:

I am struggling with the same problem too. You need to add a SurfacePreview above your button in your layout:

 <SurfaceView
    android:id="@+id/PREVIEW"
    android:layout_width="1dp"
    android:layout_height="1dp"/>

and currently my Fragment looks like this:

public class FlashlightFragment extends Fragment implements SurfaceHolder.Callback {

ImageButton btnSwitch;
//flag to detect flash is on or off
private boolean isLighOn = false;

private Camera camera;
Parameters params;

@Override
public void onStart() {
    super.onStart();
    SurfaceView preview = (SurfaceView)getView().findViewById(R.id.PREVIEW);
    SurfaceHolder mHolder = preview.getHolder();
    mHolder.addCallback(this);
}

@Override
public void onPause(){
    super.onPause();
    turnOffFlash();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.flashlight_fragment,
            container, false);

    // flash switch button
    btnSwitch = (ImageButton) view.findViewById(R.id.flashlight_button);

    // displaying button image
    toggleButtonImage();

    // Switch button click event to toggle flash on/off
    btnSwitch.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            if (isLighOn) {
                // turn off flash
                turnOffFlash();
            } else {
                // turn on flash
                turnOnFlash();
            }
        }
    });

    return view;
}

// Turning On flash
private void turnOnFlash() {

    if (!isLighOn) {
        if (camera == null || params == null) {
            return;
        }
        params = camera.getParameters();
        params.setFlashMode(Parameters.FLASH_MODE_TORCH);
        camera.setParameters(params);
        camera.startPreview();
        isLighOn = true;

        // changing button/switch image
        toggleButtonImage();
    }

}

// Turning Off flash
private void turnOffFlash() {

    if (isLighOn) {
        if (camera == null || params == null) {
            return;
        }

        params = camera.getParameters();
        params.setFlashMode(Parameters.FLASH_MODE_OFF);
        camera.setParameters(params);
        camera.stopPreview();
        isLighOn = false;

        // changing button/switch image
        toggleButtonImage();
    }
}

/*
 * Toggle switch button images
 * changing image states to on / off
 * */
private void toggleButtonImage(){
    if(isLighOn){
        btnSwitch.setImageResource(R.drawable.icon_bulb_on);
    }else{
        btnSwitch.setImageResource(R.drawable.icon_bulb_off);
    }
}

@Override
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height)   {

}

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

@Override
public void surfaceCreated(SurfaceHolder holder) {
    if (camera == null) {
        camera = Camera.open();
        params = camera.getParameters();
        try {
            camera.setPreviewDisplay(holder);
        } catch (IOException e) {
            camera.release();
            camera = null;
        }
    }
}

This appears to work fine on my Nexus 5, but force closes on Xperia Z at camera.setPreviewDisplay(mHolder); I havent been able to solve that issue yet.

Hope this helps.