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?