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.

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

mercurial