Upload
others
View
5
Download
0
Embed Size (px)
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