1

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

amirreza
  • 13
  • 4
  • Isn't the point of destroying or removing an app to stop it running? Wouldn't keeping it running also be a violation of privacy? I can't imagine many ways to do something like that unless you are creating malware. Unless I'm wrong I think that most devices would stop a service from running after it is destroyed or removed so I don't believe what you are asking is possible. (I don't know if this is true at all) So why do you need to know when a user is in a moving car? and how would you expect the app to know the difference between walking or driving? – The Grand J Sep 17 '20 at 05:09
  • @theGrandJ doesnt messaging apps use services like this to send new message notification? – amirreza Sep 17 '20 at 05:43
  • Yes but for that the app is either in the background or has to have explicit permissions set to allow it to do so. When you said destroy or remove I thought you mean delete the app from the device. Also normally i believe that when they run that way it can only be used to receive messages but not send them. (again not an expert) – The Grand J Sep 17 '20 at 06:59

2 Answers2

0

You should use Foreground Service if you want service running even your app is in background or closed

https://androidwave.com/foreground-service-android-example/

Vikas
  • 432
  • 4
  • 17
  • 2
    A link to a potential solution is always welcome, but please add context around the link so your fellow users will have some idea what it is and why it’s there. Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline. For more information check [this](https://meta.stackoverflow.com/tags/link-only-answers/info) – AgentP Sep 17 '20 at 05:41
0

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;
    }
}
   

   
             
Sibin
  • 511
  • 6
  • 10