[Twoja aplikacja – odtwarzacz audio] Powiadomienia. Część 3

W serii „Twoja aplikacja” będę pokazywał, w jaki sposób stworzyć aplikację kompletną wraz z najważniejszymi komponentami. Taka aplikacja będzie posiadać wszystkie podstawowe rzeczy, która powinna mieć. Seria będzie podzielona na części, a każda część będzie zawierać poszczególne zagadnienie.

W tej serii stworzymy aplikację do odtwarzania muzyki wraz z najważniejszymi komponentami.

  1. Część 1: MediaSession i MediaController
  2. Cześć 2: AudioFocus
  3. Cześć 3: Powiadomienia

Wiesz już czym jest MediaSsesion, MediaController AudioFocus. Cała aplikacja nie byłaby kompletna bez powiadomień. W tym wpisie własnie zajmiemy się tym zagadnieniem.

1. Kod klasy powiadomień.

Stwórz klasę podobną do tej:

public class MediaNotificationHelper  {
    private final NotificationManager mNotificationManager;
    private MediaSessionHelper mMediaSession;
    private PlayerService mService;
    private static final int NOTIFICATION_ID = 404;
    private static final String CHANNEL_ID = "MUSIC_CHANNEL";
    private int playbackState;
    public MediaNotificationHelper(PlayerService serv) {
        this.mService = serv;
        mNotificationManager = (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE);
    }
    public void updateNotification(int state) {
        playbackState = state;
        switch (playbackState) {
            case PlaybackStateCompat.STATE_PLAYING: {
                mService.startForeground(NOTIFICATION_ID, createNotification() );
                break;
            }
            case PlaybackStateCompat.STATE_PAUSED: {
                NotificationManagerCompat.from(mService).notify(NOTIFICATION_ID, createNotification());
                mService.stopForeground(false);
                break;
            }
            default: {
                mService.stopForeground(true);
                break;
            }
        }
    }
    private Notification createNotification() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createNotificationChannel();
        }
        // Get album art
        MediaControllerCompat mController = new MediaControllerCompat(mService, mMediaSession.getmMediaSession());
        MediaMetadataCompat mMetadata = mController.getMetadata();
        MediaDescriptionCompat description = mMetadata.getDescription();
        Bitmap art;
        String url = description.getIconUri().toString();
        if (url != null) {
            art = Image.getBitmap(url);
        }else {
            art = BitmapFactory.decodeResource(mService.getResources(), R.drawable.art);
        }
        // Open application after clicking on Notification
        Intent intent = new Intent(mService, MediaControllersActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(mService, 0, intent, 0);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mService, CHANNEL_ID);
        addActions(notificationBuilder);
        notificationBuilder
                .setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
                        .setShowActionsInCompactView(1)
                        .setMediaSession(mMediaSession.getMediaSessionToken())
                        // For API < 21
                        // Show "X" button
                        .setShowCancelButton(true)
                        .setCancelButtonIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(mService, PlaybackStateCompat.ACTION_STOP)))
                .setShowWhen(false)
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .setVisibility(Notification.VISIBILITY_PUBLIC)
                .setContentIntent(contentIntent)
//                .setDeleteIntent(stopService)
                .setColor(ContextCompat.getColor(mService, R.color.colorPrimaryDark))
                .setContentTitle(description.getTitle())
                .setContentText(description.getSubtitle())
                .setLargeIcon(art)
                .setSmallIcon(R.mipmap.ic_launcher);
        return notificationBuilder.build();
    }
    private void addActions(NotificationCompat.Builder notificationBuilder) {
        NotificationCompat.Action PlayPause, Prev, Next;
        Prev = new NotificationCompat.Action(android.R.drawable.ic_media_previous, "Previous",
                MediaButtonReceiver.buildMediaButtonPendingIntent(mService, PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS));
        if (playbackState == PlaybackStateCompat.STATE_PLAYING)
            PlayPause = new NotificationCompat.Action(android.R.drawable.ic_media_pause, "Pause",
                    MediaButtonReceiver.buildMediaButtonPendingIntent(mService, PlaybackStateCompat.ACTION_PLAY_PAUSE));
        else
            PlayPause = new NotificationCompat.Action(android.R.drawable.ic_media_play, "Play",
                    MediaButtonReceiver.buildMediaButtonPendingIntent(mService, PlaybackStateCompat.ACTION_PLAY_PAUSE));
        Next = new NotificationCompat.Action(android.R.drawable.ic_media_next, "Next",
                MediaButtonReceiver.buildMediaButtonPendingIntent(mService, PlaybackStateCompat.ACTION_SKIP_TO_NEXT));
        notificationBuilder.addAction(Prev);
        notificationBuilder.addAction(PlayPause);
        notificationBuilder.addAction(Next);
    }
    @RequiresApi(Build.VERSION_CODES.O)
    private void createNotificationChannel() {
        if (mNotificationManager.getNotificationChannel(CHANNEL_ID) == null) {
            NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID,
                    "AUDIO_PLAYER_Channel_ID",
                    NotificationManager.IMPORTANCE_LOW);
            notificationChannel.setDescription("Channel ID for Audio Player");
            mNotificationManager.createNotificationChannel(notificationChannel);
        }
    }
    public void setmediaSessionHelper(MediaSessionHelper mMediaSessionHelper) {
        this.mMediaSession = mMediaSessionHelper;
    }
}

W klasie z serwisem (w naszym przypadku to PlayerService) w metodzie onCreate() dodaj:

mNotification = new MediaNotificationHelper(this);
mNotification.setmediaSessionHelper(mMediaSessionHelper);

W klasie MediaSessionHelper w poszczególnych metodach onPlay() / onStop() itp. dodaj wpis:

mNotification.updateNotification(statePlaying);

2. Wyjaśnienie powiadomień.

W metodzie updateNotification() wyświetlamy powiadomienia w zależności od stanu odtwarzania. Nas głównie interesuje metoda createNotification() w której wszystko się dzieje.
W androidzie Oreo wprowadzono kanały powiadomień. Wszystkie powiadomienia muszą być przypisane do kanału. Dla każdego kanału możesz ustawić wizualne i dźwiękowe zachowania powiadomień. Użytkownik może zmieniać te ustawienia i zdecydować, w jaki sposób powiadomienia mają się zachowywać w danym kanale. Po utworzeniu kanału powiadomień nie można zmienić zachowań. Jedynym sposobem, aby zmienić zachowania powiadomień to zmiana nazwy i opisu kanału. Jeśli utworzysz powiadomienie na Androidzie 8.0 bez określania kanału, powiadomienie nie pojawi się, a system zarejestruje błąd. W naszym przypadku aplikacja do odtwarzania muzyki nie potrzebuje specjalnych zachowań, dlatego wystarczy nazwa, opis i priorytet, który mówi, że powiadomienia ma się pojawić bez dźwięków i wibracji. Więcej o kanałach możesz przeczytać tutaj.
Następnie budujemy powiadomienie o następujących atrybutach. W metodzie addActions() dodajemy przyciski które chcemy aby pokazały się w powiadomieniach. U nas wystarczą tylko trzy. Klasa MediaStyle jest specjalnie stworzona dla powiadomień aplikacji multimedialnych, warto w tym przypadku skorzystać. Związku z tym w atrybucie setStyle mamy następujące opcje:

  • setShowActionsInCompactView – która ikona ma pokazać się gdy jest kompaktowe (małe) powiadomienie. W naszym przypadku pokazuje play lub pauzę w zależności od stanu odtwarzania.
  • setMediaSession – ustawiając token, informujesz systemowy interfejs użytkownika, że ma do czynienia z aktywną sesję multimedialną i może na przykład wyświetlić okładkę albumu na ekranie blokady.
  • setShowCancelButton – dla systemu Android poniżej 5.0. Ustawiamy czy ma pokazać ikonę „X”, aby usunąć powiadomienie,
  • setCancelButtonIntent – zachowanie po przyciśnięciu ikony „X”.

Kolejne atrybuty kreatora powiadomienia to:

  • setShowWhen – czy ma pokazywać się czas utworzonego powiadomienia,
  • setPriority – ustawienie priorytetu powiadomienia. W przykładzie – brak dźwięków i wibracji,
  • setContentIntent – otwieramy aplikację po kliknięciu w powiadomienie,
  • setDeleteIntent – co ma się stać po usunięciu powiadomienia,
  • setColor – kolor tła dla Androida 6.0 i poniżej, a dla pozostałych kolor ikonek,
  • setContentTitle – ustawienie tytułu powiadomienia – w naszym przypadku artysta,
  • setContentText – ustawienie opisu powiadomienia – w naszym przypadku tytuł utworu,
  • setLargeIcon – ustawienie dużej ikony powiadomienia,
  • setSmallIcon – ustawienie małej ikony powiadomienia.

Oczywiście nie jest to lista zamknięta, możemy ustawić jeszcze własne atrybuty według potrzeb. Tutaj tylko pokazałem te, które są wymagane i warto dodać do naszej aplikacji. Poniżej przykład wyglądu powiadomień. Od lewej: Android 5, Android 7, Android 8.
Powiadomienia w poszczególnych wersjach Androida

3. Podsumowanie.

Wiesz już jak budować powiadomienia dla aplikacji multimedialnych. Gdybyś chciał więcej dowiedzieć się o powiadomieniach zobacz ten przewodnik.Teraz masz już pełnosprawną aplikację do odtwarzania muzyki. Mam nadzieje, że niedługo zobaczę Twoją aplikację multimedialną :).
Krótki wpis, ale dotarliśmy do końca i mam nadzieje, że Ci się pomógł.

Co dalej?

  • Polub stronę MYENV na Facebooku oraz śledź mnie na Twitterze
  • Zachęcam do komentowania i pisania propozycji tematów, o których chcesz przeczytać
  • Poleć ten wpis za pomocą poniższych przycisków. Będę Ci za to bardzo wdzięczny 🙂
  • Życzę Ci miłego dnia i miłego kodowania 🙂