• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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.CallSuper;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.text.TextUtils;
26 
27 import com.android.telephony.Rlog;
28 
29 import java.util.Objects;
30 import java.util.UUID;
31 
32 /**
33  * CellIdentity represents the identity of a unique cell. This is the base class for
34  * CellIdentityXxx which represents cell identity for specific network access technology.
35  */
36 public abstract class CellIdentity implements Parcelable {
37 
38     /** @hide */
39     public static final int INVALID_CHANNEL_NUMBER = Integer.MAX_VALUE;
40 
41     /**
42      * parameters for validation
43      * @hide
44      */
45     public static final int MCC_LENGTH = 3;
46 
47     /** @hide */
48     public static final int MNC_MIN_LENGTH = 2;
49     /** @hide */
50     public static final int MNC_MAX_LENGTH = 3;
51 
52     // Log tag
53     /** @hide */
54     protected final String mTag;
55     // Cell identity type
56     /** @hide */
57     protected final int mType;
58     // 3-digit Mobile Country Code in string format. Null for CDMA cell identity.
59     /** @hide */
60     protected final String mMccStr;
61     // 2 or 3-digit Mobile Network Code in string format. Null for CDMA cell identity.
62     /** @hide */
63     protected final String mMncStr;
64 
65     // long alpha Operator Name String or Enhanced Operator Name String
66     /** @hide */
67     protected String mAlphaLong;
68     // short alpha Operator Name String or Enhanced Operator Name String
69     /** @hide */
70     protected String mAlphaShort;
71 
72     // Cell Global, 3GPP TS 23.003
73     /** @hide */
74     protected String mGlobalCellId;
75 
76 
77     /** @hide */
CellIdentity(@ullable String tag, int type, @Nullable String mcc, @Nullable String mnc, @Nullable String alphal, @Nullable String alphas)78     protected CellIdentity(@Nullable String tag, int type, @Nullable String mcc,
79             @Nullable String mnc, @Nullable String alphal, @Nullable String alphas) {
80         mTag = tag;
81         mType = type;
82 
83         // Only allow INT_MAX if unknown string mcc/mnc
84         if (mcc == null || isMcc(mcc)) {
85             mMccStr = mcc;
86         } else if (mcc.isEmpty() || mcc.equals(String.valueOf(Integer.MAX_VALUE))) {
87             // If the mccStr is empty or unknown, set it as null.
88             mMccStr = null;
89         } else {
90             // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
91             // after the bug got fixed.
92             mMccStr = null;
93             log("invalid MCC format: " + mcc);
94         }
95 
96         if (mnc == null || isMnc(mnc)) {
97             mMncStr = mnc;
98         } else if (mnc.isEmpty() || mnc.equals(String.valueOf(Integer.MAX_VALUE))) {
99             // If the mncStr is empty or unknown, set it as null.
100             mMncStr = null;
101         } else {
102             // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
103             // after the bug got fixed.
104             mMncStr = null;
105             log("invalid MNC format: " + mnc);
106         }
107 
108         if ((mMccStr != null && mMncStr == null) || (mMccStr == null && mMncStr != null)) {
109             AnomalyReporter.reportAnomaly(
110                     UUID.fromString("e257ae06-ac0a-44c0-ba63-823b9f07b3e4"),
111                     "CellIdentity Missing Half of PLMN ID");
112         }
113 
114         mAlphaLong = alphal;
115         mAlphaShort = alphas;
116     }
117 
118     /** Implement the Parcelable interface */
119     @Override
describeContents()120     public int describeContents() {
121         return 0;
122     }
123 
124     /**
125      * @hide
126      * @return The type of the cell identity
127      */
getType()128     public @CellInfo.Type int getType() {
129         return mType;
130     }
131 
132     /**
133      * @return MCC or null for CDMA
134      * @hide
135      */
getMccString()136     public String getMccString() {
137         return mMccStr;
138     }
139 
140     /**
141      * @return MNC or null for CDMA
142      * @hide
143      */
getMncString()144     public String getMncString() {
145         return mMncStr;
146     }
147 
148     /**
149      * Returns the channel number of the cell identity.
150      *
151      * @hide
152      * @return The channel number, or {@link #INVALID_CHANNEL_NUMBER} if not implemented
153      */
getChannelNumber()154     public int getChannelNumber() {
155         return INVALID_CHANNEL_NUMBER;
156     }
157 
158     /**
159      * @return The long alpha tag associated with the current scan result (may be the operator
160      * name string or extended operator name string). May be null if unknown.
161      */
162     @Nullable
getOperatorAlphaLong()163     public CharSequence getOperatorAlphaLong() {
164         return mAlphaLong;
165     }
166 
167     /**
168      * @hide
169      */
setOperatorAlphaLong(String alphaLong)170     public void setOperatorAlphaLong(String alphaLong) {
171         mAlphaLong = alphaLong;
172     }
173 
174     /**
175      * @return The short alpha tag associated with the current scan result (may be the operator
176      * name string or extended operator name string).  May be null if unknown.
177      */
178     @Nullable
getOperatorAlphaShort()179     public CharSequence getOperatorAlphaShort() {
180         return mAlphaShort;
181     }
182 
183     /**
184      * @hide
185      */
setOperatorAlphaShort(String alphaShort)186     public void setOperatorAlphaShort(String alphaShort) {
187         mAlphaShort = alphaShort;
188     }
189 
190     /**
191      * @return Global Cell ID
192      * @hide
193      */
194     @Nullable
getGlobalCellId()195     public String getGlobalCellId() {
196         return mGlobalCellId;
197     }
198 
199     /**
200      * @param ci a CellIdentity to compare to the current CellIdentity.
201      * @return true if ci has the same technology and Global Cell ID; false, otherwise.
202      * @hide
203      */
isSameCell(@ullable CellIdentity ci)204     public boolean isSameCell(@Nullable CellIdentity ci) {
205         if (ci == null) return false;
206         if (this.getClass() != ci.getClass()) return false;
207         return TextUtils.equals(this.getGlobalCellId(), ci.getGlobalCellId());
208     }
209 
210     /** @hide */
getPlmn()211     public @Nullable String getPlmn() {
212         if (mMccStr == null || mMncStr == null) return null;
213         return mMccStr + mMncStr;
214     }
215 
216     /** @hide */
updateGlobalCellId()217     protected abstract void updateGlobalCellId();
218 
219     /**
220      * @return a CellLocation object for this CellIdentity
221      * @hide
222      */
223     @SystemApi
asCellLocation()224     public abstract @NonNull CellLocation asCellLocation();
225 
226     /**
227      * Create and a return a new instance of CellIdentity with location-identifying information
228      * removed.
229      *
230      * @hide
231      */
232     @SystemApi
sanitizeLocationInfo()233     public abstract @NonNull CellIdentity sanitizeLocationInfo();
234 
235     @Override
equals(Object other)236     public boolean equals(Object other) {
237         if (!(other instanceof CellIdentity)) {
238             return false;
239         }
240 
241         CellIdentity o = (CellIdentity) other;
242         return mType == o.mType
243                 && TextUtils.equals(mMccStr, o.mMccStr)
244                 && TextUtils.equals(mMncStr, o.mMncStr)
245                 && TextUtils.equals(mAlphaLong, o.mAlphaLong)
246                 && TextUtils.equals(mAlphaShort, o.mAlphaShort);
247     }
248 
249     @Override
hashCode()250     public int hashCode() {
251         return Objects.hash(mAlphaLong, mAlphaShort, mMccStr, mMncStr, mType);
252     }
253 
254     /**
255      * Used by child classes for parceling.
256      *
257      * @hide
258      */
259     @CallSuper
writeToParcel(Parcel dest, int type)260     public void writeToParcel(Parcel dest, int type) {
261         dest.writeInt(type);
262         dest.writeString(mMccStr);
263         dest.writeString(mMncStr);
264         dest.writeString(mAlphaLong);
265         dest.writeString(mAlphaShort);
266     }
267 
268     /** Used by phone interface manager to verify if a given string is valid MccMnc
269      * @hide
270      */
isValidPlmn(@onNull String plmn)271     public static boolean isValidPlmn(@NonNull String plmn) {
272         if (plmn.length() < MCC_LENGTH + MNC_MIN_LENGTH
273                 || plmn.length() > MCC_LENGTH + MNC_MAX_LENGTH) {
274             return false;
275         }
276         return (isMcc(plmn.substring(0, MCC_LENGTH)) && isMnc(plmn.substring(MCC_LENGTH)));
277     }
278 
279     /**
280      * Construct from Parcel
281      * @hide
282      */
CellIdentity(String tag, int type, Parcel source)283     protected CellIdentity(String tag, int type, Parcel source) {
284         this(tag, type, source.readString(), source.readString(),
285                 source.readString(), source.readString());
286     }
287 
288     /** Implement the Parcelable interface */
289     public static final @android.annotation.NonNull Creator<CellIdentity> CREATOR =
290             new Creator<CellIdentity>() {
291                 @Override
292                 public CellIdentity createFromParcel(Parcel in) {
293                     int type = in.readInt();
294                     switch (type) {
295                         case CellInfo.TYPE_GSM: return CellIdentityGsm.createFromParcelBody(in);
296                         case CellInfo.TYPE_WCDMA: return CellIdentityWcdma.createFromParcelBody(in);
297                         case CellInfo.TYPE_CDMA: return CellIdentityCdma.createFromParcelBody(in);
298                         case CellInfo.TYPE_LTE: return CellIdentityLte.createFromParcelBody(in);
299                         case CellInfo.TYPE_TDSCDMA:
300                             return CellIdentityTdscdma.createFromParcelBody(in);
301                         case CellInfo.TYPE_NR: return CellIdentityNr.createFromParcelBody(in);
302                         default: throw new IllegalArgumentException("Bad Cell identity Parcel");
303                     }
304                 }
305 
306                 @Override
307                 public CellIdentity[] newArray(int size) {
308                     return new CellIdentity[size];
309                 }
310             };
311 
312     /** @hide */
log(String s)313     protected void log(String s) {
314         Rlog.w(mTag, s);
315     }
316 
317     /** @hide */
inRangeOrUnavailable(int value, int rangeMin, int rangeMax)318     protected static final int inRangeOrUnavailable(int value, int rangeMin, int rangeMax) {
319         if (value < rangeMin || value > rangeMax) return CellInfo.UNAVAILABLE;
320         return value;
321     }
322 
323     /** @hide */
inRangeOrUnavailable(long value, long rangeMin, long rangeMax)324     protected static final long inRangeOrUnavailable(long value, long rangeMin, long rangeMax) {
325         if (value < rangeMin || value > rangeMax) return CellInfo.UNAVAILABLE_LONG;
326         return value;
327     }
328 
329     /** @hide */
inRangeOrUnavailable( int value, int rangeMin, int rangeMax, int special)330     protected static final int inRangeOrUnavailable(
331             int value, int rangeMin, int rangeMax, int special) {
332         if ((value < rangeMin || value > rangeMax) && value != special) return CellInfo.UNAVAILABLE;
333         return value;
334     }
335 
336     /** @hide */
isMcc(@onNull String mcc)337     private static boolean isMcc(@NonNull String mcc) {
338         // ensure no out of bounds indexing
339         if (mcc.length() != MCC_LENGTH) return false;
340 
341         // Character.isDigit allows all unicode digits, not just [0-9]
342         for (int i = 0; i < MCC_LENGTH; i++) {
343             if (mcc.charAt(i) < '0' || mcc.charAt(i) > '9') return false;
344         }
345 
346         return true;
347     }
348 
349     /** @hide */
isMnc(@onNull String mnc)350     private static boolean isMnc(@NonNull String mnc) {
351         // ensure no out of bounds indexing
352         if (mnc.length() < MNC_MIN_LENGTH || mnc.length() > MNC_MAX_LENGTH) return false;
353 
354         // Character.isDigit allows all unicode digits, not just [0-9]
355         for (int i = 0; i < mnc.length(); i++) {
356             if (mnc.charAt(i) < '0' || mnc.charAt(i) > '9') return false;
357         }
358 
359         return true;
360     }
361 }
362