tgkprog tgkprog - 1 year ago 106
Android Question

Android using a runtime strategy to support different API level?

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;

And to switch off :

if (params.getFlashMode().equals(Parameters.FLASH_MODE_OFF)) {
isFlashOn = false;

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.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){
}catch(Exception e){}
if(mBuilder == null || mSession == null) {
return false;
try {
mBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);//and etc

Answer Source

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:

    mFlashlightStrategy = new PostLollipopStrategy();
} else {
    mFlashlightStrategy = new PreLollipopStrategy();
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download