Rishabh
Rishabh

Reputation: 3852

Android-Widget : Calling BroadcastReceiver onReceive from onUpdate of Appwidgetprovider

I am making a flashlight widget which will toggle the flashlight on/off and also I am trying to toggle the icon of the widget-button on clicking the widget button, for this I have the Appwidgetprovider whose onUpdate will use RemoteViews and call the BroadcastReceiver.

In the BroadcastReceiver, the onReceive function will perform the flashlight toggle and the icon toggle for the widget. The issue I am facing is that the onReceive function is not being called and no action happening with the widget.

below is the code:

AppWidgetProvider class:

public class WidgetActivity extends AppWidgetProvider {
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        Intent receiver = new Intent(context, WidgetActivity.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_flash_layout);
        views.setOnClickPendingIntent(R.id.imageButton1, pendingIntent);

        appWidgetManager.updateAppWidget(appWidgetIds, views);

    }
}

BroadcastReceiver Class:

public class WidgetService extends BroadcastReceiver {
    private static boolean isLightOn = false;
    private static Camera camera;

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub

        RemoteViews views = new RemoteViews(context.getPackageName(),
                R.layout.widget_flash_layout);

        if (isLightOn) {
            views.setImageViewResource(R.id.imageButton1,
                    R.drawable.light_off_widget);
        } else {
            views.setImageViewResource(R.id.imageButton1,
                    R.drawable.light_on_widget);
        }

        AppWidgetManager appWidgetManager = AppWidgetManager
                .getInstance(context);
        appWidgetManager.updateAppWidget(new ComponentName(context,
                WidgetActivity.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, "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, "no flash", Toast.LENGTH_SHORT)
                            .show();
                }
            }
        }
    }
}

Manifest:

<receiver android:name="com.widget.WidgetActivity">
    <intent-filter>
              <action
                 android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data
              android:name="android.appwidget.provider"
              android:resource="@xml/flash_widget" />
</receiver>

<receiver android:name="com.widget.WidgetService">

    <action android:name="COM_FLASHLIGHT"></action>

</receiver>

In the manifest I have not wrapped the <action> tag of the widget service with <intent-filter> as it was showing a warning saying "Exported receiver does not require permission".

Upvotes: 1

Views: 8696

Answers (2)

M Moersalin
M Moersalin

Reputation: 290

enter image description here if you read the documentation, onDataSetChanged in RemoteViewsService, is called when notifyDataSetChanged() is triggered.

so, if you wanna update your WidgetService from onReceive() method, you can call notifyAppWidgetViewDataChanged() method from AppWidgetManager

@Override
public void onReceive(Context context, Intent intent) {
    super.onReceive(context, intent);

    int[] ids = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
    AppWidgetManager.getInstance(context)
            .notifyAppWidgetViewDataChanged(ids, R.id.stack_view_movies);
}

Upvotes: 0

Libin
Libin

Reputation: 17085

onReceive function is not being called and no action happening with the widget

Your intent component class should be the Broadcast Receiver class , not the WidgetProvider

Change this

 Intent receiver = new Intent(context, WidgetActivity.class);

to

Intent receiver = new Intent(context, WidgetService.class);

When you use PendingIntent.getBroadcast it expect the Intent to be broadcast. So when you click on the button in the widget, the Broadcast Receiver onResume will get called.

You don't really need to set any Action here for the receiver.

But if you want to use a custom Intent , then you can set the Intent action like this

 Intent receiver = new Intent("COM_FLASHLIGHT");

and your receiver in manifest should register with intent-filter to handle the custom action.

 <receiver android:name=".services.WidgetService">
     <intent-filter>
        <action android:name="COM_FLASHLIGHT"></action>
     </intent-filter>
 </receiver>

So, when the BroadCast Receiver onReceive get called, you can check for the specific action like this

public class WidgetService extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    if(intent.getAction().equalsIgnoreCase("COM_FLASHLIGHT")){
          // do your stuff for this action.
    }
}

Custom Actions are normally defined when you have multiple actions in a RemoteView.

Upvotes: 6

Related Questions