Widget do włączania / wyłączania latarki aparatu w Androidzie

Rozwijam widget do włączania / wyłączania diody LED aparatu w telefonie.

Zrobiłem widget, który może działać jak przycisk przełączania (on / off).

Zachowanie wygląda następująco: czasami dioda led pozostaje włączona, gdy włączam widżet. Ale nie włącza/wyłącza diody LED aparatu, ale zmienia ikonę.

Nie jestem w stanie rozgryźć, w czym tkwi problem.

To samo działa dobrze w aktywności (Zastosowanie światła latarki).

Czy ktoś może mi wyjaśnić Jak mogę rozwiązać mój problem ?

Gdzie idę źle ?

Możesz spojrzeć na poniższy kod, który zrobiłem do tej pory

onUpdate metoda

@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 metoda jest następująca:

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

private void processOffClick() {

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

processOnClick metoda

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;
    }
}
Author: Kartik Domadiya, 2011-09-22

4 answers

Po długim czasie, dostałem wolny, aby rozwiązać ten problem.

Oto, co zrobiłem.

FlashlightWidgetProvider klasa:

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

        }
}

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

Wymagane pozwolenie w pliku Manifest.xml:

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

Rejestruj również odbiorniki w pliku 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>

Ważna uwaga : ten kod działa idealnie, jeśli twój telefon ma FLASH_MODE_TORCH obsługiwane.

Testowałem w Samsung Galaxy Ace 2.2.1 i 2.3.3. Kod nie działa ponieważ to urządzenie nie ma FLASH_MODE_TORCH.

Działa dobrze w HTC Salsa, Wildfire..

Jeśli ktoś może przetestować i zamieścić wyniki tutaj, byłoby najlepiej.

 40
Author: Kartik Domadiya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-31 08:28:42

Najlepszą techniką obsługi kliknięć z RemoteViews jest utworzenie PendingIntent, który wywołuje usługę i wykonuje "rzeczy", które chcesz w usłudze, w tym wszelkie dodatkowe aktualizacje RemoteViews dla widżetu. Możesz wysłać odpowiednie dane w dodatkach intent. Usługa wywołuje stopSelf() na końcu, więc się wyłącza.

Nie możesz utrzymać żadnego stanu w BroadcastReceiver; system uruchamia je w dowolnym dostępnym wątku i nie zachowuje żadnego odniesienia do Twojej instancji po wywołanie onReceive(). Twoja mCamera zmienna nie jest gwarantowana, aby była utrzymywana pomiędzy wywołaniami Twojej BroadcastReceiver.

Jeśli naprawdę chcesz zachować stan, musisz to zrobić w usłudze i nie używać stopSelf() (do odpowiedniego czasu).

Nie potrzebujesz wątku UI, aby używać klasy Camera, chyba że robisz podgląd obrazu, który wymaga SurfaceHolder (i implikuje UI). Musisz jednak mieć aktywną pętlę zdarzeń lub Camera nie będzie publikować wywołań zwrotnych, co jest problemem, ponieważ Camera jest przede wszystkim asynchroniczny. Możesz to zrobić w ramach usługi (zobacz HandlerThread) i utrzymuj swoją usługę, dopóki nie nadejdzie czas na release() Wszystko. Wszystkie wywołania wątku Camera.open() otrzymają wywołania zwrotne.

Czy wszyscy czytali sekcję o widżetach aplikacji? http://developer.android.com/guide/topics/appwidgets/index.html

Korzystanie z sekcji AppWidgetProvider Class mówi prawie to, co mówię tutaj.

 6
Author: escape-llc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-25 16:48:35

Miałem podobną sytuację, w której muszę uruchomić pewien kod Androida w wątku UI ... który jest dostępny tylko w aktywności. Moje rozwiązanie-działanie z całkowicie przejrzystym układem. Więc po prostu widzisz ekran główny (choć nie reaguje) podczas wykonywania czynności, które w Twoim przypadku powinny być dość szybkie.

 2
Author: Yossi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-12 02:47:43

Mam jedno rozwiązanie, które nie jest świetne, ale działa. Niech widżet wywoła aktywność, a w aktywności włącz lampę błyskową, a później ją zamknij. To samo, aby go wyłączyć. Jeśli to zadziała w działaniu, to To rozwiązanie zadziała. Nie jest elegancki, ale działa. Próbowałem.

 1
Author: titusfx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-10 06:00:09