Android5 Service BroadcastReceiverlabsticc.univ-brest.fr/~bounceur/cours_pdf/android/...PETITE DÉMO...

Preview:

Citation preview

PROGRAMMATION ANDROID

Ahcène Bounceur Université de Bretagne Occidentale

1

LES RÉCEPTEURS (BROADCASTRECEIVER) LES SERVICES (SERVICE) GÉRER LE TEMPS (CALENDAR) LE MODE DOZE ALARMMANAGER ET PENDINGINTENT SERVICE EN FOREGROUND

2

Chapitre 5 Plan du cours

3

L’intérêt d’un service s’exécutant en arrière plan

tient surtout du fait que contrairement à une

application, celui-ci travaille en permanence.

BroadcastReceiver

4

BROADCASTRECEIVER

¢ Un récepteur (Receiver) permet de lancer une action automatiquement lorsqu’une action donnée est détectée. Par exemple, lorsque : �  Le chargement du système est fini �  La connexion internet est détectée �  Un appel ou un message est reçu �  L’état de la batterie change �  Écran éteint ou allumé �  …

5

BroadcastReceiver

6 Petite Démo

PETITE DÉMO

7

BroadcastReceiver

abcd (Salut)

Intent IntentFilter

PETITE DÉMO

8

Un récepteur est une classe qui hérite de la classe BroadcastReceiver

1. On crée un BroadcastReceiver

PETITE DÉMO

¢  La baliser receiver doit être ajoutée dans le ficher AndroidManifest.xml

¢ Cette balise est ajoutée automatiquement si le récepteur est créé à partir de l’interface d’Android Studio (Newà Other à BroadcastReceiver)

<receiver android:name=".MyReceiver" android:enabled="true" android:exported="true"></receiver>

9

1. On crée un BroadcastReceiver

PETITE DÉMO

public class MonBroadcastReceiver extends BroadcastReceiver {

public MonBroadcastReceiver() { } @Override public void onReceive(Context context, Intent intent) {

Log.i("LSE", "J'ai reçu quelque chose !");

}

}

10

Un récepteur est une classe qui hérite de la classe BroadcastReceiver

Qui contient une méthode onReceive à redéfinir

2. On dit ce que doit faire le BroadcastReceiver lorsqu’il reçoit un message

PETITE DÉMO

¢ Abonner (ou enregistrer) le récepteur à un intent-filter ayant comme action "abcd" :

<receiver android:name=".MyReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="abcd"></action> </intent-filter></receiver>

11

3. Enregistrer le BroadcastReceiver à un filtre d’intent (tube sur lequel il va écouter) abcd

PETITE DÉMO

¢  Lancer une action "abcd" (dans une activité par exemple) :

Intent intent = new Intent("abcd");sendBroadcast(intent);

12

Ces deux instructions vont lancer la méthode onReceive du BroadcastReceiver

4. Envoyer un message (événement) sur le tube (action) abcd

abcd

PETITE DÉMO

¢  Lancer une action "abcd" (dans une activité par exemple) :

Intent intent = new Intent("abcd");intent.putExtra("message", "Salut");sendBroadcast(intent);

13

Ces deux instructions vont lancer la méthode onReceive du BroadcastReceiver

4. Envoyer un message (événement) sur le tube (action) abcd

abcd (Salut)

BroadcastReceiver

14

BROADCASTRECEIVER

¢  La classe BroadcastReceiver reçoit les évènements auxquels elle est abonnés (enregistrés) :

MonBroadcastReceiver recepteur = new MonBroadcastReceiver();

IntentFilter intentFilter = new IntentFilter(action);registerReceiver(recepteur, intentFilter);

action à String

Exemple d’actions : Intent.ACTION_BATTERY_CHANGED : si l’état de la batterie change Intent.ACTION_NEW_OUTGOING_CALL : si un appel téléphonique est reçu "lse.intent.action.VALEURS" : personnel "abcd" : personnel … 15

"android.intent.action.BATTERY_CHANGED"

recepteur abonné à intentFilter ayant comme action action

BROADCASTRECEIVER

¢  La classe BroadcastReceiver permet de : �  Échanger des variables (en utilisant l’Intent) �  Lancer une action en appelant la méthode

sendBroadcast(intent) du context : ce qui permet de lancer la méthode onReceive de n’importe quel BroadcastReceiver ayant enregistré l’action :

sendBroadcast(intent);

16

BROADCASTRECEIVER

¢ Classe 1 : contient un attribut BroadcastReceiver

private BroadcastReceiver br = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

String s = intent.getStringExtra("a");

textView.setText(s);

}

};

IntentFilter intentFilter = new IntentFilter("abcd"); registerReceiver(br, intentFilter);

IntentFilter intentFilter = new IntentFilter();

intentFilter.setAction("abcd") ;

registerReceiver(br, intentFilter);17

Action (plusieurs actions peuvent être ajoutées

Le context (activité ou autre) ayant enregistré le récepteur

ou

BROADCASTRECEIVER

¢ Classe 2 : utilise une Intent pour lancer la méthode onReceive

Intent intent = new Intent("abcd"); intent.putExtra("a", "texte" ); sendBroadcast(intent);

18

Lance la méthode onReceive du BroadcastReceiver de la Classe 1

public void onReceive(Context context, Intent intent) {...}

A condition que l’action soit la même que celle enregistrée pour le BroadcastReceiver

Le BroadcastReceiver

Lance

BROADCASTRECEIVER

public class MonBroadcastReceiver extends BroadcastReceiver {

public MonBroadcastReceiver() { } @Override public void onReceive(Context context, Intent intent) { int niveau = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); Log.i("COURS", "Niveau = "+niveau);

}

}

19 public static final String EXTRA_LEVEL = "level";

Pour afficher le niveau de la batterie

BROADCASTRECEIVER public class MainActivity extends Activity { private MonBroadcastReceiver recepteur ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recepteur = new MonBroadcastReceiver(); } @Override protected void onResume() { super.onResume(); IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); registerReceiver(recepteur, intentFilter); } @Override protected void onPause() { super.onPause(); unregisterReceiver(recepteur); } }

20

<uses-permission android:name="android.permission.BATTERY_STATS" />

Ajouter une permission dans AndroidManifest.xml

public static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";

BROADCASTRECEIVER

21

BROADCASTRECEIVER

¢ D’autres actions :

Intent.ACTION_BATTERY_CHANGEDIntent.ACTION_BATTERY_LOWIntent.ACTION_TIME_CHANGEDIntent.ACTION_TIME_TICKIntent.ACTION_SCREEN_OFFIntent.ACTION_SCREEN_ONIntent.ACTION_POWER_CONNECTEDIntent.ACTION_POWER_DISCONNECTEDIntent.ACTION_BOOT_COMPLETEDIntent.ACTION_CALL

22

BROADCASTRECEIVER

23

¢ Enregistrer plusieurs actions :

IntentFilter intentFilter = new IntentFilter();

intentFilter.setAction(Intent.ACTION_BATTERY_CHANGED); intentFilter.setAction(Intent.ACTION_TIME_CHANGED); intentFilter.setAction(Intent.ACTION_SCREEN_OFF); intentFilter.setAction(Intent.ACTION_SCREEN_ON);

BROADCASTRECEIVER

24

¢ Comment connaître l’action qui a été déclenchée ?

@Override public void onReceive(Context context, Intent intent) { String action = intent.getAction();

}

BROADCASTRECEIVER

25

¢ Ajout direct dans le manifest :

<receiver android:name=".MyReceiver" android:enabled="true" android:exported="true" > <intent-filter> <action android:name="android.intent.action.BATTERY_CHANGED"></action> <action android:name="android.intent.action.ACTION_POWER_CONNECTED"></action> <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"></action>

</intent-filter> </receiver>

BROADCASTRECEIVER

26

¢ Remarque : �  Certaines actions ne peuvent pas être lancées à partir du fichier

AndroidManifest.xml : �  Exemple :

¢  On peut ajouter : <action android:name="android.intent.action.ACTION_POWER_CONNECTED"></action>

¢  Mais pas : <action android:name="android.intent.action.BATTERY_CHANGED"></action>

BROADCASTRECEIVER

27

¢ Remarque : �  Certaines actions ne peuvent pas être lancées à partir du fichier

AndroidManifest.xml : �  Exemple :

¢  On peut ajouter ses propres actions : <action android:name="lse.bounceur.com.monaction"></action>

BROADCASTRECEIVER

28

¢ Remarque : �  L’action Intent.ACTION_BOOT_COMPLETED a un sens

lorsqu’elle est ajoutée uniquement dans l’AndroidManifest.xml car son action est lancée automatiquement lorsque le chargement du système est complet et ne nécessite pas le lancement de l’application par l’utilisateur.

<action

android:name="android.intent.action.ACTION_BOOT_COMPLETED">

</action>

�  La détection de la fin du chargement du système requiert l’utilisation d’une permission :

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED">

</uses-permission>

BROADCASTRECEIVER

¢  Ce qui donne :

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<receiver android:name=".MyReceiver" android:enabled="true" android:exported="true" > <intent-filter>

<action android:name="android.intent.action.BOOT_COMPLETED" />

</intent-filter>

</receiver>

29

BROADCASTRECEIVER

30

¢  La priorité :

<receiver android:name=".MyReceiver" android:enabled="true" android:exported="true" > <intent-filter android:priority="100"> <action android:name="android.intent.action.BATTERY_CHANGED"></action> <action android:name="android.intent.action.ACTION_POWER_CONNECTED"></action> <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"></action>

</intent-filter> </receiver>

BROADCASTRECEIVER ET ACTIVITÉ CAS DE LA BATTERIE

31

BROADCASTRECEIVER ET ACTIVITÉ public class MainActivity extends Activity { private TextView textView; private MonBroadcastReceiver recepteur ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textView); recepteur = new MonBroadcastReceiver(textView); } @Override protected void onResume() { super.onResume(); IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); registerReceiver(recepteur, intentFilter); } @Override protected void onPause() { super.onPause(); unregisterReceiver(recepteur); }

}32

Lien entre le BroadcastReceiver et l’Activité

BROADCASTRECEIVER ET ACTIVITÉ

33

BroadcastReceiver

Activité

onReceive

TextView TextView

recepteur = new MonBroadcastReceiver(textView);

public void onReceive(Context context, Intent intent) { int niveau = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); textView.setText("Niveau = "+niveau);}

Le niveau de la batterie a changé

BROADCASTRECEIVER ET ACTIVITÉ

public class MonBroadcastReceiver extends BroadcastReceiver {

private TextView textView; public MonBroadcastReceiver() {}

public MonBroadcastReceiver(TextView textView) { this.textView = textView ; } @Override public void onReceive(Context context, Intent intent) { int niveau = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); textView.setText("Niveau = "+niveau);

}

}

34

BROADCASTRECEIVER ET ACTIVITÉ CAS GÉNÉRAL

35

Compteur

Activité

BROADCASTRECEIVER ET ACTIVITÉ

36

BroadcastReceiver

Activité

onReceive (intent)

recepteur = new MonBroadcastReceiver(textView);

TextView TextView

Intent intent = new Intent("abcd"); intent.putExtra("cle", v); activity.sendBroadcast(intent);

Compteur c = new Compteur(this); c.start();

onC

lick

s = intent.getIntExtra("cle", -1);textView.setText(""+s);

BROADCASTRECEIVER ET ACTIVITÉ public class MainActivity extends Activity { private TextView textView; private MonBroadcastReceiver recepteur ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textView); recepteur = new MonBroadcastReceiver(textView); } @Override protected void onResume() { super.onResume(); IntentFilter intentFilter = new IntentFilter("abcd"); registerReceiver(recepteur, intentFilter); } @Override protected void onPause() { super.onPause(); unregisterReceiver(recepteur); } public void onClick(View view) { Compteur c = new Compteur(this); c.start();

} }

37

BROADCASTRECEIVER ET ACTIVITÉ public class Compteur extends Thread { private Activity activity; public Compteur(Activity activity) { this.activity = activity; } @Override public void run() { for(int i=0; i<10; i++) { Intent intent = new Intent("abcd"); intent.putExtra("cle", i); activity.sendBroadcast(intent); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }

38

...@Override public void onReceive(Context context, Intent intent) { ...}

public class MonBroadcastReceiver extends BroadcastReceiver {

private TextView textView; public MonBroadcastReceiver() {}

public MonBroadcastReceiver(TextView textView) { this.textView = textView ; } @Override public void onReceive(Context context, Intent intent) { int s = intent.getIntExtra("cle", -1); textView.setText(""+s);

}

}

BROADCASTRECEIVER ET ACTIVITÉ

39

Service (Local)

40

INTRODUCTION

¢  Les applications agrégeant des informations en temps réel sont monnaie courante (résultats sportifs, info-flash, etc.), comme d’autres ne nécessitant aucune interface graphique pour fonctionner (c’est le cas du lecteur de musique lorsqu’il s’exécute en arrière-plan).

41

LES SERVICES

¢ Contrairement aux activités qui offrent une interface utilisateur, les services en sont complètement dépourvus.

¢  Ils possèdent un cycle de vie similaire à une activité et peuvent être contrôlés depuis d’autres applications.

¢  Il est commun de réaliser une application composée d’activités et d’un service.

¢ Exemple : �  un lecteur de musique utilisera une interface de sélection des

musiques (Activité) alors que le Service jouera celles-ci en arrière plan.

�  Application qui récupère les informations météo

42

LES SERVICES

¢ Un service est un composant d'application permettant à une application d'exécuter une opération plus longue sans interagir avec l'utilisateur ni de fournir des fonctionnalités pour d'autres applications

¢ Chaque Service doit être déclaré dans

l'AndroidManifest.xml en utilisant la balise <service>

43

LES SERVICES

¢  Les services peuvent être démarrés par les méthodes :

startService()

bindService()

startForegroundService() d’un contexte

44

LES SERVICES

¢  Il existe 3 types de services : �  Service Local : Service �  Service attaché à une activité : Bind �  Service Asynchrone : IntentService

45

LES SERVICES : CYCLE DE VIE

46

LA CLASSE SERVICE

47

LA CLASSE SERVICE

48

①  Nom du service ②  Peut être utilisé par d’autres applications ③  Actif

Déclaration dans AndroidManifest.xml : <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".MonService" android:enabled="true" android:exported="true"> </service> </application>

LA CLASSE SERVICE

49

LA CLASSE SERVICE public class MonService extends Service { public MonService() {} @Override public IBinder onBind(Intent intent) {

// ... return null ; } @Override public int onStartCommand(Intent intent, int flags, int startId) {

// ... return START_STICKY; } }

50

LA CLASSE SERVICE

¢ Retour de la méthode onStartCommand �  START_STICKY

¢  Si le service est tué par le système, il sera automatiquement relancé si des ressources sont disponibles mais sans garder l’état précédent de l’intent

�  START_NOT_STICKY ¢  Si le service est tué par le système, il ne sera pas automatiquement

relancé même si des ressources sont disponibles �  START_REDELIVER_INTENT

¢  Si le service est tué par le système, il sera automatiquement relancé si des ressources sont disponibles avec l’état précédent de l’intent

51

LA CLASSE SERVICE public class MonService extends Service { public MonService() {} @Override public IBinder onBind(Intent intent) { return null ;} @Override public int onStartCommand(Intent intent, int flags, int startId) { new Thread() {

@Override

public void run() {

for(int i=0; i<10; i++) {

Log.i("M2LSE", i);

try {

Thread.sleep(500);

} catch (InterruptedException e) {}

}

}

}.start();

return START_STICKY; } }

52

Service

LES SERVICES

53

Activité

Intent service = new Intent(this, MonService.class);

onStartCommand startService(service);

Lancer un service

onC

lick

@Override public int onStartCommand(Intent intent, int flags, int startId) {}

1

2

LES SERVICES public class MainActivity extends Activity { private TextView textView; private MonBroadcastReceiver recepteur ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textView); recepteur = new MonBroadcastReceiver(textView); } @Override protected void onResume() { super.onResume(); IntentFilter intentFilter = new IntentFilter("abcd"); registerReceiver(recepteur, intentFilter); } @Override protected void onPause() { super.onPause(); unregisterReceiver(recepteur); } public void onClick(View view) { Intent service = new Intent(this, MonService.class);

startService(service);

} }

54

Lancer un service

public int onStartCommand(Intent intent, ...) { ... }

Service

LIEN : SERVICE ET ACTIVITÉ

55

BroadcastReceiver

Activité

onReceive

recepteur = new MonBroadcastReceiver(textView);

TextView TextView

Intent intent = new Intent("abcd"); intent.putExtra("cle", v); sendBroadcast(intent);

Intent service = new Intent(this, MonService.class);

onStartCommand startService(service);

IntentFilter intentFilter = new IntentFilter("abcd"); registerReceiver(recepteur, intentFilter);

onC

lick

@Override public int onStartCommand(Intent intent, int flags, int startId) {}

s = intent.getIntExtra("cle", -1);textView.setText(""+s);

public class MonBroadcastReceiver extends BroadcastReceiver {

private TextView textView; public MonBroadcastReceiver() {}

public MonBroadcastReceiver(TextView textView) { this.textView = textView ; } @Override public void onReceive(Context context, Intent intent) { int s = intent.getIntExtra("cle", -1); textView.setText(""+s);

}

}

BROADCASTRECEIVER ET ACTIVITÉ

56

LA CLASSE SERVICE public class MonService extends Service { public MonService() {} @Override public IBinder onBind(Intent intent) { return null ;} @Override public int onStartCommand(Intent intent, int flags, int startId) { new Thread() {

@Override

public void run() {

for(int i=0; i<10; i++) {

Log.i("M2LSE", i);

try {

Thread.sleep(500);

} catch (InterruptedException e) {}

}

}

}.start();

return START_STICKY; } } 57

LA CLASSE SERVICE public class MonService extends Service { public MonService() {} @Override public IBinder onBind(Intent intent) { return null ;} @Override public int onStartCommand(Intent intent, int flags, int startId) { new Thread() {

@Override

public void run() {

for(int i=0; i<10; i++) {

Intent intent = new Intent("abcd"); intent.putExtra("cle", i); sendBroadcast(intent); try {

Thread.sleep(500);

} catch (InterruptedException e) {}

}

}

}.start();

return START_STICKY; } } 58

Mise à jour de la clé "cle" de l’IntentFilter (du BroadcastReceiver)

Appel de la méthode OnReceive (du BroadcastReceiver)

Service

LIEN : SERVICE ET ACTIVITÉ

59

BroadcastReceiver

Activité

onReceive

recepteur = new MonBroadcastReceiver(textView);

TextView TextView

Intent intent = new Intent("abcd"); intent.putExtra("cle", v); sendBroadcast(intent);

Intent service = new Intent(this, MonService.class);

onStartCommand

startService(service);

IntentFilter intentFilter = new IntentFilter("abcd"); registerReceiver(recepteur, intentFilter);

onC

lick

Compteur

Context

Compteur compteur = new Compteur(this); compteur.start();

s = intent.getIntExtra("cle", -1);textView.setText(""+s);

LIEN : SERVICE ET ACTIVITÉ public class MonService extends Service { public MonService() {} @Override public IBinder onBind(Intent intent) { return null ;} @Override public int onStartCommand(Intent intent, int flags, int startId) { Compteur compteur = new Compteur(this);

compteur.start();

return START_STICKY; } }

60

public class Compteur extends Thread { private Service service; public Compteur(Service service) { this.service = service; } @Override public void run() { for(int i=0; i<10; i++) { Intent intent = new Intent("abcd"); intent.putExtra("cle", i); service.sendBroadcast(intent); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }

Service Attaché (Bind)

61

LES SERVICES : CYCLE DE VIE

62

SERVICE ATTACHÉ (BIND) ¢ Service attaché:

public class MonService extends Service { private IBinder monBinder = new MonBinder(); @Override public IBinder onBind(Intent intent) { ...

return monBinder; } public class MonBinder extends Binder { MonService getMonService() { return MonService.this; } }

}

63

SERVICE (BIND) ¢ Activité :

public class MainActivity extends AppCompatActivity { private MonService monService ; private ServiceConnection monServiceConnection = new ServiceConnection() {

@Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

monService = ((MonService.MonBinder) iBinder).getMonService(); } @Override public void onServiceDisconnected(ComponentName componentName) {

monService = null; }

};

...

64

SERVICE (BIND) ¢ Activité :

public class MainActivity extends AppCompatActivity { ...

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(this, MonService.class); bindService(intent, monServiceConnection, Context.BIND_AUTO_CREATE); } }

65

Une fois le service est attaché, il est possible d’appeler ses méthodes grâce à l’objet monService

IntentService

66

LA CLASSE INTENTSERVICE

67

LA CLASSE INTENTSERVICE

public class MonIntentService extends IntentService { public MonIntentService() { super("MonIntentService"); } @Override protected void onHandleIntent(Intent intent) { if (intent != null) { for (int i = 0; i < 10; i++) { Log.i("M2LSE", ""+i); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } }

68 Intent service = new Intent(this, MonIntentService.class); startService(service);

Activité

Pas besoin de créer un Thread

ARRÊTER UN SERVICE

¢  A partir d’une autre classe : stopService(intent)

¢  A partir du service lui même : stopSelf()

69

PLUSIEURS INTENT POUR LE MÊME SERVICE !

¢ Remarque : Soient les deux services suivants : Intent intent1 = new Intent(this, MonService.class);

Intent intent2 = new Intent(this, MonService.class);

Les objets intent1 et intent2 ne font pas référence au même objet (intent1==intent2 est false), par contre, les deux objets font référence au même service : startService(intent1); à lance le service MonService stopService(intent2); à arrêter le service MonService, pareil que stopService(intent1) ;

70

LA LISTE DES SERVICES LANCÉS

¢  Obtenir la liste des services lancés d’un téléphone : Paramètres à Options pour les développeurs à Services en cours d’exécution

71

LA LISTE DES SERVICES LANCÉS

¢  Obtenir la liste des services lancés d’un téléphone : Par programmation Pour connaître le nom d’un (de mon) service :

String nom = MyService.class.getName()

72

LA LISTE DES SERVICES LANCÉS

¢  Obtenir la liste des services lancés d’un téléphone : Par programmation La liste des services lancés : ActivityManager manager =

(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);

List<ActivityManager.RunningServiceInfo> liste =

manager.getRunningServices(Integer.MAX_VALUE) ;

73

LA LISTE DES SERVICES LANCÉS

¢  Obtenir la liste des services lancés d’un téléphone : Par programmation Afficher la liste des services lancés : int size = liste.size();

for (int i=0; i<size; i++) {

ActivityManager.RunningServiceInfo service = liste.get(i) ;

Log.i ("TAG", service.service.getClassName());

}

74

GÉRER LE TEMPS

75

GÉRER LE TEMPS !

¢ Attention : La classe Date va devenir obsolète.

76

GÉRER LE TEMPS !

¢  Récupérer le temps actuel en millisecondes (depuis l’époque !) : long t = System.currentTimeMillis() ;

77

January 1, 1970 à 00h

GÉRER LE TEMPS !

¢ Récupérer le temps actuel en millisecondes (depuis le démarrage du téléphone) :

long t = SystemClock.elapsedRealtime() ;

78

Existe aussi pour le nano seconde : SystemClock.elapsedRealtimeNanos() On peut changer le temps de démarrage du téléphone : SystemClock.setCurrentTimeMillis()

Pratique pour l’utilisation du chronomètre

GÉRER LE TEMPS !

¢ Récupérer le temps actuel : Calendar calendar = Calendar.getInstance() ;

79

GÉRER LE TEMPS !

¢ Récupérer le temps actuel en millisecondes (depuis l’époque !) :

Calendar calendar = Calendar.getInstance();

long t = calendar.getTimeInMillis();

80

Pareil que System.currentTimeMillis()

GÉRER LE TEMPS !

¢ Fixer le temps en millisecondes : Calendar calendar = Calendar.getInstance();

calendar.setTimeInMillis(344560);

81

GÉRER LE TEMPS !

¢ Fixer le temps par la date : Calendar calendar = Calendar.getInstance(); calendar.set(

int annee,

int mois,

int jour,

);

82

GÉRER LE TEMPS !

¢ Fixer le temps par la date et l’heure : Calendar calendar = Calendar.getInstance(); calendar.set(

int annee,

int mois,

int jour,

int heure, int minute, int seconde

);

83

GÉRER LE TEMPS !

¢ Récupérer le temps lié à une date en millisecondes : Calendar calendar = Calendar.getInstance(); calendar.set(

2017,

9, // pour le mois 10

18,

3, 15, 58

); long t = calendar.getTimeInMillis();

84

GÉRER LE TEMPS !

¢ Récupérer des informations sur un temps donné : �  L’année :

long a = calendar.get(Calendar.YEAR);

�  Le mois : long a = calendar.get(Calendar.MONTH);

�  Le jour : long a = calendar.get(Calendar.DAY_OF_MONTH);

�  L’heure : long a = calendar.get(Calendar.HOUR_OF_DAY); // 24Hlong a = calendar.get(Calendar.HOUR); // 8H

�  La minute : long a = calendar.get(Calendar.MINUTE);

�  La seconde : long a = calendar.get(Calendar.SECOND);

85

GÉRER LE TEMPS !

¢ Ajouter 5 secondes au temps : Calendar calendar = Calendar.getInstance();

calendar.add(Calendar.SECOND, 5);long t = calendar.getTimeInMillis();

86

GÉRER LE TEMPS !

¢ Soustraire 5 minutes au temps : Calendar calendar = Calendar.getInstance();

calendar.add(Calendar.MINUTE, -5);long t = calendar.getTimeInMillis();

87

GÉRER LE TEMPS !

¢ Comparer deux temps (le comparTo de Java) :

calendar1.compareTo(calendar2) =

�  = 0 : mêmes temps (exactes)

�  = 1 : calendar1 avant calendar2�  = -1 : celendar1 après calendar2

88

GÉRER LE TEMPS !

¢ Comparer deux temps (le after) :

calendar1.after(calendar2) =

�  = false : calendar1 avant calendar2

�  = true : calendar1 après calendar2

¢ Comparer deux temps (le before) :

calendar1.before(calendar2) =

�  = false : calendar1 après calendar2�  = true : calendar1 avant calendar2

89

ALARMMANAGER ET PENDINGINTENT

90

ALARMMANAGER ET PENDINGINTENT

¢  Le AlarmManager et le PendingIntent permettant de lancer une intent après un certain temps et périodiquement même si l’on a quitté définitivement notre application.

PendingIntent pendingIntent =

PendingIntent.getActivity(context, requestCode, intent, flag);

PendingIntent.getBroadcast(context, requestCode, intent, flag);

PendingIntent.getService(context, requestCode, intent, flag);

91 requestCode à int

PendingIntent : Intent en attente

ALARMMANAGER ET PENDINGINTENT

¢  FLAG_CANCEL_CURRENT �  Indique que si le PendingIntent existe déjà et qu’il doit être annulé avant de

lancer le nouveau ¢  FLAG_IMMUTABLE

�  Indique que le PindingIntent à créer doit être immutable ¢  FLAG_NO_CREATE

�  Indique qu’il ne faut pas créer de nouveau PendingIntent s’il en existe déjà un (sinon, il sera null)

¢  FLAG_ONE_SHOT �  Indique que ce PendingIntent pourra être utilisé uniquement une seule fois

¢  FLAG_UPDATE_CURRENT �  Indique qu’il faut garder le même PendingIntent s’il existe déjà, par contre, il

faut remplacer les données extra par celle du nouveau Intent

92

flags

ALARMMANAGER ET PENDINGINTENT

Intent intent = new Intent(this, MyActivity.class);

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);

93

Déclarer un PendingIntent sur une Activité

ALARMMANAGER ET PENDINGINTENT

Intent intent = new Intent(this, MyReceiver.class);

PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);

94

Déclarer un PendingIntent sur un Récepteur

ALARMMANAGER ET PENDINGINTENT

Intent intent = new Intent(this, MyService.class);

PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);

95

Déclarer un PendingIntent sur un Service

ALARMMANAGER ET PENDINGINTENT

Intent intent = new Intent(this, MyService.class);

PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);

manager.set(

AlarmManager.RTC,

System.currentTimeMillis() + 5000,

pendingIntent

);

96

Démarrer un service dans 5 secondes

ALARMMANAGER ET PENDINGINTENT

manager.set(

AlarmManager.RTC,

System.currentTimeMillis() + 5000,

pendingIntent

);

97

set lance la méthode : onCreate : pour une activité onReceive : pour un broadcastreceiver onStartService : pour un service

ALARMMANAGER ET PENDINGINTENT

Intent intent = new Intent(this, MyService.class);

PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);

AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);

manager.setRepeating(

AlarmManager.RTC,

System.currentTimeMillis(),

60000,

pendingIntent

);

98

Démarrer immédiatement un service qui se répète chaque minute Attention : Le temps minimum pour

l’intervalle de répétition est de 1 mn

ALARMMANAGER ET PENDINGINTENT

Intent intent = new Intent(this, MyService.class);

PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);

AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);

manager.setRepeating(

AlarmManager.RTC,

System.currentTimeMillis() + 5000,

60000,

pendingIntent

);

99

Démarrer dans 5 secondes un service qui se répète chaque minute Attention : Le temps minimum pour

l’intervalle de répétition est de 1 mn

ALARMMANAGER ET PENDINGINTENT

@Override

public void onReceive(Context context, Intent intent) {

Intent intent2 = new Intent(this, MyReceiver.class);

PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent2, PendingIntent.FLAG_CANCEL_CURRENT);

AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);manager.set(

AlarmManager.RTC,

calendar.getTimeInMillis() + 60000,

pendingIntent

);

} 100

Dans onReceive d’un récepteur MyReceiver

Calendar calendar = Calendar.getInstance();

Un récepteur qui se répète chaque 1 minute

ALARMMANAGER ET PENDINGINTENT

@Override

public void onReceive(Context context, Intent intent) {

PendingIntent pendingIntent =

PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);

AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);

manager.set(

AlarmManager.RTC,

calendar.getTimeInMillis() + 60000,

pendingIntent

);

}101

Dans onReceive d’un récepteur MyReceiver

Calendar calendar = Calendar.getInstance();

Un récepteur qui se répète chaque 1 minute

102

LE MODE DOZE

Le mode veille amélioré 103

LE MODE DOZE

¢  Lors de l’annonce d’Android Marshmallow à la Google I/O, la firme de Mountain View a dévoilé deux nouvelles fonctionnalités importantes pour améliorer l’autonomie des Smartphones : �  Doze �  App Standby

104

LE MODE DOZE

¢  Lors de l’annonce d’Android 6 (Marshmallow : API 23), la firme de Mountain View a dévoilé deux fonctionnalités importantes pour améliorer l’autonomie des Smartphones : �  DOZE �  App Standby

105

LE MODE DOZE

¢  Le vrai téléphone passe en mode veille (DOZE) ¢ Ce qui peut engendrer l’arrêt d’un service ¢ Dans ce cas là, le service démarre automatiquement

lorsque l’on allume à nouveau le téléphone

106

ACTIF INACTIF (stationnaire) IDLE IDLE

Maintenance IDLE ACTIF

L’utilisateur éteint l’écran

Écran activé

Mode DOZE

Le téléphone n’est pas en

charge

Le téléphone n’est pas en mouvement

LE MODE DOZE

¢ Quand le mode Doze est activé : �  L’accès au réseau est suspendu, �  Les wake-locks sont ignorés �  Les sync adapters, JobScheduler et les alarmes classiques sont

retardés.

107

Android Marshmallow réservent ces créneaux pour que les applications puissent exécuter certaines tâches (réseau, JobsScheduler, etc.)

IMPORTANT

¢ Fermeture d’une application (2 modes) Mode 1 Fermeture définitive

Glisse vers le haut

IMPORTANT

¢ Fermeture d’une application (2 modes) Mode 2 Fermeture sans les tâches de fond

109

Glisse vers le bas

Cadenas

IMPORTANT

¢ Fermeture d’une application (2 modes) Mode 2 Fermeture sans les tâches de fond

110

Glisse vers le haut

ALARMMANAGER ET PENDINGINTENT

¢ Gérer le mode DOZE :

<uses-permission android:name="android.permission.WAKE_LOCK" />

111

ALARMMANAGER ET PENDINGINTENT

@Override

public void onReceive(Context context, Intent intent) {

AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);

PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); manager.setAndAllowWhileIdle(

AlarmManager.RTC_WAKEUP, // ou ELAPSED_REALTIME_WAKEUP,

System.currentTimeMillis() + (1000 * 60 * 15),

pendingIntent

);

}

112

Ignore le mode DOZE Avant un temps minimal de 15mn

<uses-permission android:name="android.permission.WAKE_LOCK" />

Dans onStartCommand d’un service MyService

ALARMMANAGER ET PENDINGINTENT

@Override

public void onReceive(Context context, Intent intent) {

AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);

PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); manager.setExactAndAllowWhileIdle(

AlarmManager.RTC_WAKEUP, // ou ELAPSED_REALTIME_WAKEUP,

System.currentTimeMillis() + (1000 * 60 * 15),

pendingIntent

);

}

113

Ignore le mode DOZE Avant un temps minimal de 15mn

<uses-permission android:name="android.permission.WAKE_LOCK" />

Dans onStartCommand d’un service MyService

ANNULER UN PENDINGINENT (UNE ALARME)

Intent intent = new Intent(context, MyReceiver.class) ;

PendingIntent pendingIntent =

PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE);

AlarmManager alarmManager =

(AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

alarmManager.cancel(pendingIntent);

pendingIntent.cancel();

Remarque : Le pendingIntent est null s’il n’est pas déjà lancé avec alarmManager ou s’il est annulé

114

BROADCASTRECEIVER ET LE MODE DOZE

¢ Si on veut utiliser un BroadcastReceiver qui s’exécute durant le mode DOZE, il faut hériter plutôt de :

WekefulBroadcastReceiver

115

Déconseillé (deprecated)

LE RÉCEPTEUR ET LE MODE DOZE

¢  WakefulBroadcastReceiver public class MyWakefulReceiver extends WakefulBroadcastReceiver {

@Override

public void onReceive(Context context, Intent intent) {

}

}

116

Déconsillé

<uses-permission android:name="android.permission.WAKE_LOCK" />

LE RÉCEPTEUR ET LE MODE DOZE

¢  WakefulBroadcastReceiver public class MyWakefulReceiver extends WakefulBroadcastReceiver {

@Override

public void onReceive(Context context, Intent intent) {

Intent service = new Intent(context, MyIntentService.class);

startWakefulService(context, service);

}

}

117 <uses-permission android:name="android.permission.WAKE_LOCK" />

Déconsillé

Allumer l’écran par Programmation

PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);

PowerManager.WakeLock wl =

pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "TAG");

wl.acquire();

118 <uses-permission android:name="android.permission.WAKE_LOCK" />

PowerManager.FULL_WAKE_LOCK : sortir totalement du mode veille PowerManager.PARTIAL_WAKE_LOCK : sortir partiellement du mode veille PowerManager.SCREEN_BRIGHT_WAKE_LOCK : allumer l’écran (max intensité) PowerManager.SCREEN_DIM_WAKE_LOCK : allumer l’écran (faible intensité) PowerManager.ACQUIRE_CAUSES_WAKEUP : sortir du mode veille après un aquire PowerManager.ON_AFTER_RELEASE : un reset sur le timer de l’activité

Allumer l’écran par Programmation

PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);

PowerManager.WakeLock wl =

pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "TAG");

wl.acquire();

119 <uses-permission android:name="android.permission.WAKE_LOCK" />

Allumer l’écran par Programmation

PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);

PowerManager.WakeLock wl =

pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "TAG");

wl.acquire();

120 <uses-permission android:name="android.permission.WAKE_LOCK" />

Allumer l’écran par Programmation

PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);

PowerManager.WakeLock wl =

pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "TAG");

wl.acquire(); // On peut mettre aussi wl.acquire(3000);

121 <uses-permission android:name="android.permission.WAKE_LOCK" />

Allumer l’écran pendant 3 secondes

Allumer l’écran par Programmation

PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);

PowerManager.WakeLock wl =

pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "TAG");

wl.acquire();

// Faire quelque chose ici

122 <uses-permission android:name="android.permission.WAKE_LOCK" />

Allumer l’écran par Programmation

PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);

PowerManager.WakeLock wl =

pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "TAG");

wl.acquire();

// Faire quelque chose ici

wl.release();

123 <uses-permission android:name="android.permission.WAKE_LOCK" />

DÉTECTER LE MODE DOZE

IntentFilter intentFilter = new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);

MyReceiver receiver = new MyReceiver();

registerReceiver(receiver, intentFilter);

124

TESTER UNE APPLICATION EN MODE DOZE

¢ Activer le mode charge : �  adb shell dumpsys battery reset

¢ Désactiver le mode charge : �  adb shell dumpsys battery unplug

¢ Activer le mode Doze : �  adb shell dumpsys deviceidle enable

¢ Forcer le mode Doze �  adb shell dumpsys deviceidle force-idle

¢ Quitter le mode Doze : �  adb shell dumpsys deviceidle unforce

¢ Allumer/éteindre l’écran �  adb shell input keyevent 224 (éteindre 26) 125

UN SERVICE EN FOREGROUND

Communiquer avec une activité non visible 126

UN SERVICE EN FOREGROUND

¢ Si un service doit être lancé avant une activité (activité invisible), il ne doit pas être démarré avec la méthode classique :

startService

¢ Mais plutôt avec la méthode :

startForegroundService

¢ Exemple : un récepteur (BroadcastReceiver) qui lance un service au démarrage du téléphone.

127

UN SERVICE EN FOREGROUND

¢ Dans ce cas un service lance une notification liée à l’activité avec laquelle il communique.

¢ C’est comme si l’activité se transforme en une notification mais en mode réduit

¢ Bien que l’activité est fermée : �  Elle continue son exécution et à faire ses tâches �  On peut afficher l’état d’un paramètre de l’activité �  On peut changer un paramètre de l’activité

¢ Exemple : �  Chronomètre �  Lecteur de musique :

¢  Complet dans l’activité ¢  Réduit dans la notification

128

NOTIFICATION (RAPPEL)

Notification notification =

new NotificationCompat.Builder(this)

.setSmallIcon(R.drawable.notif_icone)

.setContentTitle("Ma notification")

.setContentText("Salut!")

.build();

NotificationManager mNotificationManager = (NotificationManager) getSystemService(this.NOTIFICATION_SERVICE); mNotificationManager.notify(1, notification);

129

SERVICE ET NOTIFICATION ET PENDINGINTENT

Intent notificationIntent = new Intent(this, MainActivity.class);

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);

Notification notification =

new NotificationCompat.Builder(this)

.setSmallIcon(R.drawable.notif_icone)

.setContentTitle("Ma notification")

.setContentText("Salut!")

.setContentIntent(pendingIntent)

.build();

startForeground(1, notification);

130

Un clic sur la notification engendrera le lancement de l’activité MainActivity La pendingIntent peut être utilisée sur un service ou un récepteur

SERVICE ET NOTIFICATION ET PENDINGINTENT

¢  La notification lancée avec startForeground ne disparaît pas.

¢  La méthode startForeground existe uniquement dans un Service.

¢  L’arrêt de ce service engendrera la disparition de la notification.

¢  L’utilisation de startForeground nécessite l’ajout de la permission :

android.permission.FOREGROUND_SERVICE

131

SERVICE ET NOTIFICATION ET PENDINGINTENT

Intent notificationIntent = new Intent(this, MainActivity.class);

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);

Notification notification =

new NotificationCompat.Builder(this)

.setSmallIcon(R.drawable.notif_icone)

.setContentTitle("Ma notification")

.setContentText("Salut!")

.setSound(soundUri)

.setContentIntent(pendingIntent)

.build();

startForeground(1, notification);

132

SERVICE ET NOTIFICATION ET PENDINGINTENT Intent intent1 = new Intent(this, MyService.class);

intent1.setAction("action1");

PendingIntent pintent1 = PendingIntent.getService(this, 0, intent1, PendingIntent.FLAG_CANCEL_CURRENT);

Intent intent2 = new Intent(this, MyService.class);

intent2.setAction("action2");

PendingIntent pintent2 = PendingIntent.getService(this, 0, intent2, PendingIntent.FLAG_CANCEL_CURRENT);

...

Notification notification =

new NotificationCompat.Builder(this)

.setSmallIcon(R.drawable.notif_icone)

...

.setContentIntent(pendingIntent) .addAction(R.drawable.notif, "Action 1", pintent1) .addAction(R.drawable.notif, "Action 2", pintent2)

.build();

startForeground(1, notification);133

onStartCommand (cas d’un service)

On peut ajouter des boutons sur la notification

SERVICE ET NOTIFICATION ET PENDINGINTENT

¢  Récupérer une action : @Override public int onStartCommand(Intent intent, int flags, int startId) {

String action = intent.getAction();

}

134

SERVICE ET NOTIFICATION ET PENDINGINTENT

¢  Reconnaître une action : @Override public int onStartCommand(Intent intent, int flags, int startId) {

String action = intent.getAction();

if(action.equals("action1"))

Toast.makeText(this, "ACTION 1", Toast.LENGTH_SHORT).show();if(action.equals("action2")) Toast.makeText(this, "ACTION 2", Toast.LENGTH_SHORT).show();if(action.equals("action3")) Toast.makeText(this, "ACTION 3", Toast.LENGTH_SHORT).show();

}

135

LANCER UNE ALARME/ACTION SOUS FORME DE REVEIL (ET PÉRIODIQUEMENT)

136

SETALARMCLOCK

AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent i1 = new Intent(context, MainActivity.class); PendingIntent pi1 = PendingIntent.getActivity(context, 0, i1, PendingIntent.FLAG_CANCEL_CURRENT); Intent i2 = new Intent(context, MyService.class); PendingIntent pi2 = PendingIntent.getService(context, 0, i2, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager.AlarmClockInfo ac = new AlarmManager.AlarmClockInfo(System.currentTimeMillis()+1000, pi1);

manager.setAlarmClock(ac, pi2);

137

Dans le Service ou le Récepteur

QUESTION

¢ Peut-on afficher un toast à partir d’un service avec une application fermée ?

¢ Peut-on afficher une SnackBar à partir d’un service avec une application fermée ?

138

RÉFÉRENCES

¢  Les nouveaux modes (Power saving features) �  https://www.youtube.com/watch?v=N72ksDKrX6c �  https://www.youtube.com/watch?v=p6ZiDZBgPY8

¢  La documentation �  https://developer.android.com/training/monitoring-device-state/

doze-standby.html �  https://developer.android.com/training/scheduling/

wakelock.html#screen �  https://developer.android.com/training/scheduling/

alarms.html#boot �  https://developer.android.com/reference/android/app/

AlarmManager.html

139

140

A votre Service

Recommended