Try out hacky support for enabling the front light on some devices
[zxing.git] / android / src / com / google / zxing / client / android / FlashlightManager.java
1 /*
2  * Copyright (C) 2010 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.client.android;
18
19 import android.os.IBinder;
20 import android.util.Log;
21
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24
25 /**
26  * This class is used to activate the weak light on some camera phones (not flash)
27  * in order to illuminate surfaces for scanning. There is no official way to do this,
28  * but, classes which allow access to this function still exist on some devices.
29  * This therefore proceeds through a great deal of reflection.
30  *
31  * See <a href="http://almondmendoza.com/2009/01/05/changing-the-screen-brightness-programatically/">
32  * http://almondmendoza.com/2009/01/05/changing-the-screen-brightness-programatically/</a> and
33  * <a href="http://code.google.com/p/droidled/source/browse/trunk/src/com/droidled/demo/DroidLED.java">
34  * http://code.google.com/p/droidled/source/browse/trunk/src/com/droidled/demo/DroidLED.java</a>.
35  */
36 final class FlashlightManager {
37
38   private static final String TAG = FlashlightManager.class.getName();
39
40   private static Object iHardwareService;
41   private static Method setFlashEnabledMethod;
42   static {
43     iHardwareService = getHardwareService();
44     setFlashEnabledMethod = getSetFlashEnabledMethod(iHardwareService);
45     if (iHardwareService == null) {
46       Log.i(TAG, "This device does supports control of a flashlight");
47     } else {
48       Log.i(TAG, "This device does not support control of a flashlight");
49     }
50   }
51
52   private FlashlightManager() {
53   }
54
55   private static Object getHardwareService() {
56     Class<?> serviceManagerClass = maybeForName("android.os.ServiceManager");
57     if (serviceManagerClass == null) {
58       return null;
59     }
60
61     Method getServiceMethod = maybeGetMethod(serviceManagerClass, "getService", String.class);
62     if (getServiceMethod == null) {
63       return null;
64     }
65
66     Object hardwareService = invoke(getServiceMethod, null, "hardware");
67     if (hardwareService == null) {
68       return null;
69     }
70
71     Class<?> iHardwareServiceStubClass = maybeForName("android.os.IHardwareService$Stub");
72     if (iHardwareServiceStubClass == null) {
73       return null;
74     }
75
76     Method asInterfaceMethod = maybeGetMethod(iHardwareServiceStubClass, "asInterface", IBinder.class);
77     if (asInterfaceMethod == null) {
78       return null;
79     }
80
81     return invoke(asInterfaceMethod, null, hardwareService);
82   }
83
84   private static Method getSetFlashEnabledMethod(Object iHardwareService) {
85     if (iHardwareService == null) {
86       return null;
87     }
88     Class<?> proxyClass = iHardwareService.getClass();
89     return maybeGetMethod(proxyClass, "setFlashlightEnabled", boolean.class);
90   }
91
92   private static Class<?> maybeForName(String name) {
93     try {
94       return Class.forName(name);
95     } catch (ClassNotFoundException cnfe) {
96       // OK
97       return null;
98     } catch (RuntimeException re) {
99       Log.w(TAG, "Unexpected error while finding class " + name, re);
100       return null;
101     }
102   }
103
104   private static Method maybeGetMethod(Class<?> clazz, String name, Class<?>... argClasses) {
105     try {
106       return clazz.getMethod(name, argClasses);
107     } catch (NoSuchMethodException nsme) {
108       // OK
109       return null;
110     } catch (RuntimeException re) {
111       Log.w(TAG, "Unexpected error while finding method " + name, re);
112       return null;
113     }
114   }
115
116   private static Object invoke(Method method, Object instance, Object... args) {
117     try {
118       return method.invoke(instance, args);
119     } catch (IllegalAccessException e) {
120       Log.w(TAG, "Unexpected error while invoking " + method, e);
121       return null;
122     } catch (InvocationTargetException e) {
123       Log.w(TAG, "Unexpected error while invoking " + method, e.getCause());
124       return null;
125     } catch (RuntimeException re) {
126       Log.w(TAG, "Unexpected error while invoking " + method, re);
127       return null;
128     }
129   }
130
131   static void enableFlashlight() {
132     setFlashlight(true);
133   }
134
135   static void disableFlashlight() {
136     setFlashlight(false);
137   }
138
139   private static void setFlashlight(boolean active) {
140     if (iHardwareService != null) {
141       invoke(setFlashEnabledMethod, iHardwareService, active);
142     }
143   }
144
145 }