web-dev-qa-db-fra.com

Widget pour allumer / éteindre la lampe de poche de l'appareil photo en android

Je développe un widget pour allumer/éteindre la caméra led du téléphone.

J'ai créé un widget qui peut fonctionner comme un bouton à bascule (marche/arrêt).

Le comportement est le suivant: Parfois, la lumière LED reste allumée lorsque j'active le widget. Mais cela ne permet pas d'allumer/d'éteindre la LED de la caméra mais cela change l'icône.

Je ne suis pas en mesure de comprendre quel est le problème réel.

La même chose fonctionne très bien dans l'activité (Torch Light Application).

Quelqu'un peut-il m'expliquer comment résoudre mon problème?

Où je vais mal?

Vous pouvez regarder le code ci-dessous que j'ai fait jusqu'à présent

onUpdate méthode

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

La méthode onReceive est la suivante:

@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 méthode

private void processOffClick() {

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

processOnClick méthode

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;
    }
}
37
Kartik Domadiya

Après un long moment, je me suis libéré pour résoudre ce problème.

Voici ce que j'ai fait.

FlashlightWidgetProvider classe:

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

        }
}

et BroadcastReceiver pour 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 i.e. 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();
                                    }
                            }
                    }
            }
    }

Autorisation requise dans Manifest.xml fichier :

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

Enregistrez également les récepteurs dans Manifest.xml fichier :

<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>

Note importante: Ce code fonctionne parfaitement si votre téléphone a FLASH_MODE_TORCH prise en charge.

J'ai testé dans Samsung Galaxy Ace 2.2.1 & 2.3.3. Le code ne fonctionne pas car ce périphérique n'a pas de FLASH_MODE_TORCH.

Fonctionne bien dans HTC Salsa, Wildfire ..

Si quelqu'un peut tester et publier les résultats ici, ce serait mieux.

40
Kartik Domadiya

La meilleure technique pour gérer les clics à partir d'un RemoteViews consiste à créer un PendingIntent qui appelle un service et à exécuter la "trucs" que vous voulez dans le service, y compris toutes les mises à jour RemoteViews supplémentaires pour votre widget. Vous pouvez envoyer les données pertinentes dans les extras d'intention. Le service appelle stopSelf() à la fin, donc il s'arrête.

Vous ne pouvez conserver aucun état dans un BroadcastReceiver; le système les exécute sur n'importe quel thread disponible et ne conserve aucune référence à votre instance après avoir appelé onReceive(). Votre variable mCamera n'est pas garantie d'être maintenue entre les appels de votre BroadcastReceiver.

Si vous avez vraiment besoin de maintenir l'état, vous devez le faire dans le service et ne pas utiliser stopSelf() (jusqu'à un moment approprié).

Vous n'avez pas besoin d'un thread d'interface utilisateur pour utiliser la classe Camera, sauf si vous effectuez un aperçu d'image, qui nécessite un SurfaceHolder (et implique une interface utilisateur). Vous devez cependant avoir une boucle d'événements active, sinon Camera ne vous enverra pas de rappels, ce qui est un problème car Camera est principalement asynchrone. Vous pouvez le faire dans un service (voir HandlerThread) et maintenir votre service en marche jusqu'à ce qu'il soit temps de release() tout. Quel que soit le thread qui appelle Camera.open() recevra des rappels.

Est-ce que tout le monde a lu la section sur les widgets d'application? http://developer.Android.com/guide/topics/appwidgets/index.html

L'utilisation de la section AppWidgetProvider Class dit à peu près ce que je dis ici.

6
escape-llc

J'ai eu une situation similaire où je dois exécuter certains Android sur le thread d'interface utilisateur ... qui n'est disponible que dans une activité. Ma solution - une activité avec une mise en page complètement transparente. Donc vous il suffit de voir votre écran d'accueil (bien qu'il ne réponde pas) pendant que vous terminez vos actions, ce qui dans votre cas devrait être assez rapide.

2
Yossi

J'ai une solution qui n'est pas géniale mais qui fonctionne. Demandez au widget d'appeler une activité et, dans l'activité, activez le flash, puis fermez l'activité. La même chose pour l'éteindre. Si cela fonctionne dans l'activité, cette solution fonctionnera. Ce n'est pas élégant mais ça marche. Je l'ai essayé.

1
titusfx