mobile/android/base/GeckoBatteryManager.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko;
michael@0 7
michael@0 8 import android.content.BroadcastReceiver;
michael@0 9 import android.content.Context;
michael@0 10 import android.content.Intent;
michael@0 11 import android.content.IntentFilter;
michael@0 12 import android.os.BatteryManager;
michael@0 13 import android.os.Build;
michael@0 14 import android.os.SystemClock;
michael@0 15 import android.util.Log;
michael@0 16
michael@0 17 public class GeckoBatteryManager extends BroadcastReceiver {
michael@0 18 private static final String LOGTAG = "GeckoBatteryManager";
michael@0 19
michael@0 20 // Those constants should be keep in sync with the ones in:
michael@0 21 // dom/battery/Constants.h
michael@0 22 private final static double kDefaultLevel = 1.0;
michael@0 23 private final static boolean kDefaultCharging = true;
michael@0 24 private final static double kDefaultRemainingTime = 0.0;
michael@0 25 private final static double kUnknownRemainingTime = -1.0;
michael@0 26
michael@0 27 private static long sLastLevelChange = 0;
michael@0 28 private static boolean sNotificationsEnabled = false;
michael@0 29 private static double sLevel = kDefaultLevel;
michael@0 30 private static boolean sCharging = kDefaultCharging;
michael@0 31 private static double sRemainingTime = kDefaultRemainingTime;
michael@0 32
michael@0 33 private static GeckoBatteryManager sInstance = new GeckoBatteryManager();
michael@0 34
michael@0 35 private final IntentFilter mFilter;
michael@0 36 private Context mApplicationContext;
michael@0 37 private boolean mIsEnabled;
michael@0 38
michael@0 39 public static GeckoBatteryManager getInstance() {
michael@0 40 return sInstance;
michael@0 41 }
michael@0 42
michael@0 43 private GeckoBatteryManager() {
michael@0 44 mFilter = new IntentFilter();
michael@0 45 mFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
michael@0 46 }
michael@0 47
michael@0 48 public synchronized void start(final Context context) {
michael@0 49 if (mIsEnabled) {
michael@0 50 Log.w(LOGTAG, "Already started!");
michael@0 51 return;
michael@0 52 }
michael@0 53
michael@0 54 mApplicationContext = context.getApplicationContext();
michael@0 55 // registerReceiver will return null if registering fails.
michael@0 56 if (mApplicationContext.registerReceiver(this, mFilter) == null) {
michael@0 57 Log.e(LOGTAG, "Registering receiver failed");
michael@0 58 } else {
michael@0 59 mIsEnabled = true;
michael@0 60 }
michael@0 61 }
michael@0 62
michael@0 63 public synchronized void stop() {
michael@0 64 if (!mIsEnabled) {
michael@0 65 Log.w(LOGTAG, "Already stopped!");
michael@0 66 return;
michael@0 67 }
michael@0 68
michael@0 69 mApplicationContext.unregisterReceiver(this);
michael@0 70 mApplicationContext = null;
michael@0 71 mIsEnabled = false;
michael@0 72 }
michael@0 73
michael@0 74 @Override
michael@0 75 public void onReceive(Context context, Intent intent) {
michael@0 76 if (!intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
michael@0 77 Log.e(LOGTAG, "Got an unexpected intent!");
michael@0 78 return;
michael@0 79 }
michael@0 80
michael@0 81 boolean previousCharging = isCharging();
michael@0 82 double previousLevel = getLevel();
michael@0 83
michael@0 84 // NOTE: it might not be common (in 2012) but technically, Android can run
michael@0 85 // on a device that has no battery so we want to make sure it's not the case
michael@0 86 // before bothering checking for battery state.
michael@0 87 // However, the Galaxy Nexus phone advertizes itself as battery-less which
michael@0 88 // force us to special-case the logic.
michael@0 89 // See the Google bug: https://code.google.com/p/android/issues/detail?id=22035
michael@0 90 if (intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false) ||
michael@0 91 Build.MODEL.equals("Galaxy Nexus")) {
michael@0 92 int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
michael@0 93 if (plugged == -1) {
michael@0 94 sCharging = kDefaultCharging;
michael@0 95 Log.e(LOGTAG, "Failed to get the plugged status!");
michael@0 96 } else {
michael@0 97 // Likely, if plugged > 0, it's likely plugged and charging but the doc
michael@0 98 // isn't clear about that.
michael@0 99 sCharging = plugged != 0;
michael@0 100 }
michael@0 101
michael@0 102 if (sCharging != previousCharging) {
michael@0 103 sRemainingTime = kUnknownRemainingTime;
michael@0 104 // The new remaining time is going to take some time to show up but
michael@0 105 // it's the best way to show a not too wrong value.
michael@0 106 sLastLevelChange = 0;
michael@0 107 }
michael@0 108
michael@0 109 // We need two doubles because sLevel is a double.
michael@0 110 double current = (double)intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
michael@0 111 double max = (double)intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
michael@0 112 if (current == -1 || max == -1) {
michael@0 113 Log.e(LOGTAG, "Failed to get battery level!");
michael@0 114 sLevel = kDefaultLevel;
michael@0 115 } else {
michael@0 116 sLevel = current / max;
michael@0 117 }
michael@0 118
michael@0 119 if (sLevel == 1.0 && sCharging) {
michael@0 120 sRemainingTime = kDefaultRemainingTime;
michael@0 121 } else if (sLevel != previousLevel) {
michael@0 122 // Estimate remaining time.
michael@0 123 if (sLastLevelChange != 0) {
michael@0 124 // Use elapsedRealtime() because we want to track time across device sleeps.
michael@0 125 long currentTime = SystemClock.elapsedRealtime();
michael@0 126 long dt = (currentTime - sLastLevelChange) / 1000;
michael@0 127 double dLevel = sLevel - previousLevel;
michael@0 128
michael@0 129 if (sCharging) {
michael@0 130 if (dLevel < 0) {
michael@0 131 Log.w(LOGTAG, "When charging, level should increase!");
michael@0 132 sRemainingTime = kUnknownRemainingTime;
michael@0 133 } else {
michael@0 134 sRemainingTime = Math.round(dt / dLevel * (1.0 - sLevel));
michael@0 135 }
michael@0 136 } else {
michael@0 137 if (dLevel > 0) {
michael@0 138 Log.w(LOGTAG, "When discharging, level should decrease!");
michael@0 139 sRemainingTime = kUnknownRemainingTime;
michael@0 140 } else {
michael@0 141 sRemainingTime = Math.round(dt / -dLevel * sLevel);
michael@0 142 }
michael@0 143 }
michael@0 144
michael@0 145 sLastLevelChange = currentTime;
michael@0 146 } else {
michael@0 147 // That's the first time we got an update, we can't do anything.
michael@0 148 sLastLevelChange = SystemClock.elapsedRealtime();
michael@0 149 }
michael@0 150 }
michael@0 151 } else {
michael@0 152 sLevel = kDefaultLevel;
michael@0 153 sCharging = kDefaultCharging;
michael@0 154 sRemainingTime = kDefaultRemainingTime;
michael@0 155 }
michael@0 156
michael@0 157 /*
michael@0 158 * We want to inform listeners if the following conditions are fulfilled:
michael@0 159 * - we have at least one observer;
michael@0 160 * - the charging state or the level has changed.
michael@0 161 *
michael@0 162 * Note: no need to check for a remaining time change given that it's only
michael@0 163 * updated if there is a level change or a charging change.
michael@0 164 *
michael@0 165 * The idea is to prevent doing all the way to the DOM code in the child
michael@0 166 * process to finally not send an event.
michael@0 167 */
michael@0 168 if (sNotificationsEnabled &&
michael@0 169 (previousCharging != isCharging() || previousLevel != getLevel())) {
michael@0 170 GeckoAppShell.notifyBatteryChange(getLevel(), isCharging(), getRemainingTime());
michael@0 171 }
michael@0 172 }
michael@0 173
michael@0 174 public static boolean isCharging() {
michael@0 175 return sCharging;
michael@0 176 }
michael@0 177
michael@0 178 public static double getLevel() {
michael@0 179 return sLevel;
michael@0 180 }
michael@0 181
michael@0 182 public static double getRemainingTime() {
michael@0 183 return sRemainingTime;
michael@0 184 }
michael@0 185
michael@0 186 public static void enableNotifications() {
michael@0 187 sNotificationsEnabled = true;
michael@0 188 }
michael@0 189
michael@0 190 public static void disableNotifications() {
michael@0 191 sNotificationsEnabled = false;
michael@0 192 }
michael@0 193
michael@0 194 public static double[] getCurrentInformation() {
michael@0 195 return new double[] { getLevel(), isCharging() ? 1.0 : 0.0, getRemainingTime() };
michael@0 196 }
michael@0 197 }

mercurial