blob: 068961b64bf6c3c5dc0916a69848ef4a26585ee0 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.content.browser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build;
import android.util.Log;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import org.chromium.base.VisibleForTesting;
/**
* Android implementation of the battery status APIs.
*/
@JNINamespace("content")
class BatteryStatusManager {
private static final String TAG = "BatteryStatusManager";
// A reference to the application context in order to acquire the SensorService.
private final Context mAppContext;
private final IntentFilter mFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
BatteryStatusManager.this.onReceive(intent);
}
};
// Non-zero if and only if we're listening for events.
// To avoid race conditions on the C++ side, access must be synchronized.
private long mNativePtr;
// The lock to access the mNativePtr.
private final Object mNativePtrLock = new Object();
private boolean mEnabled = false;
protected BatteryStatusManager(Context context) {
mAppContext = context.getApplicationContext();
}
@CalledByNative
static BatteryStatusManager getInstance(Context appContext) {
return new BatteryStatusManager(appContext);
}
/**
* Start listening for intents
* @return True on success.
*/
@CalledByNative
boolean start(long nativePtr) {
synchronized (mNativePtrLock) {
if (!mEnabled && mAppContext.registerReceiver(mReceiver, mFilter) != null) {
// success
mNativePtr = nativePtr;
mEnabled = true;
}
}
return mEnabled;
}
/**
* Stop listening to intents.
*/
@CalledByNative
void stop() {
synchronized (mNativePtrLock) {
if (mEnabled) {
mAppContext.unregisterReceiver(mReceiver);
mNativePtr = 0;
mEnabled = false;
}
}
}
@VisibleForTesting
void onReceive(Intent intent) {
if (!intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
Log.e(TAG, "Unexpected intent.");
return;
}
boolean present = ignoreBatteryPresentState() ?
true : intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false);
int pluggedStatus = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
if (!present || pluggedStatus == -1) {
// No battery or no plugged status: return default values.
gotBatteryStatus(true, 0, Double.POSITIVE_INFINITY, 1);
return;
}
boolean charging = pluggedStatus != 0;
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean batteryFull = status == BatteryManager.BATTERY_STATUS_FULL;
int current = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int max = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
double level = (double) current / (double) max;
if (level < 0 || level > 1) {
// Sanity check, assume default value in this case.
level = 1.0;
}
// Currently Android does not provide charging/discharging time, as a work-around
// we could compute it manually based on level delta.
// TODO(timvolodine): add proper projection for chargingTime, dischargingTime
// (see crbug.com/401553).
double chargingTime = (charging & batteryFull) ? 0 : Double.POSITIVE_INFINITY;
double dischargingTime = Double.POSITIVE_INFINITY;
gotBatteryStatus(charging, chargingTime, dischargingTime, level);
}
/**
* Returns whether the BatteryStatusManager should ignore the battery present state.
* It is required for some devices that incorrectly set the EXTRA_PRESENT property.
*/
protected boolean ignoreBatteryPresentState() {
// BatteryManager.EXTRA_PRESENT appears to be unreliable on Galaxy Nexus,
// Android 4.2.1, it always reports false. See crbug.com/384348.
return Build.MODEL.equals("Galaxy Nexus");
}
protected void gotBatteryStatus(boolean charging, double chargingTime,
double dischargingTime, double level) {
synchronized (mNativePtrLock) {
if (mNativePtr != 0) {
nativeGotBatteryStatus(mNativePtr, charging, chargingTime, dischargingTime, level);
}
}
}
/**
* Native JNI call
* see content/browser/battery_status/battery_status_manager.cc
*/
private native void nativeGotBatteryStatus(long nativeBatteryStatusManagerAndroid,
boolean charging, double chargingTime, double dischargingTime, double level);
}