private void handleRemoveListener(int uid) {
   synchronized (mListeners) {
     if (mClientUids.indexOfKey(uid) < 0) {
       // Shouldn't be here -- don't have this uid.
       Log.w(TAG, "Unneeded remove listener for uid " + uid);
       return;
     }
     mClientUids.delete(uid);
     if (mNavigating) {
       try {
         mBatteryStats.noteStopGps(uid);
       } catch (RemoteException e) {
         Log.w(TAG, "RemoteException in removeListener");
       }
     }
   }
 }
 private void handleAddListener(int uid) {
   synchronized (mListeners) {
     if (mClientUids.indexOfKey(uid) >= 0) {
       // Shouldn't be here -- already have this uid.
       Log.w(TAG, "Duplicate add listener for uid " + uid);
       return;
     }
     mClientUids.put(uid, 0);
     if (mNavigating) {
       try {
         mBatteryStats.noteStartGps(uid);
       } catch (RemoteException e) {
         Log.w(TAG, "RemoteException in addListener");
       }
     }
   }
 }
  /** called from native code to update our status */
  private void reportStatus(int status) {
    if (VERBOSE) Log.v(TAG, "reportStatus status: " + status);

    synchronized (mListeners) {
      boolean wasNavigating = mNavigating;

      switch (status) {
        case GPS_STATUS_SESSION_BEGIN:
          mNavigating = true;
          mEngineOn = true;
          break;
        case GPS_STATUS_SESSION_END:
          mNavigating = false;
          break;
        case GPS_STATUS_ENGINE_ON:
          mEngineOn = true;
          break;
        case GPS_STATUS_ENGINE_OFF:
          mEngineOn = false;
          mNavigating = false;
          break;
      }

      // beware, the events can come out of order
      if ((mNavigating || mEngineOn) && !mWakeLock.isHeld()) {
        if (DEBUG) Log.d(TAG, "Acquiring wakelock");
        mWakeLock.acquire();
      }

      if (wasNavigating != mNavigating) {
        int size = mListeners.size();
        for (int i = 0; i < size; i++) {
          Listener listener = mListeners.get(i);
          try {
            if (mNavigating) {
              listener.mListener.onGpsStarted();
            } else {
              listener.mListener.onGpsStopped();
            }
          } catch (RemoteException e) {
            Log.w(TAG, "RemoteException in reportStatus");
            mListeners.remove(listener);
            // adjust for size of list changing
            size--;
          }
        }

        try {
          // update battery stats
          for (int i = mClientUids.size() - 1; i >= 0; i--) {
            int uid = mClientUids.keyAt(i);
            if (mNavigating) {
              mBatteryStats.noteStartGps(uid);
            } else {
              mBatteryStats.noteStopGps(uid);
            }
          }
        } catch (RemoteException e) {
          Log.w(TAG, "RemoteException in reportStatus");
        }

        // send an intent to notify that the GPS has been enabled or disabled.
        Intent intent = new Intent(GPS_ENABLED_CHANGE_ACTION);
        intent.putExtra(EXTRA_ENABLED, mNavigating);
        mContext.sendBroadcast(intent);
      }

      // beware, the events can come out of order
      if (!mNavigating && !mEngineOn && mWakeLock.isHeld()) {
        if (DEBUG) Log.d(TAG, "Releasing wakelock");
        mWakeLock.release();
      }
    }
  }
  private void processValuesLocked() {
    boolean logOutlier = false;
    long dischargeDuration = 0;

    mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
    if (mBatteryProps.chargerAcOnline) {
      mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
    } else if (mBatteryProps.chargerUsbOnline) {
      mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
    } else if (mBatteryProps.chargerWirelessOnline) {
      mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
    } else {
      mPlugType = BATTERY_PLUGGED_NONE;
    }

    if (DEBUG) {
      Slog.d(
          TAG,
          "Processing new values: "
              + "chargerAcOnline="
              + mBatteryProps.chargerAcOnline
              + ", chargerUsbOnline="
              + mBatteryProps.chargerUsbOnline
              + ", chargerWirelessOnline="
              + mBatteryProps.chargerWirelessOnline
              + ", batteryStatus="
              + mBatteryProps.batteryStatus
              + ", batteryHealth="
              + mBatteryProps.batteryHealth
              + ", batteryPresent="
              + mBatteryProps.batteryPresent
              + ", batteryLevel="
              + mBatteryProps.batteryLevel
              + ", batteryTechnology="
              + mBatteryProps.batteryTechnology
              + ", batteryVoltage="
              + mBatteryProps.batteryVoltage
              + ", batteryCurrentNow="
              + mBatteryProps.batteryCurrentNow
              + ", batteryChargeCounter="
              + mBatteryProps.batteryChargeCounter
              + ", batteryTemperature="
              + mBatteryProps.batteryTemperature
              + ", mBatteryLevelCritical="
              + mBatteryLevelCritical
              + ", mPlugType="
              + mPlugType);
    }
    if (mLastBatteryVoltage != mBatteryProps.batteryVoltage) {
      Xlog.d(
          TAG,
          "mBatteryVoltage="
              + mBatteryProps.batteryVoltage
              + ", batteryLevel="
              + mBatteryProps.batteryLevel_2nd);
    }
    // Update the battery LED
    mLed.updateLightsLocked();

    // Let the battery stats keep track of the current level.
    try {
      mBatteryStats.setBatteryState(
          mBatteryProps.batteryStatus,
          mBatteryProps.batteryHealth,
          mPlugType,
          mBatteryProps.batteryLevel,
          mBatteryProps.batteryTemperature,
          mBatteryProps.batteryVoltage);
    } catch (RemoteException e) {
      // Should never happen.
    }

    shutdownIfNoPowerLocked();
    shutdownIfOverTempLocked();

    if (mBatteryProps.batteryStatus != mLastBatteryStatus
        || mBatteryProps.batteryStatus_2nd != mLastBatteryStatus_2nd
        || mBatteryProps.batteryHealth != mLastBatteryHealth
        || mBatteryProps.batteryPresent != mLastBatteryPresent
        || mBatteryProps.batteryPresent_2nd != mLastBatteryPresent_2nd
        || mBatteryProps.batteryLevel != mLastBatteryLevel
        || mBatteryProps.batteryLevel_2nd != mLastBatteryLevel_2nd
        || mPlugType != mLastPlugType
        || mBatteryProps.batteryVoltage != mLastBatteryVoltage
        || mBatteryProps.batteryTemperature != mLastBatteryTemperature
        || mInvalidCharger != mLastInvalidCharger) {

      if (mPlugType != mLastPlugType) {
        if (mLastPlugType == BATTERY_PLUGGED_NONE) {
          // discharging -> charging

          // There's no value in this data unless we've discharged at least once and the
          // battery level has changed; so don't log until it does.
          if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {
            dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
            logOutlier = true;
            EventLog.writeEvent(
                EventLogTags.BATTERY_DISCHARGE,
                dischargeDuration,
                mDischargeStartLevel,
                mBatteryProps.batteryLevel);
            // make sure we see a discharge event before logging again
            mDischargeStartTime = 0;
          }
        } else if (mPlugType == BATTERY_PLUGGED_NONE) {
          // charging -> discharging or we just powered up
          mDischargeStartTime = SystemClock.elapsedRealtime();
          mDischargeStartLevel = mBatteryProps.batteryLevel;
        }
      }
      if (mBatteryProps.batteryStatus != mLastBatteryStatus
          || mBatteryProps.batteryHealth != mLastBatteryHealth
          || mBatteryProps.batteryPresent != mLastBatteryPresent
          || mPlugType != mLastPlugType) {
        EventLog.writeEvent(
            EventLogTags.BATTERY_STATUS,
            mBatteryProps.batteryStatus,
            mBatteryProps.batteryHealth,
            mBatteryProps.batteryPresent ? 1 : 0,
            mPlugType,
            mBatteryProps.batteryTechnology);
      }
      if (mBatteryProps.batteryLevel != mLastBatteryLevel) {
        // Don't do this just from voltage or temperature changes, that is
        // too noisy.
        EventLog.writeEvent(
            EventLogTags.BATTERY_LEVEL,
            mBatteryProps.batteryLevel,
            mBatteryProps.batteryVoltage,
            mBatteryProps.batteryTemperature);
      }
      if (mBatteryLevelCritical
          && !mLastBatteryLevelCritical
          && mPlugType == BATTERY_PLUGGED_NONE) {
        // We want to make sure we log discharge cycle outliers
        // if the battery is about to die.
        dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
        logOutlier = true;
      }

      final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
      final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;

      /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
       * - is just un-plugged (previously was plugged) and battery level is
       *   less than or equal to WARNING, or
       * - is not plugged and battery level falls to WARNING boundary
       *   (becomes <= mLowBatteryWarningLevel).
       */
      final boolean sendBatteryLow =
          !plugged
              && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
              && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel
              && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);

      sendIntentLocked();

      // Separate broadcast is sent for power connected / not connected
      // since the standard intent will not wake any applications and some
      // applications may want to have smart behavior based on this.
      if (mPlugType != 0 && mLastPlugType == 0) {
        mHandler.post(
            new Runnable() {
              @Override
              public void run() {
                Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
                statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
              }
            });
      } else if (mPlugType == 0 && mLastPlugType != 0) {
        mHandler.post(
            new Runnable() {
              @Override
              public void run() {
                Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
                statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
              }
            });
      }

      if (sendBatteryLow) {
        mSentLowBatteryBroadcast = true;
        mHandler.post(
            new Runnable() {
              @Override
              public void run() {
                Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
                statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
              }
            });
      } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
        mSentLowBatteryBroadcast = false;
        mHandler.post(
            new Runnable() {
              @Override
              public void run() {
                Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
                statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
              }
            });
      }

      // Update the battery LED
      // mLed.updateLightsLocked();

      // This needs to be done after sendIntent() so that we get the lastest battery stats.
      if (logOutlier && dischargeDuration != 0) {
        logOutlierLocked(dischargeDuration);
      }

      mLastBatteryStatus = mBatteryProps.batteryStatus;
      mLastBatteryStatus_2nd = mBatteryProps.batteryStatus_2nd;
      mLastBatteryHealth = mBatteryProps.batteryHealth;
      mLastBatteryPresent = mBatteryProps.batteryPresent;
      mLastBatteryPresent_2nd = mBatteryProps.batteryPresent_2nd;
      mLastBatteryLevel = mBatteryProps.batteryLevel;
      mLastBatteryLevel_2nd = mBatteryProps.batteryLevel_2nd;
      mLastPlugType = mPlugType;
      mLastBatteryVoltage = mBatteryProps.batteryVoltage;
      mLastBatteryTemperature = mBatteryProps.batteryTemperature;
      mLastBatteryLevelCritical = mBatteryLevelCritical;
      mLastInvalidCharger = mInvalidCharger;
    }
  }