geekdroid/src/main/java/com/geekorum/geekdroid/battery/LiveData.kt
author Da Risk <da_risk@geekorum.com>
Tue, 18 Feb 2025 00:03:44 -0400
changeset 86 84e46eaf1ea0
parent 75 534a19e25217
permissions -rw-r--r--
geekdroid: add lowBatteryFlow() and isPowerSaveModeFlow()

/*
 * Geekdroid is a utility library for development on the Android
 * Platform.
 *
 * Copyright (C) 2017-2025 by Frederic-Charles Barthelery.
 *
 * This file is part of Geekdroid.
 *
 * Geekdroid is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Geekdroid is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Geekdroid.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.geekorum.geekdroid.battery

import android.app.Application
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build
import android.os.PowerManager
import androidx.lifecycle.LiveData
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlin.math.roundToInt

/**
 * Observe the battery to know if a low level was reached
 */
@Deprecated("Use Application.lowBatteryFlow()")
class LowBatteryLiveData(
    private val application: Application
) : LiveData<Boolean>() {
    private val intentFilter = IntentFilter().apply {
        addAction(Intent.ACTION_BATTERY_LOW)
        addAction(Intent.ACTION_BATTERY_OKAY)
    }

    private val broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            when (intent?.action) {
                Intent.ACTION_BATTERY_OKAY -> value = false
                Intent.ACTION_BATTERY_LOW -> value = true
            }
        }
    }

    override fun onActive() {
        application.registerReceiver(broadcastReceiver, intentFilter)
        val batteryStatus = application.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
        value  = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            batteryStatus?.getBooleanExtra(BatteryManager.EXTRA_BATTERY_LOW, false) ?: false
        } else {
            val level = batteryStatus?.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) ?: 0
            val scale = batteryStatus?.getIntExtra(BatteryManager.EXTRA_SCALE, 100) ?: 100
            val percent = level.toFloat() / scale * 100
            percent.roundToInt() <= 15
        }
    }

    override fun onInactive() {
        application.unregisterReceiver(broadcastReceiver)
    }
}

fun Application.lowBatteryFlow() = callbackFlow {
    val broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            when (intent?.action) {
                Intent.ACTION_BATTERY_OKAY -> trySend(false)
                Intent.ACTION_BATTERY_LOW -> trySend(true)
            }
        }
    }
    val intentFilter = IntentFilter().apply {
        addAction(Intent.ACTION_BATTERY_LOW)
        addAction(Intent.ACTION_BATTERY_OKAY)
    }
    registerReceiver(broadcastReceiver, intentFilter)

    val batteryStatus = registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
    val value  = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        batteryStatus?.getBooleanExtra(BatteryManager.EXTRA_BATTERY_LOW, false) == true
    } else {
        val level = batteryStatus?.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) ?: 0
        val scale = batteryStatus?.getIntExtra(BatteryManager.EXTRA_SCALE, 100) ?: 100
        val percent = level.toFloat() / scale * 100
        percent.roundToInt() <= 15
    }
    trySend(value)

    awaitClose {
        unregisterReceiver(broadcastReceiver)
    }
}


/**
 * Observe the [PowerManager] to know if the system is in Power saving mode.
 */
@Deprecated("Use isPowerSaveModeFlow(application, powerManager)")
class BatterySaverLiveData(
    private val application: Application,
    private val powerManager: PowerManager
) : LiveData<Boolean>() {

    private val intentFilter = IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)

    private val broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            value = powerManager.isPowerSaveMode
        }
    }

    override fun onActive() {
        application.registerReceiver(broadcastReceiver, intentFilter)
        value = powerManager.isPowerSaveMode
    }

    override fun onInactive() {
        application.unregisterReceiver(broadcastReceiver)
    }
}

fun isPowerSaveModeFlow(application: Application, powerManager: PowerManager) = callbackFlow {
    val broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            trySend(powerManager.isPowerSaveMode)
        }
    }
    application.registerReceiver(broadcastReceiver, IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED))

    trySend(powerManager.isPowerSaveMode)

    awaitClose {
        application.unregisterReceiver(broadcastReceiver)
    }
}