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