First thing that will need to be done is to update the manifest file. The first thing to add is an activity named SelectExample. This will be called when the widget is added to the desktop. That is why the intent-filter android.appwidget.action.APPWIDGET_CONFIGURE is nested inside that activity definition.
Finally, a receiver needs to be added to know when the widget is updated. This is so the widget can be drawn correctly. The receiver is labelled WidgetExample below where the full manifest file is:
In the receiver block, you may notice the resource @xml/widget1_info. This is very important. You need to created a file in the res/xml folder and name it widget1_info. Below is what the contents of mine look like.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wetselsoftware.example.widgetexampleproject"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".WidgetExampleProjectActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SelectExample">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<receiver android:name=".WidgetExample" android:label="Example">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/widget1_info" />
</receiver>
</application>
</manifest>
The width and height are set so that the widget will be 2 blocks wide and 1 block tall. The updatePeriodMillis is the number of milleseconds that will pass before Android will call the receiver for a chance to update the widget, if the value is less than 30 minutes, it is ignored. Also, notice the android:configure value, this needs to point to the class that will handle the configuration of the widget when it is added to the home-screen. The layout is defined in the widget1 file referenced in this XML and will be shown below.
res/widget1_info
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="147dp"
android:minHeight="72dp"
android:updatePeriodMillis="1000"
android:configure="com.wetselsoftware.example.widgetexampleproject.SelectExample"
android:initialLayout="@layout/widget1">
</appwidget-provider>
layout/widget1
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:layout_margin="4dp"
android:background="@drawable/background">
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="@+id/widgetName"
android:layout_gravity="left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="@+id/widgetbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="Launch"
/>
</LinearLayout>
</LinearLayout>
OK, so that is the XML files. Now, lets look at the WidgetExample receiver. This class will extend the AppWidgetProvider class. Specifically, the onUpdate() function needs to be implemented for the purposes of this demo. This will update the GUI of the widget on the Home screen. Basically in onUpdate, we loop through each widgetId, and for that ID grab the Name of the widget and use RemoteViews class to update the GUI dynamically. In the SelectPet Activity which I will show next, it asks for a name for this Widget and I saved it in the SharedPrefernces and retrieved it in this class.
public class WidgetExample extends AppWidgetProvider {public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {final int N = appWidgetIds.length;Log.i("WidgetExample", "Updating widgets " + Arrays.asList(appWidgetIds));
Finally, I will show the class SelectExample. This class is called when the Widget is first added to the home screen. Basically there is a simple GUI with a text field. When the button is pressed, this class will save off the text in the TextField as the name to use for the widget. Also, I go ahead and update the views in this class so the Widget is drawn correctly right away in case onUpdate is not called immediately. It is important to set the result to RESULT_OK and return the widgetId in the result Intent.for (int i = 0; i < N; i++) {int appWidgetId = appWidgetIds[i];Intent intent = new Intent(context, WidgetExampleProjectActivity.class);intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, (int)appWidgetIds[i]);Uri data = Uri.withAppendedPath( Uri.parse("example" + "://widget/id/") ,String.valueOf(appWidgetId));intent.setData(data);PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget1);String widgetName=PreferenceManager.getDefaultSharedPreferences(context).getString("widget"+(int)appWidgetIds[i],null);views.setTextViewText(R.id.widgetName,widgetName );views.setOnClickPendingIntent(R.id.widgetbutton, pendingIntent);appWidgetManager.updateAppWidget(appWidgetId, views);}}}
So, all the pieces are here now. You can download this example project here.package com.wetselsoftware.example.widgetexampleproject;
import android.app.Activity;import android.app.PendingIntent;import android.appwidget.AppWidgetManager;import android.content.Intent;import android.content.SharedPreferences;import android.net.Uri;import android.os.Bundle;import android.preference.PreferenceManager;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.RemoteViews;
public class SelectExample extends Activity{
int mAppWidgetId=-1;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Intent intent = getIntent();Bundle extras = intent.getExtras();if (extras != null) {mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);}}@Overridepublic void onResume(){super.onResume();setUpGUI();}public void setUpGUI(){setContentView(R.layout.selectexample);Button select=(Button)findViewById(R.id.button1);select.setOnClickListener(new SelectHandler());}private class SelectHandler implements View.OnClickListener{public void onClick(View v){EditText et=(EditText)findViewById(R.id.editText1);String textName=et.getText().toString();//now save off name in the prefencesSharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getBaseContext());SharedPreferences.Editor editor = settings.edit();editor.putString("widget"+mAppWidgetId, textName);editor.commit();AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getBaseContext());Intent intent = new Intent(getBaseContext(), WidgetExampleProjectActivity.class);intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID , mAppWidgetId);Uri data = Uri.withAppendedPath( Uri.parse("example" + "://widget/id/") ,String.valueOf(mAppWidgetId));intent.setData(data);PendingIntent pendingIntent = PendingIntent.getActivity(getBaseContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);RemoteViews views = new RemoteViews(getBaseContext().getPackageName(), R.layout.widget1);views.setOnClickPendingIntent(R.id.widgetbutton, pendingIntent);views.setTextViewText(R.id.widgetName, textName);appWidgetManager.updateAppWidget(mAppWidgetId, views);Intent resultValue = new Intent();resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);setResult(RESULT_OK, resultValue);finish();}}}