Widget para encender / apagar la linterna de la cámara en android

Estoy desarrollando un widget para encender / apagar cámara led de teléfono.

He hecho un widget que puede funcionar como botón de conmutación (encendido / apagado).

El comportamiento es como sigue: A veces la luz led permanece encendida cuando habilito el widget. Pero no enciende / apaga la cámara, pero cambia el icono.

No soy capaz de averiguar cuál es el problema real.

Lo mismo funciona bien en Actividad (Torch Light Application).

¿Puede alguien por favor explicarme cómo puedo resolver mi problema?

¿A dónde voy mal?

Usted puede mirar el código abajo que he hecho hasta ahora

Método 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 es el siguiente:

 @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 ); } } } 

Método processOffClick

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

Método 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; } } 

Después de mucho tiempo, tuve libertad para resolver este problema.

Esto es lo que hice.

Clase 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); } } 

Y BroadcastReceiver para FlashlightWidgetReceiver:

 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(); } } } } } 

Permiso requerido en el archivo Manifest.xml :

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

También registre los receptores en el archivo 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> 

Nota importante : este código funciona perfecto si su teléfono tiene FLASH_MODE_TORCH soportado.

He probado en Samsung Galaxy Ace 2.2.1 y 2.3.3. El código no funciona porque ese dispositivo no tiene FLASH_MODE_TORCH.

Funciona bien en HTC Salsa, Wildfire ..

Si alguien puede probar y publicar resultados aquí, sería mejor.

La mejor técnica para manejar los clics desde una RemoteViews es crear una PendingIntent que llama a un servicio y realizar las "cosas" que desea en el servicio, incluyendo cualquier actualización de RemoteViews adicional para su widget. Puede enviar a lo largo de los datos pertinentes en los extras de la intención. El servicio llama a stopSelf() al final, por lo que se apaga.

No puede mantener ningún estado en un BroadcastReceiver ; El sistema los ejecuta en cualquier subproceso disponible y no mantiene ninguna referencia a su instancia después de llamar a onReceive() . No se garantiza que su variable mCamera se mantenga entre las invocaciones de su BroadcastReceiver .

Si realmente necesita mantener el estado, debe hacerlo en el servicio, y no use stopSelf() (hasta un momento apropiado).

No necesitas un subproceso de interfaz de usuario para usar la clase Camera , a menos que estés haciendo previsualización de imágenes, lo que requiere un SurfaceHolder (e implica una UI). Debe, sin embargo, tener un bucle de eventos activo o la Camera no publicará devoluciones de llamada, lo cual es un problema ya que la Camera es básicamente asíncrona. Puede hacerlo dentro de un servicio (ver HandlerThread ) y mantener su servicio funcionando hasta que sea el momento de release() todo. Cualquiera que sea el hilo llamado Camera.open() recibirá devoluciones de llamada.

¿Todos leen la sección de Widgets de aplicaciones? http://developer.android.com/guide/topics/appwidgets/index.html

Usar la sección de la clase AppWidgetProvider dice prácticamente lo que estoy diciendo aquí.

Tuve una situación similar en la que necesito ejecutar cierto código de android en el hilo de interfaz de usuario … que sólo está disponible en una actividad. Mi solución – una actividad con un diseño completamente transparente. Así que acaba de ver su pantalla de inicio (aunque no responde) mientras completa sus acciones, que en su caso debe ser bastante rápido.

Tengo una solución que no es grande, pero funciona. Haga que el widget llame a una Actividad y, en Actividad, active el flash y cierre la Actividad. Lo mismo para apagarlo. Si esto funciona en la actividad entonces esta solución funcionará. No es elegante, pero funciona. Lo intenté.

  • Android equivalente de UIWebView en Xcode
  • Buscar ID de widget de la pantalla de inicio
  • El widget desaparece cada vez que se actualiza la aplicación en dispositivos Samsung
  • Los botones del widget Android dejan de funcionar
  • ¿Cómo iniciar una nueva actividad desde lockscreen?
  • Cómo agregar widgets múltiples en una aplicación?
  • ¿Cómo editar / cambiar la vista desde el diseño en RemoteView o crear RemoteView desde la vista?
  • ¿Cómo puedo crear un widget de aplicación de paginación de Android compatible con versiones anteriores?
  • Widget del visor de PDF en Android
  • ¿Cómo crear una imagen de fondo nítida para 1x1 widget Android?
  • Android widget ¿cómo puede obtener el tiempo en hora y minuto de esto?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.