Skip to content

Commit

Permalink
thermal: add battery properties on Android (#29)
Browse files Browse the repository at this point in the history
* thermal: add battery parameters in Android

* remove debug-only code

* rename methods

* add documentation comments

* thermal: platform isolation

* update ThermalView.cs

* add comments

* add comments

* Remove struct ThermalStatus

* update ThermalView.cs

* bump to 2.0.0

* update date
  • Loading branch information
ruccho authored Jul 17, 2024
1 parent ff08fff commit 6f12132
Show file tree
Hide file tree
Showing 18 changed files with 1,019 additions and 180 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package jp.co.cyberagent.unitysupport.app;

import java.util.function.Consumer;

public class BatteryStatusReceiver implements jp.co.cyberagent.unitysupport.thermal.BatteryStatusReceiver {
private Consumer<Integer> onReceiveTemperature;
private Consumer<Integer> onReceiveVoltage;
private Consumer<Float> onReceiveLevel;
private Consumer<Integer> onReceiveStatus;

@Override
public void onReceiveBatteryTemperature(int temperature) {
onReceiveTemperature.accept(new Integer(temperature));
}

@Override
public void onReceiveVoltage(int voltage) {
onReceiveVoltage.accept(new Integer(voltage));
}

@Override
public void onReceiveLevel(float level) {
onReceiveLevel.accept(new Float(level));
}

@Override
public void onReceiveStatus(int status) {
onReceiveStatus.accept(new Integer(status));
}

public BatteryStatusReceiver(
Consumer<Integer> onReceiveTemperature,
Consumer<Integer> onReceiveVoltage,
Consumer<Float> onReceiveLevel,
Consumer<Integer> onReceiveStatus) {
this.onReceiveTemperature = onReceiveTemperature;
this.onReceiveVoltage = onReceiveVoltage;
this.onReceiveLevel = onReceiveLevel;
this.onReceiveStatus = onReceiveStatus;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,21 @@ protected void onCreate(Bundle savedInstanceState) {
BatteryChangedBroadcastReceiver broadcastReceiver = new BatteryChangedBroadcastReceiver();
broadcastReceiver.registerToContext(this.getApplicationContext());
TextView textViewBatteryTemperature = findViewById(R.id.textViewBatteryTemperatureValue);
broadcastReceiver.addReceiver(new BatteryTemperatureReceiver(level -> {
textViewBatteryTemperature.setText(level.toString());
}));
TextView textViewBatteryVoltage = findViewById(R.id.textViewBatteryVoltageValue);
TextView textViewBatteryLevel = findViewById(R.id.textViewBatteryLevelValue);
TextView textViewBatteryStatus = findViewById(R.id.textViewBatteryStatusValue);
broadcastReceiver.addReceiver(new BatteryStatusReceiver(
temperature -> {
textViewBatteryTemperature.setText(temperature.toString());
},
voltage -> {
textViewBatteryVoltage.setText(voltage.toString());
},
level -> {
textViewBatteryLevel.setText(level.toString());
},
status -> {
textViewBatteryStatus.setText(status.toString());
}));
}
}
66 changes: 66 additions & 0 deletions Android/app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,72 @@

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">

<TextView
android:id="@+id/textViewBatteryVoltage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="BatteryVoltage" />

<TextView
android:id="@+id/textViewBatteryVoltageValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="-" />

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">

<TextView
android:id="@+id/textViewBatteryLevel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="BatteryLevel" />

<TextView
android:id="@+id/textViewBatteryLevelValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="-" />

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">

<TextView
android:id="@+id/textViewBatteryStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="BatteryStatus" />

<TextView
android:id="@+id/textViewBatteryStatusValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="-" />

</LinearLayout>

</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
77 changes: 70 additions & 7 deletions Assets/Scripts/ThermalView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,102 @@
using System.Diagnostics;
using MobileSupport;
using UnityEngine;
using UnityEngine.Profiling;
using Debug = UnityEngine.Debug;

public class ThermalView : MonoBehaviour
{
private void Start()
{
#if UNITY_ANDROID
Thermal.OnBatteryTemperatureChanged += value => Debug.Log($"Battery Temperature: {value}");
Thermal.Android.OnBatteryTemperatureChanged += value =>
{
Profiler.BeginSample("OnBatteryTemperatureChanged");
Debug.Log($"Battery Temperature: {value}");
Profiler.EndSample();
};

Thermal.Android.OnBatteryVoltageChanged += voltage =>
{
Profiler.BeginSample("OnBatteryVoltageChanged");
Debug.Log($"Battery Voltage: {voltage} mV");
Profiler.EndSample();
};
#endif

#if UNITY_ANDROID || UNITY_IOS
Thermal.OnThermalStatusChanged += status => Debug.Log($"Thermal Status: {status}");

Thermal.OnBatteryLevelChanged += level => { Debug.Log($"Battery Level: {level}"); };

Thermal.OnBatteryStatusChanged += status => { Debug.Log($"Battery Status: {status}"); };

Thermal.OnThermalStatusChanged += status =>
{
Debug.Log($"Thermal Status: {status}");
};
Thermal.StartMonitoring();
#endif

#if UNITY_ANDROID
StartCoroutine(GetTemperaturesLooped());
StartCoroutine(GetValuesLooped());
#endif
}

private IEnumerator GetTemperaturesLooped()
#if UNITY_ANDROID
private IEnumerator GetValuesLooped()
{
Stopwatch sw = new();

double elapsed;
while (this)
{
yield return new WaitForSeconds(0.5f);

sw.Restart();
Thermal.GetThermalHeadroom(0, out var headroom, out var resultForecastSeconds, out var isLatestValue);
var elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;
Profiler.BeginSample("Android.GetThermalHeadroom");
Thermal.Android.GetThermalHeadroom(0, out var headroom, out var resultForecastSeconds,
out var isLatestValue);
Profiler.EndSample();
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;

Debug.Log(
$"Thermal Headroom: {headroom}, isLatestValue: {isLatestValue}, resultForecastSeconds: {resultForecastSeconds} (obtained in {elapsed} ms)");

sw.Restart();
var counter = Thermal.Android.GetBatteryEnergyCounter();
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;

Debug.Log(
$"Energy Counter: {counter} (obtained in {elapsed} ms)");

sw.Restart();
var currentNow = Thermal.Android.GetBatteryCurrentNow();
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;

Debug.Log(
$"Current Now: {currentNow} (obtained in {elapsed} ms)");

sw.Restart();
var capacity = Thermal.Android.GetBatteryCapacity();
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;

Debug.Log(
$"Capacity: {capacity} (obtained in {elapsed} ms)");

sw.Restart();
var chargeCounter = Thermal.Android.GetBatteryChargeCounter();
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;

Debug.Log(
$"Charge Counter: {chargeCounter} (obtained in {elapsed} ms)");

sw.Restart();
var currentAverage = Thermal.Android.GetBatteryCurrentAverage();
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;

Debug.Log($"Thermal Headroom: {headroom}, isLatestValue: {isLatestValue}, resultForecastSeconds: {resultForecastSeconds} (obtained in {elapsed} ms)");
Debug.Log(
$"Current Average: {currentAverage} (obtained in {elapsed} ms)");
}
}
#endif
}
8 changes: 8 additions & 0 deletions Packages/MobileSupportThermal/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Release notes

## v2.0.0 - 2024/07/17

- New Features :rocket:
- Thermal: New apis to get battery voltage and power consumption on Android
- Changed
- Thermal: Android-specific APIs are moved to nested class `Thermal.Android`
- Thermal: The type of `OnThermalStatusChanged` and `LatestThermalStatus` changed to platform-specific types `ThermalStatusIOS` `ThermalStatusAndroid`

## v1.0.0 - 2024/06/26

- New Features :rocket:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,93 @@
import java.util.HashSet;

public class BatteryChangedBroadcastReceiver extends BroadcastReceiver {

private static final int UNINITIALIZED_TEMPERATURE = -1;
private static final int VALUE_UNINITIALIZED = -1;
private static final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
private final HashSet<BatteryTemperatureReceiver> receivers = new HashSet<>();
private final HashSet<BatteryStatusReceiver> receivers = new HashSet<>();

private int prevTemperature = UNINITIALIZED_TEMPERATURE;
private int prevTemperature = VALUE_UNINITIALIZED;
private int prevVoltage = VALUE_UNINITIALIZED;
private int prevStatus = VALUE_UNINITIALIZED;
private float prevLevel = Float.NaN;

@Override
public void onReceive(Context context, Intent intent) {
onReceive(intent);
}

private void onReceive(Intent intent) {
// battery temperature
int temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);

int value = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
int voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, -1);

if (prevTemperature == value) return;
prevTemperature = value;
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 1); // unknown is 1

for (BatteryTemperatureReceiver receiver : receivers) {
receiver.onReceiveBatteryTemperature(value);
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
int levelScaled = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
float level = levelScaled / (float) scale;

if (prevTemperature != temperature) {
prevTemperature = temperature;
for (BatteryStatusReceiver receiver : receivers) {
receiver.onReceiveBatteryTemperature(temperature);
}
}

if (prevVoltage != voltage) {
prevVoltage = voltage;
for (BatteryStatusReceiver receiver : receivers) {
receiver.onReceiveVoltage(voltage);
}
}

if (prevStatus != status) {
prevStatus = status;
for (BatteryStatusReceiver receiver : receivers) {
receiver.onReceiveStatus(status);
}
}

if (prevLevel != level) {
prevLevel = level;
for (BatteryStatusReceiver receiver : receivers) {
receiver.onReceiveLevel(level);
}
}
}

public void registerToContext(Context context) {
context.registerReceiver(this, intentFilter);
prevTemperature = UNINITIALIZED_TEMPERATURE;
Intent stickyIntent = context.registerReceiver(this, intentFilter);
if (stickyIntent != null) {
onReceive(stickyIntent);
}
}

public void unregisterFromContext(Context context) {
context.unregisterReceiver(this);
}

public void addReceiver(BatteryTemperatureReceiver receiver) {
public void addReceiver(BatteryStatusReceiver receiver) {
receivers.add(receiver);

if(prevTemperature != UNINITIALIZED_TEMPERATURE)
{
if (prevTemperature != VALUE_UNINITIALIZED) {
receiver.onReceiveBatteryTemperature(prevTemperature);
}

if (prevVoltage != VALUE_UNINITIALIZED) {
receiver.onReceiveVoltage(prevVoltage);
}

if (prevStatus != VALUE_UNINITIALIZED) {
receiver.onReceiveStatus(prevStatus);
}

if (!Float.isNaN(prevLevel)) {
receiver.onReceiveLevel(prevLevel);
}
}

public void removeReceiver(BatteryTemperatureReceiver receiver) {
public void removeReceiver(BatteryStatusReceiver receiver) {
receivers.remove(receiver);
}
}
Loading

0 comments on commit 6f12132

Please sign in to comment.