Search code examples
javaandroidbroadcastreceiverandroid-9.0-piesamsung-galaxy

Android broadcast reciever called but doesn't starts foreground service


I set up broadcast reciever for restarting my foreground service after reboot.

I have two devices and it works on Meizu M1 note (android 5.1) but doesn't work on Samsung A8 (android 9). Looking for reason in restrictions after Oreo and seems like it ok, but just in case https://developer.android.com/about/versions/oreo/background.html

On the second one broadcast reciever called, but service not started after reboot.

Service tracks location and uses startForeground() with Notification for correct work. Also tried to add Worker to restart service after reboot, but seems like work missing after that.

Please, geve any suggestions why my reciever doesn't run service.

Thanks.

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.tracker">

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:name=".ui.di.App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:isolatedProcess="true"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <receiver android:name="com.example.tracker.ui.broadcast.ServiceRestart">
            <intent-filter>
                <action android:name="restartService" />
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.ACTION_BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

        <service
            android:name="com.example.tracker.ui.service.TrackerService"
            android:enabled="true" />

        <service
            android:name="com.example.tracker.ui.worker.RestartIntentService"
            android:enabled="true" />


        <activity android:name=".ui.screen.main.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>

Reciever:

public class ServiceRestart extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("Broadcast Listened", "Service tried to stop");
        Toast.makeText(context, "Broadcast: ServiceRestart launched " + intent.getAction(), Toast.LENGTH_LONG).show();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(new Intent(context, TrackerService.class));
        } else {
            context.startService(new Intent(context, TrackerService.class));
        }
    }
}

Service:

public class TrackerService extends Service implements LocationListener {

    public static final String TAG = "TrackerService";

    private static final int PROCESS_ID = 1024;

    private static final int INTERVAL = 120; //seconds

    private ConnectivityManager connectivityManager;

    private PeriodicWorkRequest workRequest;
    private PeriodicWorkRequest restartTrackerRequest;

    private DbFirebaseModel dbFirebaseModel = new DbFirebaseModel();

    private ServiceHandler mServiceHandler;

    private static final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message message) {
        }
    }

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

        HandlerThread mHandlerThread = new HandlerThread("TrackerService.HandlerThread");
        mHandlerThread.start();

        mServiceHandler = new ServiceHandler(mHandlerThread.getLooper());
    }

    public TrackerService() {
        super();
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);

        addNotificationAndStartForeground();

        addWorkers();

        mServiceHandler.post(() -> {
            connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            runLocationTransfer();
        });

        Log.d(TAG, "===== SERVICE START");

        return START_STICKY;
    }

    private void addWorkers() {

        workRequest = new PeriodicWorkRequest.Builder(
            FirebaseWorker.class, 15, TimeUnit.MINUTES, 2, TimeUnit.MINUTES)
            .build();
        WorkManager.getInstance(this).enqueueUniquePeriodicWork(
            FirebaseWorker.TAG,
            ExistingPeriodicWorkPolicy.REPLACE,
            workRequest);

        restartTrackerRequest = new PeriodicWorkRequest.Builder(
            TrackerRestartWorker.class, 15, TimeUnit.MINUTES, 2, TimeUnit.MINUTES
        ).build();
        WorkManager.getInstance(this).enqueueUniquePeriodicWork(
            TrackerRestartWorker.TAG,
            ExistingPeriodicWorkPolicy.REPLACE,
            restartTrackerRequest);

    }

    private void addNotificationAndStartForeground() {
        String name = getString(R.string.app_name);
        String description = "Service running...";
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);

        Notification.Builder notificationBuilder;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                Integer.toString(PROCESS_ID), "Tracker", NotificationManager.IMPORTANCE_HIGH);
            channel.setDescription("Notify me when location tracking");

            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(channel);

            notificationBuilder = new Notification.Builder(this, Integer.toString(PROCESS_ID));
            notificationBuilder.setContentTitle(name)
                .setContentText(description)
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentIntent(pendingIntent);

            notificationManager.notify(PROCESS_ID, notificationBuilder.build());
        } else {
            notificationBuilder = new Notification.Builder(this);
            notificationBuilder.setContentTitle(name)
                .setContentText(description)
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentIntent(pendingIntent);
        }

        startForeground(PROCESS_ID, notificationBuilder.build());
    }

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

        Log.d(TAG, "===== SERVICE STOP");

        if (FirebaseAuth.getInstance().getCurrentUser() == null) {
            WorkManager.getInstance(this).cancelWorkById(workRequest.getId());
            WorkManager.getInstance(this).cancelWorkById(restartTrackerRequest.getId());
            Log.d(TAG, "===== WORKERS STOP");
        }
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Log.d(TAG, "TASK REMOVED");
        Toast.makeText(this, "LOCATION TASK REMOVED", Toast.LENGTH_SHORT).show();

        super.onTaskRemoved(rootIntent);
    }

    private void runLocationTransfer() {

        LocationRequest locationRequest = new LocationRequest();
        locationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);

        locationRequest.setInterval(INTERVAL * 1000);
        locationRequest.setFastestInterval(INTERVAL * 1000);

        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
        builder.addLocationRequest(locationRequest);
        LocationSettingsRequest locationSettingsRequest = builder.build();

        SettingsClient settingsClient = LocationServices.getSettingsClient(this);
        settingsClient.checkLocationSettings(locationSettingsRequest);

        try {
            getFusedLocationProviderClient(this).requestLocationUpdates(locationRequest, new LocationCallback() {
                    @Override
                    public void onLocationResult(LocationResult locationResult) {
                        onLocationChanged(locationResult.getLastLocation());
                    }
                },
                Looper.myLooper());

        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void onLocationChanged(@NonNull Location location) {

        if (FirebaseAuth.getInstance().getCurrentUser() == null) {
            stopSelf();
            Log.d(TAG, "====== SERVICE STOPPED by itself");
        } else if (connectivityManager.getActiveNetworkInfo() != null
            && connectivityManager.getActiveNetworkInfo().isConnected()) {

            dbFirebaseModel.saveLocation(location);

            // test using sound notifications
            try {
                Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
                Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
                r.play();
            } catch (Exception e) {
                e.printStackTrace();
            }
            Toast.makeText(this, "LOCATION ------ LATITUDE: " + location.getLatitude() + " LONGITUDE: " + location.getLongitude(), Toast.LENGTH_SHORT).show();

        } else {
            saveToLocalStorage(location);
        }
    }


    private void saveToLocalStorage(Location location) {
        Hawk.init(this).build();

        String userId = Objects.requireNonNull(
            FirebaseAuth.getInstance().getCurrentUser()
        ).getUid();

        LocationData locationData = new LocationData(userId, location);

        long count = 0;
        if (Hawk.count() > count) {
            count = Hawk.count();
        }

        while (Hawk.contains(String.valueOf(count))) {
            count++;
        }

        Hawk.put(String.valueOf(count), locationData);

        Log.d(TAG, "HAWK /// Saved to local storage. COUNT = " + Hawk.count());
    }
}

Solution

  • Following steps helped me solve it:

    1. Remove and reinstall app

    2. Change manifest according to this

       <receiver android:name="com.foxminded.tracker.ui.broadcast.ServiceRestart"
       android:exported="true"
       android:enabled="true">
       <intent-filter>
           <action android:name="restartService" />
           <action android:name="android.intent.action.BOOT_COMPLETED" />
           <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
      
           <category android:name="android.intent.category.DEFAULT" />
       </intent-filter>
      

    Here added "android.intent.action.LOCKED_BOOT_COMPLETED" and android:exported="true" android:enabled="true"