Я борюсь со своей службой переднего плана. На моем устройстве (Redmi 5 Plus, Android 8.1.0) сервисное уведомление больше не отображается, когда
приложение удалено из последних приложений. На других устройствах (Android 5.0.1, Android 7.0) и эмуляторе (android 8.1 - api 27) уведомление все еще отображается при удалении приложения из последних приложений.
Из основной деятельности я использую ContextCompat.startForegroundService(this, intent)
для запуска службы.
Ниже код службы переднего плана:
package com.ngallazzi.bluetoothtests.services
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.*
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.support.v4.app.NotificationCompat
import android.support.v4.app.NotificationCompat.PRIORITY_LOW
import android.util.Log
import com.ngallazzi.blemanager.managers.DeviceScanningListener
import com.ngallazzi.blemanager.managers.InRangeDetectionManager
import com.ngallazzi.bluetoothtests.MainActivity
import com.polidea.rxandroidble2.RxBleDevice
/**
* BluetoothTests
* Created by Nicola on 12/17/2018.
* Copyright © 2018 Zehus. All rights reserved.
*/
class DeviceDetectionService : Service() {
private lateinit var detectionManager: InRangeDetectionManager
override fun onBind(intent: Intent): IBinder? {
// We don't provide binding, so return null
return null
}
override fun onCreate() {
super.onCreate()
detectionManager = InRangeDetectionManager(this)
}
@SuppressLint("MissingPermission")
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent != null) {
val action = intent.action
when (action) {
ACTION_START_FOREGROUND_SERVICE -> {
startForegroundService()
detectionManager.startDeviceScanning(object : DeviceScanningListener {
@SuppressLint("CheckResult")
override fun onDeviceFound(device: RxBleDevice) {
device.establishConnection(false).subscribe({
Log.v(TAG, "Connected")
displayNotification(getNotification("Connected with: {${device.name}}"))
}, {
displayNotification(getNotification("An error occurred: {$it.message!!}"))
})
}
override fun onError(message: String?) {
displayNotification(getNotification("An error occurred: {$message}"))
}
})
}
ACTION_STOP_FOREGROUND_SERVICE -> {
stopForegroundService()
}
}
}
return START_NOT_STICKY
}
@SuppressLint("MissingPermission")
private fun startForegroundService() {
startForeground(NOTIFICATION_ID, getNotification(SEARCHING_DEVICES_MESSAGE))
Log.v(TAG, "Device detection service started")
}
private fun getNotification(message: String): Notification {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
createChannel()
val mBuilder = NotificationCompat.Builder(this, CHANNEL_NAME).apply {
setSmallIcon(android.R.drawable.ic_menu_mylocation)
setContentTitle(message)
setContentIntent(getMainActivityPendingIntent())
}
return mBuilder
.setPriority(PRIORITY_LOW)
.setCategory(Notification.CATEGORY_SERVICE)
.build()
}
private fun displayNotification(notification: Notification) {
val mNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
mNotificationManager.notify(NOTIFICATION_ID, notification)
}
private fun getMainActivityPendingIntent(): PendingIntent {
// Create an Intent for the activity you want to start
val intent = Intent(this, MainActivity::class.java)
// Create the TaskStackBuilder
val pendingIntent = PendingIntent.getActivity(
this, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT
);
return pendingIntent!!
}
@TargetApi(26)
@Synchronized
private fun createChannel() {
val mNotificationManager = this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val importance = NotificationManager.IMPORTANCE_DEFAULT
val mChannel = NotificationChannel(CHANNEL_NAME, SEARCHING_DEVICES_MESSAGE, importance)
mNotificationManager.createNotificationChannel(mChannel)
}
private fun stopForegroundService() {
Log.d(TAG, "Stop foreground service.")
// Stop foreground service and remove the notification.
stopForeground(true)
// Stop the foreground service.
stopSelf()
}
override fun onDestroy() {
super.onDestroy()
}
companion object {
private val TAG = DeviceDetectionService::class.java.simpleName
const val NOTIFICATION_ID = 1
const val ACTION_START_FOREGROUND_SERVICE = "start_service"
const val ACTION_STOP_FOREGROUND_SERVICE = "stop_service"
const val CHANNEL_NAME = "DEVICE_DETECTION_SERVICE"
const val SEARCHING_DEVICES_MESSAGE = "Searching in range device"
}
}
А вот и мой файл манифеста:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ngallazzi.bluetoothtests">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:name=".App"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity" android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name=".services.DeviceDetectionService" android:enabled="true"/>
<receiver android:name=".BootCompletedReceiver" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.REBOOT"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
</application>
</manifest>
Что мне не хватает? Это что-то привязано к Пределам Фонового Исполнения?