Виджет для включения / выключения фонарика камеры в Android - PullRequest
37 голосов
/ 22 сентября 2011

Я разрабатываю виджет для включения / выключения светодиодов камеры телефона.

Я создал виджет, который может работать как кнопка переключения (вкл / выкл).

Поведение похоже наследует: Иногда светодиодный индикатор остается включенным, когда я включаю виджет.Но он не включает и не выключает светодиод камеры, а меняет значок.

Я не могу понять, в чем реальная проблема.

То же самое отлично работает в Activity (Torch LightПриложение).

Может кто-нибудь объяснить, пожалуйста, как я могу решить мою проблему?

Где я иду не так?

Вы можете посмотреть код ниже, что я сделал до сих пор

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

Ответы [ 4 ]

40 голосов
/ 24 ноября 2011

Спустя долгое время я смог решить эту проблему.

Вот что я сделал.

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

        }
}

и BroadcastReceiver для 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();
                                    }
                            }
                    }
            }
    }

Требуется разрешение в 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.

Я тестировал в Samsung Galaxy Ace 2.2.1 и 2.3.3. Код не работает, потому что это устройство не имеет FLASH_MODE_TORCH.

Отлично работает в HTC Salsa, Wildfire ..

Если кто-то может проверить и опубликовать результаты здесь, было бы лучше.

6 голосов
/ 12 октября 2011

Метод лучший для обработки кликов с RemoteViews заключается в создании PendingIntent, который вызывает службу, и выполнении "необходимых" действий в службе, включая любые дополнительные RemoteViews обновления для вашего виджета. Вы можете отправить соответствующие данные в намерениях дополнений. Служба вызывает stopSelf() в конце, поэтому она отключается.

Вы не можете поддерживать любое состояние в BroadcastReceiver; система запускает их в любом доступном потоке и не сохраняет никаких ссылок на ваш экземпляр после вызова onReceive(). Не гарантируется, что ваша переменная mCamera будет поддерживаться между вызовами вашего BroadcastReceiver.

Если вам действительно нужно поддерживать состояние, вы должны сделать это в службе и не использовать stopSelf() (до соответствующего времени).

Вам не нужен поток пользовательского интерфейса для использования класса Camera, если только вы не делаете предварительный просмотр изображения, для которого требуется SurfaceHolder (и подразумевает пользовательский интерфейс). Однако вы должны иметь активный цикл обработки событий, иначе Camera не будет отправлять вам обратные вызовы, что является проблемой, поскольку Camera в основном асинхронный. Вы можете сделать это в службе (см. HandlerThread) и поддерживать работу службы до тех пор, пока не наступит время release(). Какой бы поток не вызывал Camera.open(), он будет получать обратные вызовы.

Все ли читали раздел по виджетам приложений? http://developer.android.com/guide/topics/appwidgets/index.html

Использование класса AppWidgetProvider * Раздел 1031 * говорит о том, что я здесь говорю.

2 голосов
/ 12 октября 2011

У меня была похожая ситуация, когда мне нужно запустить определенный код Android в потоке пользовательского интерфейса ... который доступен только в Activity. Мое решение - деятельность с полностью прозрачным макетом. Таким образом, вы просто видите домашний экран (хотя и не отвечает), пока выполняете свои действия, что в вашем случае должно быть довольно быстрым.

1 голос
/ 06 октября 2011

У меня есть одно решение, которое не очень хорошо, но работает. Пусть виджет вызовет действие, а в действии включите вспышку, а затем закройте действие. То же самое, чтобы выключить его. Если это работает в Деятельности, тогда это решение будет работать. Это не элегантно, но работает. Я попробовал это.

...