TP Android : Les sons (musique en tache de fond)

Transcription

TP Android : Les sons (musique en tache de fond)
1
TP Android : Les sons (musique en tache de
fond)
Vincent Dubois
L’objectif de ce TP est le même que le TP précédent, c’est à dire réaliser un petit
player aléatoire. La différence est que l’on souhaite continuer à jouer la musique
quand l’activité n’est plus visible, et même quand l’écran passe en veille. Pour cela, il
nous faudra utiliser un service.
Mise en place
Ce TP nécessite quelques préparations :
Ajouter les autorisations nécessaires dans le fichier manifest.xml, juste avant la balise
application :
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
Il faut ensuite la classe AudioPlayer (la même que dans le TP précédent), dont voici le code
:
Dubois Vincent
-1/7-
15.02.2016
2
package … // N'oubliez pas de laisser votre nom de paquet
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
public class AudioPlayer implements AudioManager.OnAudioFocusChangeListener {
private static AudioPlayer audioPlayer; // On souhaite un seul audioPlayer pour l'application, quoi qu'il arrive
private Context context;
private MediaPlayer mediaPlayer;
private Uri lastUri;
private MediaPlayer.OnCompletionListener onCompletionlistener;
public void setOnCompletionlistener(MediaPlayer.OnCompletionListener onCompletionlistener) {
this.onCompletionlistener = onCompletionlistener;
if (mediaPlayer != null) mediaPlayer.setOnCompletionListener(onCompletionlistener);
}
public static AudioPlayer get(Context context){
if (audioPlayer == null) {
audioPlayer = new AudioPlayer(context);
}
// On demande à gérer les évènements liés au son
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(audioPlayer, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
release();
// could not get audio focus.
}
return audioPlayer;
}
public static void release(){
if (audioPlayer == null) return;
if (audioPlayer.mediaPlayer == null) return; // déjà libéré
if (audioPlayer.mediaPlayer.isPlaying()) audioPlayer.mediaPlayer.stop();
audioPlayer.mediaPlayer.release(); // libère le mediaplayer
audioPlayer.mediaPlayer = null; // Précise que le mediaplayer a été libéré
}
private AudioPlayer(Context context) {
this.context = context;
}
public void loadUri(Context context, Uri uri) {
if (uri != null) {
this.context = context;
this.lastUri = uri;
}
load();
}
private void load() {
if (lastUri == null) return;
if (mediaPlayer != null) {
// Si on joue déjà qq chose
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop(); // On abandonne le morceau en cours
}
mediaPlayer.release(); // On libère l'ancien
}
// On sélectionne le nouveau morceau
mediaPlayer = MediaPlayer.create(context, lastUri);
if (onCompletionlistener != null)
this.mediaPlayer.setOnCompletionListener(onCompletionlistener);
}
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
// resume playback
if (mediaPlayer == null) load(); // Si le mediaPlayer n'est pas configuré, on le configure
else if (!mediaPlayer.isPlaying()) mediaPlayer.start(); // Sinon on reprend où on en était
mediaPlayer.setVolume(1.0f, 1.0f); // On remet le volume à 100%
break;
case AudioManager.AUDIOFOCUS_LOSS:
// Lost focus for an unbounded amount of time: stop playback and release media player
if (mediaPlayer == null) break; // Déjà libéré, ne rien faire
if (mediaPlayer.isPlaying()) mediaPlayer.stop(); // On arrête la musique en cours
release();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// Lost focus for a short time, but we have to stop
// playback. We don't release the media player because playback
// is likely to resume
if (mediaPlayer == null) break;
if (mediaPlayer.isPlaying()) mediaPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
if (mediaPlayer == null) break;
if (mediaPlayer.isPlaying()) mediaPlayer.setVolume(0.1f, 0.1f);
break;
}
}
public void play() {
if (mediaPlayer == null || mediaPlayer.isPlaying()) load();
if (mediaPlayer != null) {
mediaPlayer.start();
}
}
public void stop() {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
}
public void pause() {
mediaPlayer.pause();
}
}
Dubois Vincent
-2/7-
15.02.2016
3
Créer une activité avec au moins deux boutons, d’identifiant R.id.buttonStart et
R.id.buttonStop
La première ligne autorise l’accès aux fichiers son (sur stockage externe). La deuxième
demande la permission de garder le périphérique éveillé, afin de ne pas couper la musique
lors de la mise en veille.
●
●
Création du service.
Un service est en gros une activité sans interface
graphique. Utilisez l’assistant pour créer un nouveau
service nommé MusicService.
On ajoute les champs et constantes suivants :
private AudioPlayer audioPlayer;
private String title;
public static final String COMMAND = "command";
public static final String START = "start";
public static final String STOP = "stop";
Pour gérer les commandes qui seront envoyées par
l’activité, on ajoute la méthode onStartCommand() :
@Override
public int onStartCommand(Intent intent, int flags, int
startId) {
if (intent == null) return Service.START_STICKY;
String command = intent.getExtras().getString(COMMAND);
if (START.equals(command)) {
// On joue un morceau si cela a été demandé
audioPlayer = AudioPlayer.get(this);
audioPlayer.setOnCompletionlistener(this);
selectAudioFile();
audioPlayer.play();
} else if (STOP.equals(command)){
// On libère les ressources si nécessaire
AudioPlayer.release();
}
return START_STICKY;
}
Sélectionner un fichier aléatoire se fait de la même
manière que dans le TP précédent :
Dubois Vincent
-3/7-
15.02.2016
4
private void selectAudioFile() {
//On demande la liste des fichiers audios disponibles
ContentResolver contentResolver = getContentResolver();
Uri uri = android.provider.MediaStore.Audio.Media.
EXTERNAL_CONTENT_URI;
Cursor cursor = contentResolver.query(uri, null, null,
null, null);
if (cursor == null) {
// query failed, handle error.
} else if (!cursor.moveToFirst()) {
// no media on the device
} else {
int ndx = (int) (cursor.getCount()*Math.random());
cursor.move(ndx);
int titleColumn = cursor.getColumnIndex(android.
provider.MediaStore.Audio.Media.TITLE);
int idColumn = cursor.getColumnIndex(android.
provider.MediaStore.Audio.Media._ID);
long thisId = cursor.getLong(idColumn);
this.title = cursor.getString(titleColumn);
Uri contentUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.
EXTERNAL_CONTENT_URI, thisId);
audioPlayer.loadUri(this, contentUri);
}
cursor.close();
}
Il ne reste plus qu’à faire ajouter la méthode pour
écouter l’évènement onCompletion() (fin de morceau)
(alt-entrée et choisir implements…)
Le plus simple est demander un nouveau morceau
aléatoire :
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
selectAudioFile();
audioPlayer.play();
}
Appel du service
Dans le code de l’activité, on configure dans le
onCreate() les actions des boutons :
Dubois Vincent
-4/7-
15.02.2016
5
Button buttonStart = (Button) findViewById(R.id.
buttonStart);
buttonStart.setOnClickListener(new View.OnClickListener
() {
@Override
public void onClick(View view) {
Intent music = new Intent(MainActivity.this
,MusicService.class);
music.putExtra(MusicService.COMMAND
, MusicService.START);
startService(music);
}
});
Button buttonStop = (Button) findViewById(R.id.
buttonStop);
buttonStop.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view) {
Intent music = new Intent(MainActivity.this
,MusicService.class);
music.putExtra(MusicService.COMMAND
, MusicService.STOP);
startService(music);
}
});
Le service est maintenant opérationnel.
Interdire la mise en veille
Dans le onStartCommand(), on va créer (si il n’existe
pas déjà) un objet qui servira au verrouillage de la mise
en veille :
if (wakeLock == null) {
PowerManager powerManager = (PowerManager)
getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.
PARTIAL_WAKE_LOCK, "MusicLockTag");
}
Comme d’habitude, importez les classes concernées, et
ajoutez wakeLock comme champ.
Toujours dans onStartCommand(), il faut maintenant
Dubois Vincent
-5/7-
15.02.2016
6
ajouter le verrouillage/déverrouillage proprement dit :
wakeLock.acquire();
juste avant l’appel à play()
wakeLock.release();
juste après l’appel au release de l’AudioPlayer.
Il faut aussi penser à déverrouiller la mise en veille si
on quitte le service :
@Override
public void onDestroy() {
super.onDestroy();
wakeLock.release();
}
Notification
Pour indiquer que le service est important pour
l’utilisateur, et donc qu’il faut si possible éviter de
l’arrêter dès qu’une activité a besoin de mémoire, il
faut associer une notification au service.
Les notifications nécessitant une icône, créez-en une
avec l’assistant « image assets » en choisissant le type
« notification icon ». Vous pouvez utiliser un des clipart,
ou votre propre image comme source.
Ensuite, ajoutez une méthode créant la notification
dans le code du service :
Dubois Vincent
-6/7-
15.02.2016
7
public void createNotification(){
// Crée un intenta permettant de lancer l'activité quand on clique sur la notification
if (pi== null) pi = PendingIntent.getActivity( this, 0,
new Intent(this, MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new Notification.Builder(getApplicationContext())
.setContentTitle("Playing ") //Ces 3 champs
.setContentText(title)
// sont
.setSmallIcon(R.drawable.ic_stat_mus) // obligatoires
.setContentIntent(pi)
.setOngoing(true)
.build();
startForeground(1, notification);
}
Dans la méthode selectAudioFile(), appelez cette
méthode (après avoir obtenu le nom du fichier joué).
Dans le onStartCommand(), dans la branche stop de la
conditionnelle et après les release(), demandez à
quitter l’avant-plan avec la commande suivante :
stopForeground(true);
Références
La documentation de MediaPlayer (JavaDoc) et (guide
sur Android Developer)
En complément, le TP sur les bruitages TP Android :
Les sons (bruitages)
Le TP sur la musique TP Android : Les sons (musique)
Dubois Vincent
-7/7-
15.02.2016

Documents pareils

1 et 2 - chezdom.net

1 et 2 - chezdom.net onFocusChange(View v, boolean hasFocus) onKey(View v, int keyCode, KeyEvent event) onTouch(View v, MotionEvent event)

Plus en détail