BatteryStatusManager.java revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.content.browser; 6 7import android.content.BroadcastReceiver; 8import android.content.Context; 9import android.content.Intent; 10import android.content.IntentFilter; 11import android.os.BatteryManager; 12import android.os.Build; 13import android.util.Log; 14 15import com.google.common.annotations.VisibleForTesting; 16 17import org.chromium.base.CalledByNative; 18import org.chromium.base.JNINamespace; 19 20/** 21 * Android implementation of the battery status APIs. 22 */ 23@JNINamespace("content") 24class BatteryStatusManager { 25 26 private static final String TAG = "BatteryStatusManager"; 27 28 // A reference to the application context in order to acquire the SensorService. 29 private final Context mAppContext; 30 private final IntentFilter mFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 31 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 32 @Override 33 public void onReceive(Context context, Intent intent) { 34 BatteryStatusManager.this.onReceive(intent); 35 } 36 }; 37 38 // Non-zero if and only if we're listening for events. 39 // To avoid race conditions on the C++ side, access must be synchronized. 40 private long mNativePtr; 41 // The lock to access the mNativePtr. 42 private final Object mNativePtrLock = new Object(); 43 44 private boolean mEnabled = false; 45 46 protected BatteryStatusManager(Context context) { 47 mAppContext = context.getApplicationContext(); 48 } 49 50 @CalledByNative 51 static BatteryStatusManager getInstance(Context appContext) { 52 return new BatteryStatusManager(appContext); 53 } 54 55 /** 56 * Start listening for intents 57 * @return True on success. 58 */ 59 @CalledByNative 60 boolean start(long nativePtr) { 61 synchronized (mNativePtrLock) { 62 if (!mEnabled && mAppContext.registerReceiver(mReceiver, mFilter) != null) { 63 // success 64 mNativePtr = nativePtr; 65 mEnabled = true; 66 } 67 } 68 return mEnabled; 69 } 70 71 /** 72 * Stop listening to intents. 73 */ 74 @CalledByNative 75 void stop() { 76 synchronized (mNativePtrLock) { 77 if (mEnabled) { 78 mAppContext.unregisterReceiver(mReceiver); 79 mNativePtr = 0; 80 mEnabled = false; 81 } 82 } 83 } 84 85 @VisibleForTesting 86 void onReceive(Intent intent) { 87 if (!intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) { 88 Log.e(TAG, "Unexpected intent."); 89 return; 90 } 91 92 boolean present = ignoreBatteryPresentState() ? 93 true : intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false); 94 int pluggedStatus = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); 95 96 if (!present || pluggedStatus == -1) { 97 // No battery or no plugged status: return default values. 98 gotBatteryStatus(true, 0, Double.POSITIVE_INFINITY, 1); 99 return; 100 } 101 102 boolean charging = pluggedStatus != 0; 103 int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); 104 boolean batteryFull = status == BatteryManager.BATTERY_STATUS_FULL; 105 106 int current = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); 107 int max = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); 108 double level = (double)current / (double)max; 109 if (level < 0 || level > 1) { 110 // Sanity check, assume default value in this case. 111 level = 1.0; 112 } 113 114 // Currently Android does not provide charging/discharging time, as a work-around 115 // we could compute it manually based on level delta. 116 // TODO(timvolodine): add proper projection for chargingTime, dischargingTime 117 // (see crbug.com/401553). 118 double chargingTime = (charging & batteryFull) ? 0 : Double.POSITIVE_INFINITY; 119 double dischargingTime = Double.POSITIVE_INFINITY; 120 121 gotBatteryStatus(charging, chargingTime, dischargingTime, level); 122 } 123 124 /** 125 * Returns whether the BatteryStatusManager should ignore the battery present state. 126 * It is required for some devices that incorrectly set the EXTRA_PRESENT property. 127 */ 128 protected boolean ignoreBatteryPresentState() { 129 // BatteryManager.EXTRA_PRESENT appears to be unreliable on Galaxy Nexus, 130 // Android 4.2.1, it always reports false. See crbug.com/384348. 131 return Build.MODEL.equals("Galaxy Nexus"); 132 } 133 134 protected void gotBatteryStatus(boolean charging, double chargingTime, 135 double dischargingTime, double level) { 136 synchronized (mNativePtrLock) { 137 if (mNativePtr != 0) { 138 nativeGotBatteryStatus(mNativePtr, charging, chargingTime, dischargingTime, level); 139 } 140 } 141 } 142 143 /** 144 * Native JNI call 145 * see content/browser/battery_status/battery_status_manager.cc 146 */ 147 private native void nativeGotBatteryStatus(long nativeBatteryStatusManagerAndroid, 148 boolean charging, double chargingTime, double dischargingTime, double level); 149} 150