4

When my app creates a notification, its main activity disappears without a trace. This could just be a regular uncaught exception, because I'm not sure this particular device would show an error message in that case.

This problem only occurs on a Huawei Y560-L01 running Android 5.1.1. I don't have access to the device myself, which makes it tricky to debug. I could not reproduce it on an emulator configured with similar specs and running Lollipop (5.1).

Here's how I create the notification:

private static final int NOTIFICATION_ID = 1;

private final PlaybackService service; // Inherits from Service
private Bitmap logoBitmap; // Initialized before the notification is created

private void someMethod() {
    ...
    service.startForeground(NOTIFICATION_ID, createNotification());
    ...
}

private Notification createNotification() {
    PendingIntent contentIntent = TaskStackBuilder.create(service)
        .addParentStack(MainActivity.class)
        .addNextIntent(new Intent(service, MainActivity.class))
        .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

    PendingIntent stopIntent = service.createPendingIntentForAction(PlaybackService.STOP_ACTION);
    PendingIntent pauseIntent = service.createPendingIntentForAction(PlaybackService.PAUSE_ACTION);
    PendingIntent playIntent = service.createPendingIntentForAction(PlaybackService.PLAY_ACTION);

    NotificationCompat.MediaStyle mediaStyle = new NotificationCompat.MediaStyle()
        .setShowActionsInCompactView(0 /* Play/Pause */, 1 /* Stop */)
        .setShowCancelButton(true)
        .setCancelButtonIntent(stopIntent);

    int smallIcon = player.getState() == PlayerState.PLAYING ? R.drawable.ic_status_bar_play : R.drawable.ic_status_bar_pause;
    Bitmap largeIcon = logoBitmap;

    NotificationCompat.Action playOrPauseAction;
    if (player.getState() == PlayerState.PLAYING) {
        playOrPauseAction = new NotificationCompat.Action(R.drawable.ic_pause, "Pause", pauseIntent);
    } else {
        playOrPauseAction = new NotificationCompat.Action(R.drawable.ic_play, "Play", playIntent);
    }
    NotificationCompat.Action stopAction = new NotificationCompat.Action(R.drawable.ic_stop, "Stop", stopIntent);

    return new NotificationCompat.Builder(service.getApplicationContext())
        .setContentTitle(player.getStation().getName())
        .setContentText(player.getCurrentTrack())
        .setSmallIcon(smallIcon)
        .setLargeIcon(largeIcon)
        .setCategory(NotificationCompat.CATEGORY_SERVICE)
        .setPriority(NotificationCompat.PRIORITY_LOW)
        .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
        .setOngoing(true)
        .setContentIntent(contentIntent)
        .addAction(playOrPauseAction)
        .addAction(stopAction)
        .setStyle(mediaStyle)
        .build();
}

This is the RemoteServiceException that results in the app's death:

D/AndroidRuntime(14550): Shutting down VM
E/AndroidRuntime(14550): FATAL EXCEPTION: main
E/AndroidRuntime(14550): Process: com.frozenfractal.radio, PID: 14550
E/AndroidRuntime(14550): android.app.RemoteServiceException: Bad notification posted from package com.frozenfractal.radio: Couldn't expand RemoteViews for: StatusBarNotification(pkg=com.frozenfractal.radio user=UserHandle{0} id=1 tag=null score=-10 key=0|com.frozenfractal.radio|1|null|10174: Notification(pri=-1 contentView=com.frozenfractal.radio/0x109007f vibrate=null sound=null defaults=0x0 flags=0x62 color=0x00000000 category=service actions=2 vis=PUBLIC))
E/AndroidRuntime(14550):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1480)
E/AndroidRuntime(14550):        at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(14550):        at android.os.Looper.loop(Looper.java:135)
E/AndroidRuntime(14550):        at android.app.ActivityThread.main(ActivityThread.java:5298)
E/AndroidRuntime(14550):        at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(14550):        at java.lang.reflect.Method.invoke(Method.java:372)
E/AndroidRuntime(14550):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:911)
E/AndroidRuntime(14550):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:706)
I/Process (14550): Sending signal. PID: 14550 SIG: 9

However, this is preceded by an error in StatusBar (a different process), of type android.widget.RemoteViews$ActionException, which I think might be more relevant:

E/StatusBar( 3283): couldn't inflate view for notification com.frozenfractal.radio/0x1
E/StatusBar( 3283): android.widget.RemoteViews$ActionException: view: android.view.ViewStub doesn't have method: setTextColor(int)
E/StatusBar( 3283):     at android.widget.RemoteViews.getMethod(RemoteViews.java:776)
E/StatusBar( 3283):     at android.widget.RemoteViews.access$300(RemoteViews.java:75)
E/StatusBar( 3283):     at android.widget.RemoteViews$ReflectionAction.apply(RemoteViews.java:1285)
E/StatusBar( 3283):     at android.widget.RemoteViews.performApply(RemoteViews.java:2677)
E/StatusBar( 3283):     at android.widget.RemoteViews.apply(RemoteViews.java:2637)
E/StatusBar( 3283):     at com.android.systemui.statusbar.BaseStatusBar.inflateViews(BaseStatusBar.java:1201)
E/StatusBar( 3283):     at com.android.systemui.statusbar.BaseStatusBar.createNotificationViews(BaseStatusBar.java:1415)
E/StatusBar( 3283):     at com.android.systemui.statusbar.phone.PhoneStatusBar.addNotification(PhoneStatusBar.java:1660)
E/StatusBar( 3283):     at com.android.systemui.statusbar.BaseStatusBar$4$2.run(BaseStatusBar.java:300)
E/StatusBar( 3283):     at android.os.Handler.handleCallback(Handler.java:739)
E/StatusBar( 3283):     at android.os.Handler.dispatchMessage(Handler.java:95)
E/StatusBar( 3283):     at android.os.Looper.loop(Looper.java:135)
E/StatusBar( 3283):     at android.app.ActivityThread.main(ActivityThread.java:5298)
E/StatusBar( 3283):     at java.lang.reflect.Method.invoke(Native Method)
E/StatusBar( 3283):     at java.lang.reflect.Method.invoke(Method.java:372)
E/StatusBar( 3283):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:911)
E/StatusBar( 3283):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:706)
I/StatusBar( 3283): pkg com.frozenfractal.radio block 6
W/StatusBar( 3283): removeNotification for unknown key: 0|com.frozenfractal.radio|1|null|10174
D/PhoneStatusBar( 3283): mNotificationData.hasActiveClearableNotifications()=false
D/NotificationService(  953): onNotification error pkg=com.frozenfractal.radio tag=null id=1; will crashApplication(uid=10174, pid=14550)

It's true that ViewStub doesn't have a setTextColor(int) method, so I'm guessing there should not have been a ViewStub here, but rather an (inflated) TextView or similar.

I dived into the Android sources a bit, but it wasn't really enlightening. The RemoteViews$ActionException is thrown here. This is caught and logged by BaseStatusBar here.

Possibly relevant lines from build.gradle (I know some of this is out of date, but upgrading gave me a slew of compilation errors that I don't have time for right now):

minSdkVersion 16
targetSdkVersion 24
compileSdkVersion 24
buildToolsVersion "24.0.1"

dependencies {
    compile 'com.android.support:appcompat-v7:24.2.0'
    compile 'com.android.support:design:24.2.0'
}

There are a lot of questions on StackOverflow which ask about the RemoteServiceException, but most don't show any output from the StatusBar process, so it's hard to say if they're the same. And most are unanswered anyway. Only this seems to have a possible workaround in the comments. I also found this bug report for a different app, which shows the same stack traces, and is also on a Huawei device. It apparently got fixed by a system update, so it might not entirely be my own fault for a change.

If I had access to the device, I would try to simplify the notification until the problem goes away, but unfortunately I don't have that luxury. Does anyone see anything (potentially) wrong with my code? Or have an idea how I could change the code to reproduce the issue on an emulator?

Thomas
  • 174,939
  • 50
  • 355
  • 478
  • 3
    "Does anyone see anything (potentially) wrong with my code?" -- it seems OK. This issue [was reported previously](https://issuetracker.google.com/issues/37078372), if I am interpreting that issue and your question correctly. Huawei probably tinkered with something that the support library developers did not expect. – CommonsWare Feb 11 '18 at 16:30
  • Wow, yeah, that looks quite relevant, thanks for digging it up! I was also looking at [this issue](https://issuetracker.google.com/issues/36946453) which might somehow be related as well. I can imagine the support library implementing the `MediaStyle` as a custom remote view, and if the custom view is ignored then views that should have `setTextColor` might not have it... – Thomas Feb 11 '18 at 16:35

0 Answers0