Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fix the 'background service' problem on Android 8+

Tags:

java

android

I have code running a service behind the scenes. It is set to run when we copy the text to the phone. This code works fine on Android 8 below But the problem is when I run the app on Android 8 and above

In my searches, I realized that I had to use FOREGROUND_SERVICEs and give specific access to the project.

What solutions do you suggest now?

Service Class:

public class AutoDownloadService extends Service {

    private ClipboardManager mClipboardManager;
    public static final String CHANNEL_ID = "ForegroundServiceChannel";

    @Override
    public void onCreate() {
        super.onCreate();

        mClipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
        mClipboardManager.addPrimaryClipChangedListener(mOnPrimaryClipChangedListener);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        String input = intent.getStringExtra("inputExtra");
        createNotificationChannel();
        Intent notificationIntent = new Intent(this, SettingsActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Foreground Service")
                .setContentText(input)
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentIntent(pendingIntent)
                .build();

        startForeground(1, notification);
       //  stopSelf();
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mClipboardManager != null) {
            mClipboardManager.removePrimaryClipChangedListener(mOnPrimaryClipChangedListener);
        }
    }

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

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(
                    CHANNEL_ID,
                    "Foreground Service Channel",
                    NotificationManager.IMPORTANCE_DEFAULT
            );

            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);
        }
    }

    private ClipboardManager.OnPrimaryClipChangedListener mOnPrimaryClipChangedListener =
            new ClipboardManager.OnPrimaryClipChangedListener() {
                @Override
                public void onPrimaryClipChanged() {
                    ClipData clip = mClipboardManager.getPrimaryClip();
                    String textClipBoard = clip.getItemAt(0).getText().toString();
                    Toast.makeText(AutoDownloadService.this, textClipBoard, Toast.LENGTH_SHORT).show();
                }
            };
}

Manifest

<service
      android:name=".services.AutoDownloadService"
      android:exported="false"
      android:permission="android.permission.BIND_JOB_SERVICE" />
  • and add finally uses permission
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
like image 383
Amirhf Avatar asked Nov 04 '19 17:11

Amirhf


3 Answers

I think you should use Intent Service instead of service. what you can do is if system shutdown your service you can again trigger it after sometime using alarm manger.

like image 174
Atif AbbAsi Avatar answered Nov 10 '22 03:11

Atif AbbAsi


As stated in documentation

While an app is in the foreground, it can create and run both foreground and background services freely. When an app goes into the background, it has a window of several minutes in which it is still allowed to create and use services. At the end of that window, the app is considered to be idle. At this time, the system stops the app's background services, just as if the app had called the services' Service.stopSelf() methods.

So, you solution is to run foreground service on Android >= 8.0 and do something like this

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(Intent(this, AutoDownloadService.class))
        } else {
            startService(Intent(this, AutoDownloadService.class))
        }
}
like image 40
Samir Spahic Avatar answered Nov 10 '22 02:11

Samir Spahic


First of all, you should not do this. Monitoring clipboard in background is not something right.

Android 8 added some protection on this, so you should run as foreground services, to let the end user aware your app is monitoring the clipboard.

Anyway clipboard access only available to default IME from Android 10. So, your apps will not work in Android 10.

like image 1
Fung LAM Avatar answered Nov 10 '22 03:11

Fung LAM