Category Archives: Part -3: Handling User Interaction in App Widgets and Update Widgets Respectively

Part -3: Handling User Interaction in App Widgets and Update Widgets Respectively


This app widget tutorial is with respect to the app widget present in Nepal Khabar present in the Google play store.

In the previous tutorials, I have written about

Basics of and App Widget
Multiple Sized Widdget

How to update an App Widget?

To update appwidget, we will use IntentService. IntentService is a special kind of service which performs an action and shuts itself down, once the action is complete. It is superb form small, periodic operations. IntentService can be used within the WidgetProvider class. The give code snippets will clarify this:

 public class OurWidget extends AppWidgetProvider {  
      public void onUpdate(Context context,  
                android.appwidget.AppWidgetManager appWidgetManager,  
                int[] appWidgetIds) {  
           int appWidgetId = INVALID_APPWIDGET_ID;  
           if (appWidgetIds != null) {  
                int N = appWidgetIds.length;  
                if (N == 1) {  
                     appWidgetId = appWidgetIds[0];  
                }  
           }  
           Intent intent = new Intent(context, UpdateWidgetService.class);  
           intent.putExtra(EXTRA_APPWIDGET_ID, appWidgetId);  
           intent.setAction("DO NOTHING ACTION");  
           context.startService(intent);  
      }  
      /**  
       * static class does not need instantiation UpdateWidgetService is a Service  
       * that identifies the App Widgets , instantiates AppWidgetManager and calls  
       * updateAppWidget() to update the widget values  
       */  
      public static class UpdateWidgetService extends IntentService {  
           public UpdateWidgetService() {  
                super("UpdateWidgetService");  
           } 
@Override
		protected void onHandleIntent(Intent intent) {
			AppWidgetManager appWidgetManager = AppWidgetManager
					.getInstance(this);

			int incomingAppWidgetId = intent.getIntExtra(EXTRA_APPWIDGET_ID,
					INVALID_APPWIDGET_ID);
			if (incomingAppWidgetId != INVALID_APPWIDGET_ID) {
				updateAppWidget(appWidgetManager, incomingAppWidgetId,
						intent.getAction());

			}
		} 
 }  

This service must me started from the onUpdate method of our AppWidgetProvider. onUpdate is called when the widget gets added to the homescreen.
onHandleIntent(): called each time IntentService starts. The service shuts down once we exit this method.
This service is declared in manifest as follows:

 <service android:name="OurWidget.UpdateWidgetService"/>  

Now, lets update our widget using onHandleIntent():
In order to handle user interaction with an App Widget, the following tasks must be performed:

    1 . Set a unique click handler for each App Widget control
    2. Have the click handler send a command to a registered receiver
    3. Process the command received and perform any action necessary
    4. Update the App Widget to reflect the changes

The following code snippets will clarify the above points:
The app widget is updated and user interaction is handled through the given class:

 public class OurWidget extends AppWidgetProvider {  
      public static String ACTION_WIDGET_TITLE_CLICK = "Action_widget_title_click";  
      public static String ACTION_WIDGET_CONTENT_CLICK = "Action_widget_conent_click";  
      /**  
       * Called in response to the ACTION_APPWIDGET_UPDATE broadcast when this  
       * AppWidget provider is being asked to provide RemoteViews for a set of  
       * AppWidgets. Override this method to implement your own AppWidget  
       * functionality.  
       */  
      public void onUpdate(Context context,  
                android.appwidget.AppWidgetManager appWidgetManager,  
                int[] appWidgetIds) {  
           int appWidgetId = INVALID_APPWIDGET_ID;  
           if (appWidgetIds != null) {  
                int N = appWidgetIds.length;  
                if (N == 1) {  
                     appWidgetId = appWidgetIds[0];  
                }  
           }  
           Intent intent = new Intent(context, UpdateWidgetService.class);  
           intent.putExtra(EXTRA_APPWIDGET_ID, appWidgetId);  
           intent.setAction("DO NOTHING ACTION");  
           context.startService(intent);  
      }  
      /**  
       * static class does not need instantiation UpdateWidgetService is a Service  
       * that identifies the App Widgets , instantiates AppWidgetManager and calls  
       * updateAppWidget() to update the widget values  
       */  
      public static class UpdateWidgetService extends IntentService {  
           public UpdateWidgetService() {  
                super("UpdateWidgetService");  
           }  
           @Override  
           protected void onHandleIntent(Intent intent) {  
                AppWidgetManager appWidgetManager = AppWidgetManager  
                          .getInstance(this);  
                int incomingAppWidgetId = intent.getIntExtra(EXTRA_APPWIDGET_ID,  
                          INVALID_APPWIDGET_ID);  
                if (incomingAppWidgetId != INVALID_APPWIDGET_ID) {  
                     updateOneAppWidget(appWidgetManager, incomingAppWidgetId,  
                               intent.getAction());  
                }  
           }  
           /**  
            * For the random passcode app widget with the provided ID, updates its  
            * display with a new passcode, and registers click handling for its  
            * buttons.  
            */  
           private void updateOneAppWidget(AppWidgetManager appWidgetManager,  
                     int appWidgetId, String whichButton) {  
                RemoteViews views = new RemoteViews(this.getPackageName(),  
                          R.layout.appwidget_layout);  
                onWidgetHeaderClick(views, appWidgetId);  
                onWidgetContentClick(views, appWidgetId);  
                bindDataToRemoteView(views, listOfQuedMessage.get(count));  
                //3. Process the command received and perform any action necessary  
                if (whichButton.equals(ACTION_WIDGET_VIEW_CLICK)) {  
                     views.setTextViewText(R.id.widgetHeader, "So you clicked Widget Title");                      
                } else if (whichButton.equals(ACTION_WIDGET_TITLE_VIEW_CLICK)) {  
                     views.setTextViewText(R.id.widgetContent, "So you clicked Widget Header");  
                }  
                appWidgetManager.updateAppWidget(appWidgetId, views);//4. Update the App Widget to reflect the changes  
           }  
           public void bindDataToRemoteView(RemoteViews views, Message message) {  
                views.setTextViewText(R.id.widgetHeader, "Widget Title");  
                views.setTextViewText(R.id.widgetContent, "Widget Header : Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh ");  
           }  
           //1. Set a unique click handler for each App Widget control  
           private void onWidgetHeaderClick(RemoteViews views, int appWidgetId) {  
                Intent btnNextIntent = new Intent(this, this.getClass());  
                btnNextIntent.putExtra(EXTRA_APPWIDGET_ID, appWidgetId);  
                btnNextIntent.setAction(ACTION_WIDGET_TITLE_CLICK);  
                PendingIntent btnNextPendingIntent = PendingIntent.getService(this,  
                          0, btnNextIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
                views.setOnClickPendingIntent(R.id.widgetHeader,  
                          btnNextPendingIntent);  
           }  
           private void onWidgetContentClick(RemoteViews views, int appWidgetId) {  
                Intent btnPrevIntent = new Intent(this, this.getClass());  
                btnPrevIntent.putExtra(EXTRA_APPWIDGET_ID, appWidgetId);  
                btnPrevIntent.setAction(ACTION_WIDGET_CONTENT_CLICK); //2. Have the click handler send a command to a registered receiver  
                PendingIntent btnNextPendingIntent = PendingIntent.getService(this,  
                          0, btnPrevIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
                views.setOnClickPendingIntent(R.id.widgetContent,  
                          btnNextPendingIntent);  
           }  
      }  
 }  

The layout for our App Widget:

 <?xml version="1.0" encoding="utf-8"?>  
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   android:id="@+id/full_widget"  
   android:layout_width="fill_parent"  
   android:layout_height="140dp"  
   android:layout_gravity="center_vertical"  
   android:layout_margin="20dp"  
   android:orientation="vertical" >  
   <TextView  
     android:id="@+id/widgetHeader"  
     android:layout_width="fill_parent"  
     android:layout_height="wrap_content"  
     android:background="@android:color/black"  
     android:paddingLeft="5dp"  
     android:paddingRight="5dp"  
     android:text="TEST"  
     android:textColor="#FFFFFF"  
     android:textSize="14sp"  
     android:textStyle="bold" />  
   <View  
     android:layout_width="fill_parent"  
     android:layout_height="1dp"  
     android:background="#FFFFFF" />  
   <TextView  
     android:id="@+id/widgetContent"  
     android:layout_width="fill_parent"  
     android:layout_height="wrap_content"  
     android:background="@android:color/black"  
     android:paddingLeft="5dp"  
     android:paddingRight="5dp"  
     android:text="Test"  
     android:textColor="#6F7981"  
     android:textSize="14sp"  
     android:textStyle="bold" />  
 </LinearLayout>  

The sample project is located in github.

My next tutorial will be about, Multiple instance of same app widget
References:
Styling Android
Developers Forum

Advertisements