app widget code snippets

satya - Friday, September 11, 2009 2:50:05 PM

appwidget_provider.xml


<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="60dp"
    android:minHeight="30dp"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/appwidget_provider"
    android:configure="com.....ExampleAppWidgetConfigure"
    >
</appwidget-provider>

This is where you define the nature of your widget, how it shows on the screen.

satya - Friday, September 11, 2009 2:51:34 PM

layout/appwidget_provider.xml


<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/appwidget_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="#ff000000"
/>

This is the layout. just a text box. simple enough.

satya - Friday, September 11, 2009 2:55:04 PM

Here is the configuration view


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/appwidget_configure_instructions"
    />

    <EditText
        android:id="@+id/appwidget_prefix"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
    />

    <Button
        android:id="@+id/save_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@android:string/ok"
    />

</LinearLayout>

This has three controls

This text will be shown before your date
edit box
OK button

satya - Friday, September 11, 2009 2:58:53 PM

Declaring your widget as a broadcast receiver in the manifest file


<receiver android:name=".appwidget.ExampleAppWidgetProvider">
   <meta-data android:name="android.appwidget.provider"
          android:resource="@xml/appwidget_provider" />
   <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
   </intent-filter>
</receiver>

satya - Friday, September 11, 2009 3:15:17 PM

Here is the provider


public class ExampleAppWidgetProvider extends AppWidgetProvider {

    public void onUpdate(Context context, 
                        AppWidgetManager appWidgetManager, 
                        int[] appWidgetIds) 
   {
        final int N = appWidgetIds.length;
        for (int i=0; i<N; i++) 
      {
            int appWidgetId = appWidgetIds[i];

            String titlePrefix = 
             ExampleAppWidgetConfigure.loadTitlePref(context, appWidgetId);

           updateAppWidget(context, appWidgetManager, appWidgetId, titlePrefix);
        }
    }
    
    public void onDeleted(Context context, int[] appWidgetIds) {
        final int N = appWidgetIds.length;
        for (int i=0; i<N; i++) {
            ExampleAppWidgetConfigure.deleteTitlePref(context, appWidgetIds[i]);
        }
    }

    public void onEnabled(Context context) 
   {
        // When the first widget is created, register for 
        // the TIMEZONE_CHANGED and TIME_CHANGED
        // broadcasts.  We don't want to be listening for these 
        // if nobody has our widget active.
        // This setting is sticky across reboots, but that doesn't 
        // matter, because this will
        // be called after boot if there is a widget 
        // instance for this provider.
      
        PackageManager pm = context.getPackageManager();
        pm.setComponentEnabledSetting(
                new ComponentName("com.example.android.apis", 
                       ".appwidget.ExampleBroadcastReceiver"),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
    }

    public void onDisabled(Context context) {
        // When the first widget is created, 
        // stop listening for the TIMEZONE_CHANGED and
        // TIME_CHANGED broadcasts.

        Class clazz = ExampleBroadcastReceiver.class;
        PackageManager pm = context.getPackageManager();
        pm.setComponentEnabledSetting(
                new ComponentName("com.example.android.apis", 
                ".appwidget.ExampleBroadcastReceiver"),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
    }

    static void updateAppWidget(Context context, 
                          AppWidgetManager appWidgetManager,
                           int appWidgetId, String titlePrefix) 
   {
        // Getting the string this way allows the string to be localized.  
        // The format
        // string is filled in using java.util.Formatter-style format strings.
      
        CharSequence text = context.getString(R.string.appwidget_text_format,
                ExampleAppWidgetConfigure.loadTitlePref(context, appWidgetId),
                "0x" + Long.toHexString(SystemClock.elapsedRealtime()));

        // Construct the RemoteViews object.  
        // It takes the package name (in our case, it's our
        // package, but it needs this because on the other 
        // side it's the widget host inflating
        // the layout from our package).
        RemoteViews views = new RemoteViews(context.getPackageName(), 
                            R.layout.appwidget_provider);
        views.setTextViewText(R.id.appwidget_text, text);

        // Tell the widget manager
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }
}

satya - Friday, September 11, 2009 3:18:37 PM

remoteviews api

remoteviews api

satya - Friday, September 11, 2009 3:22:27 PM

understanding pendingintent

understanding pendingintent

satya - Friday, September 11, 2009 3:30:40 PM

The configurator code


public class ExampleAppWidgetConfigure extends Activity {
    static final String TAG = "ExampleAppWidgetConfigure";

    private static final String PREFS_NAME
            = "com.example.android.apis.appwidget.ExampleAppWidgetProvider";
    private static final String PREF_PREFIX_KEY = "prefix_";

    int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
    EditText mAppWidgetPrefix;

    public ExampleAppWidgetConfigure() {
        super();
    }

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        // Set the result to CANCELED.  This will cause the widget host to cancel
        // out of the widget placement if they press the back button.
        setResult(RESULT_CANCELED);

        // Set the view layout resource to use.
        setContentView(R.layout.appwidget_configure);

        // Find the EditText
        mAppWidgetPrefix = (EditText)findViewById(R.id.appwidget_prefix);

        // Bind the action for the save button.
        findViewById(R.id.save_button).setOnClickListener(mOnClickListener);

        // Find the widget id from the intent. 
        Intent intent = getIntent();
        Bundle extras = intent.getExtras();
        if (extras != null) {
            mAppWidgetId = extras.getInt(
                    AppWidgetManager.EXTRA_APPWIDGET_ID, 
                    AppWidgetManager.INVALID_APPWIDGET_ID);
        }

        // If they gave us an intent without the widget id, just bail.
        if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
            finish();
        }

        mAppWidgetPrefix.setText(loadTitlePref(ExampleAppWidgetConfigure.this, mAppWidgetId));
    }

    View.OnClickListener mOnClickListener = new View.OnClickListener() {
        public void onClick(View v) {
            // When the button is clicked, save the string in our prefs and return that they
            // clicked OK.
            saveTitlePref(ExampleAppWidgetConfigure.this, mAppWidgetId,
                    mAppWidgetPrefix.getText().toString());

            // Make sure we pass back the original appWidgetId
            Intent resultValue = new Intent();
            resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
            setResult(RESULT_OK, resultValue);
            finish();
        }
    };

    // Write the prefix to the SharedPreferences object for this widget
    static void saveTitlePref(Context context, int appWidgetId, String text) {
        SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
        prefs.putString(PREF_PREFIX_KEY + appWidgetId, text);
        prefs.commit();
    }

    // Read the prefix from the SharedPreferences object for this widget.
    // If there is no preference saved, get the default from a resource
    static String loadTitlePref(Context context, int appWidgetId) {
        SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
        String prefix = prefs.getString(PREF_PREFIX_KEY, null);
        if (prefix != null) {
            return prefix;
        } else {
            return context.getString(R.string.appwidget_prefix_default);
        }
    }

    static void deleteTitlePref(Context context, int appWidgetId) {
    }

    static void loadAllTitlePrefs(Context context, ArrayList<Integer> appWidgetIds,
            ArrayList<String> texts) {
    }
}

satya - Saturday, September 12, 2009 8:17:12 AM

A code sample from Jeff Sharkey


/**
 * Define a simple widget that shows the Wiktionary "Word of the day." To build
 * an update we spawn a background {@link Service} to perform the API queries.
 */
public class WordWidget extends AppWidgetProvider {
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds) {
        // To prevent any ANR timeouts, we perform the update in a service
        context.startService(new Intent(context, UpdateService.class));
    }

    public static class UpdateService extends Service {
        @Override
        public void onStart(Intent intent, int startId) {
            // Build the widget update for today
            RemoteViews updateViews = buildUpdate(this);

            // Push update for this widget to the home screen
            ComponentName thisWidget = new ComponentName(this, WordWidget.class);
            AppWidgetManager manager = AppWidgetManager.getInstance(this);
            manager.updateAppWidget(thisWidget, updateViews);
        }

        /**
         * Build a widget update to show the current Wiktionary
         * "Word of the day." Will block until the online API returns.
         */
        public RemoteViews buildUpdate(Context context) {
            // Pick out month names from resources
            Resources res = context.getResources();
            String[] monthNames = res.getStringArray(R.array.month_names);

            // Find current month and day
            Time today = new Time();
            today.setToNow();

            // Build today's page title, like "Wiktionary:Word of the day/March 21"
            String pageName = res.getString(R.string.template_wotd_title,
                monthNames[today.month], today.monthDay);
            RemoteViews updateViews = null;
            String pageContent = "";

            try {
                // Try querying the Wiktionary API for today's word
                SimpleWikiHelper.prepareUserAgent(context);
                pageContent = SimpleWikiHelper.getPageContent(pageName, false);
            } catch (ApiException e) {
                Log.e("WordWidget", "Couldn't contact API", e);
            } catch (ParseException e) {
                Log.e("WordWidget", "Couldn't parse API response", e);
            }

            // Use a regular expression to parse out the word and its definition
            Pattern pattern = Pattern.compile(SimpleWikiHelper.WORD_OF_DAY_REGEX);
            Matcher matcher = pattern.matcher(pageContent);
            if (matcher.find()) {
                // Build an update that holds the updated widget contents
                updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_word);
    
                String wordTitle = matcher.group(1);
                updateViews.setTextViewText(R.id.word_title, wordTitle);
                updateViews.setTextViewText(R.id.word_type, matcher.group(2));
                updateViews.setTextViewText(R.id.definition, matcher.group(3).trim());
    
                // When user clicks on widget, launch to Wiktionary definition page
                String definePage = res.getString(R.string.template_define_url,
                        Uri.encode(wordTitle));
                Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(definePage));
                PendingIntent pendingIntent = PendingIntent.getActivity(context,
                        0 /* no requestCode */, defineIntent, 0 /* no flags */);
                updateViews.setOnClickPendingIntent(R.id.widget, pendingIntent);
    
            } else {
                // Didn't find word of day, so show error message
                updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_message);
                CharSequence errorMessage = context.getText(R.string.widget_error);
                updateViews.setTextViewText(R.id.message, errorMessage);
            }
            return updateViews;
        }

        @Override
        public IBinder onBind(Intent intent) {
            // We don't need to bind to this service
            return null;
        }
    }
}

satya - Saturday, September 12, 2009 8:18:09 AM

This code is taken from the following blog of Jeff Sharkey

This code is taken from the following blog of Jeff Sharkey