2011-03-31 98 views
53

我正在尝试在相关部件中使用相机LED手电筒。我发现几个线程关于这个主题(即the one后面提到..),现在我尝试使用,以控制光:在Android中使用相机手电筒

Camera cam = Camera.open();  
Parameters p = cam.getParameters(); 
p.setFlashMode(Parameters.FLASH_MODE_TORCH); 
cam.setParameters(p); 
cam.release(); 

在AndroidManifest.xml中尝试了不同的权限,目前我有:

<uses-permission android:name="android.permission.CAMERA" /> 
<uses-permission android:name="android.permission.FLASHLIGHT"/> 
<uses-feature android:name="android.hardware.camera" /> 
<uses-feature android:name="android.hardware.camera.autofocus" /> 
<uses-feature android:name="android.hardware.camera.flash" /> 

我在我的Galaxy Tab上测试这个,因为我手边没有任何其他Android设备:灯不亮。所以我现在有几个问题:

  1. 是否有任何方法来测试模拟器中的指示灯行为?
  2. 我在这里做错了什么?
  3. 根据this问题处理同样的问题,它在Galaxy Tab上的工作方式不同。怎么样?
  4. 最后,如果它的工作方式不同,我开始怀疑它是否仅仅是Galaxy Tab或其他设备是否也使用不同的方法。这将是很难测试,这似乎对我来说很奇怪。

感谢您的任何见解!

顺便说一句,我很快测试了quick-settings,这里提到几次。手电筒也不适用于快速设置。

请注意Galaxy Tab stil使用的是android 2.2。我发现2.2和2.3之间有一些变化。

评论: 我知道它必须以某种方式工作,因为我发现市场上的其他应用程序与Galaxy Tab完美配合。

评论2: 如果我设置cam.setParameters(p);并直接通过getFlashMode()向摄像机询问当前状态,正确返回FLASH_MODE_TORCH。但是,如果我释放相机并重新打开它,它将返回FLASH_MODE_OFF。就好像Camera对象知道请求但并没有真正传递给硬件!

-

Konstantins评论之后,我删除了cam.release();部分。他是对的,如果您释放相机,设置不会持续。如果你再次使用cam.open(),你会得到一个关闭灯光的新实例。尽管如此,光仍然不能在星系标签上工作。 所以,如果你试图通过一个小部件来控制它,我想这很难保持清晰。一旦后台服务完成,相机对象将自动释放,因此指示灯会再次关闭。我的问题依然存在,特别是为什么相机无法在第一时间开机。

+0

即使我想知道如何做到这一点。 Upvoted! – CuriousMind 2011-04-02 20:46:37

+0

我也没有任何想法,但如果你找不到解决方案,你可以从市场上下载一个手电筒应用程序,并尝试反编译它。 – RoflcoptrException 2011-04-02 20:51:04

+3

那么,在我开始逆向工程someones代码之前,我真的很想从编码器的更多洞察力在stackoverflow ;-) – pgruetter 2011-04-02 20:53:43

回答

34

每个设备是一个有点不同。三星特别喜欢让应用程序开发人员变得更加复杂。

在Galaxy Tab的你应该是不错的搭配:

Camera cam; 
void ledon() { 
    cam = Camera.open();  
    Parameters params = cam.getParameters(); 
    params.setFlashMode(Parameters.FLASH_MODE_ON); 
    cam.setParameters(params); 
    cam.startPreview(); 
    cam.autoFocus(new AutoFocusCallback() { 
       public void onAutoFocus(boolean success, Camera camera) { 
       } 
      }); 
} 

void ledoff() { 
    cam.stopPreview(); 
    cam.release(); 
} 

如果不工作,那么它可能是最初设置FLASH_MODE_OFF和startPreview后改变它的问题。

+0

非常感谢细节。快速测试没有显示任何成功。将尝试在一个单一的活动,以确保没有任何干扰。你能告诉我,你从哪里得到这些信息?你有没有在Galaxy Tab上尝试过它? – pgruetter 2011-04-08 06:15:02

+1

是的。我是TeslaLED的开发人员,实际上需要Tab的更新,我还没有机会发布,但是我做了类似以上的测试,并在T-Mobile Galaxy Tab上进行了测试。我确实从FLASH_MODE_OFF开始,然后切换到FLASH_MODE_ON。 – 2011-04-09 05:26:22

+0

@Kevin TeslaCoil:我面临同样的问题,但你的代码在三星Galaxy Ace 2.2.1中为我工作。但LED仅保持5秒的ON状态。可以这样做的原因是什么? – 2011-08-02 06:25:04

18

设置参数后,您不能松开相机。我发现在开始预览之后闪光灯被激活(在手电筒模式下)。 (适用于摩托罗拉defy,2.1)

在尝试激活它们之前,检查支持的闪光模式也是一个好主意。

在android上用摄像头设置搞乱是最黑暗的巫术:许多设备的行为不同,并且似乎没有可靠的方式将它们全部用一段代码进行定位。最安全的方法是在您的onResume()方法被调用时始终正确设置您的相机。我也会考虑在 onConfigChange()中做同样的事情,因为至少摩托罗拉屏幕锁可以强制你的应用程序进入肖像模式,完全重新启动它。

P.s.我想,当你关闭相机时,本机相机应用程序关闭,然后重新创建一个新的状态。

+0

很多好的建议,谢谢!在不释放相机实例的情况下,我现在可以询问属性,并且它再次正确返回手电筒模式,非常棒。但是,即使使用预览,手电筒仍不会开启。事情是,我试图通过一个小部件打开LED灯。这将很难基于您的意见,因为只要灯应该保持亮着,我需要握住相机对象。 – pgruetter 2011-04-04 17:39:32

+0

我在我的小型OCR应用程序中玩过火炬,发现只有当我开始预览时闪光灯才会闪光(当我要求快照时闪光灯熄灭,从而产生黑色图像)。我在JavaOCR项目中开发了小型的android演示程序 - 随时可以从中获得灵感:http://sourceforge.net/projects/javaocr/ – 2011-04-05 05:54:08

+0

太棒了!非常感谢链接。我会看看它。 – pgruetter 2011-04-05 06:07:41

8

这对我的作品上的HTC Desire ...(2.2) (当然用照相机和手电筒的权限):

Camera mycam = Camera.open(); 
    Parameters p = mycam.getParameters();// = mycam.getParameters(); 
    p.setFlashMode(Parameters.FLASH_MODE_TORCH); 
    mycam.setParameters(p); //time passes 
    try { 
     Thread.sleep(500); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    p.setFlashMode(Parameters.FLASH_MODE_OFF); 
    mycam.release(); 
+0

你在试用这款Android设备?谢谢! – pgruetter 2011-04-05 14:16:15

+0

@Horaceman无法在三星Galaxy SII上工作 - 你错过了任何机会吗?如展示预览? – AgentKnopf 2012-12-18 11:19:25

4

您也可以尝试添加表面视图。请看看我的回答LED flashlight on Galaxy Nexus controllable by what API?

+0

我试过三星Galaxy SII它没有工作。更简单的方法在其他手机上工作(注意,Xperia S),这是一个痛苦:P ... – AgentKnopf 2013-01-02 07:48:38

+0

对我来说它在SII上工作,你的表面视图是否可见? – timoschloesser 2013-01-02 11:26:57

+0

是的。我尝试了所有可能的变化。事情是:它在其他手机(也是你的样本)上工作,但不在该SII上(至少不是我在这里的那个)。奇怪的是:我们也在适当的相机对话框中将相机用于其他目的。如果我运行该手电筒代码,然后启动相机对话框,手电筒确实显示。首先,我认为是因为SurfaceView,但是因为我尝试过,并且它不起作用,可能它是其他的东西。我觉得很可怕,没有简单,统一的方式让手电筒在所有支持手电的设备上工作。 – AgentKnopf 2013-01-02 11:59:24

1
private Camera camera; 
void openCam(){ 
    camera = Camera.open(); 
    if (camera != null) { 
     Camera.Parameters params = camera.getParameters(); 
     camera.setParameters(params); 
    } 
    Camera.Parameters p = camera.getParameters(); 
    p.setFlashMode(Parameters.FLASH_MODE_TORCH); 
    camera.setParameters(p); 
} 

设置权限在清单

<uses-permission 
    android:name="android.permission.FLASHLIGHT" 
    android:permissionGroup="android.permission-group.HARDWARE_CONTROLS" 
    android:protectionLevel="normal" /> 

<uses-feature android:name="android.hardware.camera" /> 
<uses-feature android:name="android.hardware.camera.flash" /> 
11

我已经做了以下的方式,这在许多手机的工作原理:

String manuName = android.os.Build.MANUFACTURER.toLowerCase(); 
Camera mCamera; 

以下代码显示如何关闭和打开灯光:

private void processOnClick() { 

    if (manuName.contains("motorola")) { 
     DroidLED led; 
     try { 
      led = new DroidLED(); 
      led.enable(true); 
     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } else { 
     if (mCamera == null) { 
      try { 
       mCamera = Camera.open(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 

     if (mCamera != null) { 

      final Parameters params = mCamera.getParameters(); 

      List<String> flashModes = params.getSupportedFlashModes(); 

      if (flashModes == null) { 
       return; 
      } else { 
       if (count == 0) { 
        params.setFlashMode(Parameters.FLASH_MODE_OFF); 
        mCamera.setParameters(params); 
        mCamera.startPreview(); 
       } 

       String flashMode = params.getFlashMode(); 

       if (!Parameters.FLASH_MODE_TORCH.equals(flashMode)) { 

        if (flashModes.contains(Parameters.FLASH_MODE_TORCH)) { 
         params.setFlashMode(Parameters.FLASH_MODE_TORCH); 
         mCamera.setParameters(params); 
        } else { 
         // Toast.makeText(this, 
         // "Flash mode (torch) not supported",Toast.LENGTH_LONG).show(); 

         params.setFlashMode(Parameters.FLASH_MODE_ON); 

         mCamera.setParameters(params); 
         try { 
          mCamera.autoFocus(new AutoFocusCallback() { 
           public void onAutoFocus(boolean success, Camera camera) { 
            count = 1; 
           } 
          }); 
         } catch (Exception e) { 
          e.printStackTrace(); 
         } 
        } 
       } 
      } 
     } 
    } 

    if (mCamera == null) { 
     return; 
    } 
} 

private void processOffClick() { 

    if (manuName.contains("motorola")) { 
     DroidLED led; 
     try { 
      led = new DroidLED(); 
      led.enable(false); 
     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } else { 
     if (mCamera != null) { 
      count = 0; 
      mCamera.stopPreview(); 
     } 
    } 
} 

下面是类DroidLED:

class DroidLED { 

    private Object svc = null; 
    private Method getFlashlightEnabled = null; 
    private Method setFlashlightEnabled = null; 

    @SuppressWarnings("unchecked") 
    public DroidLED() throws Exception { 
      try { 
        // call ServiceManager.getService("hardware") to get an IBinder for the service. 
        // this appears to be totally undocumented and not exposed in the SDK whatsoever. 
        Class sm = Class.forName("android.os.ServiceManager"); 
        Object hwBinder = sm.getMethod("getService", String.class).invoke(null, "hardware"); 

        // get the hardware service stub. this seems to just get us one step closer to the proxy 
        Class hwsstub = Class.forName("android.os.IHardwareService$Stub"); 
        Method asInterface = hwsstub.getMethod("asInterface", android.os.IBinder.class); 
        svc = asInterface.invoke(null, (IBinder) hwBinder); 

        // grab the class (android.os.IHardwareService$Stub$Proxy) so we can reflect on its methods 
        Class proxy = svc.getClass(); 

        // save methods 
        getFlashlightEnabled = proxy.getMethod("getFlashlightEnabled"); 
        setFlashlightEnabled = proxy.getMethod("setFlashlightEnabled", boolean.class); 
      } 
      catch(Exception e) { 
        throw new Exception("LED could not be initialized"); 
      } 
    } 

    public boolean isEnabled() { 
      try { 
        return getFlashlightEnabled.invoke(svc).equals(true); 
      } 
      catch(Exception e) { 
        return false; 
      } 
    } 

    public void enable(boolean tf) { 
      try { 
        setFlashlightEnabled.invoke(svc, tf); 
      } 
      catch(Exception e) {} 
    } 

}

以下权限必须在AndroidManifest.xml中设定:

<uses-permission android:name="android.permission.CAMERA" /> 
<uses-permission android:name="android.permission.FLASHLIGHT"/> 
<uses-feature android:name="android.hardware.camera" /> 
<uses-feature android:name="android.hardware.camera.autofocus" /> 
<uses-feature android:name="android.hardware.camera.flash" /> 
+4

没有尝试过这种方法:如果你使用反射,那么你的代码迟早会崩溃。 – AgentKnopf 2013-01-02 07:47:26

+0

来自:https://code.google.com/p/droidled/source/browse/trunk/src/com/droidled/demo/DroidLED.java – hB0 2013-08-05 22:46:54

+0

与所有Reflection解决方案一样,这不是一个面向未来的解决方案。迟早Google会关闭这个大洞,像这样的反射方法根本行不通。 – ChuongPham 2014-07-30 13:38:03