Qadir Hussain
Qadir Hussain

Reputation: 8856

Huawei, Honor phones battery optimisation, Foreground Service

This question may looks very broad but I will try to sum up as short I could do.

So I am replicating a sample app on Play store Multi Timer Free

App is for setting Multiple Timers.

I have almost completed the app. but I am facing some issues of battery optimization and Alarm Manager specifically Huawai and Honor (china Andorid OS). My Foreground service stops working after some time.

Question: Sample app mentioned above works very fantastic even without battery optimization whitelist. What could be the solution for this?

I have almost tries everything mentioned in links follows. but no luck

Doze mode - do foreground services continue to run?

How to handle background services in ANDROID O?

How to turn off battery optimization on Huawei devices

How to turn off battery optimization on the Huawei devices

How to turn off battery optimization on Huawei devices

Don't kill my app!

Huawei device killing my foreground service, even with dontkillmyapp.com's solution

Keep the device awake

Optimize for Doze and App Standby

Android M startActivity battery optimization

Battery optimizations (wakelocks) on Huawei EMUI 4.0+

service killed when app cloes just in huawei device

Oreo (8.1) cannot start activity on lock screen

Creating a never ending background service in Android > 7

How does doze mode affect background/foreground services, with/without partial/full wakelocks?

What to do if alarms or sleep tracking don’t work?

Sample Code, When pressed device lock/unlock button, I want a simple TOAST to be shown when SCREEN_ON broadcast is received. This works fine for some time.

But in Huawei device => After killing the app by swipe -> after a 1 - 2 minutes my toast will stop working.

package com.demo.forgroundservicedemo

import android.content.Intent
import android.os.IBinder
import androidx.core.app.NotificationCompat
import android.os.Build
import android.app.*
import android.app.NotificationManager
import android.app.NotificationChannel
import android.content.BroadcastReceiver
import android.content.Context
import android.content.IntentFilter
import android.graphics.Color
import android.util.Log
import androidx.annotation.RequiresApi
import android.os.SystemClock
import android.app.AlarmManager
import android.app.PendingIntent
import android.widget.Toast


class ForegroundService : Service() {

    override fun onCreate() {
        Log.e("ForegroundService", "onCreate called")
        super.onCreate()
    }

@RequiresApi(Build.VERSION_CODES.O)
private fun startMyOwnForeground() {
    val NOTIFICATION_CHANNEL_ID = CONST.CHANNELID
    val channelName = CONST.channelName
    val chan = NotificationChannel(
        NOTIFICATION_CHANNEL_ID,
        channelName,
        NotificationManager.IMPORTANCE_NONE
    )
    chan.lightColor = Color.BLUE
    chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
    val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    manager.createNotificationChannel(chan)

    val notificationIntent = Intent(this, MainActivity::class.java)

    notificationIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP

    val intent = PendingIntent.getActivity(
        this, 0,
        notificationIntent, 0
    )

    val notificationBuilder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
    notificationBuilder.setContentIntent(intent)
    val notification = notificationBuilder.setOngoing(true)
        .setSmallIcon(R.mipmap.ic_launcher)
        .setContentTitle(CONST.serviceTitle)
        .setPriority(NotificationManager.IMPORTANCE_MIN)
        .setCategory(Notification.CATEGORY_SERVICE)
        .setAutoCancel(false)
        .build()

    notification.flags = notification.flags or Notification.FLAG_AUTO_CANCEL
    startForeground(2, notification)
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

    Log.e("ForegroundService", "onStartCommand called")
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        Log.e("SDK_INT", ">= Build.VERSION_CODES.O")
        startMyOwnForeground()
    } else {
        startForeground(1, Notification())
    }

    registerBroadcastReceiver()
    return START_STICKY
}

override fun onDestroy() {
    Log.e("ForegroundService", "onDestroy called")
    super.onDestroy()
}

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

private var mPowerKeyReceiver: BroadcastReceiver? = null

private fun registerBroadcastReceiver() {

    Log.e("registerBroadcast", "called")
    val theFilter = IntentFilter()
    /** System Defined Broadcast  */
    theFilter.addAction(Intent.ACTION_SCREEN_ON)
    //theFilter.addAction(Intent.ACTION_SCREEN_OFF)

    mPowerKeyReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {

            Log.e("onReceive", "onReceive called")
            val strAction = intent!!.action

            if (strAction == Intent.ACTION_SCREEN_ON) {
                Toast.makeText(context, "SCREEN ON", Toast.LENGTH_LONG).show()
            }
        }
    }

    applicationContext.registerReceiver(mPowerKeyReceiver, theFilter)
}

private fun unregisterReceiver() {
    val apiLevel = Build.VERSION.SDK_INT

    if (apiLevel >= 7) {
        try {
            applicationContext.unregisterReceiver(mPowerKeyReceiver)
        } catch (e: IllegalArgumentException) {
            mPowerKeyReceiver = null
        }

    } else {
        applicationContext.unregisterReceiver(mPowerKeyReceiver)
        mPowerKeyReceiver = null
    }
}

override fun onTaskRemoved(rootIntent: Intent?) {
    super.onTaskRemoved(rootIntent)
    Log.e("onTaskRemoved", "onTaskRemoved called")
    unregisterReceiver()

    val restartService = Intent(
        applicationContext,
        this.javaClass
    )
    restartService.setPackage(packageName)
    val restartServicePI = PendingIntent.getService(
        applicationContext, 1, restartService,
        PendingIntent.FLAG_ONE_SHOT
    )
    val alarmService =
        applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
    alarmService.setExactAndAllowWhileIdle(
        AlarmManager.ELAPSED_REALTIME,
        SystemClock.elapsedRealtime() + 500,
        restartServicePI
    )
}
}

Upvotes: 6

Views: 1372

Answers (2)

Mary
Mary

Reputation: 11

Emui 5.0 / 5. X: Settings > Application Management > Settings > special access rights Zhidao > ignore battery optimization > application, set to allow. Emui 8.0 / 8. X: Settings > apps and notifications > app Management > Settings > special access > ignore battery optimization > app, set to allow

Upvotes: 0

Simon
Simon

Reputation: 1737

Maybe the problem is that you don't have setRepeating when scheduling an alarm?

I'm doing the same thing basically (updating the widget when the screen is ON), and I'm doing it like this:

alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis() + 1000, interval, pendingIntent)

Upvotes: 0

Related Questions