Index: content/public/android/java/src/org/chromium/content/browser/BatteryStatusManager.java |
diff --git a/content/public/android/java/src/org/chromium/content/browser/BatteryStatusManager.java b/content/public/android/java/src/org/chromium/content/browser/BatteryStatusManager.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..068961b64bf6c3c5dc0916a69848ef4a26585ee0 |
--- /dev/null |
+++ b/content/public/android/java/src/org/chromium/content/browser/BatteryStatusManager.java |
@@ -0,0 +1,148 @@ |
+// 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); |
+} |