本次项目,遇到索尼手机无法使用手电筒的问题,但是HTC等用官方的方法可以搞定,经过调查发现,谷歌这小子把API隐藏了,于是乎想起了搞web时使用的反射,但是android的不能直接反射出private的常量和方法,因为andorid貌似把Class.java这个东西重新搞了,其实JDK里面是有这个方法的,需要
Class clazz=Class.forName("android.os.IHardwareService");
clazz.getClass().getDeclaredFields();
这样才能拿到,下面是手电筒的解决方法:
首先是一个管理类:
public final class FlashlightManager {
private static final String TAG = FlashlightManager.class.getSimpleName();
private static final Object iHardwareService;
private static final Method setFlashEnabledMethod;
private static final Method getFlashEnabledMethod;
/**
* Use Static Intialize Object,Setting HardwareService Manager Object and
* flash method.
*/
static {
iHardwareService = getHardwareService();
setFlashEnabledMethod = getMethod("setFlashlightEnabled", iHardwareService, boolean.class);
getFlashEnabledMethod = getMethod("getFlashlightEnabled", iHardwareService, null); //here must set null
if (iHardwareService == null) {
Log.v(TAG, "This device does supports control of a flashlight");
} else {
Log.v(TAG, "This device does not support control of a flashlight");
}
}
/**
* Get Hardware Service
*
* @return
*/
private static Object getHardwareService() {
// Use reflect get system service mamger object
Class<?> serviceManagerClass = maybeForName("android.os.ServiceManager");
if (serviceManagerClass == null) {
return null;
}
// Get getService function method object
Method getServiceMethod = maybeGetMethod(serviceManagerClass, "getService", String.class);
if (getServiceMethod == null) {
return null;
}
Object hardwareService = invoke(getServiceMethod, null, "hardware");
if (hardwareService == null) {
return null;
}
Class<?> iHardwareServiceStubClass = maybeForName("android.os.IHardwareService$Stub");
if (iHardwareServiceStubClass == null) {
return null;
}
Method asInterfaceMethod = maybeGetMethod(iHardwareServiceStubClass, "asInterface", IBinder.class);
if (asInterfaceMethod == null) {
return null;
}
return invoke(asInterfaceMethod, null, hardwareService);
}
/**
* Use reflect
*
* @param methodName
* @param iHardwareService
* @param argClasses
* @return
*/
private static Method getMethod(String methodName, Object iHardwareService, Class<?>... argClasses) {
if (iHardwareService == null) {
return null;
}
Class<?> proxyClass = iHardwareService.getClass();
// test
Method[] methods = proxyClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Log.i("method---", methods[i].getName());
}
return maybeGetMethod(proxyClass, methodName, argClasses);
}
private static Class<?> maybeForName(String name) {
try {
return Class.forName(name);
} catch (ClassNotFoundException cnfe) {
// OK
return null;
} catch (RuntimeException re) {
Log.w(TAG, "Unexpected error while finding class " + name, re);
return null;
}
}
private static Method maybeGetMethod(Class<?> clazz, String name, Class<?>... argClasses) {
try {
return clazz.getMethod(name, argClasses);
} catch (NoSuchMethodException nsme) {
// OK
return null;
} catch (RuntimeException re) {
Log.w(TAG, "Unexpected error while finding method " + name, re);
return null;
}
}
private static Object invoke(Method method, Object instance, Object... args) {
try {
return method.invoke(instance, args);
} catch (IllegalAccessException e) {
Log.w(TAG, "Unexpected error while invoking " + method, e);
return null;
} catch (InvocationTargetException e) {
Log.w(TAG, "Unexpected error while invoking " + method, e.getCause());
return null;
} catch (RuntimeException re) {
Log.w(TAG, "Unexpected error while invoking " + method, re);
return null;
}
}
public static void enableFlashlight(Camera camera) {
setFlashlight(camera, true);
}
public static void disableFlashlight(Camera camera) {
setFlashlight(camera, false);
}
/**
* Set Flahlight if activate
*
* @param camera
* @param active
*/
private static void setFlashlight(Camera camera, boolean active) {
if (iHardwareService != null && setFlashEnabledMethod != null && getFlashEnabledMethod != null) {
try {
setFlashEnabledMethod.invoke(iHardwareService, active);
Boolean enabled = (Boolean) getFlashEnabledMethod.invoke(iHardwareService, (Object[]) null);
if (active && !enabled) setFlashlightConventional(camera, active);
} catch (Exception e) {
setFlashlightConventional(camera, active);
}
} else {
setFlashlightConventional(camera, active);
}
}
private static void setFlashlightConventional(Camera camera, boolean active) {
Parameters p = camera.getParameters();
// Set
if (active)
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
else
p.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(p);
}
}
然后是具体调用方法:
private boolean isOpen;
private void flashLightoOpenOrClose(){
//Get System Camera
if(camera==null)camera=Camera.open();
isOpen=!isOpen;
if(isOpen){
FlashlightManager.enableFlashlight(camera);
}else{
FlashlightManager.disableFlashlight(camera);
}
}
今天生日,搞定了这么大个难题,实在爽.