I am developing a widget for turning on/off camera led of phone.
I have made a widget that can work like toggle button (on/off).
Behavior is like follows : Sometimes the led light remains on when i enable the widget. But it doesnot turn on/off the camera led but it changes the icon.
I am not able to figure out whats the actual problem.
The same thing works fine in Activity (Torch Light Application).
Can anyone please explain me how can i solve my problem ?
Where i am going wrong ?
You can look at the code below that i have done so far
onUpdate
method
@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
method is as follows :
@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
method
private void processOffClick() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
processOnClick
method
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;
}
}
The best technique for handling clicks from a
RemoteViews
is to create aPendingIntent
that calls a service, and perform the "stuff" you want in the service, including any additionalRemoteViews
updates for your widget. You can send along the relevant data in the intent extras. The service callsstopSelf()
at the end, so it shuts off.You cannot maintain any state in an
BroadcastReceiver
; the system runs those on any available thread, and doesn't maintain any reference to your instance after callingonReceive()
. YourmCamera
variable is not guaranteed to be maintained between invocations of yourBroadcastReceiver
.If you really need to maintain state, you must do it in the service, and don't use
stopSelf()
(until an appropriate time).You do not need a UI thread to use the
Camera
class, unless you are doing image preview, which requires aSurfaceHolder
(and implies a UI). You must, however, have an event loop active, orCamera
will not post callbacks to you, which is a problem sinceCamera
is primarily asynchronous. You can do this within a service (seeHandlerThread
) and keep your service running until it's time torelease()
everything. Whichever thread callsCamera.open()
will receive callbacks.Did everyone actually read the section on App Widgets? http://developer.android.com/guide/topics/appwidgets/index.html
Using the AppWidgetProvider Class section says pretty much what I am saying here.
After a long time, I got free to solve this problem.
Here is what I did.
FlashlightWidgetProvider
class :and BroadcastReceiver for FlashlightWidgetReceiver :
Permission required in
Manifest.xml
file :Also register receivers in
Manifest.xml
file :Important Note : This code works perfect if your phone has
FLASH_MODE_TORCH
supported.I have tested in Samsung Galaxy Ace 2.2.1 & 2.3.3. The code is not working because that device has no FLASH_MODE_TORCH.
Works fine in HTC Salsa, Wildfire..
If anyone can test and post results here, it would be best.
I had a similar situation where I need to run certain android code on the UI thread ... which is only available in an Activity. My solution - an activity with a completely transparent layout. So you just see your home screen (albeit unresponsive) while you complete your actions, which in your case should be pretty quick.
I have one solution that is not great but works. Have the widget call an Activity, and in the Activity turn the flash on, and later close the Activity. The same to turn it off. If this works in the Activity then this solution will work. It's not elegant but works. I tried it.