I am currently developing an Android project which makes use of a Homescreen Widget to display data to the user. The view that I used in the Widget is a ListView. Below are my codes:
WidgetService Class
public class WidgetService extends RemoteViewsService
{
#Override
public RemoteViewsFactory onGetViewFactory(Intent intent)
{
return (new WidgetRemoteViewsFactory(this.getApplicationContext(), intent));
}
}
WidgetProvider Class
public class WidgetProvider extends AppWidgetProvider
{
#Override
public void onDeleted(Context context, int[] appWidgetIds)
{
super.onDeleted(context, appWidgetIds);
}
#Override
public void onDisabled(Context context)
{
super.onDisabled(context);
}
#Override
public void onEnabled(Context context)
{
super.onEnabled(context);
}
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds)
{
for(int i=0;i<appWidgetIds.length;i++)
{
RemoteViews rv = new RemoteViews(context.getPackageName(),
R.layout.widget);
Intent intent = new Intent(context, WidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
appWidgetIds[i]);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
rv.setRemoteAdapter(R.id.widgetListView, intent);
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}
WidgetRemoteViewsFactory Class
public class WidgetRemoteViewsFactory implements RemoteViewsFactory
{
private Context context = null;
private int appWidgetId;
private List<String> widgetList = new ArrayList<String>();
private DBHelper dbhelper;
public WidgetRemoteViewsFactory(Context context, Intent intent)
{
this.context = context;
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
Log.d("AppWidgetId", String.valueOf(appWidgetId));
dbhelper = new DBHelper(this.context);
}
private void updateWidgetListView()
{
String[] widgetFruitsArray = dbhelper.retrieveFruitsList();
List<String> convertedToList = new ArrayList<String>(Arrays.asList(widgetFruitsArray));
this.widgetList = convertedToList;
}
#Override
public int getCount()
{
return widgetList.size();
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public RemoteViews getLoadingView()
{
// TODO Auto-generated method stub
return null;
}
#Override
public RemoteViews getViewAt(int position)
{
Log.d("WidgetCreatingView", "WidgetCreatingView");
RemoteViews remoteView = new RemoteViews(context.getPackageName(),
R.layout.listview_row_item);
Log.d("Loading", widgetList.get(position));
remoteView.setTextViewText(R.id.listTV, widgetList.get(position));
return remoteView;
}
#Override
public int getViewTypeCount()
{
// TODO Auto-generated method stub
return 0;
}
#Override
public boolean hasStableIds()
{
// TODO Auto-generated method stub
return false;
}
#Override
public void onCreate()
{
// TODO Auto-generated method stub
updateWidgetListView();
}
#Override
public void onDataSetChanged()
{
// TODO Auto-generated method stub
updateWidgetListView();
}
#Override
public void onDestroy()
{
// TODO Auto-generated method stub
widgetList.clear();
dbhelper.close();
}
}
Android Manifest File
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.listviewwithdb"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/MyTheme.Light" >
<activity
android:name="com.example.listviewwithdb.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.example.listviewwithdb.WidgetProvider" >
<intent-filter >
<action
android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widgetinfo" />
</receiver>
<service
android:name="com.example.listviewwithdb.WidgetService"
android:exported="false"
android:permission="android.permission.BIND_REMOTEVIEWS" />
</application>
</manifest>
The problem is that I can add the widget into the homescreen, but it displays the list of item in the listview with a "Loading.." message in it, I tried logging the values at getViewAt() as shown above and it displays the content that I want successfully. Is there anything that I'm missing in my codes that is causing the issue? Thanks for the help in advance
I have found out the issue. It turns out that I need to return the number of views, in which my case is 1, that I have in getViewTypeCount() in my WidgetRemoteViewsFactory class.
Related
I'm having trouble setting up a widget to my app, whenever I try to add a widget to my home screen onReceive is being called and right after that onUpdate is being called - but after onUpdate finishes - my custom RemoteViewsService is not called at all...
NotesWidgetProvider.class
public class NotesWidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.notes_widget);
Intent intent = new Intent(context, NotesWidgetService.class);
views.setRemoteAdapter(R.id.widget_notes, intent);
Intent clickIntent = new Intent(context, NoteActivity.class);
PendingIntent clickPendingIntentTemplate = TaskStackBuilder.create(context)
.addNextIntentWithParentStack(clickIntent)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_notes, clickPendingIntentTemplate);
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_notes);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(AppWidgetManager.ACTION_APPWIDGET_UPDATE)) {
AppWidgetManager mgr = AppWidgetManager.getInstance(context);
ComponentName cn = new ComponentName(context, NotesWidgetProvider.class);
mgr.notifyAppWidgetViewDataChanged(mgr.getAppWidgetIds(cn), R.id.widget_notes);
}
super.onReceive(context, intent);
}
public static void sendRefreshBroadcast(Context context) {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.setComponent(new ComponentName(context, NotesWidgetProvider.class));
context.sendBroadcast(intent);
}
}
NotesWidgetService.class
public class NotesWidgetService extends RemoteViewsService {
#Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new NotesRemoteViewsFactory(this.getApplicationContext(), intent);
}
public class NotesRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private Context mContext;
private Cursor mCursor;
public NotesRemoteViewsFactory(Context applicationContext, Intent intent) {
mContext = applicationContext;
}
#Override
public void onCreate() {
}
#Override
public void onDataSetChanged() {
if (mCursor != null) {
mCursor.close();
}
final long identityToken = Binder.clearCallingIdentity();
Uri uri = DBHandler.CONTENT_URI;
String [] projection = {Constants.TITLE_COL, Constants.CONTENT_COL, Constants.COLOR_COL, Constants.DATE_COL};
mCursor = mContext.getContentResolver().query(uri, projection, null, null, null);
Binder.restoreCallingIdentity(identityToken);
}
#Override
public void onDestroy() {
if (mCursor != null) {
mCursor.close();
}
}
#Override
public int getCount() {
return mCursor == null ? 0 : mCursor.getCount();
}
#Override
public RemoteViews getViewAt(int i) {
if (i == AdapterView.INVALID_POSITION || mCursor == null || !mCursor.moveToPosition(getCount() - 1 - i)) {
return null;
}
RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
rv.setTextViewText(R.id.widget_note_title, mCursor.getString(mCursor.getColumnIndex(Constants.TITLE_COL)));
rv.setTextViewText(R.id.widget_note_content, mCursor.getString(mCursor.getColumnIndex(Constants.CONTENT_COL)));
rv.setInt(R.id.widget_note_body, "setBackgroundColor", Color.parseColor(mCursor.getString(mCursor.getColumnIndex(Constants.COLOR_COL))));
Intent fillInIntent = new Intent();
fillInIntent.putExtra(Constants.POSITION_COL, getCount() - 1 - i);
fillInIntent.putExtra("Code", NoteActivity.EDIT_CODE);
rv.setOnClickFillInIntent(R.id.widget_note_body, fillInIntent);
return rv;
}
#Override
public RemoteViews getLoadingView() {
return null;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public long getItemId(int i) {
return mCursor.moveToPosition(i) ? mCursor.getLong(0) : i;
}
#Override
public boolean hasStableIds() {
return true;
}
}
}
Manifest
<receiver
android:name=".widget.NotesWidgetProvider"
android:label="#string/your_notes">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/notes_widget_info" />
</receiver>
<service
android:name=".widget.NotesWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS"
android:exported="false"/>
notes_widget_info.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="#layout/notes_widget"
android:minHeight="180dp"
android:minWidth="110dp"
android:previewImage="#drawable/example_appwidget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="3600000"
android:widgetCategory="home_screen"/>
What am I missing? Can someone help figure it out?
UPDATE
I figured out that the problem was that I used AppCompat.ImageButton instead of ImageButton, now onGetViewFactory is called - but when reaching onGetViewFactory the widget changes to "Problem loading widget".
It might be too late to answer, but I think your issue come from your notes_widget_info.xml, change it to the following:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="#layout/notes_widget"
android:minHeight="180dp"
android:minWidth="110dp"
android:previewImage="#drawable/example_appwidget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="3600000"
android:widgetCategory="home_screen">
</appwidget-provider>
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 have an issue with my clock widget. I run a Service to refresh it when needed (on USER_PRESENT event and each minute while screen on), but this Service seems to be killed after some time, randomly, and is not restarted.
I have set notifications in my Service's onDestroy() and onLowMemory() methods but they are never called.
I never call the stopSelf() method.
The widget is no longer visible in launched application list into the system.
When the WidgetProvider naturally updates (every 6 hours), the service is restarted and all works perfectly for a moment.
Here is my code :
(note that the Application in the manifest is not named nor created in the code. Only the provider and service. don't know if it's correct)
Widget Provider :
public class WidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] ids) {
super.onUpdate(context, appWidgetManager, ids);
Intent serviceIntent = new Intent(context.getApplicationContext(), WidgetService.class);
context.startService(serviceIntent);
}
#Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
#Override
public void onDisabled(Context context) {
Intent serviceIntent = new Intent(context.getApplicationContext(), WidgetService.class);
context.stopService(serviceIntent);
super.onDisabled(context);
}
}
The Service :
public class WidgetService extends Service {
private static String LOG = WidgetService.class.getSimpleName();
public Hashtable<Integer, ClockView> views = new Hashtable<Integer, ClockView>();
AppWidgetManager man;
private static WidgetService self;
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Toast.makeText(this, LOG+" configuration change", Toast.LENGTH_LONG).show();
}
#Override
public void onCreate() {
super.onCreate();
man = AppWidgetManager.getInstance(this);
self = this;
// Registering Intent for screen state
...
registerReceiver(screenoffReceiver, filter);
// Registering Intent for click event
...
UpdateAllWidgets();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
UpdateAllWidgets();
return START_STICKY;
}
#Override
public void onDestroy() {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.holder)
.setContentTitle("WidgetClock")
.setContentText("Destroyed at "+Calendar.getInstance().getTime());
((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).notify(1, mBuilder.build());
super.onDestroy();
}
#Override
public void onLowMemory() {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.holder)
.setContentTitle("WidgetClock")
.setContentText("LowMemory at "+Calendar.getInstance().getTime());
((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).notify(1, mBuilder.build());
super.onLowMemory();
}
public void onScreenOff() {
}
private void onScreenOn() {
}
public void onUserPresent() {
}
public void UpdateAllWidgets() {
views.clear();
int[] ids = man.getAppWidgetIds(new ComponentName(this, WidgetProvider.class));
for (int id : ids)
createViewIfNecessary(id);
}
private void createViewIfNecessary(int id) {
if (!views.containsKey(id)) {
ClockView view = new ClockView(this, id);
views.put(id, view);
}
}
public static Context getApp(){
return self;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
The manifest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.widgetclock"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme"
android:clickable="true" >
<service android:name="WidgetService"></service>
<receiver android:name="WidgetProvider"
android:clickable="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/widget_provider_file" />
</receiver>
</application>
The widget provider config XML
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="250dip"
android:minHeight="125dip"
android:updatePeriodMillis="21600000"
android:initialLayout="#layout/widget_main">
</appwidget-provider>
When I click a button in a widget, a Toast appears. But when I use a configuration activit to set the button's caption and then I click the button, the Toast doesn't appear. Why?
public class MyWidget extends AppWidgetProvider {
public static String ACTION_WIDGET_CONFIGURE = "ConfigureWidget";
public static String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
Intent intent = new Intent(context, MyWidget.class);
intent.setAction(ACTION_WIDGET_RECEIVER);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.btn_widget, actionPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews); //update our widget
}
#Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
#Override
public void onDisabled(Context context) {
super.onDisabled(context);
}
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_WIDGET_RECEIVER))
{
Toast.makeText(context, "You have just clicked the button!", Toast.LENGTH_LONG).show();
}
super.onReceive(context, intent);
}
Appwidget-provider xml:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="#layout/widget_layout"
android:minHeight="72dp"
android:minWidth="72dp"
android:configure="com.bfarago.tutorials.widget.ConfigActivity"
>
</appwidget-provider>
Manifest:
<activity
android:name=".ConfigActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<receiver android:name="MyWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.bfarago.tutorials.widget.MyWidget.ACTION_WIDGET_RECEIVER"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/widget_info"/>
</receiver>
Configuration Activity:
public class ConfigActivity extends Activity {
Button btn;
EditText et;
Context c;
AppWidgetManager awm;
int awID;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.config);
btn = (Button)findViewById(R.id.btn);
et = (EditText)findViewById(R.id.et);
c = ConfigActivity.this;
//Getting info about the widget that launched this Activity
Intent i = getIntent();
Bundle extras = i.getExtras();
if (extras != null)
{
awID = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
}
else
{
finish();
}
awm = AppWidgetManager.getInstance(c);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String newcaption = et.getText().toString();
RemoteViews views = new RemoteViews(c.getPackageName(), R.layout.widget_layout);
views.setTextViewText(R.id.btn_widget, newcaption);
views.setTextColor(R.id.btn_widget, Color.RED);
awm.updateAppWidget(awID, views);
Intent result = new Intent();
result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, awID);
setResult(RESULT_OK, result);
finish();
}
});
}
}
If I remove the line android:configure="com.bfarago.tutorials.widget.ConfigActivity" from the appwidgetprovider xml, I see the Toast.
Your configure Activity's onClick calls updateAppWidget without having called setOnClickPendingIntent on the RemoteViews it passes in, so once it has run, there will be no click event from your widget. Fix it to be the same as your onUpdate method, or better yet, refactor the code so there's only one function that creates the RemoteViews and calls updateAppWidget.
i want to create a widget that when clicked on to open a dialog with a autocompletetextview(FROM THE main.class) and execute functions from mainclass.. here is my widget class and please tell me what to put in android manifest also. thx
public class AppWidget extends AppWidgetProvider
{
#Override
public void onReceive(Context ctxt, Intent intent)
{
if(intent.getAction()==null)
{
ctxt.startService(new Intent(ctxt,ToggleService.class));
}
else
{
super.onReceive(ctxt, intent);
}
}
#Override
public void onUpdate(Context context,AppWidgetManager appWidgetManager, int [] appWidgetIds)
{
context.startService(new Intent(context,ToggleService.class));
//RemoteViews buildUpdate(context);
}
public static class ToggleService extends IntentService
{
public ToggleService() {
super("AppWidget$ToggleService");
}
#Override
protected void onHandleIntent(Intent intent)
{
ComponentName me = new ComponentName(this,AppWidget.class);
AppWidgetManager mgr= AppWidgetManager.getInstance(this);
mgr.updateAppWidget(me,buildUpdate(this));
}
private RemoteViews buildUpdate(Context context)
{
RemoteViews updateViews=new RemoteViews(context.getPackageName(),R.layout.widget);
Intent i=new Intent(this, AppWidget.class);
PendingIntent pi= PendingIntent.getBroadcast(context,0, i,0);
updateViews.setOnClickPendingIntent(R.id.phoneState,pi);
return updateViews;
}
}
}
widgetxml//
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/phoneState"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:layout_centerInParent="true"
android:src="#drawable/ic_launcher"
/>
</RelativeLayout>
// and widget_provider.xml in res/xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="79px"
android:minHeight="79px"
android:updatePeriodMillis="1800000"
android:initialLayout="#layout/widget">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Loading..." />
// and part from my manifest
<receiver android:name=".AppWidget"
android:label="Caller"
android:icon="#drawable/ic_launcher" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_provider"
/>
</receiver>
<service android:name=".AppWidget$ToggleService" />
Upadte your manifest.xml
<receiver android:name=".AppWidget"
android:label="Caller"
android:icon="#drawable/ic_launcher" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.app.example.MyWidget.ACTION_WIDGET_CLICK_RECEIVER"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_provider"
/>
</receiver>
<service android:name=".AppWidget$ToggleService" />
and Update your AppWidgetProvider:
public class MyWidget extends AppWidgetProvider {
public static String ACTION_WIDGET_CLICK_RECEIVER = "ActionReceiverWidget";
public static int appid[];
public static RemoteViews rview;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds){
updateWidgetState(context, "");
}
#Override
public void onReceive(Context paramContext, Intent paramIntent)
{
String str = paramIntent.getAction();
if (paramIntent.getAction().equals(ACTION_WIDGET_CLICK_RECEIVER)) {
updateWidgetState(paramContext, str);
}
else
{
if ("android.appwidget.action.APPWIDGET_DELETED".equals(str))
{
int i = paramIntent.getExtras().getInt("appWidgetId", 0);
if (i == 0)
{
}
else
{
int[] arrayOfInt = new int[1];
arrayOfInt[0] = i;
onDeleted(paramContext, arrayOfInt);
}
}
super.onReceive(paramContext, paramIntent);
}
}
static void updateWidgetState(Context paramContext, String paramString)
{
RemoteViews localRemoteViews = buildUpdate(paramContext, paramString);
ComponentName localComponentName = new ComponentName(paramContext, MyWidget.class);
AppWidgetManager.getInstance(paramContext).updateAppWidget(localComponentName, localRemoteViews);
}
private static RemoteViews buildUpdate(Context paramContext, String paramString)
{
// Toast.makeText(paramContext, "buildUpdate() ::"+paramString, Toast.LENGTH_SHORT).show();
rview = new RemoteViews(paramContext.getPackageName(), R.layout.widget_layout);
Intent active = new Intent(paramContext, MyWidget.class);
active.setAction(ACTION_WIDGET_RECEIVER);
active.putExtra("msg", "Message for Button 1");
PendingIntent configPendingIntent = PendingIntent.getActivity(paramContext, 0, active, 0);
rmViews.setOnClickPendingIntent(R.id.buttonus1, configPendingIntent);
if(parmString.equals(ACTION_WIDGET_CLICK_RECEIVER))
{
//open a dialog with a autocompletetextview
//your code for update and what you want on button click
}
return rview;
}
#Override
public void onEnabled(Context context){
super.onEnabled(context);
// Toast.makeText(context, "onEnabled() ", Toast.LENGTH_SHORT).show();
}
// Called each time an instance of the App Widget is removed from the host
#Override
public void onDeleted(Context context, int [] appWidgetId){
super.onDeleted(context, appWidgetId);
// Toast.makeText(context, "onDeleted() ", Toast.LENGTH_SHORT).show();
}
// Called when last instance of App Widget is deleted from the App Widget host.
#Override
public void onDisabled(Context context) {
super.onDisabled(context);
// Toast.makeText(context, "onDisabled() ", Toast.LENGTH_SHORT).show();
}
}