私は携帯電話のカメラをオン/オフするためのウィジェットを開発しています。
トグルボタン(オン/オフ)のように機能するウィジェットを作成しました。
動作は次のとおりです。ウィジェットを有効にすると、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;
}
}
久しぶりに、この問題を自由に解決できました。
これが私がしたことです。
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で正常に動作します。
誰でもここでテストして結果を投稿できるなら、それが最善でしょう。
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セクションを使用すると、私がここで言っていることのほとんどがわかります。
UIスレッドで特定のAndroidコードを実行する必要がある同様の状況がありました...これはアクティビティでのみ使用可能です。私のソリューション-完全に透過的なレイアウトのアクティビティです。アクションを完了する間、ホーム画面が表示されます(応答しませんが)。この場合、非常に高速です。
私は素晴らしいではありませんが、動作する1つのソリューションがあります。ウィジェットにアクティビティを呼び出させ、アクティビティでフラッシュをオンにして、後でアクティビティを閉じます。同じことをオフにします。これがアクティビティで機能する場合、このソリューションは機能します。エレガントではありませんが機能します。私はそれを試してみました。