1 // Copyright 2012 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base; 6 7 import android.content.BroadcastReceiver; 8 import android.content.Context; 9 import android.content.Intent; 10 import android.content.IntentFilter; 11 import android.os.BatteryManager; 12 import android.os.Build; 13 import android.os.PowerManager; 14 15 import org.jni_zero.CalledByNative; 16 import org.jni_zero.JNINamespace; 17 import org.jni_zero.NativeMethods; 18 19 import org.chromium.base.compat.ApiHelperForQ; 20 21 /** Integrates native PowerMonitor with the java side. */ 22 @JNINamespace("base::android") 23 public class PowerMonitor { 24 private static PowerMonitor sInstance; 25 26 private boolean mIsBatteryPower; 27 createForTests()28 public static void createForTests() { 29 // Applications will create this once the JNI side has been fully wired up both sides. For 30 // tests, we just need native -> java, that is, we don't need to notify java -> native on 31 // creation. 32 sInstance = new PowerMonitor(); 33 } 34 35 /** Create a PowerMonitor instance if none exists. */ create()36 public static void create() { 37 ThreadUtils.assertOnUiThread(); 38 39 if (sInstance != null) return; 40 41 Context context = ContextUtils.getApplicationContext(); 42 sInstance = new PowerMonitor(); 43 IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 44 Intent batteryStatusIntent = 45 ContextUtils.registerProtectedBroadcastReceiver(context, null, ifilter); 46 if (batteryStatusIntent != null) { 47 // Default to 0, which the EXTRA_PLUGGED docs indicate means "on battery power". There 48 // is no symbolic constant. Nonzero values indicate we have some external power source. 49 int chargePlug = batteryStatusIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); 50 // If we're not plugged, assume we're running on battery power. 51 onBatteryChargingChanged(chargePlug == 0); 52 } 53 54 IntentFilter powerConnectedFilter = new IntentFilter(); 55 powerConnectedFilter.addAction(Intent.ACTION_POWER_CONNECTED); 56 powerConnectedFilter.addAction(Intent.ACTION_POWER_DISCONNECTED); 57 ContextUtils.registerProtectedBroadcastReceiver( 58 context, 59 new BroadcastReceiver() { 60 @Override 61 public void onReceive(Context context, Intent intent) { 62 PowerMonitor.onBatteryChargingChanged( 63 intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)); 64 } 65 }, 66 powerConnectedFilter); 67 68 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 69 PowerManager powerManager = 70 (PowerManager) context.getSystemService(Context.POWER_SERVICE); 71 if (powerManager != null) { 72 PowerMonitorForQ.addThermalStatusListener(powerManager); 73 } 74 } 75 } 76 PowerMonitor()77 private PowerMonitor() {} 78 onBatteryChargingChanged(boolean isBatteryPower)79 private static void onBatteryChargingChanged(boolean isBatteryPower) { 80 assert sInstance != null; 81 sInstance.mIsBatteryPower = isBatteryPower; 82 PowerMonitorJni.get().onBatteryChargingChanged(); 83 } 84 85 @CalledByNative isBatteryPower()86 private static boolean isBatteryPower() { 87 // Creation of the PowerMonitor can be deferred based on the browser startup path. If the 88 // battery power is requested prior to the browser triggering the creation, force it to be 89 // created now. 90 if (sInstance == null) create(); 91 92 return sInstance.mIsBatteryPower; 93 } 94 95 @CalledByNative getRemainingBatteryCapacity()96 private static int getRemainingBatteryCapacity() { 97 // Creation of the PowerMonitor can be deferred based on the browser startup path. If the 98 // battery power is requested prior to the browser triggering the creation, force it to be 99 // created now. 100 if (sInstance == null) create(); 101 102 return getRemainingBatteryCapacityImpl(); 103 } 104 getRemainingBatteryCapacityImpl()105 private static int getRemainingBatteryCapacityImpl() { 106 return ((BatteryManager) 107 ContextUtils.getApplicationContext() 108 .getSystemService(Context.BATTERY_SERVICE)) 109 .getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER); 110 } 111 112 @CalledByNative getCurrentThermalStatus()113 private static int getCurrentThermalStatus() { 114 // Return invalid code that will get mapped to unknown in the native library. 115 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return -1; 116 117 // Creation of the PowerMonitor can be deferred based on the browser startup path. If the 118 // battery power is requested prior to the browser triggering the creation, force it to be 119 // created now. 120 if (sInstance == null) create(); 121 122 PowerManager powerManager = 123 (PowerManager) 124 ContextUtils.getApplicationContext() 125 .getSystemService(Context.POWER_SERVICE); 126 if (powerManager == null) return -1; 127 return ApiHelperForQ.getCurrentThermalStatus(powerManager); 128 } 129 130 @NativeMethods 131 interface Natives { onBatteryChargingChanged()132 void onBatteryChargingChanged(); 133 onThermalStatusChanged(int thermalStatus)134 void onThermalStatusChanged(int thermalStatus); 135 } 136 } 137