I'm trying to follow this example:
What is the correct way for sharing data among AppWidgetProvider and RemoteViewsService.RemoteViewsFactory
As such, I have a RemoteViewsFactory that has this:
#Override
public void onDataSetChanged() {
// Subsequent calls to get the data.
newsGetter.updateListFeed(null, new NewsGetter.OnUpdateListFeedFinishedListener() {
#Override
public void onUpdateListFeedFinished(VolleyError error) {
//async return here from volley
Intent widgetUpdateIntent = new Intent(NewsWidgetBase.FEED_UPDATED);
widgetUpdateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
LocalBroadcastManager.getInstance(context).sendBroadcast(widgetUpdateIntent);
}
});
Log.e(TAG, "******************************** onDataSetChanged PROVIDER");
}
Then I have an AppWidgetProvider that has this:
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
Log.e("WidgetBase", "******************************** onReceive ACTION_APPWIDGET_UPDATE");
} else if (FEED_UPDATED.equals(action)) {
Log.e("WidgetBase", "******************************** onReceive FEED_UPDATED");
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
updateAppWidget(context, appWidgetManager, appWidgetId);
}
super.onReceive(context, intent);
}
And in the manifest:
<receiver android:name=".widgets.a">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.myapp.FEED_UPDATED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/abc" />
</receiver>
I get the debugger log for ACTION_APPWIDGET_UPDATE, but for my own Intent broadcast, it never fires onReceive (breakpoint is never even hit). Does anyone see what I'm doing wrong?
For your own Intent broadcast to work, you have to register your BroadcastReceiver programmatically. So register your receiver as
LocalBroadcastManager.getInstance(this).registerReceiver(YourWidgetReceiver, new IntentFilter("your_intent_action"));
And then send your broadcast as
Intent intent = new Intent("your_intent_action");
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent)
;
Hope this helps.
Related
My widget app is running fine on all android version except 8 Oreo.
I get a W/BroadcastQueue: Background execution not allowed: receiving Intent message.
There is an interesting blog from CommonsWare but I don't fully understand why it applies to my case.
https://commonsware.com/blog/2017/04/11/android-o-implicit-broadcast-ban.html
My case looks pretty simple: I have a widget with a button and I want to change the text's button when it is clicked.
What is the right way to fix this issue?
TestWidget.java
public class TestWidget extends AppWidgetProvider {
private static RemoteViews views;
private static boolean buttonClicked = false;
public static final String ACTION_AUTO_UPDATE = "AUTO_UPDATE";
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
if(intent.getAction().equals(ACTION_AUTO_UPDATE))
{
Log.i("TESTWID", "get onReceive");
}
}
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
views = new RemoteViews(context.getPackageName(), R.layout.test_widget);
views.setOnClickPendingIntent(R.id.wid_btn_tst, setButton(context));
appWidgetManager.updateAppWidget(appWidgetId, views);
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
Log.i("TESTWID", "onupdate ");
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
public static PendingIntent setButton(Context context) {
Intent intent = new Intent();
intent.setAction("TEST");
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public static void pushWidgetUpdate(Context context, RemoteViews remoteViews) {
ComponentName myWidget = new ComponentName(context, TestWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(myWidget, remoteViews);
}
}
TestWidgetReceiver.java
public class TestWidgetReceiver extends BroadcastReceiver{
private static boolean isButtonON = false;
#Override
public void onReceive(Context context, Intent intent) {
Log.i("TESTWID", "onReceive "+intent.getAction());
if(intent.getAction().equals("TEST")){
updateWidgetButton(context, 2);
}
}
private void updateWidgetButton(Context context, int index) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.test_widget);
if(index == 2) {
if(isButtonON) {
remoteViews.setTextViewText(R.id.wid_btn_tst, "Test Off");
isButtonON = false;
}
else{
remoteViews.setTextViewText(R.id.wid_btn_tst, "Test On");
isButtonON = true;
}
}
TestWidget.pushWidgetUpdate(context.getApplicationContext(), remoteViews);
}
}
Manifest.xml:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="Test"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".TestWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<intent-filter>
<action android:name="AUTO_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/test_widget_info" />
</receiver>
<receiver
android:name=".TestWidgetReceiver"
android:label="widgetBroadcastReceiver" >
<intent-filter>
<action android:name="TEST" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/test_widget_info" />
</receiver>
</application>
It's subtle, but it is because of the implicit broadcast being used to trigger your TestWidgetReceiver. It is implicit because it is only specifying the action portion of the Intent. Make the broadcast Intent explicit by specifying the receiver class in the constructor:
public static PendingIntent setButton(Context context) {
Intent intent = new Intent(context, TestWidgetReceiver.class);
intent.setAction("TEST");
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
Things are changed now a days in Android. For the security & battery consumption google introduced so many ways & increased some problem for developers.
You haven't passed the Context of the TestWidgetReceiver.class to you intent.
You can do it like that in java
Intent intent = new Intent(context, TestWidgetReceiver.class);
or in kotlin
val intent = Intent(context, TestWidgetReceiver.class);
You can read more changes here
https://developer.android.com/about/versions/oreo/android-8.0-changes
Regards
I saw similar questions here on SO, but nothing seems to work in my case...
I created an appwidget with an AdapterViewFlipper (Simple ViewAnimator that will animate between two or more views that have been added to it). The appwidget has a Next button that enables the user to navigate to the next view on the widget.
It all works fine when I first add the appwidget. But if the smartphone reboots, the Next button of the widget no longer works on my Samsung S4 (the method onReceive is called, but nothings happens, it doesn't navigate to the next view and is stuck at the first view). I have to delete the widget and add it again in order for it to work...
I suspect that it is a problem of Touchwiz since I tested it on another phone (Moto G) and it worked fine.
Here are some portions of my code :
AppWidgetProvider
public class AppWidgetProvider extends AppWidgetProvider {
public static final String NEXT_ACTION = VersionUtil.getPackageName() + ".action.NEXT";
private static final String TAG = DailyAppWidget.class.getSimpleName();
#Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
}
#Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId, colorValue);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId, int primaryColor) {
Intent intent = new Intent(context, ViewFlipperWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
// When intents are compared, the extras are ignored, so we need to embed the extras
// into the data so that the extras will not be ignored.
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
// Instantiate the RemoteViews object for the app widget layout.
RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.app_widget);
// open the activity from the widget
Intent intentApp = new Intent(context, MainActivity.class);
intentApp.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intentApp, 0);
rv.setOnClickPendingIntent(R.id.widget_title, pendingIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
rv.setRemoteAdapter(R.id.adapter_flipper, intent);
} else {
rv.setRemoteAdapter(appWidgetId, R.id.adapter_flipper, intent);
}
// Bind the click intent for the next button on the widget
final Intent nextIntent = new Intent(context,
AppWidgetProvider.class);
nextIntent.setAction(AppWidgetProvider.NEXT_ACTION);
nextIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
final PendingIntent nextPendingIntent = PendingIntent
.getBroadcast(context, 0, nextIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
rv.setOnClickPendingIntent(R.id.widget_btn_next, nextPendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, mRemoteViews);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(NEXT_ACTION)) {
RemoteViews rv = new RemoteViews(context.getPackageName(),
R.layout.daily_app_widget);
rv.showNext(R.id.adapter_flipper);
int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
Log.e(TAG, "onReceive APPWIDGET ID " + appWidgetId);
AppWidgetManager.getInstance(context).partiallyUpdateAppWidget(
appWidgetId, rv);
}
super.onReceive(context, intent);
}
Service
public class FlipperRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private Context mContext;
private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
private static final String TAG = "FILPPERWIDGET";
public FlipperRemoteViewsFactory(Context context, Intent intent) {
mContext = context;
mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
//... get the data
}
#Override
public void onCreate() {
Log.e(TAG, "onCreate()");
}
#Override
public void onDataSetChanged() {
Log.i(TAG, "onDataSetChanged()");
}
#Override
public void onDestroy() {
}
#Override
public int getCount() {
//... return size of dataset
}
#Override
public RemoteViews getViewAt(int position) {
Log.i(TAG, "getViewAt()" + position);
RemoteViews page = new RemoteViews(mContext.getPackageName(), R.layout.app_widget_item);
//... set the data on the layout
return page;
}
#Override
public RemoteViews getLoadingView() {
Log.i(TAG, "getLoadingView()");
return new RemoteViews(mContext.getPackageName(), R.layout.appwidget_loading);
}
#Override
public int getViewTypeCount() {
Log.i(TAG, "getViewTypeCount()");
return 1;
}
#Override
public long getItemId(int position) {
Log.i(TAG, "getItemId()");
return position;
}
#Override
public boolean hasStableIds() {
Log.i(TAG, "hasStableIds()");
return true;
}
}
Manifest
<receiver android:name=".AppWidgetProvider"
android:label="#string/app_name"
android:enabled="#bool/is_at_least_12_api">
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/app_widget_info" />
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
</receiver>
<!-- Service serving the RemoteViews to the collection widget -->
<service android:name=".ViewFlipperWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS"
android:exported="false" />
app wigdet info
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="#layout/app_widget"
android:initialLayout="#layout/app_widget"
android:minHeight="110dp"
android:minWidth="250dp"
android:previewImage="#drawable/widget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="14400000"
android:widgetCategory="home_screen" />
Any help would be appreciated !
Depends on the launcher, there is no guarantee that your AppWidget will be updated immediately after the device started. It may be refreshed immeidately, or wait till the updatePeriodMillis passed after system started.
To solve your problem, define a BroadcastReceiver that will trigger the update of AppWidget after the reboot.
In AndroidManifest.xml, define the BootReceiver to get the boot_complete message.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".BootReceiver" android:enabled="true" android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
And define the BootReceiver.java to start your AppWidgetUpdateService
public class BootReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent){
//start appwidget update service
}
}
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".
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.
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);
}
In my widget I started Timer. It's work fine, everything is ok. But if I remove widget from home screen, onDisable or onDeleted is not called.
I try with onReceive but my Log.i() give my only onUpdate.
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
Log.i("onReceive", intent.getAction());
}
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
timer = new Timer();
timer.scheduleAtFixedRate(new TasksView(context, appWidgetManager), 100, 5000);
[...]
}
Additional, I have:
#Override
public void onDeleted(Context context, int[] appWidgetIds)
{
super.onDeleted(context, appWidgetIds);
Log.i("MyTag", "onDeleted");
}
#Override
public void onDisabled(Context context)
{
super.onDisabled(context);
Log.i("MyTag", "onDisabled");
}
and:
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.appwidget.action.APPWIDGET_DISABLED" />
<action android:name="com.opennet.supportportal.UPDATE_LIST_WARN" />
So, how I can stop my timer? Why onDisable or onDeleted is not called?
There is a bug in android 1.5 that the onDeleted method is not called. The code below placed in the onRecive fixes the problem.
#Override
public void onReceive(Context context, Intent intent)
{
final String action = intent.getAction();
if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
final int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
this.onDeleted(context, new int[] { appWidgetId });
}
} else {
super.onReceive(context, intent);
}
}
More info here
You need to add android:exported="true" in your Provider Manifest declaration.
onDelete() method not being called
I'm trying to make an Android widget, to show some info from my app.
I have succeed to show some info, but know i what to have a feature to "switch page" in my app. It means pressing a button, and new info is showing. But how do i do it? I have tried different thing, and I'm ending up with the following code:
public class HelloWidget extends AppWidgetProvider {
RemoteViews remoteViews;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
Toast.makeText(context, "onUpdate", Toast.LENGTH_SHORT).show();
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
Intent intent = new Intent();
intent.setAction(TestReceiver.TEST_INTENT);
intent.setClassName(TestReceiver.class.getPackage().getName(), TestReceiver.class.getName());
PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.bbutton1, pendingIntent);
remoteViews.setTextViewText(R.id.widgetTxt, "The textview");
appWidgetManager.updateAppWidget(appWidgetIds[0], remoteViews);
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
public class TestReceiver extends BroadcastReceiver {
public static final String TEST_INTENT = "MyTestIntent";
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "You reached the TestReceiver", Toast.LENGTH_SHORT).show();
if (intent.getAction() == TEST_INTENT) {
remoteViews.setTextViewText(R.id.widgetTxt, "Is changed");
}
}
}
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
final int appWidgetId = intent.getExtras().getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
this.onDeleted(context, new int[] { appWidgetId });
}
} else {
super.onReceive(context, intent);
}
}
#Override
public void onDeleted(Context context, int[] appWidgetIds) {
Toast.makeText(context, "onDelete", Toast.LENGTH_SHORT).show();
super.onDeleted(context, appWidgetIds);
}
}
Toast are showing "onUpdate" and then i remove it at "onDeleted". The textview also change in the onUpdate, but nothing happens when i press the button.
My Manifest look like this:
<receiver android:name=".HelloWidget" 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/hello_widget_provider" />
</receiver>
<receiver android:name=".TestReceiver" android:label="#string/app_name">
<intent-filter>
<action android:name="MyTestIntent">
</action>
</intent-filter>
</receiver>
What am i doing wrong?
Thanks
Is your TestReceiver an inner class of HelloWidget?
Then you didn't specify the correct name in the manifest.