Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / public / android / java / src / org / chromium / content / browser / BatteryStatusManager.java
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 com.google.common.annotations.VisibleForTesting;
16
17 import org.chromium.base.CalledByNative;
18 import org.chromium.base.JNINamespace;
19
20 /**
21  * Android implementation of the battery status APIs.
22  */
23 @JNINamespace("content")
24 class 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 }