How to Add Widget of an Android Application?

It’s known that many of the android apps that have installed on the phone contain widgets. The most common examples are the Calendar and the Clock widget. So what are these Widgets? Widgets are just a mini-app that lives on the home screen and apart from small launcher icons that normally appear on the home screen. Widgets do take up more space and display up to date information of the app. Some of them are user resizable too. The most common use case of the widget is to launch the application or some specific activity of it. 

A widget is basically a broadcast message that communicates with the app using a receiver so you also have to include it into your Manifest File. This seems to be a lot of work, thanks to Android Studio it can do that all for us. So, just go to Android Studio click on app->New->Widget->AppWidget. Give it a name and you are done with setting up the widget. You can even check it that after installation will be having its own widget with a Simple TextView.

Now, after a brief explanation of what a widget is, lets deep dive into how to create it. There are three steps to set up a widget of your app.

  • Step 1: A WidgetProviderClass say, MyWidget, that extends the AppWidgetProvider class.
  • Step 2: A WidgetProviderInfo which is an XML that describes the Widget Metadata including information such as min-height and width.
  • Step 3: A widget layout file that will describe how your widget looks, but it has limitations from other layout files.

MainActivity File

Now let’s come creating our own Custom Widget which requires coding now. Create a MainActivity.xml file in the Layout folder of res directory in the following manner containing a Listview. 

XML



filter_none

edit
close

play_arrow

link
brightness_4
code

<--!MainActivity.xml-->
<androidx.constraintlayout.widget.ConstraintLayout 
       xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    
     <!--List view to display all food items-->
    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recipies"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

chevron_right


  • Now create a java file initializing all views and setting up the Listview, also populating it with items.
  • Name the Java file as MainActivity.Java.

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
  
public class MainActivity extends AppCompatActivity {
    ListView recipies;
    public String[] addRecipie
        = new String[] { "Lemonade", "BreadToast" };
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        
        // Attach your aml file with java file here
        setContentView(R.layout.activity_main);
        
        // Creating Java object for List of all food items.
        recipies = findViewById(R.id.recipies);
        
        // Adapter to hold your data of all food items
        ArrayAdapter<String> adapter
            = new ArrayAdapter<String>(
                this, android.R.layout.simple_list_item_1,
                addRecipie);
        recipies.setAdapter(adapter);
        
        // Set a clickListener on each item,so on clicking
        // item an intent will launch.
        recipies.setOnItemClickListener(
            new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(
                    AdapterView<?> adapterView, View view,
                    int i, long l)
                {
                    Intent in
                        = new Intent(MainActivity.this,
                                     DetailsActivity.class);
                    
                    // putExtra method allows you to pass
                    // data between two activities easily
                    in.putExtra("name", addRecipie[i]);
                    in.putExtra("pos", i);
                    startActivity(in);
                }
            });
    }
}

chevron_right


Output:

output screen

DetailsActivity File

Now, we have added two items to our list of recipies and each item contains a clicklistener attached that would navigate to DetailsActivity.java with intended information passing through intent. The following is the layout for DetailsActivity.xml containing two textview and a AddWidget Button(ImageView).

XML

filter_none

edit
close

play_arrow

link
brightness_4
code

<--!DetailsActivity.xml>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".DetailsActivity">
        
    <!--A Textview to display name of food-->
    <TextView
        android:id="@+id/name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
      
    <!--A ImageView to let user add a widget by clicking on it -->
    <ImageView
        android:id="@+id/addToWidget"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:clickable="true"
        android:contentDescription="@string/addtowidget"
        android:focusable="true"
        android:src="@drawable/not_widget"
        app:layout_constraintBottom_toTopOf="@+id/steps"
        app:layout_constraintStart_toStartOf="parent"/>
        
      <!--A TextView to show steps -->
    <TextView
        android:id="@+id/steps"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/name"
        app:layout_constraintVertical_bias="0.158"/>
  
</androidx.constraintlayout.widget.ConstraintLayout>

chevron_right


  • Create an instance of AppWidgetManager object.
  • Give it an id,i.e AppWidgetId, to make it unique.
  • Use the app->new->vector asset->select a drawable that you want your image to display like we have chosen star vector(R.drawable.addToWidget).

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

import android.appwidget.AppWidgetManager;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
  
public class DetailsActivity extends AppCompatActivity {
    TextView name, content;
    ImageView addToWidget;
    boolean added = false;
  
    // Take your steps of food processig as String variables
    // recipie1 and recipie2.
    private String recipie1
        = "Step1: Take a Lemon and required no of glasses of water"
          "Step2: Squeeze out the lemon juice into glasses,stir well" +
          "and put iceCubes before serve";
    private String recipie2
        = "Step1: Take a bread and apply some butter on it" +
          "Step2:Put it in the toaster and it is ready";
    ArrayList<String> steps = new ArrayList<String>();
    public static Recipie recipie;
    AppWidgetManager appWidgetManager;
    int appWidgetId;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
  
        // attach xml file for detailsActivity,that will
        // show detail of every food item
        setContentView(R.layout.activity_details);
  
        // Add Steps into step ArrayList
        steps.add(recipie1);
        steps.add(recipie2);
        addToWidget = findViewById(R.id.addToWidget);
  
        // AppWidgetManager manages creating and updating
        // the multiple widgets an application can have.
        appWidgetManager = AppWidgetManager.getInstance(
            DetailsActivity.this);
        appWidgetId = 1;
  
        // Each AppWidget has a different appWidgetId to
        // make it unique.
        name = findViewById(R.id.name);
        content = findViewById(R.id.steps);
        final String heading
            = getIntent().getStringExtra("name");
        final int pos = getIntent().getIntExtra("pos", -1);
        recipie = new Recipie(heading, steps.get(pos));
        name.setText(heading);
        content.setText(steps.get(pos));
  
        // Attach clickListener on ImageView Object so when
        // we will click it will handle the widget adding
        // code.
        addToWidget.setOnClickListener(
            new View.OnClickListener() {
                @Override public void onClick(View view)
                {
                    added
                        = !added; // boolean variable to
                                  // know the state ,if
                                  // widget is added or not.
                    Toast
                        .makeText(DetailsActivity.this,
                                  "Click",
                                  Toast.LENGTH_SHORT)
                        .show();
                    if (added) {
                        // Calling updateAppWidget static
                        // method of RecipieWidget to update
                        // widges of app
                        RecipieWidget.updateAppWidget(
                            DetailsActivity.this,
                            appWidgetManager, appWidgetId,
                            recipie);
                        Toast
                            .makeText(DetailsActivity.this,
                                      "Added to Widegt",
                                      Toast.LENGTH_SHORT)
                            .show();
                        addToWidget.setImageDrawable(
                            getResources().getDrawable(
                                R.drawable.add_widget));
                    }
                    else {
  
                        addToWidget.setImageDrawable(
                            getResources().getDrawable(
                                R.drawable.not_widget));
                        RecipieWidget.updateAppWidget(
                            DetailsActivity.this,
                            appWidgetManager, appWidgetId,
                            null);
                    }
                }
            });
    }
    // This method was created to pass Recipe object
    // information to AppWidget.
    public static Recipie getRecipie() { return recipie; }
}

chevron_right


Output:

output screen



Recipe.Java File

Now, each Recipe contains a Recipe name(String) and a Recipe Steps(String) so for our ease of maintaining we will create a Recipe object.

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

package com.tanya.widgettutorial;
  
public class Recipe {
    // The recipie include name of food item and steps to
    // cook it.
    private String name;
    private String steps;
    public Recipe(String name, String steps)
    {
        this.name = name;
        this.steps = steps;
    }
    // Getters and Setters
    public String getName() { return name; }
  
    public void setName(String name) { this.name = name; }
  
    public String getSteps() { return steps; }

chevron_right


Three words you must know about a widget:

  • RemoteView: Now, previously I mentioned that widget layout is the same as any other layout. So, basically Widget Layout is based on RemoteView because they are treated as a separate app on your homescreen. RemoteView is used to describe a view hierarchy that will be displayed in another process.
  • onUpdate() method: The onUpdate() method is called when a new Widget is created and also during each update interval which is set in the Widgetinfo.xml file,i.e generated when you have created Widget for your app under the xml directory.
  • AppWidgetManager class: This class consists of all the information about the widgets that are present at home. It also provides access t force updates on all existing widgets.

RecipeWidget.Java

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.util.Log;
import android.widget.RemoteViews;
  
// Implementation of App Widget functionality.
public class RecipeWidget extends AppWidgetProvider {
  
    public static String TAG = RecipeWidget.class.getName();
  
    static void
    updateAppWidget(Context context,
                    AppWidgetManager appWidgetManager,
                    int appWidgetId, Recipie recipie)
    {
        // Create RemoteView Object to handle your view of
        // widget
        RemoteViews views
            = new RemoteViews(context.getPackageName(),
                              R.layout.recipie_widget);
  
        assert recipie != null;
        // Set what content you want to display on Widget by
        // providing id of view and corresponding content
        views.setTextViewText(R.id.heading_text,
                              recipie.getName());
        views.setTextViewText(R.id.steps_text,
                              recipie.getSteps());
        appWidgetManager.updateAppWidget(appWidgetId,
                                         views);
    }
  
    @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) {
            Recipie recipie = DetailsActivity.getRecipie();
            Log.d(TAG, recipie.getName());
            updateAppWidget(context, appWidgetManager,
                            appWidgetId, recipie);
        }
    }
  
    @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
    }
}

chevron_right


Output:

output screen

Attention reader! Don’t stop learning now. Get hold of all the important Java and Collections concepts with the Fundamentals of Java and Java Collections Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.


Article Tags :
Practice Tags :


3


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.