Could anyone provide an example which will generate ForegroundServiceStartNotAllowedException?

Viewed 530

Android 12 adds restrictions on ForegroundService launched from some background tasks. I have an app which uses multiple ForegroundServices and some of them are not in the except cases. However, the build targeted to API 31 has not encountered any problem or ForegroundServiceStartNotAllowedException when the build runs on Android 12 Beta 4 devices.

Can anyone provide an example to have the problem after built target to API 31?

1 Answers

in gradle:

compileSdkVersion 31
buildToolsVersion "31.0.0"
targetSdkVersion 31

in manifest:

 <service android:name=".MyForegroundService"
          android:exported="false"/>
       
<service android:name=".MyService"
         android:exported="false"/>

<receiver android:name=".MyBroadcastReceiver"
          android:exported="true">
              <intent-filter>
                  <action android:name="com.sdk12.foreground.ACTION"/>
              </intent-filter>
</receiver>

Receiver:

class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d("tag", "onReceive()");
        val myServiceIntent = Intent(context, MyForegroundService::class.java)
            Handler(Looper.getMainLooper()).postDelayed({ 
                try {
                    ContextCompat.startForegroundService(context,myServiceIntent)
                } catch (ex : ForegroundServiceStartNotAllowedException){
                    Log.d("tag","ForegroundServiceStartNotAllowedException")
                }
            }, 5000)
        }
}

foreground service:

class MyForegroundService : Service() {
    private lateinit var br: BroadcastReceiver

    override fun onBind(intent: Intent): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
        br = MyBroadcastReceiver()
        val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).apply {
            addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED)
        }
        registerReceiver(br, filter)

    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        val channelId = createNotificationChannel("channel1","My Background Service")

        val pendingIntent: PendingIntent =
            Intent(this, MainActivity::class.java).let { notificationIntent ->
                PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_MUTABLE)
            }

        val notificationBuilder = Notification.Builder(this, channelId )
        val notification = notificationBuilder.setOngoing(true)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle("title")
            .setContentText("contentText")
            .setCategory(Notification.CATEGORY_SERVICE)
            .setContentIntent(pendingIntent)
            .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE)
            .build()

        startForeground(1, notification)

        return START_STICKY

    }

    override fun onDestroy() {
        unregisterReceiver(br)
        super.onDestroy()
    }

    private fun createNotificationChannel(channelId: String, channelName: String): String {
        val chan = NotificationChannel(
            "channel1",
            channelName, NotificationManager.IMPORTANCE_NONE
        )
        chan.lightColor = Color.BLUE
        chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
        chan.importance = NotificationManager.IMPORTANCE_HIGH
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(chan)
        return channelId
    }
}

My Service:

class MyService : Service() {
    private lateinit var br: BroadcastReceiver

    override fun onBind(intent: Intent): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
        br = MyBroadcastReceiver()
        val filter = IntentFilter("com.sdk12.foreground.ACTION")
        registerReceiver(br, filter)

    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        return START_STICKY
    }

    override fun onDestroy() {
        unregisterReceiver(br)
        super.onDestroy()
    }
}

trigger service:

startService(Intent(this, MyService::class.java))

send your app to background and call from adb:

adb shell am broadcast -a com.sdk12.foreground.ACTION -f 0x01000000

this will make sure you are in background probably there are easier ways, but I find this most understandable

Related