Widget et boutons

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

et http://djynet.net/?p=585

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#

https://parallelcodes.com/android-widget-tutorial/

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.

Articles récents
Commentaires récents
fatima dans Bienvenue !
AdminDroid dans Bienvenue !
fatima dans Bienvenue !
Archives
Catégories