在android中打开/closures相机手电筒的小工具

我正在开发一个打开/closures手机相机的部件。

我做了一个可以像切换button(开/关)的小部件。

行为如下所示:有时,当我启用小部件时,指示灯仍然亮着。 但是它不会打开/closures摄像头,但会改变图标。

我无法弄清楚什么是实际的问题。

活动(火炬灯应用程序)同样的事情工作正常。

任何人都可以请解释我怎样才能解决我的问题?

我哪里去错了?

你可以看下面我到目前为止完成的代码

onUpdate方法

 @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { //super.onUpdate(context, appWidgetManager, appWidgetIds); remoteViews = new RemoteViews( context.getPackageName(), R.layout.widgetlayout); watchWidget = new ComponentName( context, FlashLightWidget.class ); Intent intentClick = new Intent(context,FlashLightWidget.class); intentClick.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, ""+appWidgetIds[0]); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetIds[0],intentClick, 0); remoteViews.setOnClickPendingIntent(R.id.myToggleWidget, pendingIntent); appWidgetManager.updateAppWidget( watchWidget, remoteViews ); ctx=context; } 

onReceive方法如下:

 @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub remoteViews = new RemoteViews( context.getPackageName(), R.layout.widgetlayout); if (intent.getAction()==null) { Bundle extras = intent.getExtras(); if(extras!=null) { if(status) { status=false; remoteViews.setImageViewResource(R.id.myToggleWidget, R.drawable.shutdown1); processOnClick(); Toast.makeText(context,"Status==false-onclick",Toast.LENGTH_SHORT).show(); } else { status = true; remoteViews.setImageViewResource(R.id.myToggleWidget, R.drawable.shutdown2); processOffClick(); Toast.makeText(context,"Status==true--Ofclick",Toast.LENGTH_SHORT).show(); } } watchWidget = new ComponentName( context, FlashLightWidget.class ); (AppWidgetManager.getInstance(context)).updateAppWidget( watchWidget, remoteViews ); } } } 

processOffClick方法

 private void processOffClick() { if (mCamera != null) { mCamera.stopPreview(); mCamera.setPreviewCallback(null); mCamera.release(); mCamera = null; } } 

processOnClick方法

 private void processOnClick() { if(mCamera==null) { try { mCamera = Camera.open(); } catch (Exception e) { e.printStackTrace(); } } if (mCamera != null) { Parameters params = mCamera.getParameters(); List<String> flashModes = params.getSupportedFlashModes(); if (flashModes == null) { return; } else { 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 if (mCamera == null) { //Toast.makeText(ctx, "Camera not found", Toast.LENGTH_LONG).show(); return; } } 

过了很久,我可以自由地解决这个问题。

这是我做的。

FlashlightWidgetProvider类:

 public class FlashlightWidgetProvider extends AppWidgetProvider { @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { Intent receiver = new Intent(context, FlashlightWidgetReceiver.class); receiver.setAction("COM_FLASHLIGHT"); receiver.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, receiver, 0); RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout); views.setOnClickPendingIntent(R.id.button, pendingIntent); appWidgetManager.updateAppWidget(appWidgetIds, views); } } 

和FlashlightWidgetReceiver的BroadcastReceiver:

 public class FlashlightWidgetReceiver extends BroadcastReceiver { private static boolean isLightOn = false; private static Camera camera; @Override public void onReceive(Context context, Intent intent) { RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout); if(isLightOn) { views.setImageViewResource(R.id.button, R.drawable.off); } else { views.setImageViewResource(R.id.button, R.drawable.on); } AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); appWidgetManager.updateAppWidget(new ComponentName(context, FlashlightWidgetProvider.class), views); if (isLightOn) { if (camera != null) { camera.stopPreview(); camera.release(); camera = null; isLightOn = false; } } else { // Open the default ie the first rear facing camera. camera = Camera.open(); if(camera == null) { Toast.makeText(context, R.string.no_camera, Toast.LENGTH_SHORT).show(); } else { // Set the torch flash mode Parameters param = camera.getParameters(); param.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); try { camera.setParameters(param); camera.startPreview(); isLightOn = true; } catch (Exception e) { Toast.makeText(context, R.string.no_flash, Toast.LENGTH_SHORT).show(); } } } } } 

Manifest.xml文件中需要的权限:

 <uses-permission android:name="android.permission.CAMERA"></uses-permission> 

还要在Manifest.xml文件中注册接收者:

 <receiver android:name=".FlashlightWidgetProvider" android:icon="@drawable/on" android:label="@string/app_name"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/flashlight_appwidget_info" /> </receiver> <receiver android:name="FlashlightWidgetReceiver"> <intent-filter> <action android:name="COM_FLASHLIGHT"></action> </intent-filter> </receiver> 

重要说明 :如果您的手机支持FLASH_MODE_TORCH则此代码可以正常工作。

我已经在三星Galaxy Ace 2.2.1和2.3.3testing。 代码不工作,因为该设备没有FLASH_MODE_TORCH。

在HTC Salsa,Wildfire中工作正常

如果任何人都可以在这里testing和发布结果,那将是最好的。

处理来自RemoteViews点击的最佳方法是创build一个调用服务的PendingIntent ,并在服务中执行所需的“东西”,包括您的小部件的任何其他RemoteViews更新。 您可以发送意向演员的相关数据。 该服务最后调用stopSelf() ,因此它closures。

您无法在BroadcastReceiver维护任何状态; 系统在任何可用线程上运行这些线程,并在调用onReceive()之后不维护对您的实例的任何引用。 您的mCameravariables不保证在您的BroadcastReceiver调用之间维护。

如果您确实需要维护状态,则必须在服务中执行此操作,而不要使用stopSelf() (直到适当的时间)。

你不需要UI线程来使用Camera类,除非你正在做图像预览,这需要一个SurfaceHolder (并且暗示一个UI)。 但是,必须启用事件循环,否则Camera将不会向您发送callback,这是一个问题,因为Camera主要是asynchronous的。 你可以在一个服务(见HandlerThread )中做到这一点,并保持你的服务运行,直到release()一切。 无论哪个线程调用Camera.open()都会收到callback。

大家是否真的阅读过应用程序小部件? http://developer.android.com/guide/topics/appwidgets/index.html

使用AppWidgetProvider类部分几乎说明了我在这里说的。

我有一个类似的情况,我需要在UI线程上运行某些android代码…只有在一个活动中可用。 我的解决scheme – 一个完全透明布局的活动。 所以,当你完成你的行动时,你只需看到你的主屏幕(虽然没有响应),在你的情况下,这应该是非常快的。

我有一个解决scheme不是很好,但工作。 让小部件调用一个Activity,然后在Activity中打开Flash,然后closuresActivity。 同样的把它关掉。 如果这在“活动”中起作用,则此解决scheme将起作用。 这不是优雅,但工程。 我尝试过这个。