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.NonNull;
20 import android.annotation.SystemApi;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.os.SystemClock;
24 import android.util.Range;
25 
26 import java.util.ArrayList;
27 import java.util.List;
28 
29 /**
30  * Reports modem activity information.
31  * @hide
32  */
33 @SystemApi
34 public final class ModemActivityInfo implements Parcelable {
35     /**
36      * Tx(transmit) power level. see power index below
37      * <ul>
38      *   <li> index 0 = tx_power < 0dBm. </li>
39      *   <li> index 1 = 0dBm < tx_power < 5dBm. </li>
40      *   <li> index 2 = 5dBm < tx_power < 15dBm. </li>
41      *   <li> index 3 = 15dBm < tx_power < 20dBm. </li>
42      *   <li> index 4 = tx_power > 20dBm. </li>
43      * </ul>
44      */
45     public static final int TX_POWER_LEVELS = 5;
46     private static final Range<Integer>[] TX_POWER_RANGES = new Range[] {
47         new Range<>(Integer.MIN_VALUE, 0),
48         new Range<>(0, 5),
49         new Range<>(5, 15),
50         new Range<>(15, 20),
51         new Range<>(20, Integer.MAX_VALUE)
52 
53     };
54 
55     private long mTimestamp;
56     private int mSleepTimeMs;
57     private int mIdleTimeMs;
58     private List<TransmitPower> mTransmitPowerInfo = new ArrayList<>(TX_POWER_LEVELS);
59     private int mRxTimeMs;
60 
ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs, @NonNull int[] txTimeMs, int rxTimeMs)61     public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs,
62                         @NonNull int[] txTimeMs, int rxTimeMs) {
63         mTimestamp = timestamp;
64         mSleepTimeMs = sleepTimeMs;
65         mIdleTimeMs = idleTimeMs;
66         populateTransmitPowerRange(txTimeMs);
67         mRxTimeMs = rxTimeMs;
68     }
69 
70     /** helper API to populate tx power range for each bucket **/
populateTransmitPowerRange(@onNull int[] transmitPowerMs)71     private void populateTransmitPowerRange(@NonNull int[] transmitPowerMs) {
72         int i = 0;
73         for ( ; i < Math.min(transmitPowerMs.length, TX_POWER_LEVELS); i++) {
74             mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], transmitPowerMs[i]));
75         }
76         // Make sure that mTransmitPowerInfo is fully initialized.
77         for ( ; i < TX_POWER_LEVELS; i++) {
78             mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], 0));
79         }
80     }
81 
82     @Override
toString()83     public String toString() {
84         return "ModemActivityInfo{"
85             + " mTimestamp=" + mTimestamp
86             + " mSleepTimeMs=" + mSleepTimeMs
87             + " mIdleTimeMs=" + mIdleTimeMs
88             + " mTransmitPowerInfo[]=" + mTransmitPowerInfo.toString()
89             + " mRxTimeMs=" + mRxTimeMs
90             + "}";
91     }
92 
describeContents()93     public int describeContents() {
94         return 0;
95     }
96 
97     public static final @android.annotation.NonNull Parcelable.Creator<ModemActivityInfo> CREATOR =
98             new Parcelable.Creator<ModemActivityInfo>() {
99         public ModemActivityInfo createFromParcel(Parcel in) {
100             long timestamp = in.readLong();
101             int sleepTimeMs = in.readInt();
102             int idleTimeMs = in.readInt();
103             int[] txTimeMs = new int[TX_POWER_LEVELS];
104             for (int i = 0; i < TX_POWER_LEVELS; i++) {
105                 txTimeMs[i] = in.readInt();
106             }
107             int rxTimeMs = in.readInt();
108             return new ModemActivityInfo(timestamp, sleepTimeMs, idleTimeMs,
109                                 txTimeMs, rxTimeMs);
110         }
111 
112         public ModemActivityInfo[] newArray(int size) {
113             return new ModemActivityInfo[size];
114         }
115     };
116 
writeToParcel(@onNull Parcel dest, int flags)117     public void writeToParcel(@NonNull Parcel dest, int flags) {
118         dest.writeLong(mTimestamp);
119         dest.writeInt(mSleepTimeMs);
120         dest.writeInt(mIdleTimeMs);
121         for (int i = 0; i < TX_POWER_LEVELS; i++) {
122             dest.writeInt(mTransmitPowerInfo.get(i).getTimeInMillis());
123         }
124         dest.writeInt(mRxTimeMs);
125     }
126 
127     /**
128      * @return milliseconds since boot, including mTimeInMillis spent in sleep.
129      * @see SystemClock#elapsedRealtime()
130      */
getTimestamp()131     public long getTimestamp() {
132         return mTimestamp;
133     }
134 
135     /** @hide */
setTimestamp(long timestamp)136     public void setTimestamp(long timestamp) {
137         mTimestamp = timestamp;
138     }
139 
140     /**
141      * @return an arrayList of {@link TransmitPower} with each element representing the total time where
142      * transmitter is awake time (in ms) for a given power range (in dbm).
143      *
144      * @see #TX_POWER_LEVELS
145      */
146     @NonNull
getTransmitPowerInfo()147     public List<TransmitPower> getTransmitPowerInfo() {
148         return mTransmitPowerInfo;
149     }
150 
151     /** @hide */
setTransmitTimeMillis(int[] txTimeMs)152     public void setTransmitTimeMillis(int[] txTimeMs) {
153         populateTransmitPowerRange(txTimeMs);
154     }
155 
156     /** @hide */
157     @NonNull
getTransmitTimeMillis()158     public int[] getTransmitTimeMillis() {
159         int[] transmitTimeMillis = new int[TX_POWER_LEVELS];
160         for (int i = 0; i < transmitTimeMillis.length; i++) {
161             transmitTimeMillis[i] = mTransmitPowerInfo.get(i).getTimeInMillis();
162         }
163         return transmitTimeMillis;
164     }
165 
166     /**
167      * @return total mTimeInMillis (in ms) when modem is in a low power or sleep state.
168      */
getSleepTimeMillis()169     public int getSleepTimeMillis() {
170         return mSleepTimeMs;
171     }
172 
173     /** @hide */
setSleepTimeMillis(int sleepTimeMillis)174     public void setSleepTimeMillis(int sleepTimeMillis) {
175         mSleepTimeMs = sleepTimeMillis;
176     }
177 
178     /**
179      * @return total mTimeInMillis (in ms) when modem is awake but neither the transmitter nor receiver are
180      * active.
181      */
getIdleTimeMillis()182     public int getIdleTimeMillis() {
183         return mIdleTimeMs;
184     }
185 
186     /** @hide */
setIdleTimeMillis(int idleTimeMillis)187     public void setIdleTimeMillis(int idleTimeMillis) {
188         mIdleTimeMs = idleTimeMillis;
189     }
190 
191     /**
192      * @return rx(receive) mTimeInMillis in ms.
193      */
getReceiveTimeMillis()194     public int getReceiveTimeMillis() {
195         return mRxTimeMs;
196     }
197 
198     /** @hide */
setReceiveTimeMillis(int rxTimeMillis)199     public void setReceiveTimeMillis(int rxTimeMillis) {
200         mRxTimeMs = rxTimeMillis;
201     }
202 
203     /**
204      * Indicates if the modem has reported valid {@link ModemActivityInfo}.
205      *
206      * @return {@code true} if this {@link ModemActivityInfo} record is valid,
207      * {@code false} otherwise.
208      */
isValid()209     public boolean isValid() {
210         for (TransmitPower powerInfo : getTransmitPowerInfo()) {
211             if(powerInfo.getTimeInMillis() < 0) {
212                 return false;
213             }
214         }
215 
216         return ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
217                 && (getReceiveTimeMillis() >= 0) && !isEmpty());
218     }
219 
isEmpty()220     private boolean isEmpty() {
221         for (TransmitPower txVal : getTransmitPowerInfo()) {
222             if(txVal.getTimeInMillis() != 0) {
223                 return false;
224             }
225         }
226 
227         return ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
228                 && (getReceiveTimeMillis() == 0));
229     }
230 
231     /**
232      * Transmit power Information, including the power range in dbm and the total time (in ms) where
233      * the transmitter is active/awake for this power range.
234      * e.g, range: 0dbm(lower) ~ 5dbm(upper)
235      *      time: 5ms
236      */
237     public class TransmitPower {
238         private int mTimeInMillis;
239         private Range<Integer> mPowerRangeInDbm;
240         /** @hide */
TransmitPower(@onNull Range<Integer> range, int time)241         public TransmitPower(@NonNull Range<Integer> range, int time) {
242             this.mTimeInMillis = time;
243             this.mPowerRangeInDbm = range;
244         }
245 
246         /**
247          * @return the total time in ms where the transmitter is active/wake for this power range
248          * {@link #getPowerRangeInDbm()}.
249          */
getTimeInMillis()250         public int getTimeInMillis() {
251             return mTimeInMillis;
252         }
253 
254         /**
255          * @return the power range in dbm. e.g, range: 0dbm(lower) ~ 5dbm(upper)
256          */
257         @NonNull
getPowerRangeInDbm()258         public Range<Integer> getPowerRangeInDbm() {
259             return mPowerRangeInDbm;
260         }
261 
262         @Override
toString()263         public String toString() {
264             return "TransmitPower{"
265                 + " mTimeInMillis=" + mTimeInMillis
266                 + " mPowerRangeInDbm={" + mPowerRangeInDbm.getLower()
267                 + "," + mPowerRangeInDbm.getUpper()
268                 + "}}";
269         }
270     }
271 }
272