Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Couldn't expand RemoteViews: MediaSessionCompat and NotificationCompat.MediaStyle on HUAWEI devices

My app crashes when I try to display an Notification on my HUAWEI P8 lite device running Android 5.0.1 (it works fine on Nexus and Samsung devices). Most of my code is taken from the video Media playback the right way (Big Android BBQ 2015) by Ian Lake. All of my code is inside an Android Service. If I remove the code:

builder.setStyle(new android.support.v7.app.NotificationCompat.MediaStyle()
            .setShowActionsInCompactView(0, 1)
            .setMediaSession(mMediaSessionCompat.getSessionToken()).setShowCancelButton(true)
            .setCancelButtonIntent(MediaStyleHelper.getActionIntent(this, KeyEvent.KEYCODE_MEDIA_STOP)));

Then the app does not crash and a notification is shown with a image and a title. But the Media Action buttons are missing.

StackTrace:

FATAL EXCEPTION: 
main Process: com.app.debug, PID: 21600 android.app.RemoteServiceException: 
Bad notification posted from package com.app.demo.debug: Couldn't expand RemoteViews for: 
StatusBarNotification(pkg=com.app.demo.debug user=UserHandle{0} id=1344663 tag=null score=0 key=0|com.app.demo.debug|1344663|null|10121: Notification(pri=0 contentView=com.app.demo.debug/0x109007f vibrate=null sound=null defaults=0x0 flags=0x62 color=0x00000000 category=transport actions=2 vis=PUBLIC))
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1534)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5538)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

Code:

private void setUpAsForeground(Book book) 
{

    updateMetaData(book);
    startForeground(NOTIFICATION_ID, setupAudioNotification());
}

public void updateMetaData(Book book) 
{
    if(mMediaSessionCompat!=null)
    {
        MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
        Bitmap bitmap = null;
        if(!TextUtils.isEmpty(book.imageUrl))
        {
            bitmap = getBookCover(book.imageUrl);
            if (bitmap != null) {
                builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap);
                builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, book.imageUrl);
            }
        }

        if(bitmap == null && !TextUtils.isEmpty(book.imageUrlList))
        {
            bitmap = getBookCover(book.imageUrlList);
            if (bitmap != null) {
                builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap);
                builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, book.imageUrlList);
            }
        }
        builder.putText(MediaMetadataCompat.METADATA_KEY_AUTHOR, book.authers);
        builder.putText(MediaMetadataCompat.METADATA_KEY_TITLE, book.title);
        builder.putText(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, getString(R.string.app_name));
        //builder.putText(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION, "");
        long duration = getDuration();
        if(duration!=-1)
        {
            builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration);
        }
        mMediaSessionCompat.setMetadata(builder.build());
    }

}

private Notification setupAudioNotification()
{
    android.support.v7.app.NotificationCompat.Builder builder = MediaStyleHelper.from(this, mMediaSessionCompat);
    builder.setColor(ContextCompat.getColor(this, R.color.my_black));
    builder.setSmallIcon(R.drawable.ic_stat_notify);
    setNotificationButtons(builder);

    builder.setStyle(new android.support.v7.app.NotificationCompat.MediaStyle()
            .setShowActionsInCompactView(0, 1)
            .setMediaSession(mMediaSessionCompat.getSessionToken()).setShowCancelButton(true)
            .setCancelButtonIntent(MediaStyleHelper.getActionIntent(this, KeyEvent.KEYCODE_MEDIA_STOP)));
    mNotification = builder.build();

    return mNotification;
}

private void setNotificationButtons(android.support.v7.app.NotificationCompat.Builder builder)
{
    if(isPlaying())
    {
        builder.addAction(new NotificationCompat.Action(getStopIcon(), getString(R.string.player_stop_accessibility), MediaStyleHelper.getActionIntent(this, KeyEvent.KEYCODE_MEDIA_STOP)));
        builder.addAction(new NotificationCompat.Action(getPauseIcon(), getString(R.string.player_pause_accessibility), MediaStyleHelper.getActionIntent(this, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)));

    }
    else
    {
        builder.addAction(new NotificationCompat.Action(getStopIcon(), getString(R.string.player_stop_accessibility), MediaStyleHelper.getActionIntent(this, KeyEvent.KEYCODE_MEDIA_STOP)));
        builder.addAction(new NotificationCompat.Action(getPlayIcon(), getString(R.string.player_play_accessibility), MediaStyleHelper.getActionIntent(this, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)));
    }
}

private int getStopIcon()
{
    if(AppConstants.SUPPORTS_LOLLIPOP)
    {
        return R.drawable.notification_btn_stop_black;
    }
    else
    {
        return R.drawable.notification_btn_stop_white;
    }
}
private int getPlayIcon()
{
    if(AppConstants.SUPPORTS_LOLLIPOP)
    {
        return R.drawable.notification_btn_play_black;
    }
    else
    {
        return R.drawable.notification_btn_play_white;
    }
}
private int getPauseIcon()
{
    if(AppConstants.SUPPORTS_LOLLIPOP)
    {
        return R.drawable.notification_btn_pause_black;
    }
    else
    {
        return R.drawable.notification_btn_pause_white;
    }
}


public static NotificationCompat.Builder from(
        Context context, MediaSessionCompat mediaSession) 
{
    MediaControllerCompat controller = mediaSession.getController();
    MediaMetadataCompat mediaMetadata = controller.getMetadata();
    MediaDescriptionCompat description = mediaMetadata.getDescription();

    NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
    builder
            .setContentTitle(description.getTitle())
            .setContentText(description.getSubtitle())
            .setSubText(description.getDescription())
            .setLargeIcon(description.getIconBitmap())
            .setContentIntent(controller.getSessionActivity())
            .setDeleteIntent(getActionIntent(context, KeyEvent.KEYCODE_MEDIA_STOP))
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
    return builder;
}
like image 368
Kasper Finne Nielsen Avatar asked Jan 18 '16 10:01

Kasper Finne Nielsen


1 Answers

The best solution for me, as suggested by @KasperFinneNielsen in the comments was to set the MediaStyle on devices that are not Huawei running

Build.VERSION_CODES.LOLLIPOP_MR1 

or

Build.VERSION_CODES.LOLLIPOP

So;

boolean isLollipopHuawei = (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1 ||
            android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) && Build.MANUFACTURER.equalsIgnoreCase("HUAWEI");
like image 200
Ndivhuwo Avatar answered Nov 13 '22 10:11

Ndivhuwo