4

I have a small functionality. Switching on the torch and keeping it on, till the user switches it off from my app or my app exits. Using :

            params = camera.getParameters();
            if (params.getFlashMode().equals(Parameters.FLASH_MODE_TORCH)) {
                isFlashOn = true;
                return;
            }
            params.setFlashMode(Parameters.FLASH_MODE_TORCH);
            camera.setParameters(params);
            camera.startPreview();

And to switch off :

            if (params.getFlashMode().equals(Parameters.FLASH_MODE_OFF)) {
                isFlashOn = false;
                return;
            }
            params.setFlashMode(Parameters.FLASH_MODE_OFF);
            camera.setParameters(params);
            camera.stopPreview();

But I notice that this is not very robust. Works fine the first time, but after that (especially on my API levle 22 phone) might not work. I was thinking of testing with the android.hardware.camera2 as suggested here Plan to use if (android.os.Build.VERSION.SDK_INT >20) and a strategy (a base interface implemented by two classes, one using old API and one the new camera2 API.

Is this safe on all devices? I saw that we can do it for android classes, but is it okay for our own classes too? Or are there devices which scan all our code and reject it if it has code that refers to API it does not know about?

I do not want to make two APKs as its a small functionality.

I make sure flash is available like this , not tested on all devices but in an emulator by Genymotion app did not crash.

public boolean torchInit() {
    try {
        PackageManager pm = app.getPackageManager();
        // First check if device supports flashlight
        boolean hasFlash = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
        if (!hasFlash) {
            Toast.makeText(app, "Flash not found or can\'t get hold of it. No torch", Toast.LENGTH_LONG).show();
            return false;
        }
        camera = Camera.open();
        Camera.Parameters params = camera.getParameters();
        Log.i(LogId, "camera params flash: " + params.getFlashMode());
        return true;
    } catch (Throwable e) {
        Log.e(LogId, "cameraFlashSetup " + e, e);
        Toast.makeText(app, "Flash error, no torch. Description : " + e, Toast.LENGTH_LONG).show();
        camera = null;
    }
    return false;
}

The flash interface to change between the two classes is :

public abstract class TorchInterface  {

protected AppCompatActivity app;

public void init(AppCompatActivity ap){
    app = ap;
}

public abstract boolean torchInit();

public boolean torchReInit(){
    return torchInit();//if re init is not different than init
}

public abstract boolean torchOn();

public abstract boolean torchOff();

}

Update: new code worked but only if I:

 mBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

Instead of:

mBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_MANUAL);

But then switches on flash as soon as init the app. I was going to chuck it, then realised on my Camera2Impl I can :

public boolean torchInit() {
    //do nothing on usual init that app calls on create
    return true;
}

And instead do the init on torch on (flash on):

public boolean torchOn() {
        //if not in it, try first 3 times
        if(mBuilder == null || mSession == null){
            if(firstFewTimesTorchOn >  0){
                firstFewTimesTorchOn--;
                torchInit2();
               try{
                    Thread.sleep(150);
                }catch(Exception e){}
                if(mBuilder == null || mSession == null) {
                    return false;
                }
            }
        }
        try {
            mBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);//and etc
Community
  • 1
  • 1
tgkprog
  • 4,493
  • 4
  • 41
  • 70
  • 1
    *Is this safe on all devices?* Short answer, No, not all cameras will have flash, some Android versions, Lollipop, have a bug where the flash left on after few seconds, causes handset to reboot, battery drains. Code that is written by OP is assuming all of them will have it, this could backfire if installed to device that does not have flash, I do not see a graceful handling in that case. – t0mm13b May 25 '16 at 08:57
  • @t0mm13b thanks about the lollipop heads up. on my device that does not happen, but i will add a warning. my app uses the screen as a light and the flash is optional – tgkprog May 25 '16 at 09:17
  • OP: cool, some nexus 5/5x had that problem on lollipop. Good thinking in using the screen as light for fallback, just be sure to release wakelocks, don't want to upset few android users when they see where their battery juice went to ;) – t0mm13b May 25 '16 at 09:20
  • @t0mm13b Yes releasing wake locks on stop and on pause. My device does have the problem. Dont know why I said it does not. wishful thinking. might work on future devices, works if i init only when user switches on flash. Does need stop flash on stop and pause. flash goes on if app suspended/ in background – tgkprog May 25 '16 at 22:23

2 Answers2

2

Android devices do not "scan" code - compiler does. Therefore, I don't see any issue with your idea. On contrary - using Strategy pattern is way better then if-else all over the code.

Something along these lines should work:

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
    mFlashlightStrategy = new PostLollipopStrategy();
} else {
    mFlashlightStrategy = new PreLollipopStrategy();
}
Vasiliy
  • 16,221
  • 11
  • 71
  • 127
  • yes i meant would the compiler throw an exception on android when it does its pre checks. i know it does not on web apps, was wondering about devcies cause they are more strict. anyway going ahead with exactly this – tgkprog May 25 '16 at 09:20
2

Is this safe on all devices?

Why dont't you put one check whether flash is available or not.

context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);

which will return true if a flash is available, false if not. You can write your further code in true block.

Mukesh
  • 266
  • 1
  • 4
  • 10
  • Yes already doing that (updated answer my camera var is null if this is not there and i check for null). was more worried about old and new code in same app. – tgkprog May 25 '16 at 09:19
  • Before that check you must get the runtime permission for Camera/Flash or else you will get null pointer exception in version 6+. In lower version that code wont matter, it will run fine. – Mukesh May 25 '16 at 09:27