13

I have need to start android foreground service, and launch activity from that service on device boot. I have extensively searched web and stackoverflow and tried different suggestions but it is very strange that I can not make this functionality work.

I can not understand what I am doing wrong.

Below is the code from my project and the content of manifest file.

what I am doing wrong and how to solve it, the functionality to work on most android devices?

This is my AndroidManifest.xml:

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


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


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <receiver android:name="kor.location.tracker.AutoStart">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>


        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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


        <service android:enabled="true"
            android:name="kor.location.tracker.WorkerService"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE"
            />

    </application>

</manifest>

This is my Austostart.java:

package kor.location.tracker;


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;

public class AutoStart  extends BroadcastReceiver
    {
        @Override
        public void onReceive(Context context, Intent arg1)
        {

            try {
                System.out.println("test1");
                if (Intent.ACTION_BOOT_COMPLETED.equals(arg1.getAction())) {
                    System.out.println("test2");
                    WorkerService.enqueueWork(context, new Intent());
                    System.out.println("test3");
                }

            }catch(Exception ex) {

                Toast.makeText(context, ex.getMessage(), Toast.LENGTH_LONG).show();
            }
            /*
            Intent intent = new Intent(context, WorkerService.class);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                context.startForegroundService(intent);
            } else {
                context.startService(intent);
            }
            Log.i("Autostart", "started");

             */
        }
    }

This is my service class WorkerService.java:

package kor.location.tracker;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;

public class WorkerService  extends JobIntentService
{

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, WorkerService.class, 104501, work);
    }
/*
    private static final String TAG = "MyService";
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    public void onDestroy() {
        Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
        Log.d(TAG, "onDestroy");
    }
*/
    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        Intent intents = new Intent(getBaseContext(),MainActivity.class);
        intents.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intents);
        //Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
        //Log.d(TAG, "onStart");
    }
/*
    @Override
    public void onStart(Intent intent, int startid)
    {
        final LocationListener mLocationListener = new LocationListener() {
            @Override
            public void onLocationChanged(final Location location) {
                //your code here
                String kuku = location.getLatitude() + "=" + location.getLongitude();
                Toast.makeText(WorkerService.this, kuku, Toast.LENGTH_LONG).show();
                Log.d(TAG, kuku);

                ;
                ;
                location.getAltitude();
                location.getSpeed();
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {

            }

            @Override
            public void onProviderEnabled(String provider) {

            }

            @Override
            public void onProviderDisabled(String provider) {

            }
        };

        LocationManager mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);


        try {

            mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000,
                    1, mLocationListener);

        }catch (SecurityException ex){

            Toast.makeText(this, ex.getMessage(), Toast.LENGTH_LONG).show();
            Log.d(TAG, ex.getMessage());
        }


        Intent intents = new Intent(getBaseContext(),MainActivity.class);
        intents.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intents);
        Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
        Log.d(TAG, "onStart");
    }
    */
}

And this is my activity that is not getting launched:

package kor.location.tracker;

import android.Manifest;
import android.content.pm.PackageManager;
import android.nfc.Tag;
import android.os.Bundle;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;

import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        Toast.makeText(getBaseContext(), "Hello........", Toast.LENGTH_LONG).show();


        List<String> permissions = new ArrayList<String>();

        if(getApplicationContext().checkCallingOrSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED){
            permissions.add(Manifest.permission.INTERNET);
        }

        if(getApplicationContext().checkCallingOrSelfPermission(Manifest.permission.RECEIVE_BOOT_COMPLETED) != PackageManager.PERMISSION_GRANTED){
            permissions.add(Manifest.permission.RECEIVE_BOOT_COMPLETED);
        }

        if(getApplicationContext().checkCallingOrSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
        }

        if(getApplicationContext().checkCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }

        if(getApplicationContext().checkCallingOrSelfPermission(Manifest.permission.FOREGROUND_SERVICE) != PackageManager.PERMISSION_GRANTED){
            permissions.add(Manifest.permission.FOREGROUND_SERVICE);
        }

        if(permissions.size()>0) {

            String[] arr = new String[permissions.size()];
            permissions.toArray(arr);
            //System.out.println();
            ActivityCompat.requestPermissions(this, arr, 1);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Simson
  • 3,373
  • 2
  • 24
  • 38
Tornike Shavishvili
  • 1,244
  • 4
  • 16
  • 35

4 Answers4

9

1- For Problem Starting Activity From Background

in API29 Android restricted, starting an activity from the background. The foreground service is also considered a background process. Your activity can be affected by this restriction if you test it in Android 10.

Android Q Restrictions: https://developer.android.com/guide/components/activities/background-starts

Possible solution: https://stackoverflow.com/a/59421118/11982611

2- Some brands limits applications to start in the boot to boost start up time of the device. So applications need exclusive permission to start in the boot.

Possible Solution (Programmatically) : https://stackoverflow.com/a/49167712/11982611

For Xiaomi, enabling Autostart from settings https://dontkillmyapp.com/xiaomi

Eren Tüfekçi
  • 2,463
  • 3
  • 16
  • 35
  • thank you very much. this indeed appeared to be the problem. I have managed to show notification on boot. I am testing on XIAOMI android 10 device. At this point i have two problems: the notification is disapearing automatically in several minutes after it is shown. Is there a way to tell system not to close notification? And i also have need to start foreground service automatically, once notification is shown. I have overlooked the web but unfortunately can not make it work. Maybe you could show me right a direction how to solve these two problems? I can also show you my current code. – Tornike Shavishvili Oct 19 '19 at 14:41
  • 1
    A foreground service notification shuldnt close unless you programatically close service, or your service crash. You should find out why it is closing with logs. It can be hard to find out depending the situation. And fot MI phones check auto start permission in settings. I will also think possibilities. If I can find out, will tell you. – Eren Tüfekçi Oct 19 '19 at 18:06
  • 1
    Actually I didn't understand your case. When the notification shows, it means your service is already started. Because your foreground service creates the notification. If you dont show notification with foreground service, then try start service instead of activit. Then start activity from this service – Eren Tüfekçi Oct 19 '19 at 18:34
  • 1
    I mean, in handlework method start a foreground service. And create a notification, For Android 10, add a pending intent to the notification, for other API's you can start activity from foreground service. If you can't handle it. Tell me I think we will succedd to find solution – Eren Tüfekçi Oct 19 '19 at 18:40
  • Thank you so much!!! My main goal is to start foreground service on device boot. But documentation states that BroadcastReceiver as for android 10 can only show notifications. I want to start foreground service on device boot and from that service lounch activity. i thought if i show notification on boot, i would be able to start foreground service for that notification automatically. – Tornike Shavishvili Oct 19 '19 at 19:43
  • I checked auto start permission in settings and it was off for my app and i have enabled it. i will revert all my changes back to serviceand check it. i kindly ask you: the way i am starting foreground service is correct? and what android versions will it wok? – Tornike Shavishvili Oct 19 '19 at 19:43
  • 1
    In Android 10 limits starting activity from background not starting a service. So you can start a service when boot completed. When you create a foreground service you have to create a notification. This notification can have a pending intent that opens an activity in Android 10 – Eren Tüfekçi Oct 19 '19 at 19:46
  • What is the solution proposed in this answer? – IgorGanapolsky Jun 08 '20 at 20:58
3

After I added the boot permissions in manifest file (see code below), BroadcastReceiver started to get boot completed event and the service is starting successfully. For the solution to work (as suggested by @Eren Tüfekçi) I had to enable auto start permission in phone settings for my application. If anyone has a solution, how to enable it programmatically, please let us know. Thank you.

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


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


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <receiver android:name="kor.location.tracker.AutoStart"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:directBootAware="true">
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                <action android:name="android.intent.action.REBOOT"/>
            </intent-filter>
        </receiver>


        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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


        <service android:enabled="true"
            android:name="kor.location.tracker.WorkerService"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE"
            />

    </application>

</manifest>
Tornike Shavishvili
  • 1,244
  • 4
  • 16
  • 35
1

Check this. In this way what you want to achieve should work. If you can not, logs should be followed to find out the problem.

  public class AutoStart  extends BroadcastReceiver
        {
            @Override
            public void onReceive(Context context, Intent arg1)
            {

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

                    }

                }catch(Exception ex) {

                    Toast.makeText(context, ex.getMessage(), Toast.LENGTH_LONG).show();
                }
}
}

In Service

public class WorkerService extends Service {
    public static final String CHANNEL_ID = "ForegroundServiceChannel";
    public static final String NEW_CHANNEL_ID = "AndroidForegroundServiceChannel";

    Notification notification;

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

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        {createNotificationChannel();  //for Android Oreo above notification channel mandatory }
    }

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

        try {  

            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
            {// if Android 10 create a pending intent and a full screen notification

    Intent fullScreenIntent = new Intent(this, "Your Activity".class);
    PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 2022,
            fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT); // For the activity opening when notification cliced

    notification= new NotificationCompat.Builder(this, NEW_CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle("Notification title")
            .setContentText("Notification Text")
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setCategory(NotificationCompat.CATEGORY_REMINDER)
            .setFullScreenIntent(fullScreenPendingIntent, true)
            .build();

    startForeground(2, notification);
}
            else
            {
//if below Android 10 created a notification for foreground service because it is mandatory
            Intent notificationIntent = new Intent(this, Your Activity.class);
            PendingIntent pendingNotificationIntent = PendingIntent.getActivity(this, 0022,
                    notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

            notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setContentText("Foreground Service")
                    .setSmallIcon(R.drawable.ic_notification)
                    .setSound(null)
                    .setContentIntent(pendingNotificationIntent)
                    .build();

             //for below Android 10 started activity
                    Intent i = new Intent(getApplicationContext(), Your Activity.class);
                    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);                     
                    getApplicationContext().startActivity(i);
                }


            startForeground(1, notification);
        }
        }
        catch (Exception e)
        {
            Toast.makeText(getApplicationContext(), "Foreground Service fault", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }

        return START_NOT_STICKY;
    }
   private void createNotificationChannel() {

      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            NotificationChannel serviceChannel = new NotificationChannel(
                    NEW_CHANNEL_ID,
                    "Android Foreground Service Channel",
                    NotificationManager.IMPORTANCE_HIGH
            );

            serviceChannel.setSound(null,null);
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);

        }

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

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

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

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
Eren Tüfekçi
  • 2,463
  • 3
  • 16
  • 35
  • I managed to start service on device boot and it show Toast. I have realized that it did not work previously because i had wrong boot permissions in my manifest file. The problem got solved after i added permissions in my manifest file – Tornike Shavishvili Oct 20 '19 at 12:26
1

I can still start the app on Boot. (Targeting API 29). By using broadcast receiver with intent ACTION_BOOT_COMPLETED.

The problem I faced after updating my android to version 9 on Honor brand of phone was introduction of advance app management for probably battery preservation which prevented my app from receiving the broadcast in the first place.

Go to Settings > Battery > App Launch > Go to your app and uncheck "Manage Automatically" > And make sure "Auto-launch", "Secondary launch", "Run in background" is checked and select "OK"

Reboot your phone and check if the app starts on boot or not. Hope this helps someone else.

Debasish Mitra
  • 1,394
  • 1
  • 14
  • 17