I) Principe :
Le click sur un élément du widget déclenche une action.
II) Implémentation :
a) Layout : ajouter l’attribut « clickable » pour tous les objets qui devront réagir au click
android:clickable="true"
b) Widget :
Pour permettre au bouton de réagir aux clics, on va utiliser la méthode void setOnClickPendingIntent(int viewId, PendingIntent pendingIntent)
de RemoteViews
avec viewId
l’identifiant du bouton et pendingIntent
lePendingIntent
qui contient l’Intent
qui sera exécuté en cas de clic.
Afin de faire en sorte qu’un intent lance la mise à jour de l’AppWidget, on lui mettra comme actionAppWidgetManager.ACTION_APPWIDGET_UPDATE
et comme extra les identifiants des widgets à mettre à jour ; l’identifiant de cet extra sera AppWidgetManager.EXTRA_APPWIDGET_ID
Comme AppWidgetProvider
dérive de BroadcastReceiver
, vous pouvez implémenter void onReceive(Context context, Intent intent)
pour gérer chaque intent qui lance ce receiver.
Exemple :
public class AndroAppWidget extends AppWidgetProvider {
//-- Intitulé de l'extra qui contient la direction du défilé
private final static String EXTRA_DIRECTION = "extraDirection";
private final static String EXTRA_PREVIOUS = "previous"; //-- Gauche
private final static String EXTRA_NEXT = "next"; //-- Droite
private final static String EXTRA_INDICE = "extraIndice"; //-- Indice
//-- Action qui indique qu'on essaie d'ouvrir une annonce
private final static String ACTION_OPEN_ANNONCE = "OPEN_ANNONCE";
private int indice = 0;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
//-- There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
//-- On récupère le RemoteViews qui correspond à l'AppWidget
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.andro_app_widget);
//-- On Change le texte du Widget
views.setTextViewText(R.id.appwidget_text, "texte : " + String.valueOf(indice));
//-- On gére les appuis sur les objets du widget
//*******************NEXT*********************************
Intent nextIntent = new Intent(context, AndroAppWidget.class);
//-- On veut que l'intent lance la mise à jour
nextIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
//-- On n'oublie pas les identifiants
nextIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
//-- On rajoute la direction
nextIntent.putExtra(EXTRA_DIRECTION, EXTRA_NEXT);
//-- Ainsi que l'indice
nextIntent.putExtra(EXTRA_INDICE, indice);
// Les données inutiles mais qu'il faut rajouter afin de distinguer les intents
Uri data = Uri.withAppendedPath(Uri.parse("WIDGET://widget/id/"), String.valueOf(R.id.ButtonBas));
nextIntent.setData(data);
// On insère l'intent dans un PendingIntent
PendingIntent nextPending = PendingIntent.getBroadcast(context, 0, nextIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// Et on l'associe à l'activation du bouton
views.setOnClickPendingIntent(R.id.ButtonBas,NextPending);
//*******************PREVIOUS*****************************
Intent previousIntent = new Intent(context, AndroAppWidget.class);
previousIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
previousIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
previousIntent.putExtra(EXTRA_DIRECTION, EXTRA_PREVIOUS);
previousIntent.putExtra(EXTRA_INDICE, indice);
data = Uri.withAppendedPath(Uri.parse("WIDGET://widget/id/"), String.valueOf(R.id.ButtonHaut));
previousIntent.setData(data);
PendingIntent previousPending = PendingIntent.getBroadcast(context, 1, previousIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.ButtonHaut, previousPending);
//*******************LINK*********************************
// L'intent ouvre cette classe même…
Intent linkIntent = new Intent(context, AndroAppWidget.class);
// Action l'action ACTION_OPEN_TUTO
linkIntent.setAction(ACTION_OPEN_ANNONCE);
// Et l'adresse du site à visiter
linkIntent.setData(Uri.parse("https://www.google.fr/search?q=google+.fr+mois+"+String.valueOf(indice)));
// On ajoute l'intent dans un PendingIntent
PendingIntent linkPending = PendingIntent.getBroadcast(context, 2, linkIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.appwidget_text, linkPending);
// Et il faut mettre à jour le widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
//-- On gére les actions sur le Widget dans la classe onReceive
@Override
public void onReceive(Context context, Intent intent) {
// Si l'action est celle d'ouverture du détail de l'annonce
if(intent.getAction().equals(ACTION_OPEN_ANNONCE)) {
Intent link = new Intent(Intent.ACTION_VIEW);
link.setData(intent.getData());
link.addCategory(Intent.CATEGORY_DEFAULT);
// Comme on ne se trouve pas dans une activité, on demande à créer une nouvelle tâche
link.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(link);
} else {
// Sinon, s'il s'agit d'une demande de mise à jour
// On récupère l'indice passé en extra, ou -1 s'il n'y a pas d'indice
int tmp = intent.getIntExtra(EXTRA_INDICE, -1);
// S'il y avait bien un indice passé
if(tmp != -1) {
// On récupère la direction
String extra = intent.getStringExtra(EXTRA_DIRECTION);
// Et on calcule l'indice voulu par l'utilisateur
if (extra.equals(EXTRA_PREVIOUS)) {
indice = (tmp - 1) % 6; //-- 5 annonces à afficher ou taille de la BD
if(indice < 0)
indice += 6;
} else if(extra.equals(EXTRA_NEXT))
indice = (tmp + 1) % 6;
}
}
// On revient au traitement naturel du Receiver, qui va lancer onUpdate s'il y a demande de mise à jour
super.onReceive(context, intent);
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
// When the user deletes the widget, delete the preference associated with it.
for (int appWidgetId : appWidgetIds) {
AndroAppWidgetConfigureActivity.deleteTitlePref(context, appWidgetId);
}
}
@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
}
}
Ajoutez dans le manifest partie Receiver du Widget :
<receiver android:name=".AndroAppWidget"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="OPEN_ANNONCE" /> </intent-filter> ...
Attention, pour activer le widget il est nécessaire de lancer une fois l’activité. Et de placer après super.onCreate dans l’activité principale :
sendBroadcast(new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME));
Exemple à télécharger ici
Pour appeler une classe lors du click (exemple MainActivity) :
// L'intent ouvre la classe principale
Intent linkIntent = new Intent(context, MainActivity.class);
linkIntent.setAction(ACTION_OPEN_ANNONCE);
linkIntent.putExtra("URL", "vide");
linkIntent.putExtra("DELETE", false);
linkIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
linkIntent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent linkPending = PendingIntent.getActivity(context, 2, linkIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.appwidget_image,linkPending );
Pour faire appel à un BroadCast situé dans une autre classe, dans la fonction « onUpdate », ajouter
Intent intent = new Intent(); intent.setAction(<<Nom_Du_Receiver>>.MAJ_CLICK); intent.setClassName(<<Nom_du_package>>,<<Nom_Du_Receiver>>); PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, intent,0); remoteViews.setOnClickPendingIntent(R.id.<<Objet_A_Cliquer>>, pendingIntent); // Tell the AppWidgetManager to perform an update on the current App Widget appWidgetManager.updateAppWidget(widgetId, remoteViews);
Pour la gestion du click par le widget lui même :
Et ajouter une fonction :
@Override public void onReceive(Context context, Intent intent) { Log.d("Receive", "onReceive called with " + intent.getAction()); }
d) Class BroadCast :
Ajouter une variable publique :
public static final String MAJ_CLICK= "MAJ_By_Click";
Dans la fonction onReceive on récupére l’action à réaliser via
intent.getAction()
e) Dans le Manifest :
Ajouter la gestion de l’action
<receiver android:name=".AlarmManagerBroadcastReceiver"> <intent-filter> <action android:name="MAJ_By_Click"> </action> </intent-filter> </receiver>
Cf. http://stackoverflow.com/questions/2471875/processing-more-than-one-button-click-at-android-widget
Remarque pour détecter appui sur le corps du widget :
remoteViews.setOnClickPendingIntent(R.id.widget, actionPendingIntent);
La classe du widget :
public class SampleWidgetProvider4_1 extends AppWidgetProvider {// our actions for our buttons
public static String ACTION_WIDGET_REFRESH = "ActionReceiverRefresh";
public static String ACTION_WIDGET_SETTINGS = "ActionReceiverSettings";
public static String ACTION_WIDGET_ABOUT = "ActionReceiverAbout";
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout_4_1);
Intent active = new Intent(context, SampleWidgetProvider4_1.class);
active.setAction(ACTION_WIDGET_REFRESH);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.Avant, actionPendingIntent);
active = new Intent(context, SampleWidgetProvider4_1.class);
active.setAction(ACTION_WIDGET_SETTINGS);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.Arriere, actionPendingIntent);
active = new Intent(context, SampleWidgetProvider4_1.class);
active.setAction(ACTION_WIDGET_ABOUT);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.widget, actionPendingIntent); //-- Click on the widget
remoteViews.setTextViewText(R.id.word_title, "HELLO"); //-- Write text if the widget is updated
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
@Override
public void onReceive(Context context, Intent intent) {
Log.i(Constants.TAG, "onReceive called with " + intent.getAction());
RemoteViews remoteViews = new RemoteViews(context.getPackageName (), R.layout.widget_layout_4_1);
if (intent.getAction().equals(ACTION_WIDGET_REFRESH)) {
Log.i("onReceive", ACTION_WIDGET_REFRESH);
remoteViews.setTextViewText(R.id.word_text, " Avant " );
} else if (intent.getAction().equals(ACTION_WIDGET_SETTINGS)) {
Log.i("onReceive", ACTION_WIDGET_SETTINGS);
remoteViews.setTextViewText(R.id.word_text, " Arriere " );
} else if (intent.getAction().equals(ACTION_WIDGET_ABOUT)) {
Log.i("onReceive", ACTION_WIDGET_ABOUT);
remoteViews.setTextViewText(R.id.word_text, " Widget " );
} else {
super.onReceive(context, intent);
}
ComponentName cn = new ComponentName(context, SampleWidgetProvider4_1.class);
AppWidgetManager.getInstance(context).updateAppWidget(cn, remoteViews);
}
}
Ajouter dans le manifest :
<receiver android:name=".SampleWidgetProvider4_1" android:label="@string/app_widget_4_1">
<intent-filter>
<action android:name="org.divenvrsk.widgets.ExampleProvider.ACTION_WIDGET_REFRESH"/>
<action android:name="org.divenvrsk.widgets.ExampleProvider.ACTION_WIDGET_SETTINGS"/>
<action android:name="org.divenvrsk.widgets.ExampleProvider.ACTION_WIDGET_ABOUT"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_provider_4_1" />
</receiver>
</application>
Et créez le fichier XML du widget dans res\xml :
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="294dp"
android:minHeight="72dp"
android:updatePeriodMillis="2000"
android:initialLayout="@layout/widget_layout_4_1"
/>
Pour lancer l’update du Widget, dans l’application qui gère les paramètres :
///-- On lance l'UPDATE du widget !
Intent intent = new Intent(MainActivity.this, SampleWidgetProvider4_1.class);
intent.setAction("android.appwidget.action.APPWIDGET_UPDATE");
int ids[] = AppWidgetManager.getInstance(getApplication()).getAppWidgetIds(new ComponentName(getApplication(), SampleWidgetProvider4_1.class));
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,ids);
sendBroadcast(intent);
///
Pour gérer l’actualisation du widget dans un délai inférieur à 30′ :
Il faut utiliser dans ce cas l’Alarm Manager :
1°) Créer un BroadCast qui va activer l’update du widget
public class AlarmManagerBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "YOUR TAG");
//Acquire the lock
wl.acquire();
//You can do the processing here update the widget/remote views.
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_annonces);
remoteViews.setTextViewText(R.id.appwidget_text, Utility.getCurrentTime("hh:mm:ss a"));
ComponentName thiswidget = new ComponentName(context, WidgetAnnonces.class);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(thiswidget, remoteViews);
//Release the lock
wl.release();
}
}
L’enregistrer dans le manifest :
<receiver android:name=".AlarmManagerBroadcastReceiver"/>
2°) Modifier la méthode onEnbled afin qu’elle initialise le BroadCast :
@Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
super.onEnabled(context);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
//After approximatly 30 seconds
am.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
1000 * 30, pi);
}
Il est aussi possible de rajouter l’update du widget :
cf StakOverFlow
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
AppWidgetManager appManager = AppWidgetManager.getInstance(context);
ComponentName thisWidget = new ComponentName(context, ExampleAppWidgetProvider.class);
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget1);
updateViews.setTextColor(R.id.widget1label, Color.YELLOW);
appManager.updateAppWidget(thisWidget, updateViews); }
Référence :
http://www.chupamobile.com/tutorial-android/android-homescreen-widget-with-alarmmanager-195
https://openclassrooms.com/courses/creez-des-applications-pour-android/creer-un-appwidget#
Votre commentaire