1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.telephony;
18 
19 import android.annotation.DurationMillisLong;
20 import android.annotation.ElapsedRealtimeLong;
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.SystemApi;
24 import android.annotation.TestApi;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.os.SystemClock;
28 import android.telephony.ServiceState.FrequencyRange;
29 import android.util.Range;
30 
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 import java.util.Arrays;
34 import java.util.Objects;
35 
36 /**
37  * Contains information about the modem's activity. May be useful for power stats reporting.
38  * @hide
39  */
40 @SystemApi
41 public final class ModemActivityInfo implements Parcelable {
42     private static final int TX_POWER_LEVELS = 5;
43 
44     /**
45      * Corresponds to transmit power of less than 0dBm.
46      */
47     public static final int TX_POWER_LEVEL_0 = 0;
48 
49     /**
50      * Corresponds to transmit power between 0dBm and 5dBm.
51      */
52     public static final int TX_POWER_LEVEL_1 = 1;
53 
54     /**
55      * Corresponds to transmit power between 5dBm and 15dBm.
56      */
57     public static final int TX_POWER_LEVEL_2 = 2;
58 
59     /**
60      * Corresponds to transmit power between 15dBm and 20dBm.
61      */
62     public static final int TX_POWER_LEVEL_3 = 3;
63 
64     /**
65      * Corresponds to transmit power above 20dBm.
66      */
67     public static final int TX_POWER_LEVEL_4 = 4;
68 
69     /**
70      * The number of transmit power levels. Fixed by HAL definition.
71      */
getNumTxPowerLevels()72     public static int getNumTxPowerLevels() {
73         return TX_POWER_LEVELS;
74     }
75 
76     /** @hide */
77     @IntDef(prefix = {"TX_POWER_LEVEL_"}, value = {
78             TX_POWER_LEVEL_0,
79             TX_POWER_LEVEL_1,
80             TX_POWER_LEVEL_2,
81             TX_POWER_LEVEL_3,
82             TX_POWER_LEVEL_4,
83     })
84     @Retention(RetentionPolicy.SOURCE)
85     public @interface TxPowerLevel {}
86 
87     private static final Range<Integer>[] TX_POWER_RANGES = new Range[] {
88         new Range<>(Integer.MIN_VALUE, 0),
89         new Range<>(0, 5),
90         new Range<>(5, 15),
91         new Range<>(15, 20),
92         new Range<>(20, Integer.MAX_VALUE)
93     };
94 
95     private long mTimestamp;
96     private int mSleepTimeMs;
97     private int mIdleTimeMs;
98     private int[] mTotalTxTimeMs;
99     private int mTotalRxTimeMs;
100     private int mSizeOfSpecificInfo;
101     private ActivityStatsTechSpecificInfo[] mActivityStatsTechSpecificInfo;
102 
103     /**
104      * @hide
105      */
106     @TestApi
ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs, @NonNull int[] txTimeMs, int rxTimeMs)107     public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs,
108                         @NonNull int[] txTimeMs, int rxTimeMs) {
109         Objects.requireNonNull(txTimeMs);
110         if (txTimeMs.length != TX_POWER_LEVELS) {
111             throw new IllegalArgumentException("txTimeMs must have length == TX_POWER_LEVELS");
112         }
113         mTimestamp = timestamp;
114         mSleepTimeMs = sleepTimeMs;
115         mIdleTimeMs = idleTimeMs;
116         mTotalTxTimeMs = txTimeMs;
117         mTotalRxTimeMs = rxTimeMs;
118 
119         mActivityStatsTechSpecificInfo = new ActivityStatsTechSpecificInfo[1];
120         mSizeOfSpecificInfo = mActivityStatsTechSpecificInfo.length;
121         mActivityStatsTechSpecificInfo[0] =
122                 new ActivityStatsTechSpecificInfo(
123                         AccessNetworkConstants.AccessNetworkType.UNKNOWN,
124                         ServiceState.FREQUENCY_RANGE_UNKNOWN,
125                         txTimeMs,
126                         rxTimeMs);
127     }
128 
129     /**
130      * Provided for convenience in manipulation since the API exposes long values but internal
131      * representations are ints.
132      * @hide
133      */
ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs, @NonNull int[] txTimeMs, long rxTimeMs)134     public ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs,
135             @NonNull int[] txTimeMs, long rxTimeMs) {
136         this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, txTimeMs, (int) rxTimeMs);
137     }
138 
139     /** @hide */
ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs, @NonNull ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo)140     public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs,
141                         @NonNull ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo) {
142         mTimestamp = timestamp;
143         mSleepTimeMs = sleepTimeMs;
144         mIdleTimeMs = idleTimeMs;
145         mActivityStatsTechSpecificInfo = activityStatsTechSpecificInfo;
146         mSizeOfSpecificInfo = mActivityStatsTechSpecificInfo.length;
147         mTotalTxTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
148         for (int i = 0; i < getNumTxPowerLevels(); i++) {
149             for (int j = 0; j < getSpecificInfoLength(); j++) {
150                 mTotalTxTimeMs[i] = mTotalTxTimeMs[i]
151                             + (int) mActivityStatsTechSpecificInfo[j].getTransmitTimeMillis(i);
152             }
153         }
154         mTotalRxTimeMs = 0;
155         for (int i = 0; i < getSpecificInfoLength(); i++) {
156             mTotalRxTimeMs =
157                     mTotalRxTimeMs + (int) mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
158         }
159     }
160 
161     /**
162      * Provided for convenience in manipulation since the API exposes long values but internal
163      * representations are ints.
164      * @hide
165      */
ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs, @NonNull ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo)166     public ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs,
167                         @NonNull ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo) {
168         this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, activityStatsTechSpecificInfo);
169     }
170 
171     @Override
toString()172     public String toString() {
173         return "ModemActivityInfo{"
174             + " mTimestamp="
175             + mTimestamp
176             + " mSleepTimeMs="
177             + mSleepTimeMs
178             + " mIdleTimeMs="
179             + mIdleTimeMs
180             + " mActivityStatsTechSpecificInfo="
181             + Arrays.toString(mActivityStatsTechSpecificInfo)
182             + "}";
183     }
184 
describeContents()185     public int describeContents() {
186         return 0;
187     }
188 
189     public static final @android.annotation.NonNull Parcelable.Creator<ModemActivityInfo> CREATOR =
190             new Parcelable.Creator<ModemActivityInfo>() {
191         public ModemActivityInfo createFromParcel(@NonNull Parcel in) {
192             long timestamp = in.readLong();
193             int sleepTimeMs = in.readInt();
194             int idleTimeMs = in.readInt();
195             Parcelable[] tempSpecifiers =
196                     in.createTypedArray(ActivityStatsTechSpecificInfo.CREATOR);
197             ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo;
198             activityStatsTechSpecificInfo =
199                     new ActivityStatsTechSpecificInfo[tempSpecifiers.length];
200             for (int i = 0; i < tempSpecifiers.length; i++) {
201                 activityStatsTechSpecificInfo[i] =
202                                 (ActivityStatsTechSpecificInfo) tempSpecifiers[i];
203                     }
204             return new ModemActivityInfo(
205                     timestamp, sleepTimeMs, idleTimeMs, activityStatsTechSpecificInfo);
206         }
207 
208         public ModemActivityInfo[] newArray(int size) {
209             return new ModemActivityInfo[size];
210         }
211     };
212 
213     /**
214      * @param dest The Parcel in which the object should be written.
215      * @param flags Additional flags about how the object should be written.
216      */
writeToParcel(@onNull Parcel dest, int flags)217     public void writeToParcel(@NonNull Parcel dest, int flags) {
218         dest.writeLong(mTimestamp);
219         dest.writeInt(mSleepTimeMs);
220         dest.writeInt(mIdleTimeMs);
221         dest.writeTypedArray(mActivityStatsTechSpecificInfo, flags);
222     }
223 
224     /**
225      * Gets the timestamp at which this modem activity info was recorded.
226      *
227      * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this {@link
228      *     ModemActivityInfo} was recorded.
229      */
getTimestampMillis()230     public @ElapsedRealtimeLong long getTimestampMillis() {
231         return mTimestamp;
232     }
233 
234     /** @hide */
setTimestamp(long timestamp)235     public void setTimestamp(long timestamp) {
236         mTimestamp = timestamp;
237     }
238 
239     /**
240      * Gets the amount of time the modem spent transmitting at a certain power level.
241      *
242      * @param powerLevel The power level to query.
243      * @return The amount of time, in milliseconds, that the modem spent transmitting at the given
244      *     power level.
245      */
getTransmitDurationMillisAtPowerLevel( @xPowerLevel int powerLevel)246     public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
247             @TxPowerLevel int powerLevel) {
248         long txTimeMsAtPowerLevel = 0;
249         for (int i = 0; i < getSpecificInfoLength(); i++) {
250             txTimeMsAtPowerLevel +=
251                     mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
252         }
253         return txTimeMsAtPowerLevel;
254     }
255 
256     /** @hide */
getTransmitDurationMillisAtPowerLevel( @xPowerLevel int powerLevel, int rat)257     public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
258             @TxPowerLevel int powerLevel, int rat) {
259         for (int i = 0; i < getSpecificInfoLength(); i++) {
260             if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
261                 return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
262             }
263         }
264         return 0;
265     }
266 
267     /** @hide */
getTransmitDurationMillisAtPowerLevel( @xPowerLevel int powerLevel, int rat, @FrequencyRange int freq)268     public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
269             @TxPowerLevel int powerLevel, int rat, @FrequencyRange int freq) {
270         for (int i = 0; i < getSpecificInfoLength(); i++) {
271             if (mActivityStatsTechSpecificInfo[i].getRat() == rat
272                     && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
273                 return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
274             }
275         }
276         return 0;
277     }
278     /**
279      * Gets the range of transmit powers corresponding to a certain power level.
280      *
281      * @param powerLevel The power level to query
282      * @return A {@link Range} object representing the range of intensities (in dBm) to which this
283      * power level corresponds.
284      */
getTransmitPowerRange(@xPowerLevel int powerLevel)285     public @NonNull Range<Integer> getTransmitPowerRange(@TxPowerLevel int powerLevel) {
286         return TX_POWER_RANGES[powerLevel];
287     }
288 
289     /** @hide */
getSpecificInfoRat(int index)290     public int getSpecificInfoRat(int index) {
291         return mActivityStatsTechSpecificInfo[index].getRat();
292     }
293 
294     /** @hide */
getSpecificInfoFrequencyRange(int index)295     public int getSpecificInfoFrequencyRange(int index) {
296         return mActivityStatsTechSpecificInfo[index].getFrequencyRange();
297     }
298     /** @hide */
setTransmitTimeMillis(int[] txTimeMs)299     public void setTransmitTimeMillis(int[] txTimeMs) {
300         mTotalTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
301     }
302     /** @hide */
setTransmitTimeMillis(int rat, int[] txTimeMs)303     public void setTransmitTimeMillis(int rat, int[] txTimeMs) {
304         for (int i = 0; i < getSpecificInfoLength(); i++) {
305             if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
306                 mActivityStatsTechSpecificInfo[i].setTransmitTimeMillis(txTimeMs);
307             }
308         }
309     }
310     /** @hide */
setTransmitTimeMillis(int rat, int freq, int[] txTimeMs)311     public void setTransmitTimeMillis(int rat, int freq, int[] txTimeMs) {
312         for (int i = 0; i < getSpecificInfoLength(); i++) {
313             if (mActivityStatsTechSpecificInfo[i].getRat() == rat
314                     && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
315                 mActivityStatsTechSpecificInfo[i].setTransmitTimeMillis(txTimeMs);
316             }
317         }
318     }
319     /**
320      * @return The raw array of transmit power durations
321      * @hide
322      */
323     @NonNull
getTransmitTimeMillis()324     public int[] getTransmitTimeMillis() {
325         return mTotalTxTimeMs;
326     }
327 
328     /** @hide */
getTransmitTimeMillis(@ccessNetworkConstants.RadioAccessNetworkType int rat)329     public int[] getTransmitTimeMillis(@AccessNetworkConstants.RadioAccessNetworkType int rat) {
330         for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
331             if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
332                 return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis();
333             }
334         }
335         return new int[5];
336     }
337 
338     /** @hide */
getTransmitTimeMillis( @ccessNetworkConstants.RadioAccessNetworkType int rat, @FrequencyRange int freq)339     public int[] getTransmitTimeMillis(
340             @AccessNetworkConstants.RadioAccessNetworkType int rat, @FrequencyRange int freq) {
341         for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
342             if (mActivityStatsTechSpecificInfo[i].getRat() == rat
343                     && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
344                 return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis();
345             }
346         }
347         return new int[5];
348     }
349 
350     /**
351      * Gets the amount of time (in milliseconds) when the modem is in a low power or sleep state.
352      *
353      * @return Time in milliseconds.
354      */
getSleepTimeMillis()355     public @DurationMillisLong long getSleepTimeMillis() {
356         return mSleepTimeMs;
357     }
358 
359     /** @hide */
setSleepTimeMillis(int sleepTimeMillis)360     public void setSleepTimeMillis(int sleepTimeMillis) {
361         mSleepTimeMs = sleepTimeMillis;
362     }
363 
364     /**
365      * Provided for convenience, since the API surface needs to return longs but internal
366      * representations are ints.
367      *
368      * @hide
369      */
setSleepTimeMillis(long sleepTimeMillis)370     public void setSleepTimeMillis(long sleepTimeMillis) {
371         mSleepTimeMs = (int) sleepTimeMillis;
372     }
373 
374     /**
375      * Computes the difference between this instance of {@link ModemActivityInfo} and another
376      * instance.
377      *
378      * This method should be used to compute the amount of activity that has happened between two
379      * samples of modem activity taken at separate times. The sample passed in as an argument to
380      * this method should be the one that's taken later in time (and therefore has more activity).
381      * @param other The other instance of {@link ModemActivityInfo} to diff against.
382      * @return An instance of {@link ModemActivityInfo} representing the difference in modem
383      * activity.
384      */
getDelta(@onNull ModemActivityInfo other)385     public @NonNull ModemActivityInfo getDelta(@NonNull ModemActivityInfo other) {
386         ActivityStatsTechSpecificInfo[] mDeltaSpecificInfo;
387         mDeltaSpecificInfo = new ActivityStatsTechSpecificInfo[other.getSpecificInfoLength()];
388 
389         boolean matched;
390         for (int i = 0; i < other.getSpecificInfoLength(); i++) {
391             matched = false;
392             for (int j = 0; j < getSpecificInfoLength(); j++) {
393                 int rat = mActivityStatsTechSpecificInfo[j].getRat();
394                 if (rat == other.mActivityStatsTechSpecificInfo[i].getRat() && !matched) {
395                     if (mActivityStatsTechSpecificInfo[j].getRat()
396                             == AccessNetworkConstants.AccessNetworkType.NGRAN) {
397                         if (other.mActivityStatsTechSpecificInfo[i].getFrequencyRange()
398                                 == mActivityStatsTechSpecificInfo[j].getFrequencyRange()) {
399                             int freq = mActivityStatsTechSpecificInfo[j].getFrequencyRange();
400                             int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
401                             for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
402                                 txTimeMs[lvl] =
403                                         (int) (other.getTransmitDurationMillisAtPowerLevel(
404                                                             lvl, rat, freq)
405                                                         - getTransmitDurationMillisAtPowerLevel(
406                                                             lvl, rat, freq));
407                             }
408                             matched = true;
409                             mDeltaSpecificInfo[i] =
410                                     new ActivityStatsTechSpecificInfo(
411                                             rat,
412                                             freq,
413                                             txTimeMs,
414                                             (int) (other.getReceiveTimeMillis(rat, freq)
415                                                         - getReceiveTimeMillis(rat, freq)));
416                         }
417                     } else {
418                         int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
419                         for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
420                             txTimeMs[lvl] =
421                                     (int) (other.getTransmitDurationMillisAtPowerLevel(lvl, rat)
422                                                 - getTransmitDurationMillisAtPowerLevel(lvl, rat));
423                         }
424                         matched = true;
425                         mDeltaSpecificInfo[i] =
426                                 new ActivityStatsTechSpecificInfo(
427                                         rat,
428                                         ServiceState.FREQUENCY_RANGE_UNKNOWN,
429                                         txTimeMs,
430                                         (int) (other.getReceiveTimeMillis(rat)
431                                                      - getReceiveTimeMillis(rat)));
432                     }
433                 }
434             }
435             if (!matched) {
436                 mDeltaSpecificInfo[i] = other.mActivityStatsTechSpecificInfo[i];
437             }
438         }
439         return new ModemActivityInfo(
440                 other.getTimestampMillis(),
441                 other.getSleepTimeMillis() - getSleepTimeMillis(),
442                 other.getIdleTimeMillis() - getIdleTimeMillis(),
443                 mDeltaSpecificInfo);
444     }
445 
446     /**
447      * Gets the amount of time (in milliseconds) when the modem is awake but neither transmitting
448      * nor receiving.
449      *
450      * @return Time in milliseconds.
451      */
getIdleTimeMillis()452     public @DurationMillisLong long getIdleTimeMillis() {
453         return mIdleTimeMs;
454     }
455 
456     /** @hide */
setIdleTimeMillis(int idleTimeMillis)457     public void setIdleTimeMillis(int idleTimeMillis) {
458         mIdleTimeMs = idleTimeMillis;
459     }
460 
461     /**
462      * Provided for convenience, since the API surface needs to return longs but internal
463      * representations are ints.
464      *
465      * @hide
466      */
setIdleTimeMillis(long idleTimeMillis)467     public void setIdleTimeMillis(long idleTimeMillis) {
468         mIdleTimeMs = (int) idleTimeMillis;
469     }
470 
471     /**
472      * Gets the amount of time (in milliseconds) when the modem is awake and receiving data.
473      *
474      * @return Time in milliseconds.
475      */
getReceiveTimeMillis()476     public @DurationMillisLong long getReceiveTimeMillis() {
477         return mTotalRxTimeMs;
478     }
479 
480     /** @hide */
getReceiveTimeMillis(int rat)481     public @DurationMillisLong long getReceiveTimeMillis(int rat) {
482         for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
483             if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
484                 return mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
485             }
486         }
487         return 0;
488     }
489     /** @hide */
getReceiveTimeMillis(int rat, int freq)490     public @DurationMillisLong long getReceiveTimeMillis(int rat, int freq) {
491         for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
492             if (mActivityStatsTechSpecificInfo[i].getRat() == rat
493                     && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
494                 return mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
495             }
496         }
497         return 0;
498     }
499 
500     /** @hide */
setReceiveTimeMillis(int rxTimeMillis)501     public void setReceiveTimeMillis(int rxTimeMillis) {
502         mTotalRxTimeMs = rxTimeMillis;
503     }
504 
505     /**
506      * Provided for convenience, since the API surface needs to return longs but internal
507      * representations are ints.
508      *
509      * @hide
510      */
setReceiveTimeMillis(long receiveTimeMillis)511     public void setReceiveTimeMillis(long receiveTimeMillis) {
512         mTotalRxTimeMs = (int) receiveTimeMillis;
513     }
514 
515     /** @hide */
setReceiveTimeMillis(int rat, long receiveTimeMillis)516     public void setReceiveTimeMillis(int rat, long receiveTimeMillis) {
517         for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
518             if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
519                 mActivityStatsTechSpecificInfo[i].setReceiveTimeMillis(receiveTimeMillis);
520             }
521         }
522     }
523 
524     /** @hide */
setReceiveTimeMillis(int rat, int freq, long receiveTimeMillis)525     public void setReceiveTimeMillis(int rat, int freq, long receiveTimeMillis) {
526         for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
527             if (mActivityStatsTechSpecificInfo[i].getRat() == rat
528                     && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
529                 mActivityStatsTechSpecificInfo[i].setReceiveTimeMillis(receiveTimeMillis);
530             }
531         }
532     }
533 
534     /** @hide */
getSpecificInfoLength()535     public int getSpecificInfoLength() {
536         return mSizeOfSpecificInfo;
537     }
538 
539     /**
540      * Indicates if the modem has reported valid {@link ModemActivityInfo}.
541      *
542      * @return {@code true} if this {@link ModemActivityInfo} record is valid,
543      * {@code false} otherwise.
544      * @hide
545      */
546     @TestApi
isValid()547     public boolean isValid() {
548         if (mActivityStatsTechSpecificInfo == null) {
549             return false;
550         } else {
551             boolean isTxPowerValid = true;
552             boolean isRxPowerValid = true;
553             for (int i = 0; i < getSpecificInfoLength(); i++) {
554                 if (!mActivityStatsTechSpecificInfo[i].isTxPowerValid()) {
555                     isTxPowerValid = false;
556                 }
557                 if (!mActivityStatsTechSpecificInfo[i].isRxPowerValid()) {
558                     isRxPowerValid = false;
559                 }
560             }
561             return isTxPowerValid
562                     && isRxPowerValid
563                     && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0) && !isEmpty());
564         }
565     }
566 
567     /** @hide */
568     @TestApi
isEmpty()569     public boolean isEmpty() {
570         boolean isTxPowerEmpty = true;
571         boolean isRxPowerEmpty = true;
572         for (int i = 0; i < getSpecificInfoLength(); i++) {
573             if (!mActivityStatsTechSpecificInfo[i].isTxPowerEmpty()) {
574                 isTxPowerEmpty = false;
575             }
576             if (!mActivityStatsTechSpecificInfo[i].isRxPowerEmpty()) {
577                 isRxPowerEmpty = false;
578             }
579         }
580         return isTxPowerEmpty
581                 && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0) && isRxPowerEmpty);
582     }
583 
584     @Override
equals(Object o)585     public boolean equals(Object o) {
586         if (this == o) return true;
587         if (o == null || getClass() != o.getClass()) return false;
588         ModemActivityInfo that = (ModemActivityInfo) o;
589         return mTimestamp == that.mTimestamp
590                 && mSleepTimeMs == that.mSleepTimeMs
591                 && mIdleTimeMs == that.mIdleTimeMs
592                 && mSizeOfSpecificInfo == that.mSizeOfSpecificInfo
593                 && Arrays.equals(
594                         mActivityStatsTechSpecificInfo, that.mActivityStatsTechSpecificInfo);
595     }
596 
597     @Override
hashCode()598     public int hashCode() {
599         int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mTotalRxTimeMs);
600         result = 31 * result + Arrays.hashCode(mTotalTxTimeMs);
601         return result;
602     }
603 }
604