1 /*
2  * Copyright (C) 2012 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.ElapsedRealtimeLong;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.hardware.radio.V1_4.CellInfo.Info;
24 import android.hardware.radio.V1_5.CellInfo.CellInfoRatSpecificInfo;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 import java.util.Objects;
33 
34 /**
35  * Immutable cell information from a point in time.
36  */
37 public abstract class CellInfo implements Parcelable {
38 
39     /**
40      * This value indicates that the integer field is unreported.
41      */
42     public static final int UNAVAILABLE = Integer.MAX_VALUE;
43 
44     /**
45      * This value indicates that the long field is unreported.
46      */
47     public static final long UNAVAILABLE_LONG = Long.MAX_VALUE;
48 
49     /**
50      * Cell identity type
51      * @hide
52      */
53     @Retention(RetentionPolicy.SOURCE)
54     @IntDef(prefix = "TYPE_",
55             value = {TYPE_GSM, TYPE_CDMA, TYPE_LTE, TYPE_WCDMA, TYPE_TDSCDMA, TYPE_NR})
56     public @interface Type {}
57 
58     /**
59      * Unknown cell identity type
60      * @hide
61      */
62     public static final int TYPE_UNKNOWN = 0;
63 
64     /**
65      * GSM cell identity type
66      * @hide
67      */
68     public static final int TYPE_GSM = 1;
69 
70     /**
71      * CDMA cell identity type
72      * @hide
73      */
74     public static final int TYPE_CDMA = 2;
75 
76     /**
77      * LTE cell identity type
78      * @hide
79      */
80     public static final int TYPE_LTE = 3;
81 
82     /**
83      * WCDMA cell identity type
84      * @hide
85      */
86     public static final int TYPE_WCDMA = 4;
87 
88     /**
89      * TD-SCDMA cell identity type
90      * @hide
91      */
92     public static final int TYPE_TDSCDMA = 5;
93 
94     /**
95      * 5G cell identity type
96      * @hide
97      */
98     public static final int TYPE_NR = 6;
99 
100     // Type to distinguish where time stamp gets recorded.
101 
102     /** @hide */
103     @UnsupportedAppUsage
104     public static final int TIMESTAMP_TYPE_UNKNOWN = 0;
105     /** @hide */
106     @UnsupportedAppUsage
107     public static final int TIMESTAMP_TYPE_ANTENNA = 1;
108     /** @hide */
109     @UnsupportedAppUsage
110     public static final int TIMESTAMP_TYPE_MODEM = 2;
111     /** @hide */
112     @UnsupportedAppUsage
113     public static final int TIMESTAMP_TYPE_OEM_RIL = 3;
114     /** @hide */
115     @UnsupportedAppUsage
116     public static final int TIMESTAMP_TYPE_JAVA_RIL = 4;
117 
118     /** @hide */
119     @Retention(RetentionPolicy.SOURCE)
120     @IntDef({
121         CONNECTION_NONE,
122         CONNECTION_PRIMARY_SERVING,
123         CONNECTION_SECONDARY_SERVING,
124         CONNECTION_UNKNOWN
125     })
126     public @interface CellConnectionStatus {}
127 
128     /**
129      * Cell is not a serving cell.
130      *
131      * <p>The cell has been measured but is neither a camped nor serving cell (3GPP 36.304).
132      */
133     public static final int CONNECTION_NONE = 0;
134 
135     /** UE is connected to cell for signalling and possibly data (3GPP 36.331, 25.331). */
136     public static final int CONNECTION_PRIMARY_SERVING = 1;
137 
138     /** UE is connected to cell for data (3GPP 36.331, 25.331). */
139     public static final int CONNECTION_SECONDARY_SERVING = 2;
140 
141     /** Connection status is unknown. */
142     public static final int CONNECTION_UNKNOWN = Integer.MAX_VALUE;
143 
144     /** A cell connection status */
145     private int mCellConnectionStatus;
146 
147     // True if device is mRegistered to the mobile network
148     private boolean mRegistered;
149 
150     // Observation time stamped as type in nanoseconds since boot
151     private long mTimeStamp;
152 
153     /** @hide */
CellInfo()154     protected CellInfo() {
155         this.mRegistered = false;
156         this.mTimeStamp = Long.MAX_VALUE;
157         this.mCellConnectionStatus = CONNECTION_NONE;
158     }
159 
160     /** @hide */
CellInfo(CellInfo ci)161     protected CellInfo(CellInfo ci) {
162         this.mRegistered = ci.mRegistered;
163         this.mTimeStamp = ci.mTimeStamp;
164         this.mCellConnectionStatus = ci.mCellConnectionStatus;
165     }
166 
167     /**
168      * True if the phone is registered to a mobile network that provides service on this cell
169      * and this cell is being used or would be used for network signaling.
170      */
isRegistered()171     public boolean isRegistered() {
172         return mRegistered;
173     }
174 
175     /** @hide */
setRegistered(boolean registered)176     public void setRegistered(boolean registered) {
177         mRegistered = registered;
178     }
179 
180     /**
181      * Approximate time this cell information was received from the modem.
182      *
183      * @return a time stamp in millis since boot.
184      */
185     @ElapsedRealtimeLong
getTimestampMillis()186     public long getTimestampMillis() {
187         return mTimeStamp / 1000000;
188     }
189 
190     /**
191      * Approximate time this cell information was received from the modem.
192      *
193      * @return a time stamp in nanos since boot.
194      * @deprecated Use {@link #getTimestampMillis} instead.
195      */
196     @Deprecated
getTimeStamp()197     public long getTimeStamp() {
198         return mTimeStamp;
199     }
200 
201     /** @hide */
202     @VisibleForTesting
setTimeStamp(long ts)203     public void setTimeStamp(long ts) {
204         mTimeStamp = ts;
205     }
206 
207     /**
208      * @return a {@link CellIdentity} instance.
209      */
210     @NonNull
getCellIdentity()211     public abstract CellIdentity getCellIdentity();
212 
213     /**
214      * @return a {@link CellSignalStrength} instance.
215      */
216     @NonNull
getCellSignalStrength()217     public abstract CellSignalStrength getCellSignalStrength();
218 
219     /** @hide */
sanitizeLocationInfo()220     public CellInfo sanitizeLocationInfo() {
221         return null;
222     }
223 
224     /**
225      * Gets the connection status of this cell.
226      *
227      * @see #CONNECTION_NONE
228      * @see #CONNECTION_PRIMARY_SERVING
229      * @see #CONNECTION_SECONDARY_SERVING
230      * @see #CONNECTION_UNKNOWN
231      *
232      * @return The connection status of the cell.
233      */
234     @CellConnectionStatus
getCellConnectionStatus()235     public int getCellConnectionStatus() {
236         return mCellConnectionStatus;
237     }
238     /** @hide */
setCellConnectionStatus(@ellConnectionStatus int cellConnectionStatus)239     public void setCellConnectionStatus(@CellConnectionStatus int cellConnectionStatus) {
240         mCellConnectionStatus = cellConnectionStatus;
241     }
242 
243     @Override
hashCode()244     public int hashCode() {
245         return Objects.hash(mCellConnectionStatus, mRegistered, mTimeStamp);
246     }
247 
248     @Override
equals(Object o)249     public boolean equals(Object o) {
250         if (this == o) return true;
251         if (!(o instanceof CellInfo)) return false;
252         CellInfo cellInfo = (CellInfo) o;
253         return mCellConnectionStatus == cellInfo.mCellConnectionStatus
254                 && mRegistered == cellInfo.mRegistered
255                 && mTimeStamp == cellInfo.mTimeStamp;
256     }
257 
258     @Override
toString()259     public String toString() {
260         StringBuffer sb = new StringBuffer();
261 
262         sb.append("mRegistered=").append(mRegistered ? "YES" : "NO");
263         sb.append(" mTimeStamp=").append(mTimeStamp).append("ns");
264         sb.append(" mCellConnectionStatus=").append(mCellConnectionStatus);
265 
266         return sb.toString();
267     }
268 
269     /**
270      * Implement the Parcelable interface
271      */
272     @Override
describeContents()273     public int describeContents() {
274         return 0;
275     }
276 
277     /** Implement the Parcelable interface */
278     @Override
writeToParcel(Parcel dest, int flags)279     public abstract void writeToParcel(Parcel dest, int flags);
280 
281     /**
282      * Used by child classes for parceling.
283      *
284      * @hide
285      */
writeToParcel(Parcel dest, int flags, int type)286     protected void writeToParcel(Parcel dest, int flags, int type) {
287         dest.writeInt(type);
288         dest.writeInt(mRegistered ? 1 : 0);
289         dest.writeLong(mTimeStamp);
290         dest.writeInt(mCellConnectionStatus);
291     }
292 
293     /**
294      * Used by child classes for parceling
295      *
296      * @hide
297      */
CellInfo(Parcel in)298     protected CellInfo(Parcel in) {
299         mRegistered = (in.readInt() == 1) ? true : false;
300         mTimeStamp = in.readLong();
301         mCellConnectionStatus = in.readInt();
302     }
303 
304     /** Implement the Parcelable interface */
305     public static final @android.annotation.NonNull Creator<CellInfo> CREATOR = new Creator<CellInfo>() {
306         @Override
307         public CellInfo createFromParcel(Parcel in) {
308                 int type = in.readInt();
309                 switch (type) {
310                     case TYPE_GSM: return CellInfoGsm.createFromParcelBody(in);
311                     case TYPE_CDMA: return CellInfoCdma.createFromParcelBody(in);
312                     case TYPE_LTE: return CellInfoLte.createFromParcelBody(in);
313                     case TYPE_WCDMA: return CellInfoWcdma.createFromParcelBody(in);
314                     case TYPE_TDSCDMA: return CellInfoTdscdma.createFromParcelBody(in);
315                     case TYPE_NR: return CellInfoNr.createFromParcelBody(in);
316                     default: throw new RuntimeException("Bad CellInfo Parcel");
317                 }
318         }
319 
320         @Override
321         public CellInfo[] newArray(int size) {
322             return new CellInfo[size];
323         }
324     };
325 
326     /** @hide */
CellInfo(android.hardware.radio.V1_0.CellInfo ci)327     protected CellInfo(android.hardware.radio.V1_0.CellInfo ci) {
328         this.mRegistered = ci.registered;
329         this.mTimeStamp = ci.timeStamp;
330         this.mCellConnectionStatus = CONNECTION_UNKNOWN;
331     }
332 
333     /** @hide */
CellInfo(android.hardware.radio.V1_2.CellInfo ci)334     protected CellInfo(android.hardware.radio.V1_2.CellInfo ci) {
335         this.mRegistered = ci.registered;
336         this.mTimeStamp = ci.timeStamp;
337         this.mCellConnectionStatus = ci.connectionStatus;
338     }
339 
340     /** @hide */
CellInfo(android.hardware.radio.V1_4.CellInfo ci, long timeStamp)341     protected CellInfo(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
342         this.mRegistered = ci.isRegistered;
343         this.mTimeStamp = timeStamp;
344         this.mCellConnectionStatus = ci.connectionStatus;
345     }
346 
347     /** @hide */
CellInfo(android.hardware.radio.V1_5.CellInfo ci, long timeStamp)348     protected CellInfo(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
349         this.mRegistered = ci.registered;
350         this.mTimeStamp = timeStamp;
351         this.mCellConnectionStatus = ci.connectionStatus;
352     }
353 
354     /** @hide */
create(android.hardware.radio.V1_0.CellInfo ci)355     public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
356         if (ci == null) return null;
357         switch(ci.cellInfoType) {
358             case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci);
359             case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci);
360             case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci);
361             case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci);
362             case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci);
363             default: return null;
364         }
365     }
366 
367     /** @hide */
create(android.hardware.radio.V1_2.CellInfo ci)368     public static CellInfo create(android.hardware.radio.V1_2.CellInfo ci) {
369         if (ci == null) return null;
370         switch(ci.cellInfoType) {
371             case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci);
372             case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci);
373             case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci);
374             case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci);
375             case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci);
376             default: return null;
377         }
378     }
379 
380     /** @hide */
create(android.hardware.radio.V1_4.CellInfo ci, long timeStamp)381     public static CellInfo create(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
382         if (ci == null) return null;
383         switch (ci.info.getDiscriminator()) {
384             case Info.hidl_discriminator.gsm: return new CellInfoGsm(ci, timeStamp);
385             case Info.hidl_discriminator.cdma: return new CellInfoCdma(ci, timeStamp);
386             case Info.hidl_discriminator.lte: return new CellInfoLte(ci, timeStamp);
387             case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci, timeStamp);
388             case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci, timeStamp);
389             case Info.hidl_discriminator.nr: return new CellInfoNr(ci, timeStamp);
390             default: return null;
391         }
392     }
393 
394     /** @hide */
create(android.hardware.radio.V1_5.CellInfo ci, long timeStamp)395     public static CellInfo create(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
396         if (ci == null) return null;
397         switch (ci.ratSpecificInfo.getDiscriminator()) {
398             case CellInfoRatSpecificInfo.hidl_discriminator.gsm:
399                 return new CellInfoGsm(ci, timeStamp);
400             case CellInfoRatSpecificInfo.hidl_discriminator.cdma:
401                 return new CellInfoCdma(ci, timeStamp);
402             case CellInfoRatSpecificInfo.hidl_discriminator.lte:
403                 return new CellInfoLte(ci, timeStamp);
404             case CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
405                 return new CellInfoWcdma(ci, timeStamp);
406             case CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
407                 return new CellInfoTdscdma(ci, timeStamp);
408             case CellInfoRatSpecificInfo.hidl_discriminator.nr:
409                 return new CellInfoNr(ci, timeStamp);
410             default: return null;
411         }
412     }
413 }
414