Thursday, June 4, 2015

How to create Widget in Android

Table of contents
  1. Android Widget Example
    • AppWidgetProvider
    • ComponentName
    • RemoteViews
    • AppWidgetManager
    • Intent
    • Intent setAction()
    • PendingIntent
    • RemoteViews setOnClickPendingIntent()
    • AppWidgetProvider onUpdate()
    • AppWidgetProvider onEnabled()
    • AppWidgetProvider onDisabled()
    • AppWidgetProvider onReceive()
    • RemoteViews setTextViewText()
    • AppWidgetManager updateAppWidget()

1. Android Widget Example

MyAppWidget.java

package com.example.user.widgetexample;

import android.content.ComponentName;
import android.widget.RemoteViews;
import android.content.Context;
import android.appwidget.AppWidgetProvider;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.app.PendingIntent;
import android.widget.Toast;
import java.util.Random;

/**
 * Implementation of App Widget functionality.
 */
public class MyAppWidget extends AppWidgetProvider {

    private static final String RED_CLICKED = "RED CLICKED";
    private static final String GREEN_CLICKED = "GREEN CLICKED";

    /*
        public void onUpdate (Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
            Called in response to the ACTION_APPWIDGET_UPDATE and ACTION_APPWIDGET_RESTORED
            broadcasts when this AppWidget provider is being asked to provide RemoteViews for a
            set of AppWidgets. Override this method to implement your own AppWidget functionality.
     */
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

        /*
            RemoteViews
                A class that describes a view hierarchy that can be displayed in another process.
                The hierarchy is inflated from a layout resource file, and this class provides
                some basic operations for modifying the content of the inflated hierarchy.
         */
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.my_app_widget);

        /*
            ComponentName
                Identifier for a specific application component (Activity, Service,
                BroadcastReceiver, or ContentProvider) that is available. Two pieces of
                information, encapsulated here, are required to identify a component: the package
                (a String) it exists in, and the class (a String) name inside of that package.
         */
        ComponentName watchWidget = new ComponentName(context, MyAppWidget.class);

        /*
            public static PendingIntent getBroadcast
                (Context context, int requestCode, Intent intent, int flags)

                requestCode Private request code for the sender
        */

        /*
            setOnClickPendingIntent(int viewId, PendingIntent pendingIntent)
                Equivalent to calling setOnClickListener(android.view.View.OnClickListener)
                to launch the provided PendingIntent.
            */

        // Set a Click Listener for Red TextView
        remoteViews.setOnClickPendingIntent(
                R.id.tv_red,
                getPendingSelfIntent(context, RED_CLICKED)
        );

        // Set a Click Listener for Green TextView
        remoteViews.setOnClickPendingIntent(
                R.id.tv_green,
                getPendingSelfIntent(context, GREEN_CLICKED)
        );

        /*
            AppWidgetManager
                Updates AppWidget state; gets information about installed
                AppWidget providers and other AppWidget related state.

            updateAppWidget(ComponentName provider, RemoteViews views)
                Set the RemoteViews to use for all AppWidget
                instances for the supplied AppWidget provider.
         */
        appWidgetManager.updateAppWidget(watchWidget, remoteViews);
    }

    /*
        public void onEnabled (Context context)
            Called in response to the ACTION_APPWIDGET_ENABLED broadcast when the a AppWidget
            for this provider is instantiated. Override this method to implement your
            own AppWidget functionality.
     */
    @Override
    public void onEnabled(Context context) {
        // Enter relevant functionality for when the first widget is created
    }

    /*
        public void onDisabled (Context context)
            Called in response to the ACTION_APPWIDGET_DISABLED broadcast, which is sent when the
            last AppWidget instance for this provider is deleted. Override this method
            to implement your own AppWidget functionality.
     */
    @Override
    public void onDisabled(Context context) {
        // Enter relevant functionality for when the last widget is disabled
    }

    // Action is important to catch the view which is clicked
    protected PendingIntent getPendingSelfIntent(Context context, String action) {
        Intent intent = new Intent(context, getClass());
        intent.setAction(action);

        Toast.makeText(context, "Clicked: "+action, Toast.LENGTH_SHORT).show();
        return PendingIntent.getBroadcast(context, 0, intent, 0);
    }

    /*
        public void onReceive (Context context, Intent intent)
            Implements onReceive(Context, Intent) to dispatch calls
            to the various other methods on AppWidgetProvider.
     */
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub
        super.onReceive(context, intent);

        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.my_app_widget);
        ComponentName watchWidget = new ComponentName(context, MyAppWidget.class);

        // Display which View is clicked
        Toast.makeText(context,"onReceive: "+intent.getAction(),Toast.LENGTH_LONG).show();

        // Generate a random number
        Random rand = new Random();
        Integer randomNumber = rand.nextInt(25);

            /*
                String getAction()
                Retrieve the general action to be performed, such as ACTION_VIEW.
            */

        if (RED_CLICKED.equals(intent.getAction())) {
            // If the Red TextView clicked, then do that
            remoteViews.setTextViewText(R.id.tv_red, "" + randomNumber);
        }

        if (GREEN_CLICKED.equals(intent.getAction())) {
            // If the Green TextView clicked, then do that
            remoteViews.setTextViewText(R.id.tv_green, "" + randomNumber);
        }
        appWidgetManager.updateAppWidget(watchWidget, remoteViews);
    }

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetId) {
        // Construct the RemoteViews object
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_app_widget);

        Toast.makeText(context,"updateAppWidget",Toast.LENGTH_LONG).show();
        // Instruct the widget manager to update the widget
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }
}
res/layout/my_app_widget.xml

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/widget_margin"
    >
    <TextView
        android:id="@+id/tv_red"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Red"
        android:background="@drawable/tv_red_bg"
        android:gravity="center"
        android:textStyle="bold|italic"
        />
    <TextView
        android:id="@+id/tv_green"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Green"
        android:background="@drawable/tv_green_bg"
        android:layout_toRightOf="@+id/tv_red"
        android:gravity="center"
        android:textStyle="bold|italic"
        />
</RelativeLayout>
res/drawable/tv_red_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="oval">
            <size android:height="70dp" android:width="70dp"/>
            <solid android:color="#ffff0100"/>
            <stroke android:width="5dp" android:color="#ffc20100"/>
        </shape>
    </item>
</selector>
res/drawable/tv_green_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="oval">
            <size android:height="70dp" android:width="70dp"/>
            <solid android:color="#ff60c060"/>
            <stroke android:width="5dp" android:color="#ff4c974c"/>
        </shape>
    </item>
</selector>
res/xml/my_app_widget_info.xml

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="80dp"
    android:minHeight="40dp"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/my_app_widget"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen"
    android:initialKeyguardLayout="@layout/my_app_widget"
    >
</appwidget-provider>
AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.user.widgetexample" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <receiver android:name=".MyAppWidget" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/my_app_widget_info" />
        </receiver>
    </application>

</manifest>
More android examples