Chapter 55: Screen Orientation & Device APIs

The Battery Status API

Monitor device power telemetry, charging states, and energy depletion rates with `navigator.getBattery()` to engineer adaptive power-saving web experiences.

LEARNING OBJECTIVES
  • Query hardware battery status asynchronously using navigator.getBattery().
  • Inspect and interpret charging, level, chargingTime, and dischargingTime properties on the BatteryManager interface.
  • Listen to real-time power state transitions using levelchange and chargingchange events.
  • Implement an adaptive energy-saving UI mode that automatically downgrades CPU/GPU load when the device is low on battery.
  • Understand why Firefox and Safari removed the Battery Status API due to hardware fingerprinting concerns.
🎬 INTERACTIVE VISUAL PIPELINE Core Architecture Simulation
🌐
1. Input
Directives & Tags
⚙️
2. Parse
Tokenizer & AST
🌳
3. Layout
Box Model & Flow
🎨
4. Render
GPU Paint & Composite
PHASE 1: INPUT & DIRECTIVES
Browser receives declarative markup stream, parsing tag tokens and initializing component state.

📖 The Mental Model & Story (Intuitive Foundation)

Imagine driving an electric vehicle on a long cross-country road trip. When the battery drops below $15%$, the car's dashboard automatically enters "Eco-Mode": it dims the cabin displays, throttles air conditioning, and reroutes navigation to the nearest fast charger.

                    [ DEVICE HARDWARE BATTERY GAUGE ]
                                   │
                                   ▼
                    +─────────────────────────────+
                    │    navigator.getBattery()   │
                    │   (Resolves BatteryManager) │
                    +─────────────────────────────+
                                   │
                ┌──────────────────┴──────────────────┐
                ▼                                     ▼
      [ POWER TELEMETRY ]                    [ LIFECYCLE EVENTS ]
      - .charging (true/false)               - 'chargingchange'
      - .level (0.0 to 1.0)                  - 'levelchange'
      - .chargingTime (seconds)              - 'chargingtimechange'
      - .dischargingTime (seconds)           - 'dischargingtimechange'
                │                                     │
                └──────────────────┬──────────────────┘
                                   │
                                   ▼
                +─────────────────────────────────────+
                │      ADAPTIVE WEB ARCHITECTURE      │
                │ • Low Power (<20% & Discharging):   │
                │   - Throttle 60fps canvas to 30fps  │
                │   - Disable heavy CSS blur filters  │
                │   - Pause background polling        │
                │ • High Power (Charging / 100%):     │
                │   - Full 120fps animations & WebGL  │
                +─────────────────────────────────────+

The W3C Battery Status API exposes this same power intelligence to client-side web applications. Instead of blindly running intensive animations, WebGL shaders, or heavy background network polling, your app can gracefully adapt to the user's real-world power constraints.


Technical Deep Dive & Specifications

The BatteryManager Interface

Invoking navigator.getBattery() returns a Promise that resolves with a BatteryManager instance:

interface Navigator {
  getBattery?(): Promise<BatteryManager>;
}

interface BatteryManager extends EventTarget {
  readonly attribute boolean charging;
  readonly attribute double chargingTime;    // Seconds until 100% (or 0 / Infinity)
  readonly attribute double dischargingTime; // Seconds until 0% (or Infinity)
  readonly attribute double level;           // 0.0 (0%) to 1.0 (100%)

  attribute EventHandler onchargingchange;
  attribute EventHandler onchargingtimechange;
  attribute EventHandler ondischargingtimechange;
  attribute EventHandler onlevelchange;
}

Telemetry Properties Matrix

Property Type Range / Format Behavior & Edge Cases
level number 0.0 to 1.0 1.0 represents $100%$, 0.5 represents $50%$. Updated in discrete steps by the OS.
charging boolean true or false true if connected to AC/USB power, false if running on battery.
chargingTime number Seconds or Infinity Seconds until battery is full. If fully charged, returns 0. If discharging or unable to calculate, returns Infinity.
dischargingTime number Seconds or Infinity Seconds until battery is empty. If charging or unable to estimate, returns Infinity.

The Four Reactive Event Listeners

+---------------------------------------------------------------------------------------------------+
|                                BATTERYMANAGER EVENT DISPATCH PIPELINE                             |
+---------------------------------------------------------------------------------------------------+
|                                                                                                   |
|  [ User Plugs In Charger ] ──────────────► 'chargingchange' (battery.charging = true)            |
|                                                                                                   |
|  [ Charge Percentage Drops ] ────────────► 'levelchange' (battery.level: 0.85 -> 0.84)            |
|                                                                                                   |
|  [ OS Recalculates Charge Time ] ────────► 'chargingtimechange' (battery.chargingTime updated)    |
|                                                                                                   |
|  [ OS Recalculates Drain Time ] ─────────► 'dischargingtimechange' (battery.dischargingTime)     |
|                                                                                                   |
+---------------------------------------------------------------------------------------------------+

The Privacy & Fingerprinting Controversy

[!WARNING] Browser Support Status: In 2016, security researchers demonstrated that the combination of high-precision level (e.g. 0.562341) and dischargingTime created a unique short-term tracking fingerprint across incognito sessions. As a result:

  • Mozilla Firefox: Removed the API in Firefox 52.
  • Apple Safari / WebKit: Never implemented the API.
  • Chromium (Chrome, Edge, Brave, Opera, Samsung Internet): Retained support, but rounds values (e.g., level quantized to 2 decimal places) and restricts access in cross-origin iframes.

Always test if ('getBattery' in navigator) before calling!


💻 Interactive Code Playground

Starter Code

Line-by-Line Code Breakdown

  • Lines 131–137: Formats raw seconds into human-readable hours and minutes strings (e.g. 2h 15m), safely guarding against Infinity.
  • Lines 139–153: Converts the fractional battery.level ($0.0 \dots 1.0$) into an integer percentage and dynamically changes the battery bar color (Green $\to$ Amber $\to$ Red).
  • Lines 156–164: Checks battery.charging and toggles the charging lightning bolt icon.
  • Lines 169–178: Implements the Eco-Mode trigger: when the battery is $\le 20%$ and not charging, the application enters an energy-saving state.
  • Lines 181–188: Evaluates 'getBattery' in navigator to gracefully fail on unsupported browsers (Firefox, Safari).
  • Lines 195–198: Binds listeners to all four core battery lifecycle events (chargingchange, levelchange, chargingtimechange, dischargingtimechange).

Expected Browser Render Output


SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
HTML STARSHIP CODE TERMINAL playground.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...
🔋 Battery Status & Eco Engine
Real-time hardware power diagnostics and adaptive workload throttling.

             ┌───────────────────────┐
             │ [████████████]   85%  │ ▌ ⚡
             └───────────────────────┘

POWER SOURCE                     BATTERY LEVEL
Plugged In (AC)                  85%

TIME TO FULL                     TIME REMAINING
25 mins                          N/A

⚡ PERFORMANCE MODE: Normal operation.

🏋️ Hands-On Exercise

🎯 The Challenge: Build an Adaptive WebGL / Canvas Frame Rate Governor

Instructions:

  1. Create a dynamic Canvas animation loop driven by requestAnimationFrame.
  2. Inspect the device battery state via navigator.getBattery().
  3. If battery.level <= 0.20 && !battery.charging:
    • Throttle the Canvas frame rate to 15 FPS.
    • Display a "Power Saver: 15 FPS" indicator.
  4. If battery.charging or battery.level > 0.20:
    • Run at full 60 FPS.

🏁 Starter Code Sandbox

SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
STARTER CODE SANDBOX exercise.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...

⚠️ Common Pitfalls

  1. Assuming dischargingTime is Always a Number: When plugged into power or when the battery management microcontroller is calibrating, dischargingTime returns Infinity. Never divide by it without checking Number.isFinite().
  2. Neglecting Privacy Deprecation: Writing web apps that crash if navigator.getBattery is undefined will break completely for all Apple Safari and Mozilla Firefox users. Always check 'getBattery' in navigator.
  3. Over-Polling Battery Status: Never poll getBattery() inside a setInterval(). It returns a singleton BatteryManager that pushes updates via event listeners (levelchange, chargingchange).

💡 Pro Tips

  1. Quantized Privacy Levels: Modern Chromium browsers intentionally round battery.level to the nearest $0.01$ (1%) or $0.05$ (5%) to prevent micro-entropy fingerprinting.
  2. Combine Battery with Network Awareness: When both battery is $< 20%$ AND network is on metered connection (navigator.connection.saveData === true), suspend all non-critical background fetch requests.

📌 Key Takeaways

  • navigator.getBattery() returns a Promise resolving to the BatteryManager interface.
  • level provides battery percentage from 0.0 to 1.0.
  • charging provides a boolean indicating whether the device is receiving external power.
  • The four key events are chargingchange, levelchange, chargingtimechange, and dischargingtimechange.
  • Firefox and Safari disabled this API to protect user privacy against persistent device fingerprinting.
  • --
⭐ LEARN: HTML 🌟 ⚔️ QUIZ BATTLE ARENA // ACTIVE
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 1 / 3

What value does battery.dischargingTime return when a laptop is plugged into an AC wall charger?

Question 1 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 2 / 3

Why did Mozilla Firefox and Apple Safari remove or refuse to implement the Battery Status API?

Question 2 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 3 / 3

Which event fires on the BatteryManager object when the user disconnects their phone from the charging cable?

Question 3 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP