5

I have a service which runs in foreground with, among other things, a stopwatch. When the service starts the notification appears, and when it ends I update it with sound and some text that indicates that it's finished. The problem is that this works well until api 25, but for 26 and 27 it updates the notification alright, but makes no sound. Here's the relevant code:

The creation of the notification inside the service:

mBuilder = new NotificationCompat.Builder(context, "Main")
            .setSmallIcon(R.drawable.ic_notification_temp)
            .setContentTitle(step.getDescription())
            .setContentText(getString(R.string.notification_text))
            .setVisibility(VISIBILITY_PUBLIC)
            .setOngoing(true);
            .setDeleteIntent(deletePendingIntent);
            .setContentIntent(contentPendingIntent);
            .addAction(R.drawable.ic_stop_red_24dp, getString(R.string.cancel),finnishPendingIntent);

mNotificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(mId, mBuilder.build());

The update to the notification builder when the "work" is finished:

mBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));        
mBuilder.setVibrate(new long[]{0, 300, 0, 400, 0, 500});
mBuilder.setOngoing(false);
mBuilder.setAutoCancel(true);
mBuilder.setContentText(getString(R.string.notification_finished_text));

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    mBuilder.setChannelId("Sound");
    mBuilder.setCategory(NotificationCompat.CATEGORY_ALARM);
}
mNotificationManager.notify(mId, mBuilder.build());

The 2 channels created just for api 26 or up on app start:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    // Create the normal NotificationChannel
    CharSequence name = getString(R.string.app_name);
    int importance = NotificationManager.IMPORTANCE_LOW;
    NotificationChannel channel = new NotificationChannel("Main", name, importance);
    // Register the channel with the system; you can't change the importance
    // or other notification behaviors after this
    NotificationManager notificationManager = (NotificationManager) getSystemService(
            NOTIFICATION_SERVICE);
    notificationManager.createNotificationChannel(channel);

    // Create theNotificationChannel with sound
    importance = NotificationManager.IMPORTANCE_HIGH;
    name = getString(R.string.notification_channel_sound);
    NotificationChannel sound = new NotificationChannel("Sound", name, importance);
    sound.enableVibration(true);
    sound.setVibrationPattern(new long[]{0, 300, 0, 400, 0, 500});
    AudioAttributes aa = new AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
            .setLegacyStreamType(AudioManager.STREAM_NOTIFICATION)
            .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
            .build();
    sound.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), aa);
    notificationManager.createNotificationChannel(sound);
}

And that's where I'm at now. I've tried to not use setsound() as I've read that the notification should just play the default sound with the appropriate importance (and of course I've even uninstalled the app between tries to correctly update the channel settings) but nothing seems to work for api 26 and I just don't know what I'm doing wrong.

TXinTXe
  • 63
  • 1
  • 7
  • what do you see in notification settings when you install your app? do you have your activity running when showing notification? – Viktor Yakunin Mar 12 '18 at 10:28
  • Did you check https://stackoverflow.com/questions/46019496/notification-sound-on-api-26/46192246? – Mohammad Tabbara Mar 12 '18 at 10:30
  • @ViktorYakunin The two channels are created successfully, but the notifications run from a service, although I tried to have the activity that calls the service active just in case. The notification show and behave correctly (first just the badge in the drawer with no visual interruption, then the updated text and the notification shows as it should, just without any sound). – TXinTXe Mar 12 '18 at 10:32
  • @MohammadTabbara yes, I tried like that to test if it was simply a problem of the emulator somehow not having the default notification sound, but it sounds just fine like that. But that workaround has it's share of problems... – TXinTXe Mar 12 '18 at 10:34
  • again, what do you see in Settings->Apps&Notifications->[your app]->App notifications ? – Viktor Yakunin Mar 12 '18 at 10:36
  • @ViktorYakunin First the notifications are on, the notification dot is also on and then on categories there are two, the main one with no sound and checked and the alarm one with make sound and pop on screen also checked. I think that that's all correct there. – TXinTXe Mar 12 '18 at 10:44
  • @TXinTXe if this is OK, than you need to try on real device with volume on - your code doesn't have any issues – Viktor Yakunin Mar 12 '18 at 10:56
  • @ViktorYakunin thanks, My problem is that neither me nor anyone I know has android 8 or up available. I'll try to find someone somewhere though, thanks again. – TXinTXe Mar 12 '18 at 11:43
  • @TXinTXe I'm having the same issue with the emulator. Happens for new AVDs, but works fine on one of my old AVDs and on a real device. Did you find a solution in the mean time? – mdiener Jul 03 '18 at 12:27
  • @mdiener nope, but it works in real devices no problem so no biggy – TXinTXe Jul 03 '18 at 15:52

2 Answers2

2

I had the exact same problems with most of my emulator AVDs. The following fixed it for me:

  • start the affected AVD
  • long press the AVD's power button
  • restart the AVD

Afterwards it should work again.

mdiener
  • 528
  • 3
  • 16
1

Tried to reproduce your issue and finished with created MVP, maybe this will help you to find the problem:

Activity:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        View btn = findViewById(R.id.clickMe);
        btn.setTag(NotifService.CHANNEL_ID_MAIN);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String channelId = (String) v.getTag();
                Intent intent = new Intent(v.getContext(), NotifService.class);
                intent.putExtra(NotifService.TAG, channelId);
                if (channelId.equals(NotifService.CHANNEL_ID_MAIN)) {
                    v.setTag(NotifService.CHANNEL_ID_SOUND);
                } else {
                    v.setTag(NotifService.CHANNEL_ID_MAIN);
                }
                v.getContext().startService(intent);
            }
        });
    }
}

Service:

public class NotifService extends IntentService {
    public static final String TAG = "NotificationService";
    public static final String CHANNEL_ID_MAIN = "Main";
    public static final String CHANNEL_ID_SOUND = "Sound";
    public static final int NOTIFICATION_ID = 123;

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     */
    public NotifService() {
        super(TAG);//Used to name the worker thread, important only for debugging.
    }

    @Override
    public void onCreate() {
        super.onCreate();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID_MAIN, "Channel Main", NotificationManager.IMPORTANCE_LOW);
        NotificationChannel sound = new NotificationChannel(CHANNEL_ID_SOUND, "Channel Sound", NotificationManager.IMPORTANCE_HIGH);
            sound.enableVibration(true);
            sound.setVibrationPattern(new long[]{0, 300, 0, 400, 0, 500});
            AudioAttributes aa = new AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setLegacyStreamType(AudioManager.STREAM_NOTIFICATION)
                    .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
                    .build();
            sound.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), aa);
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            if (notificationManager != null) {
                notificationManager.createNotificationChannel(channel);
                notificationManager.createNotificationChannel(sound);
            }
        }
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        String channelId = intent.getStringExtra(TAG);
        showNotification(channelId);
    }

    private void showNotification(String channelId) {
        boolean inProgress = channelId.equals(CHANNEL_ID_MAIN);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentTitle("Work")
                .setContentText(inProgress ? "InProgress" : "Finished")
                .setOngoing(inProgress)
                .setVisibility(VISIBILITY_PUBLIC)
                .setAutoCancel(!inProgress);

        if (!inProgress) {
            builder.setCategory(NotificationCompat.CATEGORY_ALARM);
        }

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (notificationManager != null) {
            notificationManager.notify(NOTIFICATION_ID, builder.build());
        }
    }
}

This works good on my device 8.1 and Emulator 8.1 (without sound on first click for first notification and with vibration + sound on second click for work complete notification).

Viktor Yakunin
  • 2,927
  • 3
  • 24
  • 39
  • 1
    Ok. I've just copied all your code to a new project and tried it here and it does the same, the notification shows but without sound. So it has to be a problem with my emulator or something... Thank you very much! – TXinTXe Mar 12 '18 at 13:24