2
votes

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
would you mind stripping your code to show only the relevant portion of code? Its really long.Illegal Argument
The two routines of turn flash on and flash off seem fine. Do you have the correct permissions set to allow this feature?jamesgates1
has anyone found anything on how can I resolve this? Any help is appreciated :)Michele La Ferla

1 Answers

4
votes

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.