web-dev-qa-db-ja.com

androidでカメラの懐中電灯をオン/オフにするためのウィジェット

私は携帯電話のカメラをオン/オフするためのウィジェットを開発しています。

トグルボタン(オン/オフ)のように機能するウィジェットを作成しました。

動作は次のとおりです。ウィジェットを有効にすると、LEDライトが点灯したままになることがあります。ただし、カメラのLEDのオン/オフは切り替わりませんが、アイコンは変わります。

実際の問題を把握することはできません。

アクティビティ(トーチライトアプリケーション)でも同じことがうまくいきます。

誰も私に問題を解決する方法を説明してもらえますか?

どこがおかしいの?

これまでに行った以下のコードを見ることができます

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

久しぶりに、この問題を自由に解決できました。

これが私がしたことです。

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 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で正常に動作します。

誰でもここでテストして結果を投稿できるなら、それが最善でしょう。

40
Kartik Domadiya

RemoteViewsからのクリックを処理するためのbestテクニックは、サービスを呼び出すPendingIntentを作成し、ウィジェットの追加のRemoteViews更新を含む、サービスに必要な「もの」。関連データをインテントエキストラで送信できます。サービスは最後にstopSelf()を呼び出すため、停止します。

BroadcastReceiverで状態を維持することはできません。システムは使用可能なスレッドでそれらを実行し、onReceive()を呼び出した後、インスタンスへの参照を維持しません。 mCamera変数は、BroadcastReceiverの呼び出し間で維持される保証はありません。

本当に状態を維持する必要がある場合は、サービスでそれを行う必要があり、stopSelf()を使用しないでください(適切な時間まで)。

Cameraクラスを使用するためのUIスレッドは必要ありませんが、SurfaceHolderを必要とする(およびUIを意味する)イメージプレビューを行う場合を除きます。ただし、イベントループをアクティブにする必要があります。そうでない場合、Cameraはコールバックをポストしません。これは、Cameraが主に非同期であるため問題です。これはサービス内で行うことができ(HandlerThreadを参照)、release()すべてを実行するまでサービスを実行し続けます。 Camera.open()を呼び出すスレッドは、コールバックを受け取ります。

誰もが実際にアプリウィジェットのセクションを読みましたか? http://developer.Android.com/guide/topics/appwidgets/index.html

AppWidgetProvider Classセクションを使用すると、私がここで言っていることのほとんどがわかります。

6
escape-llc

UIスレッドで特定のAndroidコードを実行する必要がある同様の状況がありました...これはアクティビティでのみ使用可能です。私のソリューション-完全に透過的なレイアウトのアクティビティです。アクションを完了する間、ホーム画面が表示されます(応答しませんが)。この場合、非常に高速です。

2
Yossi

私は素晴らしいではありませんが、動作する1つのソリューションがあります。ウィジェットにアクティビティを呼び出させ、アクティビティでフラッシュをオンにして、後でアクティビティを閉じます。同じことをオフにします。これがアクティビティで機能する場合、このソリューションは機能します。エレガントではありませんが機能します。私はそれを試してみました。

1
titusfx