Start collecting mobile radio activity from the radio.

Hook in to the new radio API to find out when the radio
is active and use that to track its state in batter stats.
We also still have the data being tracked from the kernel's
emulation, and continue to use that if we don't get data from
the radio.

Currently this monitoring is turned off until some issues
in the radio can be fixed that are providing bad data.

Also add a new API to get estimated drain and charge times.

Change-Id: Ifc4900fabb8f848f9cda361dce698664ea75f175
diff --git a/api/current.txt b/api/current.txt
index ef6aed7..323f8f0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25441,18 +25441,6 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
-  public class DataConnectionRealTimeInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getDcPowerState();
-    method public long getTime();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public static int DC_POWER_STATE_HIGH;
-    field public static int DC_POWER_STATE_LOW;
-    field public static int DC_POWER_STATE_MEDIUM;
-    field public static int DC_POWER_STATE_UNKNOWN;
-  }
-
   public class NeighboringCellInfo implements android.os.Parcelable {
     ctor public deprecated NeighboringCellInfo();
     ctor public deprecated NeighboringCellInfo(int, int);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e640649..f05ddde 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -130,8 +130,8 @@
     // NOTE: Update this list if you add/change any stats above.
     // These characters are supposed to represent "total", "last", "current", 
     // and "unplugged". They were shortened for efficiency sake.
-    private static final String[] STAT_NAMES = { "t", "l", "c", "u" };
-    
+    private static final String[] STAT_NAMES = { "l", "c", "u" };
+
     /**
      * Bump the version on this if the checkin format changes.
      */
@@ -186,7 +186,7 @@
          * Returns the count associated with this Counter for the
          * selected type of statistics.
          *
-         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+         * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
          */
         public abstract int getCountLocked(int which);
 
@@ -205,7 +205,7 @@
          * Returns the count associated with this Counter for the
          * selected type of statistics.
          *
-         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+         * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
          */
         public abstract long getCountLocked(int which);
 
@@ -224,7 +224,7 @@
          * Returns the count associated with this Timer for the
          * selected type of statistics.
          *
-         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+         * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
          */
         public abstract int getCountLocked(int which);
 
@@ -233,7 +233,7 @@
          * selected type of statistics.
          *
          * @param elapsedRealtimeUs current elapsed realtime of system in microseconds
-         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+         * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
          * @return a time in microseconds
          */
         public abstract long getTotalTimeLocked(long elapsedRealtimeUs, int which);
@@ -385,27 +385,27 @@
             /**
              * Returns the total time (in 1/100 sec) spent executing in user code.
              *
-             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              */
             public abstract long getUserTime(int which);
 
             /**
              * Returns the total time (in 1/100 sec) spent executing in system code.
              *
-             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              */
             public abstract long getSystemTime(int which);
 
             /**
              * Returns the number of times the process has been started.
              *
-             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              */
             public abstract int getStarts(int which);
 
             /**
              * Returns the cpu time spent in microseconds while the process was in the foreground.
-             * @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED
+             * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              * @return foreground cpu time in microseconds
              */
             public abstract long getForegroundTime(int which);
@@ -414,7 +414,7 @@
              * Returns the approximate cpu time spent in microseconds, at a certain CPU speed.
              * @param speedStep the index of the CPU speed. This is not the actual speed of the
              * CPU.
-             * @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED
+             * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              * @see BatteryStats#getCpuSpeedSteps()
              */
             public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
@@ -433,7 +433,7 @@
              * Returns the number of times this package has done something that could wake up the
              * device from sleep.
              *
-             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              */
             public abstract int getWakeups(int which);
 
@@ -451,7 +451,7 @@
                  * Returns the amount of time spent started.
                  *
                  * @param batteryUptime elapsed uptime on battery in microseconds.
-                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+                 * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
                  * @return
                  */
                 public abstract long getStartTime(long batteryUptime, int which);
@@ -459,14 +459,14 @@
                 /**
                  * Returns the total number of times startService() has been called.
                  *
-                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+                 * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
                  */
                 public abstract int getStarts(int which);
 
                 /**
                  * Returns the total number times the service has been launched.
                  *
-                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+                 * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
                  */
                 public abstract int getLaunches(int which);
             }
@@ -1285,7 +1285,7 @@
      * Returns the total, last, or current battery uptime in microseconds.
      *
      * @param curTime the elapsed realtime in microseconds.
-     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
      */
     public abstract long computeBatteryUptime(long curTime, int which);
 
@@ -1293,7 +1293,7 @@
      * Returns the total, last, or current battery realtime in microseconds.
      *
      * @param curTime the current elapsed realtime in microseconds.
-     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
      */
     public abstract long computeBatteryRealtime(long curTime, int which);
 
@@ -1301,7 +1301,7 @@
      * Returns the total, last, or current battery screen off uptime in microseconds.
      *
      * @param curTime the elapsed realtime in microseconds.
-     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
      */
     public abstract long computeBatteryScreenOffUptime(long curTime, int which);
 
@@ -1309,7 +1309,7 @@
      * Returns the total, last, or current battery screen off realtime in microseconds.
      *
      * @param curTime the current elapsed realtime in microseconds.
-     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
      */
     public abstract long computeBatteryScreenOffRealtime(long curTime, int which);
 
@@ -1317,18 +1317,38 @@
      * Returns the total, last, or current uptime in microseconds.
      *
      * @param curTime the current elapsed realtime in microseconds.
-     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
      */
     public abstract long computeUptime(long curTime, int which);
 
     /**
      * Returns the total, last, or current realtime in microseconds.
-     * *
+     *
      * @param curTime the current elapsed realtime in microseconds.
-     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
      */
     public abstract long computeRealtime(long curTime, int which);
-    
+
+    /**
+     * Compute an approximation for how much run time (in microseconds) is remaining on
+     * the battery.  Returns -1 if no time can be computed: either there is not
+     * enough current data to make a decision, or the battery is currently
+     * charging.
+     *
+     * @param curTime The current elepsed realtime in microseconds.
+     */
+    public abstract long computeBatteryTimeRemaining(long curTime);
+
+    /**
+     * Compute an approximation for how much time (in microseconds) remains until the battery
+     * is fully charged.  Returns -1 if no time can be computed: either there is not
+     * enough current data to make a decision, or the battery is currently
+     * discharging.
+     *
+     * @param curTime The current elepsed realtime in microseconds.
+     */
+    public abstract long computeChargeTimeRemaining(long curTime);
+
     public abstract Map<String, ? extends LongCounter> getWakeupReasonStats();
 
     public abstract Map<String, ? extends Timer> getKernelWakelockStats();
@@ -1430,7 +1450,7 @@
      * @param timer a Timer object contining the wakelock times.
      * @param elapsedRealtimeUs the current on-battery time in microseconds.
      * @param name the name of the wakelock.
-     * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
      * @param linePrefix a String to be prepended to each line of output.
      * @return the line prefix
      */
@@ -1464,7 +1484,7 @@
      * @param timer a Timer object contining the wakelock times.
      * @param elapsedRealtimeUs the current time in microseconds.
      * @param name the name of the wakelock.
-     * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
      * @param linePrefix a String to be prepended to each line of output.
      * @return the line prefix
      */
@@ -1682,7 +1702,7 @@
             }
         }
         
-        BatteryStatsHelper helper = new BatteryStatsHelper(context);
+        BatteryStatsHelper helper = new BatteryStatsHelper(context, false);
         helper.create(this);
         helper.refreshStats(which, UserHandle.USER_ALL);
         List<BatterySipper> sippers = helper.getUsageList();
@@ -1929,6 +1949,8 @@
         final long whichBatteryScreenOffUptime = computeBatteryScreenOffUptime(rawUptime, which);
         final long whichBatteryScreenOffRealtime = computeBatteryScreenOffRealtime(rawRealtime,
                 which);
+        final long batteryTimeRemaining = computeBatteryTimeRemaining(rawRealtime);
+        final long chargeTimeRemaining = computeChargeTimeRemaining(rawRealtime);
 
         StringBuilder sb = new StringBuilder(128);
         
@@ -1963,7 +1985,20 @@
                 sb.append("realtime, ");
                 formatTimeMs(sb, totalUptime / 1000);
                 sb.append("uptime");
-        pw.println(sb.toString());
+        if (batteryTimeRemaining >= 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                    sb.append("  Battery time remaining: ");
+                    formatTimeMs(sb, batteryTimeRemaining / 1000);
+            pw.println(sb.toString());
+        }
+        if (chargeTimeRemaining >= 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                    sb.append("  Charge time remaining: ");
+                    formatTimeMs(sb, chargeTimeRemaining / 1000);
+            pw.println(sb.toString());
+        }
         pw.print("  Start clock time: ");
         pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString());
 
@@ -2268,7 +2303,7 @@
             pw.println();
         }
 
-        BatteryStatsHelper helper = new BatteryStatsHelper(context);
+        BatteryStatsHelper helper = new BatteryStatsHelper(context, false);
         helper.create(this);
         helper.refreshStats(which, UserHandle.USER_ALL);
         List<BatterySipper> sippers = helper.getUsageList();
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 32f700d..fc89b31 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -19,6 +19,7 @@
 import com.android.internal.os.BatteryStatsImpl;
 
 import android.os.WorkSource;
+import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.SignalStrength;
 
 interface IBatteryStats {
@@ -55,7 +56,7 @@
     void noteScreenOff();
     void noteInputEvent();
     void noteUserActivity(int uid, int event);
-    void noteDataConnectionActive(int type, boolean active, long timestampNs);
+    void noteMobileRadioPowerState(int powerState, long timestampNs);
     void notePhoneOn();
     void notePhoneOff();
     void notePhoneSignalStrength(in SignalStrength signalStrength);
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 1dd1f5e..7ff949e 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -22,6 +22,8 @@
 import static android.os.BatteryStats.NETWORK_WIFI_TX_DATA;
 
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
 import android.net.ConnectivityManager;
@@ -60,11 +62,14 @@
     private static final String TAG = BatteryStatsHelper.class.getSimpleName();
 
     private static BatteryStats sStatsXfer;
+    private static Intent sBatteryBroadcastXfer;
 
     final private Context mContext;
+    final private boolean mCollectBatteryBroadcast;
 
     private IBatteryStats mBatteryInfo;
     private BatteryStats mStats;
+    private Intent mBatteryBroadcast;
     private PowerProfile mPowerProfile;
 
     private final List<BatterySipper> mUsageList = new ArrayList<BatterySipper>();
@@ -85,6 +90,8 @@
     long mBatteryUptime;
     long mTypeBatteryRealtime;
     long mTypeBatteryUptime;
+    long mBatteryTimeRemaining;
+    long mChargeTimeRemaining;
 
     private long mStatsPeriod = 0;
     private double mMaxPower = 1;
@@ -102,7 +109,12 @@
     private long mAppWifiRunning;
 
     public BatteryStatsHelper(Context context) {
+        this(context, true);
+    }
+
+    public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast) {
         mContext = context;
+        mCollectBatteryBroadcast = collectBatteryBroadcast;
     }
 
     /** Clears the current stats and forces recreating for future use. */
@@ -117,6 +129,13 @@
         return mStats;
     }
 
+    public Intent getBatteryBroadcast() {
+        if (mBatteryBroadcast == null && mCollectBatteryBroadcast) {
+            load();
+        }
+        return mBatteryBroadcast;
+    }
+
     public PowerProfile getPowerProfile() {
         return mPowerProfile;
     }
@@ -129,6 +148,7 @@
     public void create(Bundle icicle) {
         if (icicle != null) {
             mStats = sStatsXfer;
+            mBatteryBroadcast = sBatteryBroadcastXfer;
         }
         mBatteryInfo = IBatteryStats.Stub.asInterface(
                 ServiceManager.getService(BatteryStats.SERVICE_NAME));
@@ -137,6 +157,7 @@
 
     public void storeState() {
         sStatsXfer = mStats;
+        sBatteryBroadcastXfer = mBatteryBroadcast;
     }
 
     public static String makemAh(double power) {
@@ -190,6 +211,8 @@
         mBatteryRealtime = mStats.getBatteryRealtime(rawRealtimeUs);
         mTypeBatteryUptime = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
         mTypeBatteryRealtime = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
+        mBatteryTimeRemaining = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
+        mChargeTimeRemaining = mStats.computeChargeTimeRemaining(rawRealtimeUs);
 
         if (DEBUG) {
             Log.d(TAG, "Raw time: realtime=" + (rawRealtimeUs/1000) + " uptime="
@@ -787,6 +810,10 @@
         return mMaxDrainedPower;
     }
 
+    public long getBatteryTimeRemaining() { return mBatteryTimeRemaining; }
+
+    public long getChargeTimeRemaining() { return mChargeTimeRemaining; }
+
     private void load() {
         if (mBatteryInfo == null) {
             return;
@@ -803,5 +830,9 @@
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException:", e);
         }
+        if (mCollectBatteryBroadcast) {
+            mBatteryBroadcast = mContext.registerReceiver(null,
+                    new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+        }
     }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index eaedba5..343c507 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -38,6 +38,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.WorkSource;
+import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
@@ -87,7 +88,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 101 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 103 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -284,7 +285,7 @@
     int mBluetoothState = -1;
     final StopwatchTimer[] mBluetoothStateTimer = new StopwatchTimer[NUM_BLUETOOTH_STATES];
 
-    boolean mMobileRadioActive;
+    int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
     StopwatchTimer mMobileRadioActiveTimer;
     StopwatchTimer mMobileRadioActivePerAppTimer;
     LongSamplingCounter mMobileRadioActiveAdjustedTime;
@@ -306,7 +307,9 @@
      */
     int mDischargeStartLevel;
     int mDischargeUnplugLevel;
+    int mDischargePlugLevel;
     int mDischargeCurrentLevel;
+    int mCurrentBatteryLevel;
     int mLowDischargeAmountSinceCharge;
     int mHighDischargeAmountSinceCharge;
     int mDischargeScreenOnUnplugLevel;
@@ -2736,40 +2739,41 @@
         }
     }
 
-    public void noteDataConnectionActive(int type, boolean active, long timestampNs) {
-        if (ConnectivityManager.isNetworkTypeMobile(type)) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
-            if (mMobileRadioActive != active) {
-                long realElapsedRealtimeMs;
-                if (active) {
+    public void noteMobileRadioPowerState(int powerState, long timestampNs) {
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long uptime = SystemClock.uptimeMillis();
+        if (mMobileRadioPowerState != powerState) {
+            long realElapsedRealtimeMs;
+            final boolean active =
+                    powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
+                            || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
+            if (active) {
+                realElapsedRealtimeMs = elapsedRealtime;
+                mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+            } else {
+                realElapsedRealtimeMs = timestampNs / (1000*1000);
+                long lastUpdateTimeMs = mMobileRadioActiveTimer.getLastUpdateTimeMs();
+                if (realElapsedRealtimeMs < lastUpdateTimeMs) {
+                    Slog.wtf(TAG, "Data connection inactive timestamp " + realElapsedRealtimeMs
+                            + " is before start time " + lastUpdateTimeMs);
                     realElapsedRealtimeMs = elapsedRealtime;
-                    mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
-                } else {
-                    realElapsedRealtimeMs = timestampNs / (1000*1000);
-                    long lastUpdateTimeMs = mMobileRadioActiveTimer.getLastUpdateTimeMs();
-                    if (realElapsedRealtimeMs < lastUpdateTimeMs) {
-                        Slog.wtf(TAG, "Data connection inactive timestamp " + realElapsedRealtimeMs
-                                + " is before start time " + lastUpdateTimeMs);
-                        realElapsedRealtimeMs = elapsedRealtime;
-                    } else if (realElapsedRealtimeMs < elapsedRealtime) {
-                        mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtime
-                                - realElapsedRealtimeMs);
-                    }
-                    mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+                } else if (realElapsedRealtimeMs < elapsedRealtime) {
+                    mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtime
+                            - realElapsedRealtimeMs);
                 }
-                if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
-                        + Integer.toHexString(mHistoryCur.states));
-                addHistoryRecordLocked(elapsedRealtime, uptime);
-                mMobileRadioActive = active;
-                if (active) {
-                    mMobileRadioActiveTimer.startRunningLocked(elapsedRealtime);
-                    mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
-                } else {
-                    mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
-                    updateNetworkActivityLocked(NET_UPDATE_MOBILE, realElapsedRealtimeMs);
-                    mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
-                }
+                mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+            }
+            if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
+                    + Integer.toHexString(mHistoryCur.states));
+            addHistoryRecordLocked(elapsedRealtime, uptime);
+            mMobileRadioPowerState = powerState;
+            if (active) {
+                mMobileRadioActiveTimer.startRunningLocked(elapsedRealtime);
+                mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
+            } else {
+                mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
+                updateNetworkActivityLocked(NET_UPDATE_MOBILE, realElapsedRealtimeMs);
+                mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
             }
         }
     }
@@ -5520,7 +5524,9 @@
         initTimes(uptime, realtime);
         mDischargeStartLevel = 0;
         mDischargeUnplugLevel = 0;
+        mDischargePlugLevel = -1;
         mDischargeCurrentLevel = 0;
+        mCurrentBatteryLevel = 0;
         initDischarge();
         clearHistoryLocked();
     }
@@ -5726,7 +5732,8 @@
         mDischargeStartLevel = mHistoryCur.batteryLevel;
         pullPendingStateUpdatesLocked();
         addHistoryRecordLocked(mSecRealtime, mSecUptime);
-        mDischargeCurrentLevel = mDischargeUnplugLevel = mHistoryCur.batteryLevel;
+        mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel
+                = mCurrentBatteryLevel = mHistoryCur.batteryLevel;
         mOnBatteryTimeBase.reset(uptime, realtime);
         mOnBatteryScreenOffTimeBase.reset(uptime, realtime);
         if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
@@ -5907,7 +5914,7 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(mSecRealtime, mSecUptime);
-            mDischargeCurrentLevel = level;
+            mDischargeCurrentLevel = mDischargePlugLevel = level;
             if (level < mDischargeUnplugLevel) {
                 mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
                 mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
@@ -5971,6 +5978,10 @@
                     startRecordingHistory(elapsedRealtime, uptime, true);
                 }
             }
+            mCurrentBatteryLevel = level;
+            if (mDischargePlugLevel < 0) {
+                mDischargePlugLevel = level;
+            }
             if (onBattery != mOnBattery) {
                 mHistoryCur.batteryLevel = (byte)level;
                 mHistoryCur.batteryStatus = (byte)status;
@@ -6224,6 +6235,42 @@
         return mOnBatteryScreenOffTimeBase.computeRealtime(curTime, which);
     }
 
+    @Override
+    public long computeBatteryTimeRemaining(long curTime) {
+        if (!mOnBattery) {
+            return -1;
+        }
+        int discharge = (getLowDischargeAmountSinceCharge()+getHighDischargeAmountSinceCharge())/2;
+        if (discharge < 2) {
+            return -1;
+        }
+        long duration = computeBatteryRealtime(curTime, STATS_SINCE_CHARGED);
+        if (duration < 1000*1000) {
+            return -1;
+        }
+        long usPerLevel = duration/discharge;
+        return usPerLevel * mCurrentBatteryLevel;
+    }
+
+    @Override
+    public long computeChargeTimeRemaining(long curTime) {
+        if (true || mOnBattery) {
+            // Not yet working.
+            return -1;
+        }
+        int curLevel = mCurrentBatteryLevel;
+        int plugLevel = mDischargePlugLevel;
+        if (plugLevel < 0 || curLevel < (plugLevel+1)) {
+            return -1;
+        }
+        long duration = computeBatteryRealtime(curTime, STATS_SINCE_UNPLUGGED);
+        if (duration < 1000*1000) {
+            return -1;
+        }
+        long usPerLevel = duration/(curLevel-plugLevel);
+        return usPerLevel * (100-curLevel);
+    }
+
     long getBatteryUptimeLocked() {
         return mOnBatteryTimeBase.getUptime(SystemClock.uptimeMillis() * 1000);
     }
@@ -6722,7 +6769,9 @@
         mOnBatteryTimeBase.readSummaryFromParcel(in);
         mOnBatteryScreenOffTimeBase.readSummaryFromParcel(in);
         mDischargeUnplugLevel = in.readInt();
+        mDischargePlugLevel = in.readInt();
         mDischargeCurrentLevel = in.readInt();
+        mCurrentBatteryLevel = in.readInt();
         mLowDischargeAmountSinceCharge = in.readInt();
         mHighDischargeAmountSinceCharge = in.readInt();
         mDischargeAmountScreenOnSinceCharge = in.readInt();
@@ -6749,7 +6798,7 @@
             mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
             mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
         }
-        mMobileRadioActive = false;
+        mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
         mMobileRadioActiveTimer.readSummaryFromParcelLocked(in);
         mMobileRadioActivePerAppTimer.readSummaryFromParcelLocked(in);
         mMobileRadioActiveAdjustedTime.readSummaryFromParcelLocked(in);
@@ -6974,7 +7023,9 @@
         mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
         mOnBatteryScreenOffTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
         out.writeInt(mDischargeUnplugLevel);
+        out.writeInt(mDischargePlugLevel);
         out.writeInt(mDischargeCurrentLevel);
+        out.writeInt(mCurrentBatteryLevel);
         out.writeInt(getLowDischargeAmountSinceCharge());
         out.writeInt(getHighDischargeAmountSinceCharge());
         out.writeInt(getDischargeAmountScreenOnSinceCharge());
@@ -7262,7 +7313,7 @@
             mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
             mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
         }
-        mMobileRadioActive = false;
+        mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
         mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase, in);
         mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase,
                 in);
@@ -7284,7 +7335,9 @@
                     null, mOnBatteryTimeBase, in);
         }
         mDischargeUnplugLevel = in.readInt();
+        mDischargePlugLevel = in.readInt();
         mDischargeCurrentLevel = in.readInt();
+        mCurrentBatteryLevel = in.readInt();
         mLowDischargeAmountSinceCharge = in.readInt();
         mHighDischargeAmountSinceCharge = in.readInt();
         mDischargeAmountScreenOn = in.readInt();
@@ -7402,7 +7455,9 @@
             mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
         }
         out.writeInt(mDischargeUnplugLevel);
+        out.writeInt(mDischargePlugLevel);
         out.writeInt(mDischargeCurrentLevel);
+        out.writeInt(mCurrentBatteryLevel);
         out.writeInt(mLowDischargeAmountSinceCharge);
         out.writeInt(mHighDischargeAmountSinceCharge);
         out.writeInt(mDischargeAmountScreenOn);
@@ -7499,6 +7554,7 @@
                 pr.println("*** Data connection type #" + i + ":");
                 mPhoneDataConnectionsTimer[i].logState(pr, "  ");
             }
+            pr.println("*** mMobileRadioPowerState=" + mMobileRadioPowerState);
             pr.println("*** Mobile network active timer:");
             mMobileRadioActiveTimer.logState(pr, "  ");
             pr.println("*** Mobile network active adjusted timer:");
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index 62eb663..0d1e122 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -20,6 +20,7 @@
 import android.net.LocalSocketAddress;
 import android.os.Build;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -59,6 +60,8 @@
 
     private final PowerManager.WakeLock mWakeLock;
 
+    private final Looper mLooper;
+
     private INativeDaemonConnectorCallbacks mCallbacks;
     private Handler mCallbackHandler;
 
@@ -74,6 +77,13 @@
 
     NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
             int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) {
+        this(callbacks, socket, responseQueueSize, logTag, maxLogSize, wl,
+                FgThread.get().getLooper());
+    }
+
+    NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
+            int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl,
+            Looper looper) {
         mCallbacks = callbacks;
         mSocket = socket;
         mResponseQueue = new ResponseQueue(responseQueueSize);
@@ -81,6 +91,7 @@
         if (mWakeLock != null) {
             mWakeLock.setReferenceCounted(true);
         }
+        mLooper = looper;
         mSequenceNumber = new AtomicInteger(0);
         TAG = logTag != null ? logTag : "NativeDaemonConnector";
         mLocalLog = new LocalLog(maxLogSize);
@@ -88,7 +99,7 @@
 
     @Override
     public void run() {
-        mCallbackHandler = new Handler(FgThread.get().getLooper(), this);
+        mCallbackHandler = new Handler(mLooper, this);
 
         while (true) {
             try {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 705862a..7ce45f7 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -58,6 +58,8 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.PhoneStateListener;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -143,21 +145,25 @@
         public static final int InterfaceDnsServerInfo    = 615;
     }
 
+    static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
+
     /**
      * Binder context for this service
      */
-    private Context mContext;
+    private final Context mContext;
 
     /**
      * connector object for communicating with netd
      */
-    private NativeDaemonConnector mConnector;
+    private final NativeDaemonConnector mConnector;
 
     private final Handler mFgHandler;
+    private final Handler mDaemonHandler;
+    private final PhoneStateListener mPhoneStateListener;
 
     private IBatteryStats mBatteryStats;
 
-    private Thread mThread;
+    private final Thread mThread;
     private CountDownLatch mConnectedSignal = new CountDownLatch(1);
 
     private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
@@ -191,6 +197,9 @@
     private volatile boolean mBandwidthControlEnabled;
     private volatile boolean mFirewallEnabled;
 
+    private boolean mMobileActivityFromRadio = false;
+    private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+
     private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
             new RemoteCallbackList<INetworkActivityListener>();
     private boolean mNetworkActive;
@@ -207,20 +216,35 @@
         mFgHandler = new Handler(FgThread.get().getLooper());
 
         if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+            mConnector = null;
+            mThread = null;
+            mDaemonHandler = null;
+            mPhoneStateListener = null;
             return;
         }
 
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         // Don't need this wake lock, since we now have a time stamp for when
         // the network actually went inactive.  (It might be nice to still do this,
         // but I don't want to do it through the power manager because that pollutes the
         // battery stats history with pointless noise.)
+        //PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         PowerManager.WakeLock wl = null; //pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NETD_TAG);
 
         mConnector = new NativeDaemonConnector(
-                new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl);
+                new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl,
+                FgThread.get().getLooper());
         mThread = new Thread(mConnector, NETD_TAG);
 
+        mDaemonHandler = new Handler(FgThread.get().getLooper());
+        mPhoneStateListener = new PhoneStateListener(mDaemonHandler.getLooper()) {
+            public void onDataConnectionRealTimeInfoChanged(
+                    DataConnectionRealTimeInfo dcRtInfo) {
+                // Disabled for now, until we are getting good data.
+                //notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
+                //        dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true);
+            }
+        };
+
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
     }
@@ -368,36 +392,62 @@
     /**
      * Notify our observers of a change in the data activity state of the interface
      */
-    private void notifyInterfaceClassActivity(int type, boolean active, long tsNanos) {
-        try {
-            getBatteryStats().noteDataConnectionActive(type, active, tsNanos);
-        } catch (RemoteException e) {
-        }
-
-        final int length = mObservers.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
+    private void notifyInterfaceClassActivity(int type, int powerState, long tsNanos,
+            boolean fromRadio) {
+        final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
+        if (isMobile) {
+            if (!fromRadio) {
+                if (mMobileActivityFromRadio) {
+                    // If this call is not coming from a report from the radio itself, but we
+                    // have previously received reports from the radio, then we will take the
+                    // power state to just be whatever the radio last reported.
+                    powerState = mLastPowerStateFromRadio;
+                }
+            } else {
+                mMobileActivityFromRadio = true;
+            }
+            if (mLastPowerStateFromRadio != powerState) {
+                mLastPowerStateFromRadio = powerState;
                 try {
-                    mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
-                            Integer.toString(type), active, tsNanos);
+                    getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos);
                 } catch (RemoteException e) {
-                } catch (RuntimeException e) {
                 }
             }
-        } finally {
-            mObservers.finishBroadcast();
+        }
+
+        boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
+                || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
+
+        if (!isMobile || fromRadio || !mMobileActivityFromRadio) {
+            // Report the change in data activity.  We don't do this if this is a change
+            // on the mobile network, that is not coming from the radio itself, and we
+            // have previously seen change reports from the radio.  In that case only
+            // the radio is the authority for the current state.
+            final int length = mObservers.beginBroadcast();
+            try {
+                for (int i = 0; i < length; i++) {
+                    try {
+                        mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
+                                Integer.toString(type), isActive, tsNanos);
+                    } catch (RemoteException e) {
+                    } catch (RuntimeException e) {
+                    }
+                }
+            } finally {
+                mObservers.finishBroadcast();
+            }
         }
 
         boolean report = false;
         synchronized (mIdleTimerLock) {
             if (mActiveIdleTimers.isEmpty()) {
-                // If there are no idle times, we are not monitoring activity, so we
+                // If there are no idle timers, we are not monitoring activity, so we
                 // are always considered active.
-                active = true;
+                isActive = true;
             }
-            if (mNetworkActive != active) {
-                mNetworkActive = active;
-                report = active;
+            if (mNetworkActive != isActive) {
+                mNetworkActive = isActive;
+                report = isActive;
             }
         }
         if (report) {
@@ -611,10 +661,13 @@
                         try {
                             timestampNanos = Long.parseLong(cooked[4]);
                         } catch(NumberFormatException ne) {}
+                    } else {
+                        timestampNanos = SystemClock.elapsedRealtimeNanos();
                     }
                     boolean isActive = cooked[2].equals("active");
                     notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
-                            isActive, timestampNanos);
+                            isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+                            : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW, timestampNanos, false);
                     return true;
                     // break;
             case NetdResponseCode.InterfaceAddressChange:
@@ -1301,9 +1354,11 @@
             if (ConnectivityManager.isNetworkTypeMobile(type)) {
                 mNetworkActive = false;
             }
-            mFgHandler.post(new Runnable() {
+            mDaemonHandler.post(new Runnable() {
                 @Override public void run() {
-                    notifyInterfaceClassActivity(type, true, SystemClock.elapsedRealtimeNanos());
+                    notifyInterfaceClassActivity(type,
+                            DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
+                            SystemClock.elapsedRealtimeNanos(), false);
                 }
             });
         }
@@ -1328,10 +1383,11 @@
                 throw e.rethrowAsParcelableException();
             }
             mActiveIdleTimers.remove(iface);
-            mFgHandler.post(new Runnable() {
+            mDaemonHandler.post(new Runnable() {
                 @Override public void run() {
-                    notifyInterfaceClassActivity(params.type, false,
-                            SystemClock.elapsedRealtimeNanos());
+                    notifyInterfaceClassActivity(params.type,
+                            DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
+                            SystemClock.elapsedRealtimeNanos(), false);
                 }
             });
         }
@@ -1941,6 +1997,9 @@
         pw.println();
 
         pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
+        pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
+                pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
+        pw.print("mNetworkActive="); pw.println(mNetworkActive);
 
         synchronized (mQuotaLock) {
             pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 037a744..d4565b6 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -393,6 +393,14 @@
         if (!checkNotifyPermission("notifyServiceState()")){
             return;
         }
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mBatteryStats.notePhoneState(state.getState());
+        } catch (RemoteException re) {
+            // Can't do much
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
         synchronized (mRecords) {
             mServiceState = state;
             for (Record r : mRecords) {
@@ -802,15 +810,6 @@
     //
 
     private void broadcastServiceStateChanged(ServiceState state) {
-        long ident = Binder.clearCallingIdentity();
-        try {
-            mBatteryStats.notePhoneState(state.getState());
-        } catch (RemoteException re) {
-            // Can't do much
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-
         Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
         Bundle data = new Bundle();
         state.fillInNotifierBundle(data);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 0ddb827..dbe773c 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -32,6 +32,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
 import android.util.Slog;
@@ -248,10 +249,10 @@
         }
     }
 
-    public void noteDataConnectionActive(int type, boolean active, long timestampNs) {
+    public void noteMobileRadioPowerState(int powerState, long timestampNs) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteDataConnectionActive(type, active, timestampNs);
+            mStats.noteMobileRadioPowerState(powerState, timestampNs);
         }
     }
 
diff --git a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
index 4a9ae39..96069213 100644
--- a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
+++ b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
@@ -23,6 +23,7 @@
  * Data connection real time information
  *
  * TODO: How to handle multiple subscriptions?
+ * @hide
  */
 public class DataConnectionRealTimeInfo implements Parcelable {
     private long mTime;             // Time the info was collected since boot in nanos;
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 7c5c648..59ec6f5 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -18,6 +18,7 @@
 
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
@@ -199,7 +200,67 @@
      */
     public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO           = 0x00002000;
 
+    private final Handler mHandler;
+
     public PhoneStateListener() {
+        this(Looper.myLooper());
+    }
+
+    /** @hide */
+    public PhoneStateListener(Looper looper) {
+        mHandler = new Handler(looper) {
+            public void handleMessage(Message msg) {
+                //Rlog.d("TelephonyRegistry", "what=0x" + Integer.toHexString(msg.what)
+                // + " msg=" + msg);
+                switch (msg.what) {
+                    case LISTEN_SERVICE_STATE:
+                        PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
+                        break;
+                    case LISTEN_SIGNAL_STRENGTH:
+                        PhoneStateListener.this.onSignalStrengthChanged(msg.arg1);
+                        break;
+                    case LISTEN_MESSAGE_WAITING_INDICATOR:
+                        PhoneStateListener.this.onMessageWaitingIndicatorChanged(msg.arg1 != 0);
+                        break;
+                    case LISTEN_CALL_FORWARDING_INDICATOR:
+                        PhoneStateListener.this.onCallForwardingIndicatorChanged(msg.arg1 != 0);
+                        break;
+                    case LISTEN_CELL_LOCATION:
+                        PhoneStateListener.this.onCellLocationChanged((CellLocation)msg.obj);
+                        break;
+                    case LISTEN_CALL_STATE:
+                        PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj);
+                        break;
+                    case LISTEN_DATA_CONNECTION_STATE:
+                        PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1, msg.arg2);
+                        PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1);
+                        break;
+                    case LISTEN_DATA_ACTIVITY:
+                        PhoneStateListener.this.onDataActivity(msg.arg1);
+                        break;
+                    case LISTEN_SIGNAL_STRENGTHS:
+                        PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj);
+                        break;
+                    case LISTEN_OTASP_CHANGED:
+                        PhoneStateListener.this.onOtaspChanged(msg.arg1);
+                        break;
+                    case LISTEN_CELL_INFO:
+                        PhoneStateListener.this.onCellInfoChanged((List<CellInfo>)msg.obj);
+                        break;
+                    case LISTEN_PRECISE_CALL_STATE:
+                        PhoneStateListener.this.onPreciseCallStateChanged((PreciseCallState)msg.obj);
+                        break;
+                    case LISTEN_PRECISE_DATA_CONNECTION_STATE:
+                        PhoneStateListener.this.onPreciseDataConnectionStateChanged(
+                                (PreciseDataConnectionState)msg.obj);
+                        break;
+                    case LISTEN_DATA_CONNECTION_REAL_TIME_INFO:
+                        PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
+                                (DataConnectionRealTimeInfo)msg.obj);
+                        break;
+                }
+            }
+        };
     }
 
     /**
@@ -424,56 +485,4 @@
                     dcRtInfo).sendToTarget();
         }
     };
-
-    Handler mHandler = new Handler() {
-        public void handleMessage(Message msg) {
-            //Rlog.d("TelephonyRegistry", "what=0x" + Integer.toHexString(msg.what) + " msg=" + msg);
-            switch (msg.what) {
-                case LISTEN_SERVICE_STATE:
-                    PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
-                    break;
-                case LISTEN_SIGNAL_STRENGTH:
-                    PhoneStateListener.this.onSignalStrengthChanged(msg.arg1);
-                    break;
-                case LISTEN_MESSAGE_WAITING_INDICATOR:
-                    PhoneStateListener.this.onMessageWaitingIndicatorChanged(msg.arg1 != 0);
-                    break;
-                case LISTEN_CALL_FORWARDING_INDICATOR:
-                    PhoneStateListener.this.onCallForwardingIndicatorChanged(msg.arg1 != 0);
-                    break;
-                case LISTEN_CELL_LOCATION:
-                    PhoneStateListener.this.onCellLocationChanged((CellLocation)msg.obj);
-                    break;
-                case LISTEN_CALL_STATE:
-                    PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj);
-                    break;
-                case LISTEN_DATA_CONNECTION_STATE:
-                    PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1, msg.arg2);
-                    PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1);
-                    break;
-                case LISTEN_DATA_ACTIVITY:
-                    PhoneStateListener.this.onDataActivity(msg.arg1);
-                    break;
-                case LISTEN_SIGNAL_STRENGTHS:
-                    PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj);
-                    break;
-                case LISTEN_OTASP_CHANGED:
-                    PhoneStateListener.this.onOtaspChanged(msg.arg1);
-                    break;
-                case LISTEN_CELL_INFO:
-                    PhoneStateListener.this.onCellInfoChanged((List<CellInfo>)msg.obj);
-                    break;
-                case LISTEN_PRECISE_CALL_STATE:
-                    PhoneStateListener.this.onPreciseCallStateChanged((PreciseCallState)msg.obj);
-                    break;
-                case LISTEN_PRECISE_DATA_CONNECTION_STATE:
-                    PhoneStateListener.this.onPreciseDataConnectionStateChanged((PreciseDataConnectionState)msg.obj);
-                    break;
-                case LISTEN_DATA_CONNECTION_REAL_TIME_INFO:
-                    PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
-                            (DataConnectionRealTimeInfo)msg.obj);
-                    break;
-            }
-        }
-    };
 }