3

I have generated local notifications using Service. When the app is open, window the notifications works properly and they are show up. But when app is going to background or gets closed notifications, they are not showing. When I reopen my app all notifications shows up.

I have gone through lots of threads about this problem. So I tried startForeground, AlarmManager, BroadcastReceiver and nothing helps. Still local notifications are showing only if app is open. I figured out that when I set battery settings to set to run my app in the background in phone settings, then it is working properly and notifications do show up. But the user will not know that he should do this.

MyService:

public class MyService2 extends Service {

private boolean running = true;
private MyAsyncTask myAsyncTask;

@Override
public IBinder onBind(Intent arg0) {
    // TODO Auto-generated method stub
    return null;
}

public void onCreate() {
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    startForeground(1, showAndGetNotification(getApplicationContext(), "Twoja aplikacja działa w tle", "", new Intent(getApplicationContext(), MainActivity.class)));
    myAsyncTask = new MyAsyncTask();
    myAsyncTask.execute();
    return START_STICKY;
}

public void onDestroy() {
    super.onDestroy();
    stopForeground(true);
    stopSelf();
    if (myAsyncTask != null) {
        myAsyncTask.cancel(true);
    }
    running = false;
    SharedPreferences sharedPref = getSharedPreferences("service", Activity.MODE_PRIVATE);
    boolean fromAppStop = sharedPref.getBoolean("fromAppStop", false);
    if (!fromAppStop) {
        Intent broadcastIntent = new Intent(this, SensorRestarterBroadcastReceiver.class);
        sendBroadcast(broadcastIntent);
    }
    SharedPreferences.Editor editor = sharedPref.edit();
    editor.putBoolean("fromAppStop", false);
    editor.commit();
}

private class MyAsyncTask extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... voids) {
        try {
            while (running) {
                List<Map<String, String>> medicinesToTake = getMedicinesToTake();
                for (Map<String, String> medicineToTake : medicinesToTake) {
                    String medicineName = medicineToTake.keySet().toArray()[0].toString();
                    Thread.sleep(countSleepToNextTake(medicineToTake.get(medicineName)));
                    doAlarm("Czas na lek", medicineName, medicineName);
                }
                Thread.sleep(countLeftTimeForNextDay());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
}

private void doAlarm(String title, String medicineName, String body) {
    Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
    intent.putExtra("title", title);
    intent.putExtra("medicineName", medicineName);
    intent.putExtra("body", body);
    AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    int id = generateUniqueId();
    PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), id, intent, PendingIntent.FLAG_CANCEL_CURRENT);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pendingIntent);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pendingIntent);
    } else {
        alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pendingIntent);
    }
}

public Notification showAndGetNotification(Context context, String title, String body, Intent intent) {
    NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

    Date now = new Date();
    int notificationId = Integer.parseInt(new SimpleDateFormat("ddHHmmss", Locale.UK).format(now)) + new Random().nextInt();
    //String channelId = "channel-01";
    String channelId = UUID.randomUUID().toString();
    String channelName = "Channel Name";
    int importance = NotificationManager.IMPORTANCE_HIGH;

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        NotificationChannel mChannel = new NotificationChannel(
                channelId, channelName, importance);
        notificationManager.createNotificationChannel(mChannel);
    }

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setAutoCancel(true)
            .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
            .setContentText(body);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addNextIntent(intent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
            generateUniqueId(),
            PendingIntent.FLAG_UPDATE_CURRENT
    );
    mBuilder.setContentIntent(resultPendingIntent);

    notificationManager.notify(notificationId, mBuilder.build());

    return mBuilder.build();
}

private int generateUniqueId() {
    UUID idOne = UUID.randomUUID();
    String str = "" + idOne;
    int uid = str.hashCode();
    String filterStr = "" + uid;
    str = filterStr.replaceAll("-", "");
    return Integer.parseInt(str);
}
}

MyAlarmReceiver:

public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    String medicineName = intent.getStringExtra("medicineName");
    String body = intent.getStringExtra("body");

    Intent notificationIntent = null;
    String title = intent.getStringExtra("title");
    if (title.equals("Czas na lek")) {
        notificationIntent = new Intent(context, TimeForMedicineActivity.class);
        notificationIntent.putExtra("medicineName", medicineName);
    } else if (title.equals("Twój lek się skończył")) {
        notificationIntent = new Intent(context, AddOrDeleteMyMedicineActivity.class);
    } else if (title.equals("Twój lek się kończy")) {
        notificationIntent = new Intent(context, MainActivity.class);
    }

    NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

    Date now = new Date();
    int notificationId = Integer.parseInt(new SimpleDateFormat("ddHHmmss", Locale.UK).format(now)) + new Random().nextInt();
    String channelId = UUID.randomUUID().toString();
    String channelName = "Channel Name";
    int importance = NotificationManager.IMPORTANCE_HIGH;

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        NotificationChannel mChannel = new NotificationChannel(
                channelId, channelName, importance);
        notificationManager.createNotificationChannel(mChannel);
    }

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setAutoCancel(true)
            .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
            .setContentText(body);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addNextIntent(notificationIntent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
            generateUniqueId(),
            PendingIntent.FLAG_UPDATE_CURRENT
    );
    mBuilder.setContentIntent(resultPendingIntent);

    notificationManager.notify(notificationId, mBuilder.build());
}


private int generateUniqueId() {
    UUID idOne = UUID.randomUUID();
    String str = "" + idOne;
    int uid = str.hashCode();
    String filterStr = "" + uid;
    str = filterStr.replaceAll("-", "");
    return Integer.parseInt(str);
}
}
Akshay
  • 2,506
  • 4
  • 34
  • 55
Daniel
  • 41
  • 1
  • 4

1 Answers1

0

The problem is with MIUI OS that Huawei uses. It violates android spec, which says that services that used startForeground should be treated as foreground.

I have the same problem in my app. I found no better solution, other than detecting if the app is running on MIUI, and then opening an alert telling the user that if they want foreground, they should manually open the battery settings and add the app to exception.

You can try

        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        if (!pm.isIgnoringBatteryOptimizations(packageName)) {
            intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
            intent.setData(Uri.parse("package:" + packageName));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }

with

<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

but that will probably not work on MIUI.

f.khantsis
  • 3,256
  • 5
  • 50
  • 67