Intent Service running properly on android 9 when app is in background - android

I have an Intent service & a BroadcastReceiver.
As per background limitation on Android Oreo & above, the background applications(when an application is not foreground ) cannot use the started service. When you call startService() method from the background applications simply through the IllegalStateException.
But In my case, My intent service is running properly even when the app is in the background.
I am using ADB cmd to trigger broadcast.
Please correct where I am missing.
adb shell am broadcast -a android.intent.action.TEST --es maxCountValue 10 -n com.example.servicedemo/.MyReceiver
enter code here
BroadcastReceiver class
class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(context, "CompleteReceiver", Toast.LENGTH_LONG).show()
if (intent!!.action.equals("android.intent.action.TEST")) {
val mIntent = Intent(context, MyIntentService::class.java).apply {
Log.v("MyIntentService", intent.data.toString())
this.putExtra("maxCountValue", 100)
}
context?.startService(mIntent)
}
}
}
Intent Service
private const val SERVICE_NAME = "MyIntentService"
class MyIntentService : IntentService(SERVICE_NAME) {
private val handler = Handler()
override fun onCreate() {
super.onCreate()
showToast("Job Execution Started")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
showToast("Job Execution onStartCommand")
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
showToast("Job Execution onDestroy")
}
override fun onHandleIntent(intent: Intent?) {
val maxCount = intent!!.getIntExtra("maxCountValue", -1)
for (i in 0 until maxCount) {
Log.d(SERVICE_NAME, "onHandleWork: The number is: $i")
try {
Thread.sleep(100)
} catch (e: InterruptedException) {
Log.d(SERVICE_NAME, "Exception: ")
e.printStackTrace()
}
}
}
private fun showToast(msg: String) {
handler.post {
Toast.makeText(this#MyIntentService, msg, Toast.LENGTH_LONG).show()
}
}
}
Manifest :
<service android:name=".MyIntentService"/>
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.TEST" />
</intent-filter>
</receiver>

"The definition of background for purposes of service limitations is distinct from the definition used by memory management; an app might be in the background as pertains to memory management, but in the foreground as pertains to its ability to launch services."
-
https://developer.android.com/about/versions/oreo/background
PS that's the whole purpose of services

Related

How to launch a service app from another app in Android?

I have a service app with no activity. I want to connect it with my main app, because I will send data from main app to service, then get response from it. Service should be launched programmatically.
If they was in same project, i could tag it in manifest like <service android:name.../> . I tried to intent but packageManager.getLaunchIntentForPackage also didn't work. Other apps with activity works with this way but service app is different.
Main App - Try to intent
val i = packageManager.getLaunchIntentForPackage("com.myexample.serviceapp")
if (i!=null) {
Log.d("MyService","Success")
startService(i)
} else {
Toast.makeText(this,"Fail",Toast.LENGTH_SHORT).show()
}
Main App - Manifest
<queries>
<package android:name="com.myexample.serviceapp"/>
</queries>
Service App
class RegistryService : Service() {
override fun onBind(p0: Intent?): IBinder? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("MyService","working")
Thread {
while (true) {
Log.d("MyService","working 2")
}
}.start()
return START_STICKY
}
}
Service Manifest
<service android:name=".RegistryService" />
It solve the problem.
val i = Intent().apply {
this.setClassName("com.myexample.serviceapp", "com.myexample.serviceapp.RegistryService")
}
startForegroundService(i)

Android background service not starting

I have read multiple threads on this issue but none of them solved my problem, so I gave up and decided to write this.
I have a service (right now it's a background service but I am going to turn it into a foreground service) which monitors the battery level so it can notify the user when it reaches a certain percentage.
abstract class MonitoringService : Service() {
private var maxPercentage: Int = -1
private var thread: Thread? = null
private lateinit var batteryManager: BatteryManager
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
batteryManager = getSystemService(BATTERY_SERVICE) as BatteryManager
Log.d(null, "created service")
}
override fun onDestroy() {
thread?.interrupt()
updateServiceState(false)
Log.d(null, "destroyed service")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
println("started service")
if (intent == null) {
stopSelf(startId)
updateServiceState(false)
report(applicationContext, "service started with intent null")
return START_NOT_STICKY
}
when (intent.action) {
ACTION_START_SERVICE -> {
// if a thread is already active interrupt it
thread?.interrupt()
if (updateMaxPercentage(intent, startId) == 1) return START_NOT_STICKY
thread = Thread(Runnable {
while (true) {
if (batteryManager.isCharging && batteryManager.getIntProperty(
BatteryManager.BATTERY_PROPERTY_CAPACITY
) == maxPercentage
) {
Log.d(null, "time to do it")
}
Log.d(null, "time to not do it")
try {
// sleep for 1 minute
Thread.sleep(60000)
} catch (exception: InterruptedException) {
stopSelf(startId)
updateServiceState(false)
return#Runnable
}
}
})
thread?.start()
updateServiceState(true)
}
ACTION_STOP_SERVICE -> {
thread?.interrupt()
stopSelf(startId)
updateServiceState(false)
return START_NOT_STICKY
}
ACTION_UPDATE_SERVICE -> if (updateMaxPercentage(intent, startId) == 1) return START_NOT_STICKY
else -> {
stopSelf(startId)
updateServiceState(false)
report(applicationContext, "service started with action null")
return START_NOT_STICKY
}
}
return START_REDELIVER_INTENT
}
}
I start the service like so from my activity
private fun start() {
val serviceIntent = Intent(applicationContext, MonitoringService::class.java)
serviceIntent.action = ACTION_START_SERVICE
serviceIntent.putExtra("maxPercentage", maxPercentage)
println(startService(intent))
Log.d(null, "startService")
}
This is my AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.segv.batconv">
<application
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:theme="#style/Theme.Batconv"
tools:targetApi="31">
<service
android:name=".MonitoringService"
android:enabled="true"/>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I am testing this on an Android 11 device. The logs show no errors but the service doesn't start.
Thanks.
Remove the abstract keyword from your MonitoringService declaration:
class MonitoringService : Service()
By declaring it abstract, you are saying that nothing can create an instance of that class.

Foreground service is getting killed outside without calling selfStop?

I am working on scheduling app in which i have to run the app until it completes it process
but the problem is , Process is getting killed after few minute even it is running on foreground service ...
class MyService : Service(){
#RequiresApi(Build.VERSION_CODES.O)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
showNotification()
println("intent ${startId}")
isServiceStarted =true
val action = intent?.action
when(action){
ADD_SERVICE ->{
val sms = intent.getParcelableExtra<Sms>(Add_kEY)
if(sms!=null) {
schedule(sms) } }
DELETE_SERVICE ->{ }
}
return START_REDELIVER_INTENT
}
}
// Manifest file
<service android:name=".service.MyService "
android:foregroundServiceType="dataSync"
/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
you should call startForeground() in your service to attach your service to your application lifecycle to prevent OS from killing your service.
foreground-services

How to track the removal of the application and send a notification?

There is a task to make it so that when an application is deleted from the phone, my application sends a notification: "application name" has been deleted.
I do it like this:
Manifest
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="servicereload" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" >
</service>
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val notificationManagerCompat = NotificationManagerCompat.from(this)
notificationManagerCompat.cancelAll()
val serviceIntent = Intent(this, MyService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(this, serviceIntent)
} else {
startService(Intent(this, MyService::class.java))
}
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED)
intentFilter.addDataScheme("package")
registerReceiver(MyReceiver(), intentFilter)
}
}
MyReceiver
class MyReceiver: BroadcastReceiver() {
val CHANNEL_ID = "ServiceChannel"
#SuppressLint("RemoteViewLayout")
override fun onReceive(context: Context?, intent: Intent?) {
var packageName = ""
try {
packageName = Objects.requireNonNull(intent!!.data)!!.encodedSchemeSpecificPart
Toast.makeText(context, "USER UNINSTALL : $packageName", Toast.LENGTH_SHORT).show()
Log.i("MyLog", "USER UNINSTALL : $packageName")
} catch (ex: Exception) {
Log.i("MyLog", "Exception: $ex")
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannel = NotificationChannel(CHANNEL_ID, "Channel", NotificationManager.IMPORTANCE_DEFAULT)
val notificationManager = context!!.getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(notificationChannel)
}
val notifyIntent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val notifyPendingIntent = PendingIntent.getActivity(context, 200, notifyIntent, 0)
val builder: NotificationCompat.Builder = NotificationCompat.Builder(context!!, CHANNEL_ID).apply {
setSmallIcon(R.mipmap.ic_launcher)
setContentTitle(context.getString(R.string.app_name))
setContentText("App ${packageName.substringAfterLast(".")} has been deleted")
priority = NotificationCompat.PRIORITY_DEFAULT
setContentIntent(notifyPendingIntent)
}
with(NotificationManagerCompat.from(context!!)) {
notify(200, builder.build())
}
}
}
MyService
class MyService : Service() {
override fun onBind(intent: Intent?): IBinder? {
return null
}
#RequiresApi(api = Build.VERSION_CODES.N)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.i("MyLog", "onStartCommand()")
someTask()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
Log.i("MyLog", "Service onDestroy()")
val intent = Intent()
intent.action = "servicereload"
intent.setClass(this, MyReceiver::class.java)
this.sendBroadcast(intent)
}
override fun onCreate() {
super.onCreate()
Log.i("MyLog", "Service onCreate()")
}
override fun onTaskRemoved(rootIntent: Intent?) {
val intent = Intent(applicationContext, this.javaClass)
intent.setPackage(packageName)
val pendingIntent = PendingIntent.getService(applicationContext, 1, intent, PendingIntent.FLAG_ONE_SHOT)
val alarmManager = applicationContext.getSystemService(ALARM_SERVICE) as AlarmManager
alarmManager.set(AlarmManager.ELAPSED_REALTIME,1000,pendingIntent)
super.onTaskRemoved(rootIntent)
}
private fun someTask() {
Log.i("MyLog", "Service someTask()")
// val intentFilter = IntentFilter()
// intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED)
// intentFilter.addDataScheme("package")
// registerReceiver(MyReceiver(), intentFilter)
Thread {
for (i in 1..50) {
Log.i("MyLog", "Service i = $i")
try {
TimeUnit.SECONDS.sleep(1)
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
// stopSelf()
}.start()
}
}
someTask() method, just to see if the service is up and running. I check on API 29+ emulators, if I manage to delete the application before 10 seconds, it works well but starts the second service in parallel, which is not good, and I don’t understand why?! If there is nothing to do, after 10 seconds it throws android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{ab817c0 u0 com.testappremovel/.MyService} If I remove onDestroy () or onTaskRemoved () in the service, there is no problem with parallel launch, but after 10 seconds it is cut down in any case and, accordingly, does not turn back on. I also have methods for determining the name and icon of the application by package in order to display them in the notification, but of course, when the application is already remote, I cannot get this data. Please tell me, how to do it right, so that everything works as it should?

How to solve the error: Not allowed to start service Intent : app is in background uid?

I have a service which started by on booted completed event it, but the app crashes with the error message as in above. Please help on how can I start my Service on BroadCast receiver event of Boot_Completed.
MyService.kt
class MyService : Service() {
override fun onCreate() {
Log.d(TAG, "onCreate")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onDestroy() {
Log.d(TAG, "DO SOME STAFF")
}
}
MyBroadCaster.kt
class StartRelayServiceAtBootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (Intent.ACTION_BOOT_COMPLETED == intent.action) {
val serviceIntent = Intent(context, MyService::class.java)
context.startService(serviceIntent)
}
}
}
Upon some searching I got the answer that I had to check the SDK version that I can then start it as foreground service or just with starteService;
class StartRelayServiceAtBootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (Intent.ACTION_BOOT_COMPLETED == intent.action) {
val intent = Intent(context, MyService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
Log.i("Autostart", "started")
}
}
}
There are limitations on apps in the background. Obviously, if the device just booted, all apps are "in the background". You cannot start a Service from a background app. You probably need to use JobScheduler to to what you want.
See this document for a discussion about the limitations on background apps and how to migrate to other solutions that are allowed:
https://developer.android.com/about/versions/oreo/background

Categories

Resources