Search in sources :

Example 11 with MediaSessionCompat

use of android.support.v4.media.session.MediaSessionCompat in project kdeconnect-android by KDE.

the class MprisMediaSession method updateMediaNotification.

/**
 * Update the media control notification
 */
private void updateMediaNotification() {
    BackgroundService.RunCommand(context, service -> {
        // If the user disabled the media notification, do not show it
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        if (!prefs.getBoolean(context.getString(R.string.mpris_notification_key), true)) {
            closeMediaNotification();
            return;
        }
        // Make sure our information is up-to-date
        updateCurrentPlayer(service);
        // If the player disappeared (and no other playing one found), just remove the notification
        if (notificationPlayer == null) {
            closeMediaNotification();
            return;
        }
        // Update the metadata and playback status
        if (mediaSession == null) {
            mediaSession = new MediaSessionCompat(context, MPRIS_MEDIA_SESSION_TAG);
            mediaSession.setCallback(mediaSessionCallback);
            mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
        }
        MediaMetadataCompat.Builder metadata = new MediaMetadataCompat.Builder();
        // Fallback because older KDE connect versions do not support getTitle()
        if (!notificationPlayer.getTitle().isEmpty()) {
            metadata.putString(MediaMetadataCompat.METADATA_KEY_TITLE, notificationPlayer.getTitle());
        } else {
            metadata.putString(MediaMetadataCompat.METADATA_KEY_TITLE, notificationPlayer.getCurrentSong());
        }
        if (!notificationPlayer.getArtist().isEmpty()) {
            metadata.putString(MediaMetadataCompat.METADATA_KEY_AUTHOR, notificationPlayer.getArtist());
            metadata.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, notificationPlayer.getArtist());
        }
        if (!notificationPlayer.getAlbum().isEmpty()) {
            metadata.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, notificationPlayer.getAlbum());
        }
        if (notificationPlayer.getLength() > 0) {
            metadata.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, notificationPlayer.getLength());
        }
        Bitmap albumArt = notificationPlayer.getAlbumArt();
        if (albumArt != null) {
            metadata.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt);
        }
        mediaSession.setMetadata(metadata.build());
        PlaybackStateCompat.Builder playbackState = new PlaybackStateCompat.Builder();
        if (notificationPlayer.isPlaying()) {
            playbackState.setState(PlaybackStateCompat.STATE_PLAYING, notificationPlayer.getPosition(), 1.0f);
        } else {
            playbackState.setState(PlaybackStateCompat.STATE_PAUSED, notificationPlayer.getPosition(), 0.0f);
        }
        // Create all actions (previous/play/pause/next)
        Intent iPlay = new Intent(service, MprisMediaNotificationReceiver.class);
        iPlay.setAction(MprisMediaNotificationReceiver.ACTION_PLAY);
        iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
        iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
        PendingIntent piPlay = PendingIntent.getBroadcast(service, 0, iPlay, PendingIntent.FLAG_UPDATE_CURRENT);
        NotificationCompat.Action.Builder aPlay = new NotificationCompat.Action.Builder(R.drawable.ic_play_white, service.getString(R.string.mpris_play), piPlay);
        Intent iPause = new Intent(service, MprisMediaNotificationReceiver.class);
        iPause.setAction(MprisMediaNotificationReceiver.ACTION_PAUSE);
        iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
        iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
        PendingIntent piPause = PendingIntent.getBroadcast(service, 0, iPause, PendingIntent.FLAG_UPDATE_CURRENT);
        NotificationCompat.Action.Builder aPause = new NotificationCompat.Action.Builder(R.drawable.ic_pause_white, service.getString(R.string.mpris_pause), piPause);
        Intent iPrevious = new Intent(service, MprisMediaNotificationReceiver.class);
        iPrevious.setAction(MprisMediaNotificationReceiver.ACTION_PREVIOUS);
        iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
        iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
        PendingIntent piPrevious = PendingIntent.getBroadcast(service, 0, iPrevious, PendingIntent.FLAG_UPDATE_CURRENT);
        NotificationCompat.Action.Builder aPrevious = new NotificationCompat.Action.Builder(R.drawable.ic_previous_white, service.getString(R.string.mpris_previous), piPrevious);
        Intent iNext = new Intent(service, MprisMediaNotificationReceiver.class);
        iNext.setAction(MprisMediaNotificationReceiver.ACTION_NEXT);
        iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
        iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
        PendingIntent piNext = PendingIntent.getBroadcast(service, 0, iNext, PendingIntent.FLAG_UPDATE_CURRENT);
        NotificationCompat.Action.Builder aNext = new NotificationCompat.Action.Builder(R.drawable.ic_next_white, service.getString(R.string.mpris_next), piNext);
        Intent iOpenActivity = new Intent(service, MprisActivity.class);
        iOpenActivity.putExtra("deviceId", notificationDevice);
        iOpenActivity.putExtra("player", notificationPlayer.getPlayer());
        /*
                TODO: Remove when Min SDK >= 16
                The only way the intent extra's are delivered on API 14 and 15 is by either using a different requestCode every time
                or using PendingIntent.FLAG_CANCEL_CURRENT instead of PendingIntent.FLAG_UPDATE_CURRENT
             */
        PendingIntent piOpenActivity = TaskStackBuilder.create(context).addNextIntentWithParentStack(iOpenActivity).getPendingIntent(Build.VERSION.SDK_INT > 15 ? 0 : (int) System.currentTimeMillis(), PendingIntent.FLAG_UPDATE_CURRENT);
        NotificationCompat.Builder notification = new NotificationCompat.Builder(context, NotificationHelper.Channels.MEDIA_CONTROL);
        notification.setAutoCancel(false).setContentIntent(piOpenActivity).setSmallIcon(R.drawable.ic_play_white).setShowWhen(false).setColor(ContextCompat.getColor(service, R.color.primary)).setVisibility(androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC).setSubText(service.getDevice(notificationDevice).getName());
        if (!notificationPlayer.getTitle().isEmpty()) {
            notification.setContentTitle(notificationPlayer.getTitle());
        } else {
            notification.setContentTitle(notificationPlayer.getCurrentSong());
        }
        // Only set the notification body text if we have an author and/or album
        if (!notificationPlayer.getArtist().isEmpty() && !notificationPlayer.getAlbum().isEmpty()) {
            notification.setContentText(notificationPlayer.getArtist() + " - " + notificationPlayer.getAlbum() + " (" + notificationPlayer.getPlayer() + ")");
        } else if (!notificationPlayer.getArtist().isEmpty()) {
            notification.setContentText(notificationPlayer.getArtist() + " (" + notificationPlayer.getPlayer() + ")");
        } else if (!notificationPlayer.getAlbum().isEmpty()) {
            notification.setContentText(notificationPlayer.getAlbum() + " (" + notificationPlayer.getPlayer() + ")");
        } else {
            notification.setContentText(notificationPlayer.getPlayer());
        }
        if (albumArt != null) {
            notification.setLargeIcon(albumArt);
        }
        if (!notificationPlayer.isPlaying()) {
            Intent iCloseNotification = new Intent(service, MprisMediaNotificationReceiver.class);
            iCloseNotification.setAction(MprisMediaNotificationReceiver.ACTION_CLOSE_NOTIFICATION);
            iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
            iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
            PendingIntent piCloseNotification = PendingIntent.getBroadcast(service, 0, iCloseNotification, PendingIntent.FLAG_UPDATE_CURRENT);
            notification.setDeleteIntent(piCloseNotification);
        }
        // Add media control actions
        int numActions = 0;
        long playbackActions = 0;
        if (notificationPlayer.isGoPreviousAllowed()) {
            notification.addAction(aPrevious.build());
            playbackActions |= PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
            ++numActions;
        }
        if (notificationPlayer.isPlaying() && notificationPlayer.isPauseAllowed()) {
            notification.addAction(aPause.build());
            playbackActions |= PlaybackStateCompat.ACTION_PAUSE;
            ++numActions;
        }
        if (!notificationPlayer.isPlaying() && notificationPlayer.isPlayAllowed()) {
            notification.addAction(aPlay.build());
            playbackActions |= PlaybackStateCompat.ACTION_PLAY;
            ++numActions;
        }
        if (notificationPlayer.isGoNextAllowed()) {
            notification.addAction(aNext.build());
            playbackActions |= PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
            ++numActions;
        }
        // Documentation says that this was added in Lollipop (21) but it seems to cause crashes on < Pie (28)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            if (notificationPlayer.isSeekAllowed()) {
                playbackActions |= PlaybackStateCompat.ACTION_SEEK_TO;
            }
        }
        playbackState.setActions(playbackActions);
        mediaSession.setPlaybackState(playbackState.build());
        // Only allow deletion if no music is notificationPlayer
        notification.setOngoing(notificationPlayer.isPlaying());
        // Use the MediaStyle notification, so it feels like other media players. That also allows adding actions
        MediaStyle mediaStyle = new MediaStyle();
        if (numActions == 1) {
            mediaStyle.setShowActionsInCompactView(0);
        } else if (numActions == 2) {
            mediaStyle.setShowActionsInCompactView(0, 1);
        } else if (numActions >= 3) {
            mediaStyle.setShowActionsInCompactView(0, 1, 2);
        }
        mediaStyle.setMediaSession(mediaSession.getSessionToken());
        notification.setStyle(mediaStyle);
        notification.setGroup("MprisMediaSession");
        // Display the notification
        mediaSession.setActive(true);
        final NotificationManager nm = ContextCompat.getSystemService(context, NotificationManager.class);
        nm.notify(MPRIS_MEDIA_NOTIFICATION_ID, notification.build());
    });
}
Also used : MediaMetadataCompat(android.support.v4.media.MediaMetadataCompat) NotificationManager(android.app.NotificationManager) SharedPreferences(android.content.SharedPreferences) MediaStyle(androidx.media.app.NotificationCompat.MediaStyle) TaskStackBuilder(androidx.core.app.TaskStackBuilder) Intent(android.content.Intent) PendingIntent(android.app.PendingIntent) MediaSessionCompat(android.support.v4.media.session.MediaSessionCompat) PlaybackStateCompat(android.support.v4.media.session.PlaybackStateCompat) Bitmap(android.graphics.Bitmap) NotificationCompat(androidx.core.app.NotificationCompat) PendingIntent(android.app.PendingIntent)

Example 12 with MediaSessionCompat

use of android.support.v4.media.session.MediaSessionCompat in project kdeconnect-android by KDE.

the class MprisMediaNotificationReceiver method onReceive.

@Override
public void onReceive(Context context, Intent intent) {
    // First case: buttons send by other applications via the media session APIs
    if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
        // Route these buttons to the media session, which will handle them
        MediaSessionCompat mediaSession = MprisMediaSession.getMediaSession();
        if (mediaSession == null)
            return;
        mediaSession.getController().dispatchMediaButtonEvent(intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
    } else {
        // Second case: buttons on the notification, which we created ourselves
        // Get the correct device, the mpris plugin and the mpris player
        BackgroundService service = BackgroundService.getInstance();
        if (service == null)
            return;
        Device device = service.getDevice(intent.getStringExtra(EXTRA_DEVICE_ID));
        if (device == null)
            return;
        MprisPlugin mpris = device.getPlugin(MprisPlugin.class);
        if (mpris == null)
            return;
        MprisPlugin.MprisPlayer player = mpris.getPlayerStatus(intent.getStringExtra(EXTRA_MPRIS_PLAYER));
        if (player == null)
            return;
        // Forward the action to the player
        switch(intent.getAction()) {
            case ACTION_PLAY:
                player.play();
                break;
            case ACTION_PAUSE:
                player.pause();
                break;
            case ACTION_PREVIOUS:
                player.previous();
                break;
            case ACTION_NEXT:
                player.next();
                break;
            case ACTION_CLOSE_NOTIFICATION:
                // The user dismissed the notification: actually handle its removal correctly
                MprisMediaSession.getInstance().closeMediaNotification();
        }
    }
}
Also used : BackgroundService(org.kde.kdeconnect.BackgroundService) Device(org.kde.kdeconnect.Device) MediaSessionCompat(android.support.v4.media.session.MediaSessionCompat)

Example 13 with MediaSessionCompat

use of android.support.v4.media.session.MediaSessionCompat in project cordova-plugin-local-notifications by katzer.

the class Options method getMediaSessionToken.

/**
 * Gets the token for the specified media session.
 *
 * @return null if there no session.
 */
MediaSessionCompat.Token getMediaSessionToken() {
    String tag = options.optString("mediaSession", null);
    if (tag == null)
        return null;
    MediaSessionCompat session = new MediaSessionCompat(context, tag);
    return session.getSessionToken();
}
Also used : MediaSessionCompat(android.support.v4.media.session.MediaSessionCompat)

Example 14 with MediaSessionCompat

use of android.support.v4.media.session.MediaSessionCompat in project Signal-Android by WhisperSystems.

the class VoiceNotePlaybackService method onCreate.

@Override
public void onCreate() {
    super.onCreate();
    mediaSession = new MediaSessionCompat(this, TAG);
    voiceNotePlaybackParameters = new VoiceNotePlaybackParameters(mediaSession);
    mediaSessionConnector = new MediaSessionConnector(mediaSession);
    becomingNoisyReceiver = new BecomingNoisyReceiver(this, mediaSession.getSessionToken());
    keyClearedReceiver = new KeyClearedReceiver(this, mediaSession.getSessionToken());
    player = new VoiceNotePlayer(this);
    voiceNoteNotificationManager = new VoiceNoteNotificationManager(this, mediaSession.getSessionToken(), new VoiceNoteNotificationManagerListener());
    voiceNotePlaybackPreparer = new VoiceNotePlaybackPreparer(this, player, voiceNotePlaybackParameters);
    player.addListener(new VoiceNotePlayerEventListener());
    mediaSessionConnector.setPlayer(player);
    mediaSessionConnector.setEnabledPlaybackActions(SUPPORTED_ACTIONS);
    mediaSessionConnector.setPlaybackPreparer(voiceNotePlaybackPreparer);
    mediaSessionConnector.setQueueNavigator(new VoiceNoteQueueNavigator(mediaSession));
    VoiceNotePlaybackController voiceNotePlaybackController = new VoiceNotePlaybackController(player.getInternalPlayer(), voiceNotePlaybackParameters);
    mediaSessionConnector.registerCustomCommandReceiver(voiceNotePlaybackController);
    setSessionToken(mediaSession.getSessionToken());
    mediaSession.setActive(true);
    keyClearedReceiver.register();
}
Also used : MediaSessionCompat(android.support.v4.media.session.MediaSessionCompat) MediaSessionConnector(com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector)

Example 15 with MediaSessionCompat

use of android.support.v4.media.session.MediaSessionCompat in project zype-android by zype.

the class PlayerFragment method initMediaSession.

private void initMediaSession() {
    // ComponentName mediaButtonReceiver = new ComponentName(getContext().getApplicationContext(),
    // MediaButtonReceiver.class);
    ComponentName mediaButtonReceiver = new ComponentName(getContext().getApplicationContext(), RemoteControlReceiver.class);
    mediaSession = new MediaSessionCompat(getContext().getApplicationContext(), "TAG_MEDIA_SESSION", mediaButtonReceiver, null);
    mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
    Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
    mediaButtonIntent.setClass(getActivity(), RemoteControlReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 0, mediaButtonIntent, 0);
    mediaSession.setMediaButtonReceiver(pendingIntent);
    PlaybackStateCompat.Builder stateBuilder = new PlaybackStateCompat.Builder().setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PLAY_PAUSE);
    mediaSession.setPlaybackState(stateBuilder.build());
    mediaSession.setCallback(new MediaSessionCompat.Callback() {

        @Override
        public void onPlay() {
            super.onPlay();
        }

        @Override
        public void onPause() {
            super.onPause();
        }

        @Override
        public void onPlayFromMediaId(String mediaId, Bundle extras) {
            super.onPlayFromMediaId(mediaId, extras);
        }

        @Override
        public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
            return super.onMediaButtonEvent(mediaButtonEvent);
        }
    });
    MediaControllerCompat mediaController = new MediaControllerCompat(getActivity(), mediaSession);
    MediaControllerCompat.setMediaController(getActivity(), mediaController);
}
Also used : PlaybackStateCompat(android.support.v4.media.session.PlaybackStateCompat) Bundle(android.os.Bundle) ComponentName(android.content.ComponentName) PendingIntent(android.app.PendingIntent) Intent(android.content.Intent) PendingIntent(android.app.PendingIntent) MediaControllerCompat(android.support.v4.media.session.MediaControllerCompat) MediaSessionCompat(android.support.v4.media.session.MediaSessionCompat)

Aggregations

MediaSessionCompat (android.support.v4.media.session.MediaSessionCompat)31 Intent (android.content.Intent)17 PendingIntent (android.app.PendingIntent)16 ComponentName (android.content.ComponentName)10 PlaybackStateCompat (android.support.v4.media.session.PlaybackStateCompat)8 MediaMetadataCompat (android.support.v4.media.MediaMetadataCompat)5 Bundle (android.os.Bundle)4 Context (android.content.Context)3 NotificationCompat (android.support.v4.app.NotificationCompat)3 MediaControllerCompat (android.support.v4.media.session.MediaControllerCompat)3 KeyEvent (android.view.KeyEvent)3 SuppressLint (android.annotation.SuppressLint)2 NotificationManager (android.app.NotificationManager)2 IntentFilter (android.content.IntentFilter)2 Bitmap (android.graphics.Bitmap)2 NonNull (android.support.annotation.NonNull)2 Builder (com.google.android.gms.cast.Cast.CastOptions.Builder)2 NotificationChannel (android.app.NotificationChannel)1 SharedPreferences (android.content.SharedPreferences)1 Canvas (android.graphics.Canvas)1