23

I need to get the remaining battery life in a Windows system. How can I do it?

Aquarius_Girl
  • 21,790
  • 65
  • 230
  • 411
suresh
  • 231
  • 1
  • 2
  • 3

1 Answers1

43

I assume you're talking about a laptop. No such API exist in Standard Java SE API. This information is available in the operating system platform native API only. You would need at least JNI or JNA (JavaWorld article) to be able to communicate with platform native API.

In Windows, you'd like to hook on SYSTEM_POWER_STATUS structure. It offers among others the BatteryLifePercent property which may be of your interest. I found a helpful JNA based code snippet in an old forums.sun.com topic which is currently not available anymore. So the credit actually goes to the Author Whose Name Shall Not Be Known.

To get it to work, first drop jna.jar in the classpath and then copy the following class unmodified into your project:

package com.stackoverflow.q3434719;

import java.util.ArrayList;
import java.util.List;

import com.sun.jna.Native;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary;

public interface Kernel32 extends StdCallLibrary {

    public Kernel32 INSTANCE = Native.load("Kernel32", Kernel32.class);

    /**
     * @see https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-system_power_status
     */
    public class SYSTEM_POWER_STATUS extends Structure {
        public byte ACLineStatus;
        public byte BatteryFlag;
        public byte BatteryLifePercent;
        public byte Reserved1;
        public int BatteryLifeTime;
        public int BatteryFullLifeTime;

        @Override
        protected List<String> getFieldOrder() {
            ArrayList<String> fields = new ArrayList<String>();
            fields.add("ACLineStatus");
            fields.add("BatteryFlag");
            fields.add("BatteryLifePercent");
            fields.add("Reserved1");
            fields.add("BatteryLifeTime");
            fields.add("BatteryFullLifeTime");
            return fields;
        }

        /**
         * The AC power status
         */
        public String getACLineStatusString() {
            switch (ACLineStatus) {
                case (0): return "Offline";
                case (1): return "Online";
                default: return "Unknown";
            }
        }

        /**
         * The battery charge status
         */
        public String getBatteryFlagString() {
            switch (BatteryFlag) {
                case (1): return "High, more than 66 percent";
                case (2): return "Low, less than 33 percent";
                case (4): return "Critical, less than five percent";
                case (8): return "Charging";
                case ((byte) 128): return "No system battery";
                default: return "Unknown";
            }
        }

        /**
         * The percentage of full battery charge remaining
         */
        public String getBatteryLifePercent() {
            return (BatteryLifePercent == (byte) 255) ? "Unknown" : BatteryLifePercent + "%";
        }

        /**
         * The number of seconds of battery life remaining
         */
        public String getBatteryLifeTime() {
            return (BatteryLifeTime == -1) ? "Unknown" : BatteryLifeTime + " seconds";
        }

        /**
         * The number of seconds of battery life when at full charge
         */
        public String getBatteryFullLifeTime() {
            return (BatteryFullLifeTime == -1) ? "Unknown" : BatteryFullLifeTime + " seconds";
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("ACLineStatus: " + getACLineStatusString() + "\n");
            sb.append("Battery Flag: " + getBatteryFlagString() + "\n");
            sb.append("Battery Life: " + getBatteryLifePercent() + "\n");
            sb.append("Battery Left: " + getBatteryLifeTime() + "\n");
            sb.append("Battery Full: " + getBatteryFullLifeTime() + "\n");
            return sb.toString();
        }
    }

    /**
     * Fill the structure.
     */
    public int GetSystemPowerStatus(SYSTEM_POWER_STATUS result);
}

Here's how you can use it, e.g. in your main() method:

Kernel32.SYSTEM_POWER_STATUS batteryStatus = new Kernel32.SYSTEM_POWER_STATUS();
Kernel32.INSTANCE.GetSystemPowerStatus(batteryStatus);

System.out.println(batteryStatus); // Shows result of toString() method.

This prints successfully the following at my Latitude E5500:

ACLineStatus: Online
Battery Flag: High, more than 66 percent
Battery Life: 100%
Battery Left: Unknown
Battery Full: Unknown

And after plugging off the AC for 10 minutes:

ACLineStatus: Offline
Battery Flag: High, more than 66 percent
Battery Life: 82%
Battery Left: 2954 seconds
Battery Full: Unknown

(no, no bad battery, I am just compiling a movie and continuously transferring over wifi right now ;) )

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 1
    @LittleChild: no, it's the block of code below "Here's how you can use it". Just copypaste those lines into your `main()`. You don't need to edit the `Kernel32` interface/class (expect of the package if necessary of course, but that's nothing more than obvious). – BalusC Jan 15 '13 at 15:45
  • The example getBatteryFlagString() method could be a bit misleading since the referenced documentation states that BatteryFlag "can contain one or more of the following flags." With 1, 2, 4, 8, 128, and 255 being listed. A more reliable approach might be to use a "bitwise AND" for each value if the flag is not 255. Although, the "charging" value (8) is probably the only thing you would ever see with 1, 2, or 4. – jt. Mar 28 '14 at 21:40
  • Drop jna.jar in the classpath? A bit of explanation for a newbie here? – pollaris Jul 11 '17 at 20:56
  • jna is available in the Maven Repository: https://mvnrepository.com/artifact/net.java.dev.jna/jna – oizulain May 10 '19 at 11:15
  • @oizulain: That's correct. The link in the answer already points there. – BalusC May 10 '19 at 12:09