1

We are creating internal app which needs to have unkillable or very long living websocket connection. How can I achieve that? I have it working in foreground service, disabled battery optimization etc. but it doesnt seem to work. I tried all standard options.

Command adb shell dumpsys deviceidle whitelist +PACKAGE doesnt seem to help either.

Would rooting phone and setting app as system app help? Are there enterprise Custom ROMs which give control over battery optimizations and other stuff?

KubenQPL
  • 113
  • 2
  • 11
  • If at all possible you shouldn't do this- Android is not set up to work this way. I would describe what you're using it for, so we can give you alternatives. – Gabe Sechan Sep 27 '21 at 15:35
  • @GabeSechan it must work this way. It is project working only in local network so FCM is not an alternative to my websocket. It is crucial for my use case that it works non stop and getting websocket messages instantly. Answer made by Graziano solved my problem. – KubenQPL Sep 28 '21 at 06:54
  • His solution isn't going to be stable if the device is actually used- even with a wakelock foreground services can and will be killed for resources. If this is what you need, Android is not an appropriate OS. Or change the requirement that the device is only on the local network so FCM will work. – Gabe Sechan Sep 28 '21 at 13:29

1 Answers1

2

You should use a Foreground Service with a partial wakelock, in order to prevent the phone from sleeping. Here below an example of Foreground Service Class that implements a Wakelock:

public class ICService extends Service {
    
    private static final int ID = 1;                        // The id of the notification
    
    private NotificationCompat.Builder builder;
    private NotificationManager mNotificationManager;
    private PowerManager.WakeLock wakeLock;                 // PARTIAL_WAKELOCK
    
    /**
     * Returns the instance of the service
     */
    public class LocalBinder extends Binder {
        public ICService getServiceInstance(){
            return ICService.this;
        }
    }
    private final IBinder mBinder = new LocalBinder();      // IBinder
    
    @Override
    public void onCreate() {
        super.onCreate();
        // PARTIAL_WAKELOCK
        PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"INSERT_YOUR_APP_NAME:wakelock");
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        startForeground(ID, getNotification());
        return START_NOT_STICKY;
    }
    
    @SuppressLint("WakelockTimeout")
    @Override
    public IBinder onBind(Intent intent) {
        if (wakeLock != null && !wakeLock.isHeld()) {
            wakeLock.acquire();
        }
        return mBinder;
    }
    
    @Override
    public void onDestroy() {
        // PARTIAL_WAKELOCK
        if (wakeLock != null && wakeLock.isHeld()) {
            wakeLock.release();
        }
        super.onDestroy();
    }

    private Notification getNotification() {
        final String CHANNEL_ID = "YOUR_SERVICE_CHANNEL";

        builder = new NotificationCompat.Builder(this, CHANNEL_ID);
        //builder.setSmallIcon(R.drawable.ic_notification_24dp)
        builder.setSmallIcon(R.mipmap.YOUR_RESOURCE_ICON)
            .setColor(getResources().getColor(R.color.colorPrimaryLight))
            .setContentTitle(getString(R.string.app_name))
            .setShowWhen(false)
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .setCategory(NotificationCompat.CATEGORY_SERVICE)
            .setOngoing(true)
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            .setContentText(composeContentText());

        final Intent startIntent = new Intent(getApplicationContext(), ICActivity.class);
        startIntent.setAction(Intent.ACTION_MAIN);
        startIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        startIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 1, startIntent, 0);
        builder.setContentIntent(contentIntent);
        return builder.build();
    }
}

Obviously you still have also to disable battery optimization for your app. You can browse a real working example of this service (but used for GPS) here.

Graziano
  • 313
  • 1
  • 4
  • 11