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