Search code examples
javaandroidserviceactivity-recognition

android service always running and notify user when needed


I need a service to make a notification whenever the user is in a moving car. I use ActivityRecognition to find out when the user is in a car.the issue is I need my service to run even when the app is destroyed or removed by the user. I tried running the service on a different process but after a few minutes the service stops working.I also tried using foreground service but I had the same issue with that to.

this is my service class.

public class SpeedCheckerService extends Service {
    private final String CHANNEL_ID = "my_channel";

    private static SpeedCheckerService speedCheckerService;
    private ActivityRecognitionClient mActivityRecognitionClient;
    private boolean started = false;
    Date lastNotification;
    CountDownTimer countDownTimer;
    Intent intent;


    @Override
    public void onCreate() {
        createNotificationChannel();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    @Override
    public int onStartCommand(final Intent intent, int flags, int startId) {
        this.intent=intent;
        countDownTimer = new CountDownTimer(99999999,1000 * 60 * 1) {
            @Override
            public void onTick(long l) {
                recognizeActivity();
            }

            @Override
            public void onFinish() {
                countDownTimer.start();
            }
        }.start();
        return START_STICKY;
    }

    String detectedActivitiesToJson(ArrayList<DetectedActivity> detectedActivitiesList) {
        Type type = new TypeToken<ArrayList<DetectedActivity>>() {}.getType();
        System.out.println(detectedActivitiesList.toString());
        if ((detectedActivitiesList.size()>=1)&&(detectedActivitiesList.get(0).getType() == DetectedActivity.STILL) && (detectedActivitiesList.get(0).getConfidence()) >= 60){
            if(lastNotification!=null){
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(lastNotification);
                calendar.add(Calendar.MINUTE,5);
                Date newDate = calendar.getTime();
                calendar.clear();
                System.out.println(lastNotification.toString());
                System.out.println(newDate.toString());
                if(newDate.after(calendar.getTime()) == true)
                return null;
            }
            speedCheckerService.makeNotification();
            lastNotification = Calendar.getInstance().getTime();
        }
        return new Gson().toJson(detectedActivitiesList, type);
    }

    public void makeNotification() {
        createNotificationChannel();
        Intent intent = new Intent(this, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("title")
                .setContentText("text")
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setContentIntent(pendingIntent)
                .setSmallIcon(R.drawable.mapbox_logo_icon)
                .setColor(Color.parseColor("#00ff00"))
                .setAutoCancel(true);
        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
        notificationManager.notify(70, builder.build());
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = "guardian";
            String description = "alerting user";
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
            channel.setDescription(description);
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }

    public void recognizeActivity() {
        if((mActivityRecognitionClient==null)&&(!started))

        {
            mActivityRecognitionClient = new ActivityRecognitionClient(this);
            mActivityRecognitionClient.requestActivityUpdates(0, PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
            started = true;
        }

        speedCheckerService =this;

        if(ActivityRecognitionResult.hasResult(intent))

        {
            ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
            ArrayList<DetectedActivity> detectedActivities = (ArrayList) result.getProbableActivities();
            detectedActivitiesToJson(detectedActivities);
        }
    }

}

I would greatly appreciate if you can help me with my problem


Solution

  • Use foreground service instead of normal service and do the below changes

    public class SampleService extends Service {
    
      
        private NotificationManager mNotificationManager;
        /**
         * The identifier for the notification displayed for the foreground service.
         */
        private static final int NOTIFICATION_ID = 1231234;
       
    
        static void startService(Context context, String message) {
            Intent startIntent = new Intent(context, SampleService.class);
            startIntent.putExtra("inputExtra", message);
            ContextCompat.startForegroundService(context, startIntent);
    
        }
    
        static void stopService(Context context) {
            Intent stopIntent = new Intent(context, SampleService.class);
            context.stopService(stopIntent);
        }
    
        private void createNotificationChannel() {
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
                CharSequence name = "Sample Notification";
                // Create the channel for the notification
                NotificationChannel mChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, name,
                        NotificationManager.IMPORTANCE_DEFAULT);
                mChannel.setSound(null, null);
                // Set the Notification Channel for the Notification Manager.
                notificationManager.createNotificationChannel(mChannel);
            }
        }
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.d("Service", "onCreate");
            createNotificationChannel();
            mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
          
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d("Service", "onStartCommand");
         
            startForeground(NOTIFICATION_ID, getNotification(message);
           
           **// This is important, When your service got killed it will try to restart //the service. But some android vendor phones are restricted this autostart**
    
            return START_REDELIVER_INTENT;
        }
    
        @Override
        public void onDestroy() {
         
            super.onDestroy();
    
            Log.d("Service", "Service Destroyed");
        }
    
        @Override
        public void onTaskRemoved(Intent rootIntent) {
            Log.e("Service", "onTaskRemoved");
            super.onTaskRemoved(rootIntent);
        }
    
        private Notification getNotification(String contentMessage) {
            String title = getString(R.string.notification_title,
                    DateFormat.getDateTimeInstance().format(new Date()));
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this,
                    NOTIFICATION_CHANNEL_ID).setContentTitle(title).setContentText(contentMessage)
                    .setSmallIcon(R.drawable.notification)
                    .setOngoing(true)
                    .setPriority(Notification.PRIORITY_MAX)
                    .setTicker(contentMessage)
                    .setAutoCancel(false)
                    .setWhen(System.currentTimeMillis());
            return builder.build();
        }  
              
        /**
         * Returns true if this is a foreground service.
         *
         * @param context The {@link Context}.
         */
        public boolean serviceIsRunningInForeground(Context context) {
            ActivityManager manager = (ActivityManager) context.getSystemService(
                    Context.ACTIVITY_SERVICE);
            for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
                    Integer.MAX_VALUE)) {
                if (getClass().getName().equals(service.service.getClassName())){
                    if (service.foreground){
                        return true;
                    }
                }
            }
            return false;
        }
    }