• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.text.TextUtils.formatSimple;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.compat.annotation.UnsupportedAppUsage;
24 import android.os.Build;
25 import android.os.Parcel;
26 import android.telephony.gsm.GsmCellLocation;
27 import android.text.TextUtils;
28 import android.util.ArraySet;
29 
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.Objects;
34 import java.util.Set;
35 
36 /**
37  * CellIdentity is to represent a unique LTE cell
38  */
39 public final class CellIdentityLte extends CellIdentity {
40     private static final String TAG = CellIdentityLte.class.getSimpleName();
41     private static final boolean DBG = false;
42 
43     private static final int MAX_CI = 268435455;
44     private static final int MAX_PCI = 503;
45     private static final int MAX_TAC = 65535;
46     private static final int MAX_EARFCN = 262143;
47     private static final int MAX_BANDWIDTH = 20000;
48 
49     // 28-bit cell identity
50     private final int mCi;
51     // physical cell id 0..503
52     private final int mPci;
53     // 16-bit tracking area code
54     private final int mTac;
55     // 18-bit Absolute RF Channel Number
56     private final int mEarfcn;
57     // cell bandwidth, in kHz
58     private final int mBandwidth;
59     // cell bands
60     private final int[] mBands;
61 
62     // a list of additional PLMN-IDs reported for this cell
63     private final ArraySet<String> mAdditionalPlmns;
64 
65     private ClosedSubscriberGroupInfo mCsgInfo;
66 
67     /**
68      * @hide
69      */
70     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
CellIdentityLte()71     public CellIdentityLte() {
72         super(TAG, CellInfo.TYPE_LTE, null, null, null, null);
73         mCi = CellInfo.UNAVAILABLE;
74         mPci = CellInfo.UNAVAILABLE;
75         mTac = CellInfo.UNAVAILABLE;
76         mEarfcn = CellInfo.UNAVAILABLE;
77         mBands = new int[] {};
78         mBandwidth = CellInfo.UNAVAILABLE;
79         mAdditionalPlmns = new ArraySet<>();
80         mCsgInfo = null;
81         mGlobalCellId = null;
82     }
83 
84     /**
85      *
86      * @param mcc 3-digit Mobile Country Code, 0..999
87      * @param mnc 2 or 3-digit Mobile Network Code, 0..999
88      * @param ci 28-bit Cell Identity
89      * @param pci Physical Cell Id 0..503
90      * @param tac 16-bit Tracking Area Code
91      *
92      * @hide
93      */
94     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac)95     public CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac) {
96         this(ci, pci, tac, CellInfo.UNAVAILABLE, new int[] {}, CellInfo.UNAVAILABLE,
97                 String.valueOf(mcc), String.valueOf(mnc), null, null, new ArraySet<>(),
98                 null);
99     }
100 
101     /**
102      *
103      * @param ci 28-bit Cell Identity
104      * @param pci Physical Cell Id 0..503
105      * @param tac 16-bit Tracking Area Code
106      * @param earfcn 18-bit LTE Absolute RF Channel Number
107      * @param bandwidth cell bandwidth in kHz
108      * @param mccStr 3-digit Mobile Country Code in string format
109      * @param mncStr 2 or 3-digit Mobile Network Code in string format
110      * @param alphal long alpha Operator Name String or Enhanced Operator Name String
111      * @param alphas short alpha Operator Name String or Enhanced Operator Name String
112      * @param additionalPlmns a list of additional PLMN IDs broadcast by the cell
113      * @param csgInfo info about the closed subscriber group broadcast by the cell
114      *
115      * @hide
116      */
CellIdentityLte(int ci, int pci, int tac, int earfcn, @NonNull int[] bands, int bandwidth, @Nullable String mccStr, @Nullable String mncStr, @Nullable String alphal, @Nullable String alphas, @NonNull Collection<String> additionalPlmns, @Nullable ClosedSubscriberGroupInfo csgInfo)117     public CellIdentityLte(int ci, int pci, int tac, int earfcn, @NonNull int[] bands,
118             int bandwidth, @Nullable String mccStr, @Nullable String mncStr,
119             @Nullable String alphal, @Nullable String alphas,
120             @NonNull Collection<String> additionalPlmns,
121             @Nullable ClosedSubscriberGroupInfo csgInfo) {
122         super(TAG, CellInfo.TYPE_LTE, mccStr, mncStr, alphal, alphas);
123         mCi = inRangeOrUnavailable(ci, 0, MAX_CI);
124         mPci = inRangeOrUnavailable(pci, 0, MAX_PCI);
125         mTac = inRangeOrUnavailable(tac, 0, MAX_TAC);
126         mEarfcn = inRangeOrUnavailable(earfcn, 0, MAX_EARFCN);
127         mBands = bands;
128         mBandwidth = inRangeOrUnavailable(bandwidth, 0, MAX_BANDWIDTH);
129         mAdditionalPlmns = new ArraySet<>(additionalPlmns.size());
130         for (String plmn : additionalPlmns) {
131             if (isValidPlmn(plmn)) {
132                 mAdditionalPlmns.add(plmn);
133             }
134         }
135         mCsgInfo = csgInfo;
136         updateGlobalCellId();
137     }
138 
139     /** @hide */
CellIdentityLte(@onNull android.hardware.radio.V1_0.CellIdentityLte cid)140     public CellIdentityLte(@NonNull android.hardware.radio.V1_0.CellIdentityLte cid) {
141         this(cid.ci, cid.pci, cid.tac, cid.earfcn, new int[] {},
142                 CellInfo.UNAVAILABLE, cid.mcc, cid.mnc, "", "", new ArraySet<>(), null);
143     }
144 
145     /** @hide */
CellIdentityLte(@onNull android.hardware.radio.V1_2.CellIdentityLte cid)146     public CellIdentityLte(@NonNull android.hardware.radio.V1_2.CellIdentityLte cid) {
147         this(cid.base.ci, cid.base.pci, cid.base.tac, cid.base.earfcn, new int[] {},
148                 cid.bandwidth, cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong,
149                 cid.operatorNames.alphaShort, new ArraySet<>(), null);
150     }
151 
152     /** @hide */
CellIdentityLte(@onNull android.hardware.radio.V1_5.CellIdentityLte cid)153     public CellIdentityLte(@NonNull android.hardware.radio.V1_5.CellIdentityLte cid) {
154         this(cid.base.base.ci, cid.base.base.pci, cid.base.base.tac, cid.base.base.earfcn,
155                 cid.bands.stream().mapToInt(Integer::intValue).toArray(), cid.base.bandwidth,
156                 cid.base.base.mcc, cid.base.base.mnc, cid.base.operatorNames.alphaLong,
157                 cid.base.operatorNames.alphaShort, cid.additionalPlmns,
158                 cid.optionalCsgInfo.getDiscriminator()
159                         == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo
160                                 ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo())
161                                         : null);
162     }
163 
CellIdentityLte(@onNull CellIdentityLte cid)164     private CellIdentityLte(@NonNull CellIdentityLte cid) {
165         this(cid.mCi, cid.mPci, cid.mTac, cid.mEarfcn, cid.mBands, cid.mBandwidth, cid.mMccStr,
166                 cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo);
167     }
168 
169     /** @hide */
170     @Override
sanitizeLocationInfo()171     public @NonNull CellIdentityLte sanitizeLocationInfo() {
172         return new CellIdentityLte(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
173                 CellInfo.UNAVAILABLE, mBands, CellInfo.UNAVAILABLE,
174                 mMccStr, mMncStr, mAlphaLong, mAlphaShort, mAdditionalPlmns, null);
175     }
176 
copy()177     @NonNull CellIdentityLte copy() {
178         return new CellIdentityLte(this);
179     }
180 
181     /** @hide */
182     @Override
updateGlobalCellId()183     protected void updateGlobalCellId() {
184         mGlobalCellId = null;
185         String plmn = getPlmn();
186         if (plmn == null) return;
187 
188         if (mCi == CellInfo.UNAVAILABLE) return;
189 
190         mGlobalCellId = plmn + formatSimple("%07x", mCi);
191     }
192 
193     /**
194      * @return 3-digit Mobile Country Code, 0..999,
195      *         {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
196      * @deprecated Use {@link #getMccString} instead.
197      */
198     @Deprecated
getMcc()199     public int getMcc() {
200         return (mMccStr != null) ? Integer.valueOf(mMccStr) : CellInfo.UNAVAILABLE;
201     }
202 
203     /**
204      * @return 2 or 3-digit Mobile Network Code, 0..999,
205      *         {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
206      * @deprecated Use {@link #getMncString} instead.
207      */
208     @Deprecated
getMnc()209     public int getMnc() {
210         return (mMncStr != null) ? Integer.valueOf(mMncStr) : CellInfo.UNAVAILABLE;
211     }
212 
213     /**
214      * @return 28-bit Cell Identity,
215      *         {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
216      */
getCi()217     public int getCi() {
218         return mCi;
219     }
220 
221     /**
222      * @return Physical Cell Id 0..503,
223      *         {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
224      */
getPci()225     public int getPci() {
226         return mPci;
227     }
228 
229     /**
230      * @return 16-bit Tracking Area Code,
231      *         {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
232      */
getTac()233     public int getTac() {
234         return mTac;
235     }
236 
237     /**
238      * @return 18-bit Absolute RF Channel Number,
239      *         {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
240      */
getEarfcn()241     public int getEarfcn() {
242         return mEarfcn;
243     }
244 
245     /**
246      * Get bands of the cell
247      *
248      * Reference: 3GPP TS 36.101 section 5.5
249      *
250      * @return Array of band number or empty array if not available.
251      */
252     @NonNull
getBands()253     public int[] getBands() {
254         return Arrays.copyOf(mBands, mBands.length);
255     }
256 
257     /**
258      * @return Cell bandwidth in kHz,
259      *         {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
260      */
getBandwidth()261     public int getBandwidth() {
262         return mBandwidth;
263     }
264 
265     /**
266      * @return Mobile Country Code in string format, null if unavailable.
267      */
268     @Nullable
getMccString()269     public String getMccString() {
270         return mMccStr;
271     }
272 
273     /**
274      * @return Mobile Network Code in string format, null if unavailable.
275      */
276     @Nullable
getMncString()277     public String getMncString() {
278         return mMncStr;
279     }
280 
281     /**
282      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown.
283      */
284     @Nullable
getMobileNetworkOperator()285     public String getMobileNetworkOperator() {
286         return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
287     }
288 
289     /** @hide */
290     @Override
getChannelNumber()291     public int getChannelNumber() {
292         return mEarfcn;
293     }
294 
295     /**
296      * @return a list of additional PLMN IDs supported by this cell.
297      */
298     @NonNull
getAdditionalPlmns()299     public Set<String> getAdditionalPlmns() {
300         return Collections.unmodifiableSet(mAdditionalPlmns);
301     }
302 
303     /**
304      * @return closed subscriber group information about the cell if available, otherwise null.
305      */
306     @Nullable
getClosedSubscriberGroupInfo()307     public ClosedSubscriberGroupInfo getClosedSubscriberGroupInfo() {
308         return mCsgInfo;
309     }
310 
311     /**
312      * A hack to allow tunneling of LTE information via GsmCellLocation
313      * so that older Network Location Providers can return some information
314      * on LTE only networks, see bug 9228974.
315      *
316      * The tunnel'd LTE information is returned as follows:
317      *   LAC = TAC field
318      *   CID = CI field
319      *   PSC = 0.
320      *
321      * @hide
322      */
323     @NonNull
324     @Override
asCellLocation()325     public GsmCellLocation asCellLocation() {
326         GsmCellLocation cl = new GsmCellLocation();
327         int tac = mTac != CellInfo.UNAVAILABLE ? mTac : -1;
328         int cid = mCi != CellInfo.UNAVAILABLE ? mCi : -1;
329         cl.setLacAndCid(tac, cid);
330         cl.setPsc(0);
331         return cl;
332     }
333 
334     @Override
hashCode()335     public int hashCode() {
336         return Objects.hash(mCi, mPci, mTac, mEarfcn, Arrays.hashCode(mBands),
337                 mBandwidth, mAdditionalPlmns.hashCode(), mCsgInfo, super.hashCode());
338     }
339 
340     @Override
equals(Object other)341     public boolean equals(Object other) {
342         if (this == other) {
343             return true;
344         }
345 
346         if (!(other instanceof CellIdentityLte)) {
347             return false;
348         }
349 
350         CellIdentityLte o = (CellIdentityLte) other;
351         return mCi == o.mCi
352                 && mPci == o.mPci
353                 && mTac == o.mTac
354                 && mEarfcn == o.mEarfcn
355                 && Arrays.equals(mBands, o.mBands)
356                 && mBandwidth == o.mBandwidth
357                 && TextUtils.equals(mMccStr, o.mMccStr)
358                 && TextUtils.equals(mMncStr, o.mMncStr)
359                 && mAdditionalPlmns.equals(o.mAdditionalPlmns)
360                 && Objects.equals(mCsgInfo, o.mCsgInfo)
361                 && super.equals(other);
362     }
363 
364     @Override
toString()365     public String toString() {
366         return new StringBuilder(TAG)
367         .append(":{ mCi=").append(mCi)
368         .append(" mPci=").append(mPci)
369         .append(" mTac=").append(mTac)
370         .append(" mEarfcn=").append(mEarfcn)
371         .append(" mBands=").append(Arrays.toString(mBands))
372         .append(" mBandwidth=").append(mBandwidth)
373         .append(" mMcc=").append(mMccStr)
374         .append(" mMnc=").append(mMncStr)
375         .append(" mAlphaLong=").append(mAlphaLong)
376         .append(" mAlphaShort=").append(mAlphaShort)
377         .append(" mAdditionalPlmns=").append(mAdditionalPlmns)
378         .append(" mCsgInfo=").append(mCsgInfo)
379         .append("}").toString();
380     }
381 
382     /** Implement the Parcelable interface */
383     @Override
writeToParcel(Parcel dest, int flags)384     public void writeToParcel(Parcel dest, int flags) {
385         if (DBG) log("writeToParcel(Parcel, int): " + toString());
386         super.writeToParcel(dest, CellInfo.TYPE_LTE);
387         dest.writeInt(mCi);
388         dest.writeInt(mPci);
389         dest.writeInt(mTac);
390         dest.writeInt(mEarfcn);
391         dest.writeIntArray(mBands);
392         dest.writeInt(mBandwidth);
393         dest.writeArraySet(mAdditionalPlmns);
394         dest.writeParcelable(mCsgInfo, flags);
395     }
396 
397     /** Construct from Parcel, type has already been processed */
CellIdentityLte(Parcel in)398     private CellIdentityLte(Parcel in) {
399         super(TAG, CellInfo.TYPE_LTE, in);
400         mCi = in.readInt();
401         mPci = in.readInt();
402         mTac = in.readInt();
403         mEarfcn = in.readInt();
404         mBands = in.createIntArray();
405         mBandwidth = in.readInt();
406         mAdditionalPlmns = (ArraySet<String>) in.readArraySet(null);
407         mCsgInfo = in.readParcelable(null);
408 
409         updateGlobalCellId();
410         if (DBG) log(toString());
411     }
412 
413     /** Implement the Parcelable interface */
414     @SuppressWarnings("hiding")
415     public static final @android.annotation.NonNull Creator<CellIdentityLte> CREATOR =
416             new Creator<CellIdentityLte>() {
417                 @Override
418                 public CellIdentityLte createFromParcel(Parcel in) {
419                     in.readInt();   // skip;
420                     return createFromParcelBody(in);
421                 }
422 
423                 @Override
424                 public CellIdentityLte[] newArray(int size) {
425                     return new CellIdentityLte[size];
426                 }
427             };
428 
429     /** @hide */
createFromParcelBody(Parcel in)430     protected static CellIdentityLte createFromParcelBody(Parcel in) {
431         return new CellIdentityLte(in);
432     }
433 }
434