2

I have developed an Android application that connects via Bluetooth to a gamepad controller and shows button presses, joy stick movements, etc made on the handheld controller on the Android device.

Application and source code are on Github here: https://github.com/portsample/gamecontroller

An elusive goal of this endeavor has been having battery state of the gamepad controller captured by the application and shown on the Android device. This may or may not be possible using the Google Android API for SDK 33 or more recent. Any suggestions or advice would be highly appreciated.

May 3, 2024 Update: This is close,

 private int getBatteryLevel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { int[] deviceIds = InputDevice.getDeviceIds(); for (int deviceId : deviceIds) { InputDevice inputDevice = InputDevice.getDevice(deviceId); if (inputDevice != null && (inputDevice.getSources() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { //float batteryLevel = inputDevice.getBatteryCapacity(); float batteryLevel = inputDevice.getBatteryState(); //float batteryLevel = 27; return (int) (batteryLevel * 100); // Convert battery level to percentage } } } return -1; // Battery level not available } 

But still no cigar. Error message is,

error: incompatible types: BatteryState cannot be converted to float float batteryLevel = inputDevice.getBatteryState(); 

How to do this with BatteryState() object and GetCapacity() function?

1
  • Take a look at the question you deleted yesterday with the same topic and understand that // batteryLevel = inputDevice.getBatteryState(); can't work. Note: The remaining battery capacity is only part of the BatteryState object. Commented Apr 17, 2024 at 12:13

4 Answers 4

2
+25

Read the docs.

The docs state "The BatteryState class is a representation of a single battery on a device.", it goes on to show that it is not a float (or a numerical value), but a class that has multiple members.

Again according to the linked docs, to get the battery percentage as a float, use the method:

abstract float getCapacity(): Get remaining battery capacity as float percentage [0.0f, 1.0f] of total capacity Returns NaN when battery capacity can't be read.

so to recap, the correct code you're looking for:

//float from 0 to 1: float batteryLevel = inputDevice.getBatteryState().getCapacity(); 
Sign up to request clarification or add additional context in comments.

1 Comment

Returns batteryLevel = 0 for a device with non-zero battery charge.
1

Xbox controllers are Bluetooth Low Energy (BLE) devices and implement the Battery Service (service UUID 0x180f) to expose the battery level and other information for a battery.

hid-playstation.c is the Linux driver for Sony PlayStation 4 and 5 gamepads. dualshock4_parse_report and dualsense_parse_report parse the data sent by the gamepad, including the battery level.

hid-nintendo.c is the Linux driver for Nintendo Switch gamepads. joycon_parse_battery_status reads the battery level.

I'm not sure if it's possible to get this info through Android APIs.

1 Comment

Yes, Android can also make the information from such a driver available to the userland applications. This is done via the InputDevice() class, which returns a BatteryState() object, which then returns the remaining battery charge via the getCapacity() function.
0

Try getBatteryState().getCapacity() it will be float value and you won't get error while converting to float.

Get remaining battery capacity as float percentage [0.0f, 1.0f] of total capacity Returns NaN when battery capacity can't be read.

Returns float the battery capacity. Value is between -1.0f and 1.0f both inclusive.

Note: Android provides various ways through which the battery capacity can be fetched programmatically. Accurate battery capacity might not be available or correct all the time because it depends on several factors, some of which include the manufacturer of a device. Efficiency of the battery i.e the cycle count it has already completed.


Reference link - https://developer.android.com/reference/android/hardware/BatteryState#getCapacity()

6 Comments

"NaN" was what I got back trying to pull just the float value via Toast from ThemoonIsacheese's suggested code.
@portsample please check my comment Returns NaN when battery capacity can't be read.
I saw that. In initial pairing between Android device and controller, the battery state of the controller is shown. I am looking to poll battery state from within my application.
@portsample is it possible for you to test this on some other gamepad controller. As I am preety much sure there is some issue with either the device or its manufacturer.
Negative. I only have one. It is a current Microsoft Xbox unit. Device is brand new. Am able to capture all other joystick and key events as expected. Thanks for your time and suggestions.
|
0

This works.

 import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattService; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import java.util.UUID; public class MainActivity extends AppCompatActivity { private static final String TAG = "GamepadBattery"; private static final UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb"); private static final UUID BATTERY_LEVEL_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); private BluetoothAdapter bluetoothAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); getBatteryLevel(); } private void getBatteryLevel() { BluetoothDevice device = getXboxController(); if (device == null) { Log.e(TAG, "No Xbox controller found."); Toast.makeText(this, "No Xbox controller found.", Toast.LENGTH_SHORT).show(); return; } device.connectGatt(this, false, new BluetoothGattCallback() { @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { BluetoothGattService batteryService = gatt.getService(BATTERY_SERVICE_UUID); if (batteryService != null) { BluetoothGattCharacteristic batteryLevelChar = batteryService.getCharacteristic(BATTERY_LEVEL_UUID); if (batteryLevelChar != null) { gatt.readCharacteristic(batteryLevelChar); } } } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS && BATTERY_LEVEL_UUID.equals(characteristic.getUuid())) { int batteryLevel = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0); Toast.makeText(MainActivity.this, "Battery level is " + batteryLevel + "%", Toast.LENGTH_LONG).show(); gatt.close(); } } }); } private BluetoothDevice getXboxController() { if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) { return null; } for (BluetoothDevice device : bluetoothAdapter.getBondedDevices()) { if (device.getName() != null && device.getName().toLowerCase().contains("xbox")) { return device; } } return null; } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.