In this step by step example you will learn how to create a sample widget using the AppWidgetManager
.
Here is the demo image:
Step 1: Create Project
Start by creating an empty Android Studio
project.
Step 2: Dependencies
Because we are using Kotlin we will add the kotlin-stdlib-jdk
dependency:
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
Then the usual AppCompat and ConstraintLayout:
implementation "androidx.appcompat:appcompat:$buildToolsVer"
implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion"
Step 3: Create Sample Widget XML
First create a folder in your res
directory known as xml
and add the following file:
sample_widget_info.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="@layout/sample_widget"
android:initialLayout="@layout/sample_widget"
android:minHeight="110dp"
android:minWidth="110dp"
android:previewImage="@mipmap/ic_launcher"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen|keyguard"></appwidget-provider>
Step 4: Design the Layouts
We will need two layouts:
(a). sample_widget.xml
Add the code containing the UI elements for your custom widget here:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/widget_margin"
android:orientation="vertical">
<TextView
android:id="@+id/appwidget_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
android:contentDescription="@string/appwidget_text"
android:text="This is widget example"
android:textSize="24sp"
android:textStyle="bold|italic" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="HIT ME"
android:id="@+id/widget_button"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="OPEN GOOGLE PLEASE"
android:id="@+id/google_button"/>
</LinearLayout>
(b). activity_main.xml
Then design the MainActivity layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edit_text"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
android:text="press"/>
</LinearLayout>
Step 5: Write Widget Code
Start by creating the SampleWidget.kt
file and add the following imports including the android.appwidget.AppWidgetManager
and android.appwidget.AppWidgetProvider
:
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.util.Log
import android.widget.RemoteViews
import android.app.PendingIntent
import android.content.Intent
import android.net.Uri
import android.content.ComponentName
Create a class that extends the AppWidgetProvider
:
class SampleWidget : AppWidgetProvider() {
Define two strings:
private val ACTION_SIMPLEAPPWIDGET = "ACTION_BROADCASTWIDGETSAMPLE"
private val WIDGET_TAG = "SAMPLE_WIDGET_TAG"
Override the onUpdate()
:
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
There may be multiple widgets active, so loop and update all of them:
for (appWidgetId in appWidgetIds) {
Log.d(WIDGET_TAG,"update")
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
Override the onEnabled
and onDisabled
functions:
override fun onEnabled(context: Context) {
// Enter relevant functionality for when the first widget is created
Log.d(WIDGET_TAG,"enabled")
}
override fun onDisabled(context: Context) {
// Enter relevant functionality for when the last widget is disabled
Log.d(WIDGET_TAG,"disabled")
}
Now override the onReceive()
callback:
override fun onReceive(context: Context, intent: Intent) {
super.onReceive(context, intent)
Write code that will be called when the button is clicked:
if ((intent.action.equals(ACTION_SIMPLEAPPWIDGET))) {
val views = RemoteViews(context.packageName, R.layout.sample_widget)
views.setTextViewText(R.id.widget_button, "HIT ME AGAIN!")
val appWidget = ComponentName(context, SampleWidget::class.java!!)
val appWidgetManager = AppWidgetManager.getInstance(context)
appWidgetManager.updateAppWidget(appWidget, views)
}
Also write code that will be called broadcast inside the activity:
else if ((intent.action.equals("ACTIVITY_ACTION"))) {
val views = RemoteViews(context.packageName, R.layout.sample_widget)
val text = intent.getStringExtra("name")
views.setTextViewText(R.id.widget_button, text)
val appWidget = ComponentName(context, SampleWidget::class.java!!)
val appWidgetManager = AppWidgetManager.getInstance(context)
appWidgetManager.updateAppWidget(appWidget, views)
}
}
Finally create the updateAppWidget()
function:
private fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.sample_widget)
views.setTextViewText(R.id.appwidget_text, "WIDGET INITIALIZED")
//Sample intent for action example
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"))
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
views.setOnClickPendingIntent(R.id.widget_button, pendingIntent)
// Construct an Intent which is pointing this class.
val intentTwo = Intent(context, SampleWidget::class.java)
intentTwo.action = ACTION_SIMPLEAPPWIDGET
val pendingIntentTwo = PendingIntent.getBroadcast(context, 0, intentTwo, PendingIntent.FLAG_UPDATE_CURRENT)
views.setOnClickPendingIntent(R.id.google_button, pendingIntent)
views.setOnClickPendingIntent(R.id.widget_button, pendingIntentTwo)
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
Here is the full code:
SampleWidget.kt
package pramonow.com.widgetexample
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.util.Log
import android.widget.RemoteViews
import android.app.PendingIntent
import android.content.Intent
import android.net.Uri
import android.content.ComponentName
/**
* Implementation of App Widget functionality.
*/
class SampleWidget : AppWidgetProvider() {
private val ACTION_SIMPLEAPPWIDGET = "ACTION_BROADCASTWIDGETSAMPLE"
private val WIDGET_TAG = "SAMPLE_WIDGET_TAG"
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
// There may be multiple widgets active, so update all of them
for (appWidgetId in appWidgetIds) {
Log.d(WIDGET_TAG,"update")
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
override fun onEnabled(context: Context) {
// Enter relevant functionality for when the first widget is created
Log.d(WIDGET_TAG,"enabled")
}
override fun onDisabled(context: Context) {
// Enter relevant functionality for when the last widget is disabled
Log.d(WIDGET_TAG,"disabled")
}
override fun onReceive(context: Context, intent: Intent) {
super.onReceive(context, intent)
//This will be called when the button is clicked
if ((intent.action.equals(ACTION_SIMPLEAPPWIDGET))) {
val views = RemoteViews(context.packageName, R.layout.sample_widget)
views.setTextViewText(R.id.widget_button, "HIT ME AGAIN!")
val appWidget = ComponentName(context, SampleWidget::class.java!!)
val appWidgetManager = AppWidgetManager.getInstance(context)
appWidgetManager.updateAppWidget(appWidget, views)
}
//This will be called by broadcast inside the activity
else if ((intent.action.equals("ACTIVITY_ACTION"))) {
val views = RemoteViews(context.packageName, R.layout.sample_widget)
val text = intent.getStringExtra("name")
views.setTextViewText(R.id.widget_button, text)
val appWidget = ComponentName(context, SampleWidget::class.java!!)
val appWidgetManager = AppWidgetManager.getInstance(context)
appWidgetManager.updateAppWidget(appWidget, views)
}
}
private fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.sample_widget)
views.setTextViewText(R.id.appwidget_text, "WIDGET INITIALIZED")
//Sample intent for action example
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"))
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
views.setOnClickPendingIntent(R.id.widget_button, pendingIntent)
// Construct an Intent which is pointing this class.
val intentTwo = Intent(context, SampleWidget::class.java)
intentTwo.action = ACTION_SIMPLEAPPWIDGET
val pendingIntentTwo = PendingIntent.getBroadcast(context, 0, intentTwo, PendingIntent.FLAG_UPDATE_CURRENT)
views.setOnClickPendingIntent(R.id.google_button, pendingIntent)
views.setOnClickPendingIntent(R.id.widget_button, pendingIntentTwo)
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
Step 6: Write MainActivity code
Go to MainActivity.kt
and add imports:
import android.os.Bundle
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import android.view.View
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import androidx.core.view.accessibility.AccessibilityEventCompat.setAction
import android.content.Intent
import android.widget.Button
import android.widget.EditText
Extend the AppCompatActivity
and override the onCreate()
:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Reference the editText and button:
var editText = findViewById<EditText>(R.id.edit_text)
var button = findViewById<Button>(R.id.button)
Create an intent:
val intent = Intent(this, SampleWidget::class.java)
intent.action = "ACTIVITY_ACTION"
Create a button that when clicked will send broadcast to update the widget:
button.setOnClickListener { _ ->
AppWidgetManager.getInstance(application).getAppWidgetIds(ComponentName(application,SampleWidget::class.java))
intent.putExtra("name", editText.text.toString())
sendBroadcast(intent)}
}
}
Here is the full code:
MainActivity.kt
import android.os.Bundle
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import android.view.View
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import androidx.core.view.accessibility.AccessibilityEventCompat.setAction
import android.content.Intent
import android.widget.Button
import android.widget.EditText
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var editText = findViewById<EditText>(R.id.edit_text)
var button = findViewById<Button>(R.id.button)
val intent = Intent(this, SampleWidget::class.java)
intent.action = "ACTIVITY_ACTION"
//This action will send broadcast to update the widget
button.setOnClickListener { _ ->
AppWidgetManager.getInstance(application).getAppWidgetIds(ComponentName(application,SampleWidget::class.java))
intent.putExtra("name", editText.text.toString())
sendBroadcast(intent)}
}
}
Step 7: Register Components
Go to your AndroidManifest.xml
And register your MainActivity
as your launcher activity:
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
Then register our AppWidget:
<receiver android:name=".SampleWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/sample_widget_info" />
</receiver>
Run
Copy the code or download it in the link below, build and run.
Reference
Here are the reference links:
Number | Link |
---|---|
1. | Download Example |
2. | Follow code author |
3. | Code: Apache 2.0 License |