Loading core/java/com/android/internal/os/BatteryStatsImpl.java +89 −24 Original line number Original line Diff line number Diff line Loading @@ -11492,10 +11492,10 @@ public class BatteryStatsImpl extends BatteryStats { return; return; } } final ArrayMap<Uid, Double> uidEstimatedConsumptionMah = final SparseDoubleArray uidEstimatedConsumptionMah = (mGlobalMeasuredEnergyStats != null (mGlobalMeasuredEnergyStats != null && mWifiPowerCalculator != null && consumedChargeUC > 0) ? && mWifiPowerCalculator != null && consumedChargeUC > 0) ? new ArrayMap<>() : null; new SparseDoubleArray() : null; double totalEstimatedConsumptionMah = 0; double totalEstimatedConsumptionMah = 0; SparseLongArray rxPackets = new SparseLongArray(); SparseLongArray rxPackets = new SparseLongArray(); Loading Loading @@ -11583,7 +11583,7 @@ public class BatteryStatsImpl extends BatteryStats { } } } } addDoubleToUidMap(uidEstimatedConsumptionMah, u, uidEstimatedConsumptionMah.add(u.getUid(), mWifiPowerCalculator.calcPowerWithoutControllerDataMah( mWifiPowerCalculator.calcPowerWithoutControllerDataMah( entry.rxPackets, entry.txPackets, entry.rxPackets, entry.txPackets, uidRunningMs, uidScanMs, uidBatchScanMs)); uidRunningMs, uidScanMs, uidBatchScanMs)); Loading Loading @@ -11709,7 +11709,7 @@ public class BatteryStatsImpl extends BatteryStats { if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { double uidEstMah = mWifiPowerCalculator.calcPowerFromControllerDataMah( double uidEstMah = mWifiPowerCalculator.calcPowerFromControllerDataMah( scanRxTimeSinceMarkMs, scanTxTimeSinceMarkMs, myIdleTimeMs); scanRxTimeSinceMarkMs, scanTxTimeSinceMarkMs, myIdleTimeMs); addDoubleToUidMap(uidEstimatedConsumptionMah, uid, uidEstMah); uidEstimatedConsumptionMah.add(uid.getUid(), uidEstMah); } } } } Loading @@ -11731,7 +11731,7 @@ public class BatteryStatsImpl extends BatteryStats { uid.getOrCreateWifiControllerActivityLocked().getTxTimeCounters()[0] uid.getOrCreateWifiControllerActivityLocked().getTxTimeCounters()[0] .addCountLocked(myTxTimeMs); .addCountLocked(myTxTimeMs); if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { addDoubleToUidMap(uidEstimatedConsumptionMah, uid, uidEstimatedConsumptionMah.add(uid.getUid(), mWifiPowerCalculator.calcPowerFromControllerDataMah( mWifiPowerCalculator.calcPowerFromControllerDataMah( 0, myTxTimeMs, 0)); 0, myTxTimeMs, 0)); } } Loading @@ -11750,7 +11750,7 @@ public class BatteryStatsImpl extends BatteryStats { uid.getOrCreateWifiControllerActivityLocked().getRxTimeCounter() uid.getOrCreateWifiControllerActivityLocked().getRxTimeCounter() .addCountLocked(myRxTimeMs); .addCountLocked(myRxTimeMs); if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { addDoubleToUidMap(uidEstimatedConsumptionMah, uid, uidEstimatedConsumptionMah.add(uid.getUid(), mWifiPowerCalculator.calcPowerFromControllerDataMah( mWifiPowerCalculator.calcPowerFromControllerDataMah( myRxTimeMs, 0, 0)); myRxTimeMs, 0, 0)); } } Loading Loading @@ -12086,10 +12086,10 @@ public class BatteryStatsImpl extends BatteryStats { Slog.d(TAG, " Idle Time: " + idleTimeMs + " ms"); Slog.d(TAG, " Idle Time: " + idleTimeMs + " ms"); } } final ArrayMap<Uid, Double> uidEstimatedConsumptionMah = final SparseDoubleArray uidEstimatedConsumptionMah = (mGlobalMeasuredEnergyStats != null (mGlobalMeasuredEnergyStats != null && mBluetoothPowerCalculator != null && consumedChargeUC > 0) ? && mBluetoothPowerCalculator != null && consumedChargeUC > 0) ? new ArrayMap<>() : null; new SparseDoubleArray() : null; long totalScanTimeMs = 0; long totalScanTimeMs = 0; Loading Loading @@ -12150,7 +12150,7 @@ public class BatteryStatsImpl extends BatteryStats { counter.getTxTimeCounters()[0].addCountLocked(scanTimeTxSinceMarkMs); counter.getTxTimeCounters()[0].addCountLocked(scanTimeTxSinceMarkMs); if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { addDoubleToUidMap(uidEstimatedConsumptionMah, u, uidEstimatedConsumptionMah.add(u.getUid(), mBluetoothPowerCalculator.calculatePowerMah( mBluetoothPowerCalculator.calculatePowerMah( scanTimeRxSinceMarkMs, scanTimeTxSinceMarkMs, 0)); scanTimeRxSinceMarkMs, scanTimeTxSinceMarkMs, 0)); } } Loading Loading @@ -12217,7 +12217,7 @@ public class BatteryStatsImpl extends BatteryStats { counter.getRxTimeCounter().addCountLocked(timeRxMs); counter.getRxTimeCounter().addCountLocked(timeRxMs); if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { addDoubleToUidMap(uidEstimatedConsumptionMah, u, uidEstimatedConsumptionMah.add(u.getUid(), mBluetoothPowerCalculator.calculatePowerMah(timeRxMs, 0, 0)); mBluetoothPowerCalculator.calculatePowerMah(timeRxMs, 0, 0)); } } } } Loading @@ -12230,7 +12230,7 @@ public class BatteryStatsImpl extends BatteryStats { counter.getTxTimeCounters()[0].addCountLocked(timeTxMs); counter.getTxTimeCounters()[0].addCountLocked(timeTxMs); if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { addDoubleToUidMap(uidEstimatedConsumptionMah, u, uidEstimatedConsumptionMah.add(u.getUid(), mBluetoothPowerCalculator.calculatePowerMah(0, timeTxMs, 0)); mBluetoothPowerCalculator.calculatePowerMah(0, timeTxMs, 0)); } } } } Loading Loading @@ -12452,7 +12452,7 @@ public class BatteryStatsImpl extends BatteryStats { // If multidisplay becomes a reality, this is probably more reasonable than pooling. // If multidisplay becomes a reality, this is probably more reasonable than pooling. // On the first pass, collect total time since mark so that we can normalize power. // On the first pass, collect total time since mark so that we can normalize power. final ArrayMap<Uid, Double> fgTimeUsArray = new ArrayMap<>(); final SparseDoubleArray fgTimeUsArray = new SparseDoubleArray(); final long elapsedRealtimeUs = elapsedRealtimeMs * 1000; final long elapsedRealtimeUs = elapsedRealtimeMs * 1000; // TODO(b/175726779): Update and optimize the algorithm (e.g. avoid iterating over ALL uids) // TODO(b/175726779): Update and optimize the algorithm (e.g. avoid iterating over ALL uids) final int uidStatsSize = mUidStats.size(); final int uidStatsSize = mUidStats.size(); Loading @@ -12460,7 +12460,7 @@ public class BatteryStatsImpl extends BatteryStats { final Uid uid = mUidStats.valueAt(i); final Uid uid = mUidStats.valueAt(i); final long fgTimeUs = uid.markProcessForegroundTimeUs(elapsedRealtimeMs, true); final long fgTimeUs = uid.markProcessForegroundTimeUs(elapsedRealtimeMs, true); if (fgTimeUs == 0) continue; if (fgTimeUs == 0) continue; fgTimeUsArray.put(uid, (double) fgTimeUs); fgTimeUsArray.put(uid.getUid(), (double) fgTimeUs); } } distributeEnergyToUidsLocked(powerBucket, chargeUC, fgTimeUsArray, 0); distributeEnergyToUidsLocked(powerBucket, chargeUC, fgTimeUsArray, 0); } } Loading Loading @@ -12523,10 +12523,11 @@ public class BatteryStatsImpl extends BatteryStats { * <p>A consequence of minRatioDenominator is that the sum over all uids might be less than * <p>A consequence of minRatioDenominator is that the sum over all uids might be less than * totalConsumedChargeUC. This is intentional; the remainder is purposefully unnaccounted rather * totalConsumedChargeUC. This is intentional; the remainder is purposefully unnaccounted rather * than incorrectly blamed on uids, and implies unknown (non-uid) sources of drain. * than incorrectly blamed on uids, and implies unknown (non-uid) sources of drain. * * <p>All uids in ratioNumerators must exist in mUidStats already. */ */ // TODO(b/182845832): Use some sort of "SparseDoubleArray" instead of ArrayMap<Uid, Double>. private void distributeEnergyToUidsLocked(@StandardPowerBucket int bucket, private void distributeEnergyToUidsLocked(@StandardPowerBucket int bucket, long totalConsumedChargeUC, ArrayMap<Uid, Double> ratioNumerators, long totalConsumedChargeUC, SparseDoubleArray ratioNumerators, double minRatioDenominator) { double minRatioDenominator) { // If the sum of all app usage was greater than the total, use that instead: // If the sum of all app usage was greater than the total, use that instead: Loading @@ -12538,7 +12539,7 @@ public class BatteryStatsImpl extends BatteryStats { if (ratioDenominator <= 0) return; if (ratioDenominator <= 0) return; for (int i = ratioNumerators.size() - 1; i >= 0; i--) { for (int i = ratioNumerators.size() - 1; i >= 0; i--) { final Uid uid = ratioNumerators.keyAt(i); final Uid uid = getAvailableUidStatsLocked(ratioNumerators.keyAt(i)); final double ratioNumerator = ratioNumerators.valueAt(i); final double ratioNumerator = ratioNumerators.valueAt(i); final long uidActualUC final long uidActualUC = (long) (totalConsumedChargeUC * ratioNumerator / ratioDenominator + 0.5); = (long) (totalConsumedChargeUC * ratioNumerator / ratioDenominator + 0.5); Loading @@ -12546,15 +12547,79 @@ public class BatteryStatsImpl extends BatteryStats { } } } } /** Adds the summand to the value stored in uidMap for the given uid. */ /** // TODO(b/182845832): Use some sort of "SparseDoubleArray" instead of ArrayMap<Uid, Double>. * SparseDoubleArray map integers to doubles. private static void addDoubleToUidMap(ArrayMap<Uid, Double> uidMap, Uid uid, double summand) { * Its implementation is the same as that of {@link SparseLongArray}; see there for details. if (uidMap == null) return; * final Double oldVal = uidMap.get(uid); * @see SparseLongArray if (oldVal != null) { */ summand += oldVal; private static class SparseDoubleArray { /** * The int->double map, but storing the doubles as longs using * {@link Double.doubleToRawLongBits(double)}. */ private final SparseLongArray mValues = new SparseLongArray(); /** * Gets the double mapped from the specified key, or <code>0</code> * if no such mapping has been made. */ public double get(int key) { if (mValues.indexOfKey(key) >= 0) { return Double.longBitsToDouble(mValues.get(key)); } return 0; } /** * Adds a mapping from the specified key to the specified value, * replacing the previous mapping from the specified key if there * was one. */ public void put(int key, double value) { mValues.put(key, Double.doubleToRawLongBits(value)); } /** * Adds a mapping from the specified key to the specified value, * <b>adding</b> to the previous mapping from the specified key if there * was one. */ public void add(int key, double summand) { final double oldValue = get(key); put(key, oldValue + summand); } /** * Returns the number of key-value mappings that this SparseDoubleArray * currently stores. */ public int size() { return mValues.size(); } } uidMap.put(uid, summand); /** * Given an index in the range <code>0...size()-1</code>, returns * the key from the <code>index</code>th key-value mapping that this * SparseDoubleArray stores. * * @see SparseLongArray#keyAt(int) */ public int keyAt(int index) { return mValues.keyAt(index); } /** * Given an index in the range <code>0...size()-1</code>, returns * the value from the <code>index</code>th key-value mapping that this * SparseDoubleArray stores. * * @see SparseLongArray#valueAt(int) */ public double valueAt(int index) { return Double.longBitsToDouble(mValues.valueAt(index)); } } } /** /** Loading Loading
core/java/com/android/internal/os/BatteryStatsImpl.java +89 −24 Original line number Original line Diff line number Diff line Loading @@ -11492,10 +11492,10 @@ public class BatteryStatsImpl extends BatteryStats { return; return; } } final ArrayMap<Uid, Double> uidEstimatedConsumptionMah = final SparseDoubleArray uidEstimatedConsumptionMah = (mGlobalMeasuredEnergyStats != null (mGlobalMeasuredEnergyStats != null && mWifiPowerCalculator != null && consumedChargeUC > 0) ? && mWifiPowerCalculator != null && consumedChargeUC > 0) ? new ArrayMap<>() : null; new SparseDoubleArray() : null; double totalEstimatedConsumptionMah = 0; double totalEstimatedConsumptionMah = 0; SparseLongArray rxPackets = new SparseLongArray(); SparseLongArray rxPackets = new SparseLongArray(); Loading Loading @@ -11583,7 +11583,7 @@ public class BatteryStatsImpl extends BatteryStats { } } } } addDoubleToUidMap(uidEstimatedConsumptionMah, u, uidEstimatedConsumptionMah.add(u.getUid(), mWifiPowerCalculator.calcPowerWithoutControllerDataMah( mWifiPowerCalculator.calcPowerWithoutControllerDataMah( entry.rxPackets, entry.txPackets, entry.rxPackets, entry.txPackets, uidRunningMs, uidScanMs, uidBatchScanMs)); uidRunningMs, uidScanMs, uidBatchScanMs)); Loading Loading @@ -11709,7 +11709,7 @@ public class BatteryStatsImpl extends BatteryStats { if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { double uidEstMah = mWifiPowerCalculator.calcPowerFromControllerDataMah( double uidEstMah = mWifiPowerCalculator.calcPowerFromControllerDataMah( scanRxTimeSinceMarkMs, scanTxTimeSinceMarkMs, myIdleTimeMs); scanRxTimeSinceMarkMs, scanTxTimeSinceMarkMs, myIdleTimeMs); addDoubleToUidMap(uidEstimatedConsumptionMah, uid, uidEstMah); uidEstimatedConsumptionMah.add(uid.getUid(), uidEstMah); } } } } Loading @@ -11731,7 +11731,7 @@ public class BatteryStatsImpl extends BatteryStats { uid.getOrCreateWifiControllerActivityLocked().getTxTimeCounters()[0] uid.getOrCreateWifiControllerActivityLocked().getTxTimeCounters()[0] .addCountLocked(myTxTimeMs); .addCountLocked(myTxTimeMs); if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { addDoubleToUidMap(uidEstimatedConsumptionMah, uid, uidEstimatedConsumptionMah.add(uid.getUid(), mWifiPowerCalculator.calcPowerFromControllerDataMah( mWifiPowerCalculator.calcPowerFromControllerDataMah( 0, myTxTimeMs, 0)); 0, myTxTimeMs, 0)); } } Loading @@ -11750,7 +11750,7 @@ public class BatteryStatsImpl extends BatteryStats { uid.getOrCreateWifiControllerActivityLocked().getRxTimeCounter() uid.getOrCreateWifiControllerActivityLocked().getRxTimeCounter() .addCountLocked(myRxTimeMs); .addCountLocked(myRxTimeMs); if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { addDoubleToUidMap(uidEstimatedConsumptionMah, uid, uidEstimatedConsumptionMah.add(uid.getUid(), mWifiPowerCalculator.calcPowerFromControllerDataMah( mWifiPowerCalculator.calcPowerFromControllerDataMah( myRxTimeMs, 0, 0)); myRxTimeMs, 0, 0)); } } Loading Loading @@ -12086,10 +12086,10 @@ public class BatteryStatsImpl extends BatteryStats { Slog.d(TAG, " Idle Time: " + idleTimeMs + " ms"); Slog.d(TAG, " Idle Time: " + idleTimeMs + " ms"); } } final ArrayMap<Uid, Double> uidEstimatedConsumptionMah = final SparseDoubleArray uidEstimatedConsumptionMah = (mGlobalMeasuredEnergyStats != null (mGlobalMeasuredEnergyStats != null && mBluetoothPowerCalculator != null && consumedChargeUC > 0) ? && mBluetoothPowerCalculator != null && consumedChargeUC > 0) ? new ArrayMap<>() : null; new SparseDoubleArray() : null; long totalScanTimeMs = 0; long totalScanTimeMs = 0; Loading Loading @@ -12150,7 +12150,7 @@ public class BatteryStatsImpl extends BatteryStats { counter.getTxTimeCounters()[0].addCountLocked(scanTimeTxSinceMarkMs); counter.getTxTimeCounters()[0].addCountLocked(scanTimeTxSinceMarkMs); if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { addDoubleToUidMap(uidEstimatedConsumptionMah, u, uidEstimatedConsumptionMah.add(u.getUid(), mBluetoothPowerCalculator.calculatePowerMah( mBluetoothPowerCalculator.calculatePowerMah( scanTimeRxSinceMarkMs, scanTimeTxSinceMarkMs, 0)); scanTimeRxSinceMarkMs, scanTimeTxSinceMarkMs, 0)); } } Loading Loading @@ -12217,7 +12217,7 @@ public class BatteryStatsImpl extends BatteryStats { counter.getRxTimeCounter().addCountLocked(timeRxMs); counter.getRxTimeCounter().addCountLocked(timeRxMs); if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { addDoubleToUidMap(uidEstimatedConsumptionMah, u, uidEstimatedConsumptionMah.add(u.getUid(), mBluetoothPowerCalculator.calculatePowerMah(timeRxMs, 0, 0)); mBluetoothPowerCalculator.calculatePowerMah(timeRxMs, 0, 0)); } } } } Loading @@ -12230,7 +12230,7 @@ public class BatteryStatsImpl extends BatteryStats { counter.getTxTimeCounters()[0].addCountLocked(timeTxMs); counter.getTxTimeCounters()[0].addCountLocked(timeTxMs); if (uidEstimatedConsumptionMah != null) { if (uidEstimatedConsumptionMah != null) { addDoubleToUidMap(uidEstimatedConsumptionMah, u, uidEstimatedConsumptionMah.add(u.getUid(), mBluetoothPowerCalculator.calculatePowerMah(0, timeTxMs, 0)); mBluetoothPowerCalculator.calculatePowerMah(0, timeTxMs, 0)); } } } } Loading Loading @@ -12452,7 +12452,7 @@ public class BatteryStatsImpl extends BatteryStats { // If multidisplay becomes a reality, this is probably more reasonable than pooling. // If multidisplay becomes a reality, this is probably more reasonable than pooling. // On the first pass, collect total time since mark so that we can normalize power. // On the first pass, collect total time since mark so that we can normalize power. final ArrayMap<Uid, Double> fgTimeUsArray = new ArrayMap<>(); final SparseDoubleArray fgTimeUsArray = new SparseDoubleArray(); final long elapsedRealtimeUs = elapsedRealtimeMs * 1000; final long elapsedRealtimeUs = elapsedRealtimeMs * 1000; // TODO(b/175726779): Update and optimize the algorithm (e.g. avoid iterating over ALL uids) // TODO(b/175726779): Update and optimize the algorithm (e.g. avoid iterating over ALL uids) final int uidStatsSize = mUidStats.size(); final int uidStatsSize = mUidStats.size(); Loading @@ -12460,7 +12460,7 @@ public class BatteryStatsImpl extends BatteryStats { final Uid uid = mUidStats.valueAt(i); final Uid uid = mUidStats.valueAt(i); final long fgTimeUs = uid.markProcessForegroundTimeUs(elapsedRealtimeMs, true); final long fgTimeUs = uid.markProcessForegroundTimeUs(elapsedRealtimeMs, true); if (fgTimeUs == 0) continue; if (fgTimeUs == 0) continue; fgTimeUsArray.put(uid, (double) fgTimeUs); fgTimeUsArray.put(uid.getUid(), (double) fgTimeUs); } } distributeEnergyToUidsLocked(powerBucket, chargeUC, fgTimeUsArray, 0); distributeEnergyToUidsLocked(powerBucket, chargeUC, fgTimeUsArray, 0); } } Loading Loading @@ -12523,10 +12523,11 @@ public class BatteryStatsImpl extends BatteryStats { * <p>A consequence of minRatioDenominator is that the sum over all uids might be less than * <p>A consequence of minRatioDenominator is that the sum over all uids might be less than * totalConsumedChargeUC. This is intentional; the remainder is purposefully unnaccounted rather * totalConsumedChargeUC. This is intentional; the remainder is purposefully unnaccounted rather * than incorrectly blamed on uids, and implies unknown (non-uid) sources of drain. * than incorrectly blamed on uids, and implies unknown (non-uid) sources of drain. * * <p>All uids in ratioNumerators must exist in mUidStats already. */ */ // TODO(b/182845832): Use some sort of "SparseDoubleArray" instead of ArrayMap<Uid, Double>. private void distributeEnergyToUidsLocked(@StandardPowerBucket int bucket, private void distributeEnergyToUidsLocked(@StandardPowerBucket int bucket, long totalConsumedChargeUC, ArrayMap<Uid, Double> ratioNumerators, long totalConsumedChargeUC, SparseDoubleArray ratioNumerators, double minRatioDenominator) { double minRatioDenominator) { // If the sum of all app usage was greater than the total, use that instead: // If the sum of all app usage was greater than the total, use that instead: Loading @@ -12538,7 +12539,7 @@ public class BatteryStatsImpl extends BatteryStats { if (ratioDenominator <= 0) return; if (ratioDenominator <= 0) return; for (int i = ratioNumerators.size() - 1; i >= 0; i--) { for (int i = ratioNumerators.size() - 1; i >= 0; i--) { final Uid uid = ratioNumerators.keyAt(i); final Uid uid = getAvailableUidStatsLocked(ratioNumerators.keyAt(i)); final double ratioNumerator = ratioNumerators.valueAt(i); final double ratioNumerator = ratioNumerators.valueAt(i); final long uidActualUC final long uidActualUC = (long) (totalConsumedChargeUC * ratioNumerator / ratioDenominator + 0.5); = (long) (totalConsumedChargeUC * ratioNumerator / ratioDenominator + 0.5); Loading @@ -12546,15 +12547,79 @@ public class BatteryStatsImpl extends BatteryStats { } } } } /** Adds the summand to the value stored in uidMap for the given uid. */ /** // TODO(b/182845832): Use some sort of "SparseDoubleArray" instead of ArrayMap<Uid, Double>. * SparseDoubleArray map integers to doubles. private static void addDoubleToUidMap(ArrayMap<Uid, Double> uidMap, Uid uid, double summand) { * Its implementation is the same as that of {@link SparseLongArray}; see there for details. if (uidMap == null) return; * final Double oldVal = uidMap.get(uid); * @see SparseLongArray if (oldVal != null) { */ summand += oldVal; private static class SparseDoubleArray { /** * The int->double map, but storing the doubles as longs using * {@link Double.doubleToRawLongBits(double)}. */ private final SparseLongArray mValues = new SparseLongArray(); /** * Gets the double mapped from the specified key, or <code>0</code> * if no such mapping has been made. */ public double get(int key) { if (mValues.indexOfKey(key) >= 0) { return Double.longBitsToDouble(mValues.get(key)); } return 0; } /** * Adds a mapping from the specified key to the specified value, * replacing the previous mapping from the specified key if there * was one. */ public void put(int key, double value) { mValues.put(key, Double.doubleToRawLongBits(value)); } /** * Adds a mapping from the specified key to the specified value, * <b>adding</b> to the previous mapping from the specified key if there * was one. */ public void add(int key, double summand) { final double oldValue = get(key); put(key, oldValue + summand); } /** * Returns the number of key-value mappings that this SparseDoubleArray * currently stores. */ public int size() { return mValues.size(); } } uidMap.put(uid, summand); /** * Given an index in the range <code>0...size()-1</code>, returns * the key from the <code>index</code>th key-value mapping that this * SparseDoubleArray stores. * * @see SparseLongArray#keyAt(int) */ public int keyAt(int index) { return mValues.keyAt(index); } /** * Given an index in the range <code>0...size()-1</code>, returns * the value from the <code>index</code>th key-value mapping that this * SparseDoubleArray stores. * * @see SparseLongArray#valueAt(int) */ public double valueAt(int index) { return Double.longBitsToDouble(mValues.valueAt(index)); } } } /** /** Loading