3

Android Oreo stops my foreground service when I turn off screen. It happens, when device is unpluged. I test my app on Huawei MediaPad T5. I send test request every 30 seconds with Handler.postDelayed.

I read about background executions limits in Android 8. In migration guide, is written, that foreground service should work. I can't use JobScheduler, JobIntenService or WorkManager, because they can repeat only every 15 minutes.

I can't use Firebase Cloud Messaging, because my app does part of work offline.

I use also bound service, because it should not have background restrictions. Unfortunately, my app still not works correct.

I tried to use WakeLock, give service to another process, AlarmManager, add my app to Whitelist and it still not work.

I test running in background by simple post reqest. I connect to test server by Retrofit Library.

MainActivity

private LocalService mService;
private boolean mBound = false;
private Intent mIntent;

private ServiceConnection connection = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName className, IBinder service) {
        LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }

    @Override
    public void onServiceDisconnected(ComponentName arg0) {
        mBound = false;
        mService = null;
    }

};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mIntent = new Intent(this, LocalService.class);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        ContextCompat.startForegroundService(getApplicationContext(), mIntent);
    }
    PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
    cpuLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "kb:wl");
}

@Override
protected void onStart() {
    super.onStart();
    Intent intent = new Intent(this, LocalService.class);
    bindService(intent, connection, Context.BIND_AUTO_CREATE);
}

@Override
protected void onStop() {
    super.onStop();
    cpuLock.acquire();
}


public void onButtonClick(View v) {
    if (mBound) {
        bindService(mIntent, connection, BIND_AUTO_CREATE);
        mService.send();
    }
}

@Override
protected void onRestart() {
    super.onRestart();
    cpuLock.release();
}

LocalService class

public class LocalService extends Service {

    private IBinder mBinder = new LocalBinder();

    Handler mHandler;
    String DEBUG_TAG = "local";

    public class LocalBinder extends Binder {
        LocalService getService() {
            return LocalService.this;
        }
    }

    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager notificationManager =
                    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

            String channelId = "some_channel_id";
            CharSequence channelName = "Channel La Manche";
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel notificationChannel = new NotificationChannel(channelId, channelName, importance);
            notificationManager.createNotificationChannel(notificationChannel);

            Intent notificationIntent = new Intent(this, MainActivity.class);
            PendingIntent pendingIntent =
                    PendingIntent.getActivity(this, 0, notificationIntent, 0);

            Notification notification =
                    new Notification.Builder(this, channelId)
                            .setContentTitle("post title")
                            .setContentText("post text")
                            .setSmallIcon(R.drawable.ic_launcher_foreground)
                            .setContentIntent(pendingIntent)
                            .setTicker("post ticker")
                            .setOngoing(true)
                            .build();

            startForeground(1, notification);
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        mHandler = new Handler();
        return mBinder;
    }

    public void send() {
        mHandler.postDelayed(test, 1000);
    }

    private Runnable test = new Runnable() {

        public void run() {
            Retrofit retrofit = new Retrofit.Builder()
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .baseUrl("https://test.server.url/")
                    .build();
            Post servicePost = retrofit.create(Post.class);
            Call<String> request = servicePost.send("");
            request.enqueue(new Callback<String>() {

                @Override
                public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
                    Log.i(DEBUG_TAG, "Code " + response.code());
                }

                @Override
                public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
                    Log.i(DEBUG_TAG, "Not connected to server. " + t.getMessage());
                }

            });

            mHandler.postDelayed(test, 30 * 1000);
        }

    };

Post interface

@Headers("Content-Type: application/json" )
@POST("api/test")
Call<String> send(@Body String empty);

App works perfect, when tablet is charging or not charging and screen is on. Endomondo works correct even if screen is off. What do I wrong?

ali
  • 49
  • 1
  • 7

1 Answers1

2

You can solve your problem with the help of this repository. This repository is for location but I am sure it will help you a lot.

Miroslav Glamuzina
  • 4,472
  • 2
  • 19
  • 33
BlackBlind
  • 772
  • 9
  • 26
  • Thank you. It generally works good. I noticed that I can't get location from cell tower when screen is off. I tried to add Wakelock, but it didn't work. Is it possible to get this type of location? – ali May 17 '19 at 10:39
  • It not work on my device (tablet Huawei MediaPad T5). I turn off GPS, Wi-Fi, Wi-Fi scanning and screen. It should get location only from cell tower. I set also ignore optimalization option to true. App works only, when I press power button. Do you know, how to solve it? – ali May 20 '19 at 04:30
  • [Here](https://stackoverflow.com/questions/23710045/android-location-using-cell-tower) is link for you where you can get location from cell tower add this in that repository. – BlackBlind May 20 '19 at 06:49
  • I have one more question. I noticed system killed this app, when I opened Settings or Camera app. I tried to change return value in onSTartCommand to START_STICKY, but it didn't work. Is it possible, in order to system doesn't kill app? I read about change priority of app, but this requires root device. – ali May 27 '19 at 05:09
  • I donot know about that but can more describe me about your problem. – BlackBlind Jun 05 '19 at 06:18
  • I open and click some options in Android's Settings. For example I go to about app screen, I click uninstall button and then click no, I click clear storage of app and I click then no. Sometimes, system kills Local app. If I change return value in onStartCommand to START_STICKY, then system restarts app's foreground service after some seconds. It looks like problem with free memory. I checked RAM usage, but Android has average 700 MB of memory. Only problem is, when Android kills service and user turns off screen. Foreground service not restarts. – ali Jun 07 '19 at 10:55