Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stream Battery Eco Mode #16

Merged
merged 2 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.2.0

> Add Eco Mode Stream

- **FEAT**: Add eco mode stream `isBatteryEcoModeStream`.

## 0.0.1

> Initial release
Expand Down
31 changes: 16 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,22 @@ also to offer a less energy-consuming app.

## Features

| Feature | Android | iOS | Runtime | Event |
|:---------------------------------------------------------------------------------------------|:---------------------------------------:|:---------------------------------------:|:-------------------------------------:|:-----:|
| getPlatformInfo() | Yes | Yes | | |
| getBatteryLevel() | Yes | Yes | X | |
| getBatteryState() | No | Yes | X | |
| isBatteryInLowPowerMode() | Yes | Yes | X | |
| lowPowerModeEventStream() | Yes | Yes | X | X |
| getThermalState() | Yes | Yes | X | |
| getProcessorCount() | Yes | Yes | | |
| getTotalMemory() | Yes | Yes | | |
| getFreeMemory() | Yes | Yes | X | |
| getTotalStorage() | Yes | Yes | | |
| getFreeStorage() | Yes | Yes | X | |
| <span style="color: #3CB371">**isBatteryEcoMode()**</span> | <span style="color: #3CB371">Yes</span> | <span style="color: #3CB371">Yes</span> | <span style="color: #3CB371">X</span> | |
| <span style="color: #3CB371">**getEcoRange**()</span> | <span style="color: #3CB371">Yes</span> | <span style="color: #3CB371">Yes</span> | <span style="color: #3CB371">X</span> | |
| Feature | Android | iOS | Runtime | Event |
|:---------------------------------------------------------------------------------------------------|:---------------------------------------:|:---------------------------------------:|:-------------------------------------:|:-----:|
| getPlatformInfo() | Yes | Yes | | |
| getBatteryLevel() | Yes | Yes | X | |
| getBatteryState() | No | Yes | X | |
| isBatteryInLowPowerMode() | Yes | Yes | X | |
| lowPowerModeEventStream() | Yes | Yes | X | X |
| getThermalState() | Yes | Yes | X | |
| getProcessorCount() | Yes | Yes | | |
| getTotalMemory() | Yes | Yes | | |
| getFreeMemory() | Yes | Yes | X | |
| getTotalStorage() | Yes | Yes | | |
| getFreeStorage() | Yes | Yes | X | |
| isBatteryEcoModeStream | Yes | No | | X |
| <span style="color: #3CB371">**isBatteryEcoMode()**</span> | <span style="color: #3CB371">Yes</span> | <span style="color: #3CB371">Yes</span> | <span style="color: #3CB371">X</span> | |
| <span style="color: #3CB371">**getEcoRange**()</span> | <span style="color: #3CB371">Yes</span> | <span style="color: #3CB371">Yes</span> | <span style="color: #3CB371">X</span> | |


## Eco Mode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,66 @@ package sncf.connect.tech.flutter_eco_mode
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_BATTERY_CHANGED
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.BatteryManager.BATTERY_STATUS_CHARGING
import android.os.BatteryManager.BATTERY_STATUS_DISCHARGING
import android.os.BatteryManager.BATTERY_STATUS_FULL
import android.os.BatteryManager.BATTERY_STATUS_NOT_CHARGING
import android.os.Build
import android.os.Environment
import android.os.PowerManager
import android.os.PowerManager.THERMAL_STATUS_CRITICAL
import android.os.PowerManager.THERMAL_STATUS_EMERGENCY
import android.os.PowerManager.THERMAL_STATUS_LIGHT
import android.os.PowerManager.THERMAL_STATUS_MODERATE
import android.os.PowerManager.THERMAL_STATUS_NONE
import android.os.PowerManager.THERMAL_STATUS_SEVERE
import android.os.PowerManager.THERMAL_STATUS_SHUTDOWN
import android.os.StatFs
import androidx.annotation.RequiresApi
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.EventChannel
import sncf.connect.tech.flutter_eco_mode.BatteryState.CHARGING
import sncf.connect.tech.flutter_eco_mode.BatteryState.DISCHARGING
import sncf.connect.tech.flutter_eco_mode.BatteryState.FULL
import sncf.connect.tech.flutter_eco_mode.BatteryState.UNKNOWN
import sncf.connect.tech.flutter_eco_mode.ThermalState.CRITICAL
import sncf.connect.tech.flutter_eco_mode.ThermalState.FAIR
import sncf.connect.tech.flutter_eco_mode.ThermalState.SAFE
import sncf.connect.tech.flutter_eco_mode.ThermalState.SERIOUS

class FlutterEcoModePlugin : FlutterPlugin, EcoModeApi, EventChannel.StreamHandler {

class FlutterEcoModePlugin : FlutterPlugin, EcoModeApi {
private lateinit var context: Context

private val lowPowerModeEventChannel = "sncf.connect.tech/battery.isLowPowerMode"
private var eventSink: EventChannel.EventSink? = null

private var powerSavingReceiver: BroadcastReceiver? = null
private val batteryStateEventChannel = "sncf.connect.tech/battery.state"
private val batteryLevelEventChannel = "sncf.connect.tech/battery.level"

override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
EcoModeApi.setUp(flutterPluginBinding.binaryMessenger, this)
context = flutterPluginBinding.applicationContext
EventChannel(
flutterPluginBinding.binaryMessenger,
lowPowerModeEventChannel
).setStreamHandler(this)
lowPowerModeEventChannel,
).setStreamHandler(PowerModeStreamHandler(context))
EventChannel(
flutterPluginBinding.binaryMessenger,
batteryStateEventChannel,
).setStreamHandler(BatteryStateStreamHandler(context))
EventChannel(
flutterPluginBinding.binaryMessenger,
batteryLevelEventChannel,
).setStreamHandler(BatteryLevelStreamHandler(context))
}


override fun onDetachedFromEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
EcoModeApi.setUp(flutterPluginBinding.binaryMessenger, null)
}

override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
eventSink = events
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setupPowerSavingReceiver()
}
}

override fun onCancel(arguments: Any?) {
eventSink = null
context.unregisterReceiver(powerSavingReceiver)
}

override fun getPlatformInfo(): String {
val release: String = Build.VERSION.RELEASE
val device: String = Build.DEVICE
Expand All @@ -55,15 +72,12 @@ class FlutterEcoModePlugin : FlutterPlugin, EcoModeApi, EventChannel.StreamHandl
return "Android - $release - $device - $hardware - $product - $type"
}

override fun getBatteryLevel(): Double {
val batteryStatus = getBatteryStatus()
val batteryLevel: Double? = batteryStatus?.let { intent ->
val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
level * 100 / scale.toDouble()
}
return batteryLevel ?: 0.0
}
override fun getBatteryLevel(): Double = getBatteryLevel(getBatteryStatus())
private fun getBatteryLevel(intent: Intent?): Double = intent?.let {
val level: Int = it.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale: Int = it.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
level * 100 / scale.toDouble()
} ?: 0.0

override fun getBatteryState(): BatteryState {
val batteryStatus = getBatteryStatus()
Expand All @@ -79,18 +93,6 @@ class FlutterEcoModePlugin : FlutterPlugin, EcoModeApi, EventChannel.StreamHandl
return false // can't return null so we return false for older versions
}

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun setupPowerSavingReceiver() {
powerSavingReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
eventSink?.success(powerManager.isPowerSaveMode)
}
}
val filter = IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)
context.registerReceiver(powerSavingReceiver, filter)
}

override fun getThermalState(): ThermalState {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
Expand Down Expand Up @@ -141,27 +143,138 @@ class FlutterEcoModePlugin : FlutterPlugin, EcoModeApi, EventChannel.StreamHandl
}

private fun getBatteryStatus(): Intent? {
return IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { intentFilter ->
return IntentFilter(ACTION_BATTERY_CHANGED).let { intentFilter ->
context.registerReceiver(null, intentFilter)
}
}

private fun convertBatteryState(state: Int): BatteryState {
return when (state) {
BatteryManager.BATTERY_STATUS_CHARGING -> BatteryState.CHARGING
BatteryManager.BATTERY_STATUS_FULL -> BatteryState.FULL
BatteryManager.BATTERY_STATUS_DISCHARGING, BatteryManager.BATTERY_STATUS_NOT_CHARGING -> BatteryState.DISCHARGING
else -> BatteryState.UNKNOWN
BATTERY_STATUS_CHARGING -> CHARGING
BATTERY_STATUS_FULL -> FULL
BATTERY_STATUS_DISCHARGING, BATTERY_STATUS_NOT_CHARGING -> DISCHARGING
else -> UNKNOWN
}
}

private fun convertThermalState(state: Int): ThermalState {
return when (state) {
PowerManager.THERMAL_STATUS_NONE -> ThermalState.SAFE
PowerManager.THERMAL_STATUS_MODERATE, PowerManager.THERMAL_STATUS_LIGHT -> ThermalState.FAIR
PowerManager.THERMAL_STATUS_SEVERE -> ThermalState.SERIOUS
PowerManager.THERMAL_STATUS_CRITICAL, PowerManager.THERMAL_STATUS_EMERGENCY, PowerManager.THERMAL_STATUS_SHUTDOWN -> ThermalState.CRITICAL
THERMAL_STATUS_NONE -> SAFE
THERMAL_STATUS_MODERATE, THERMAL_STATUS_LIGHT -> FAIR
THERMAL_STATUS_SEVERE -> SERIOUS
THERMAL_STATUS_CRITICAL, THERMAL_STATUS_EMERGENCY, THERMAL_STATUS_SHUTDOWN -> CRITICAL
else -> ThermalState.UNKNOWN
}
}
}

class PowerModeStreamHandler(private val context: Context) : EventChannel.StreamHandler {

private var lowPowerModeEventSink: EventChannel.EventSink? = null
private var powerSavingReceiver: BroadcastReceiver? = null

override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
lowPowerModeEventSink = events

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setupPowerSavingReceiver()
}
}

override fun onCancel(p0: Any?) {
context.unregisterReceiver(powerSavingReceiver)
}

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun setupPowerSavingReceiver() {
powerSavingReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
lowPowerModeEventSink?.success(powerManager.isPowerSaveMode)
}
}
val filter = IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)
context.registerReceiver(powerSavingReceiver, filter)
}

}

class BatteryStateStreamHandler(private val context: Context) : EventChannel.StreamHandler {

private var batteryStateEventSink: EventChannel.EventSink? = null
private var batteryStateReceiver: BroadcastReceiver? = null

override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
batteryStateEventSink = events

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setupBatteryStateReceiver()
}
}

override fun onCancel(p0: Any?) {
context.unregisterReceiver(batteryStateReceiver)
}

@RequiresApi(Build.VERSION_CODES.M)
private fun setupBatteryStateReceiver() {
batteryStateReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
val event = when (intent?.action) {
ACTION_BATTERY_CHANGED ->
when (intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)) {
BATTERY_STATUS_CHARGING -> CHARGING.name
BATTERY_STATUS_FULL -> FULL.name
BATTERY_STATUS_DISCHARGING, BATTERY_STATUS_NOT_CHARGING -> DISCHARGING.name
else -> UNKNOWN.name
}
else -> DISCHARGING.name
}
batteryStateEventSink?.success(event)
}
}
val filterBatteryState = IntentFilter()
filterBatteryState.addAction(ACTION_BATTERY_CHANGED)
context.registerReceiver(batteryStateReceiver, filterBatteryState)
}

}

class BatteryLevelStreamHandler(private val context: Context) : EventChannel.StreamHandler {

private var batteryLevelEventSink: EventChannel.EventSink? = null
private var batteryLevelReceiver: BroadcastReceiver? = null

override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
batteryLevelEventSink = events

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setupBatteryLevelReceiver()
}
}

override fun onCancel(p0: Any?) {
context.unregisterReceiver(batteryLevelReceiver)
}


@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun setupBatteryLevelReceiver() {

batteryLevelReceiver = object : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent?) {
val batteryPct = intent?.let { i ->
val level: Int = i.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale: Int = i.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
level * 100 / scale.toFloat()
}
batteryLevelEventSink?.success(batteryPct?.toDouble())
}
}
val filter = IntentFilter(ACTION_BATTERY_CHANGED)
context.registerReceiver(batteryLevelReceiver, filter)

}

}
Loading
Loading