Skip to content

Commit 6f12132

Browse files
authored
thermal: add battery properties on Android (#29)
* 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
1 parent ff08fff commit 6f12132

18 files changed

Lines changed: 1019 additions & 180 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package jp.co.cyberagent.unitysupport.app;
2+
3+
import java.util.function.Consumer;
4+
5+
public class BatteryStatusReceiver implements jp.co.cyberagent.unitysupport.thermal.BatteryStatusReceiver {
6+
private Consumer<Integer> onReceiveTemperature;
7+
private Consumer<Integer> onReceiveVoltage;
8+
private Consumer<Float> onReceiveLevel;
9+
private Consumer<Integer> onReceiveStatus;
10+
11+
@Override
12+
public void onReceiveBatteryTemperature(int temperature) {
13+
onReceiveTemperature.accept(new Integer(temperature));
14+
}
15+
16+
@Override
17+
public void onReceiveVoltage(int voltage) {
18+
onReceiveVoltage.accept(new Integer(voltage));
19+
}
20+
21+
@Override
22+
public void onReceiveLevel(float level) {
23+
onReceiveLevel.accept(new Float(level));
24+
}
25+
26+
@Override
27+
public void onReceiveStatus(int status) {
28+
onReceiveStatus.accept(new Integer(status));
29+
}
30+
31+
public BatteryStatusReceiver(
32+
Consumer<Integer> onReceiveTemperature,
33+
Consumer<Integer> onReceiveVoltage,
34+
Consumer<Float> onReceiveLevel,
35+
Consumer<Integer> onReceiveStatus) {
36+
this.onReceiveTemperature = onReceiveTemperature;
37+
this.onReceiveVoltage = onReceiveVoltage;
38+
this.onReceiveLevel = onReceiveLevel;
39+
this.onReceiveStatus = onReceiveStatus;
40+
}
41+
}

Android/app/src/main/java/jp/co/cyberagent/unitysupport/app/BatteryTemperatureReceiver.java

Lines changed: 0 additions & 20 deletions
This file was deleted.

Android/app/src/main/java/jp/co/cyberagent/unitysupport/app/MainActivity.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,21 @@ protected void onCreate(Bundle savedInstanceState) {
2727
BatteryChangedBroadcastReceiver broadcastReceiver = new BatteryChangedBroadcastReceiver();
2828
broadcastReceiver.registerToContext(this.getApplicationContext());
2929
TextView textViewBatteryTemperature = findViewById(R.id.textViewBatteryTemperatureValue);
30-
broadcastReceiver.addReceiver(new BatteryTemperatureReceiver(level -> {
31-
textViewBatteryTemperature.setText(level.toString());
32-
}));
30+
TextView textViewBatteryVoltage = findViewById(R.id.textViewBatteryVoltageValue);
31+
TextView textViewBatteryLevel = findViewById(R.id.textViewBatteryLevelValue);
32+
TextView textViewBatteryStatus = findViewById(R.id.textViewBatteryStatusValue);
33+
broadcastReceiver.addReceiver(new BatteryStatusReceiver(
34+
temperature -> {
35+
textViewBatteryTemperature.setText(temperature.toString());
36+
},
37+
voltage -> {
38+
textViewBatteryVoltage.setText(voltage.toString());
39+
},
40+
level -> {
41+
textViewBatteryLevel.setText(level.toString());
42+
},
43+
status -> {
44+
textViewBatteryStatus.setText(status.toString());
45+
}));
3346
}
3447
}

Android/app/src/main/res/layout/activity_main.xml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,72 @@
7575

7676
</LinearLayout>
7777

78+
<LinearLayout
79+
android:layout_width="match_parent"
80+
android:layout_height="wrap_content"
81+
android:layout_weight="1"
82+
android:orientation="horizontal">
83+
84+
<TextView
85+
android:id="@+id/textViewBatteryVoltage"
86+
android:layout_width="wrap_content"
87+
android:layout_height="wrap_content"
88+
android:layout_weight="1"
89+
android:text="BatteryVoltage" />
90+
91+
<TextView
92+
android:id="@+id/textViewBatteryVoltageValue"
93+
android:layout_width="wrap_content"
94+
android:layout_height="wrap_content"
95+
android:layout_weight="1"
96+
android:text="-" />
97+
98+
</LinearLayout>
99+
100+
<LinearLayout
101+
android:layout_width="match_parent"
102+
android:layout_height="wrap_content"
103+
android:layout_weight="1"
104+
android:orientation="horizontal">
105+
106+
<TextView
107+
android:id="@+id/textViewBatteryLevel"
108+
android:layout_width="wrap_content"
109+
android:layout_height="wrap_content"
110+
android:layout_weight="1"
111+
android:text="BatteryLevel" />
112+
113+
<TextView
114+
android:id="@+id/textViewBatteryLevelValue"
115+
android:layout_width="wrap_content"
116+
android:layout_height="wrap_content"
117+
android:layout_weight="1"
118+
android:text="-" />
119+
120+
</LinearLayout>
121+
122+
<LinearLayout
123+
android:layout_width="match_parent"
124+
android:layout_height="wrap_content"
125+
android:layout_weight="1"
126+
android:orientation="horizontal">
127+
128+
<TextView
129+
android:id="@+id/textViewBatteryStatus"
130+
android:layout_width="wrap_content"
131+
android:layout_height="wrap_content"
132+
android:layout_weight="1"
133+
android:text="BatteryStatus" />
134+
135+
<TextView
136+
android:id="@+id/textViewBatteryStatusValue"
137+
android:layout_width="wrap_content"
138+
android:layout_height="wrap_content"
139+
android:layout_weight="1"
140+
android:text="-" />
141+
142+
</LinearLayout>
143+
78144
</LinearLayout>
79145

80146
</androidx.constraintlayout.widget.ConstraintLayout>

Assets/Scripts/ThermalView.cs

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,102 @@
66
using System.Diagnostics;
77
using MobileSupport;
88
using UnityEngine;
9+
using UnityEngine.Profiling;
910
using Debug = UnityEngine.Debug;
1011

1112
public class ThermalView : MonoBehaviour
1213
{
1314
private void Start()
1415
{
1516
#if UNITY_ANDROID
16-
Thermal.OnBatteryTemperatureChanged += value => Debug.Log($"Battery Temperature: {value}");
17+
Thermal.Android.OnBatteryTemperatureChanged += value =>
18+
{
19+
Profiler.BeginSample("OnBatteryTemperatureChanged");
20+
Debug.Log($"Battery Temperature: {value}");
21+
Profiler.EndSample();
22+
};
23+
24+
Thermal.Android.OnBatteryVoltageChanged += voltage =>
25+
{
26+
Profiler.BeginSample("OnBatteryVoltageChanged");
27+
Debug.Log($"Battery Voltage: {voltage} mV");
28+
Profiler.EndSample();
29+
};
1730
#endif
1831

1932
#if UNITY_ANDROID || UNITY_IOS
20-
Thermal.OnThermalStatusChanged += status => Debug.Log($"Thermal Status: {status}");
33+
34+
Thermal.OnBatteryLevelChanged += level => { Debug.Log($"Battery Level: {level}"); };
35+
36+
Thermal.OnBatteryStatusChanged += status => { Debug.Log($"Battery Status: {status}"); };
37+
38+
Thermal.OnThermalStatusChanged += status =>
39+
{
40+
Debug.Log($"Thermal Status: {status}");
41+
};
2142
Thermal.StartMonitoring();
2243
#endif
2344

2445
#if UNITY_ANDROID
25-
StartCoroutine(GetTemperaturesLooped());
46+
StartCoroutine(GetValuesLooped());
2647
#endif
2748
}
2849

29-
private IEnumerator GetTemperaturesLooped()
50+
#if UNITY_ANDROID
51+
private IEnumerator GetValuesLooped()
3052
{
3153
Stopwatch sw = new();
3254

55+
double elapsed;
3356
while (this)
3457
{
3558
yield return new WaitForSeconds(0.5f);
3659

3760
sw.Restart();
38-
Thermal.GetThermalHeadroom(0, out var headroom, out var resultForecastSeconds, out var isLatestValue);
39-
var elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;
61+
Profiler.BeginSample("Android.GetThermalHeadroom");
62+
Thermal.Android.GetThermalHeadroom(0, out var headroom, out var resultForecastSeconds,
63+
out var isLatestValue);
64+
Profiler.EndSample();
65+
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;
66+
67+
Debug.Log(
68+
$"Thermal Headroom: {headroom}, isLatestValue: {isLatestValue}, resultForecastSeconds: {resultForecastSeconds} (obtained in {elapsed} ms)");
69+
70+
sw.Restart();
71+
var counter = Thermal.Android.GetBatteryEnergyCounter();
72+
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;
73+
74+
Debug.Log(
75+
$"Energy Counter: {counter} (obtained in {elapsed} ms)");
76+
77+
sw.Restart();
78+
var currentNow = Thermal.Android.GetBatteryCurrentNow();
79+
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;
80+
81+
Debug.Log(
82+
$"Current Now: {currentNow} (obtained in {elapsed} ms)");
83+
84+
sw.Restart();
85+
var capacity = Thermal.Android.GetBatteryCapacity();
86+
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;
87+
88+
Debug.Log(
89+
$"Capacity: {capacity} (obtained in {elapsed} ms)");
90+
91+
sw.Restart();
92+
var chargeCounter = Thermal.Android.GetBatteryChargeCounter();
93+
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;
94+
95+
Debug.Log(
96+
$"Charge Counter: {chargeCounter} (obtained in {elapsed} ms)");
97+
98+
sw.Restart();
99+
var currentAverage = Thermal.Android.GetBatteryCurrentAverage();
100+
elapsed = (double)sw.ElapsedTicks / Stopwatch.Frequency * 1000;
40101

41-
Debug.Log($"Thermal Headroom: {headroom}, isLatestValue: {isLatestValue}, resultForecastSeconds: {resultForecastSeconds} (obtained in {elapsed} ms)");
102+
Debug.Log(
103+
$"Current Average: {currentAverage} (obtained in {elapsed} ms)");
42104
}
43105
}
106+
#endif
44107
}

Packages/MobileSupportThermal/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Release notes
22

3+
## v2.0.0 - 2024/07/17
4+
5+
- New Features :rocket:
6+
- Thermal: New apis to get battery voltage and power consumption on Android
7+
- Changed
8+
- Thermal: Android-specific APIs are moved to nested class `Thermal.Android`
9+
- Thermal: The type of `OnThermalStatusChanged` and `LatestThermalStatus` changed to platform-specific types `ThermalStatusIOS` `ThermalStatusAndroid`
10+
311
## v1.0.0 - 2024/06/26
412

513
- New Features :rocket:

Packages/MobileSupportThermal/Runtime/Plugins/Android/MobileSupportThermal.androidlib/src/main/java/jp/co/cyberagent/unitysupport/thermal/BatteryChangedBroadcastReceiver.java

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,93 @@
99
import java.util.HashSet;
1010

1111
public class BatteryChangedBroadcastReceiver extends BroadcastReceiver {
12-
13-
private static final int UNINITIALIZED_TEMPERATURE = -1;
12+
private static final int VALUE_UNINITIALIZED = -1;
1413
private static final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
15-
private final HashSet<BatteryTemperatureReceiver> receivers = new HashSet<>();
14+
private final HashSet<BatteryStatusReceiver> receivers = new HashSet<>();
1615

17-
private int prevTemperature = UNINITIALIZED_TEMPERATURE;
16+
private int prevTemperature = VALUE_UNINITIALIZED;
17+
private int prevVoltage = VALUE_UNINITIALIZED;
18+
private int prevStatus = VALUE_UNINITIALIZED;
19+
private float prevLevel = Float.NaN;
1820

1921
@Override
2022
public void onReceive(Context context, Intent intent) {
23+
onReceive(intent);
24+
}
25+
26+
private void onReceive(Intent intent) {
27+
// battery temperature
28+
int temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
2129

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

24-
if (prevTemperature == value) return;
25-
prevTemperature = value;
32+
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 1); // unknown is 1
2633

27-
for (BatteryTemperatureReceiver receiver : receivers) {
28-
receiver.onReceiveBatteryTemperature(value);
34+
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
35+
int levelScaled = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
36+
float level = levelScaled / (float) scale;
37+
38+
if (prevTemperature != temperature) {
39+
prevTemperature = temperature;
40+
for (BatteryStatusReceiver receiver : receivers) {
41+
receiver.onReceiveBatteryTemperature(temperature);
42+
}
43+
}
44+
45+
if (prevVoltage != voltage) {
46+
prevVoltage = voltage;
47+
for (BatteryStatusReceiver receiver : receivers) {
48+
receiver.onReceiveVoltage(voltage);
49+
}
50+
}
51+
52+
if (prevStatus != status) {
53+
prevStatus = status;
54+
for (BatteryStatusReceiver receiver : receivers) {
55+
receiver.onReceiveStatus(status);
56+
}
57+
}
58+
59+
if (prevLevel != level) {
60+
prevLevel = level;
61+
for (BatteryStatusReceiver receiver : receivers) {
62+
receiver.onReceiveLevel(level);
63+
}
2964
}
3065
}
3166

3267
public void registerToContext(Context context) {
33-
context.registerReceiver(this, intentFilter);
34-
prevTemperature = UNINITIALIZED_TEMPERATURE;
68+
Intent stickyIntent = context.registerReceiver(this, intentFilter);
69+
if (stickyIntent != null) {
70+
onReceive(stickyIntent);
71+
}
3572
}
3673

3774
public void unregisterFromContext(Context context) {
3875
context.unregisterReceiver(this);
3976
}
4077

41-
public void addReceiver(BatteryTemperatureReceiver receiver) {
78+
public void addReceiver(BatteryStatusReceiver receiver) {
4279
receivers.add(receiver);
4380

44-
if(prevTemperature != UNINITIALIZED_TEMPERATURE)
45-
{
81+
if (prevTemperature != VALUE_UNINITIALIZED) {
4682
receiver.onReceiveBatteryTemperature(prevTemperature);
4783
}
84+
85+
if (prevVoltage != VALUE_UNINITIALIZED) {
86+
receiver.onReceiveVoltage(prevVoltage);
87+
}
88+
89+
if (prevStatus != VALUE_UNINITIALIZED) {
90+
receiver.onReceiveStatus(prevStatus);
91+
}
92+
93+
if (!Float.isNaN(prevLevel)) {
94+
receiver.onReceiveLevel(prevLevel);
95+
}
4896
}
4997

50-
public void removeReceiver(BatteryTemperatureReceiver receiver) {
98+
public void removeReceiver(BatteryStatusReceiver receiver) {
5199
receivers.remove(receiver);
52100
}
53101
}

0 commit comments

Comments
 (0)