1 /*
2  * Copyright 2019 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.Nullable;
22 import android.annotation.SuppressLint;
23 import android.annotation.SystemApi;
24 import android.annotation.TestApi;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.util.SparseArray;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.util.List;
32 import java.util.Objects;
33 
34 /**
35  * Provides the barring configuration for a particular service type.
36  *
37  * Provides indication about the barring of a particular service for use. Certain barring types
38  * are only valid for certain technology families. Any service that does not have a barring
39  * configuration is unbarred by default.
40  */
41 public final class BarringInfo implements Parcelable {
42 
43     /**
44      * Barring Service Type
45      *
46      * @hide
47      */
48     @Retention(RetentionPolicy.SOURCE)
49     @IntDef(prefix = "BARRING_SERVICE_TYPE_", value = {
50             BARRING_SERVICE_TYPE_CS_SERVICE,
51             BARRING_SERVICE_TYPE_PS_SERVICE,
52             BARRING_SERVICE_TYPE_CS_VOICE,
53             BARRING_SERVICE_TYPE_MO_SIGNALLING,
54             BARRING_SERVICE_TYPE_MO_DATA,
55             BARRING_SERVICE_TYPE_CS_FALLBACK,
56             BARRING_SERVICE_TYPE_MMTEL_VOICE,
57             BARRING_SERVICE_TYPE_MMTEL_VIDEO,
58             BARRING_SERVICE_TYPE_EMERGENCY,
59             BARRING_SERVICE_TYPE_SMS})
60     public @interface BarringServiceType {}
61 
62     /* Applicabe to UTRAN */
63     /** Barring indicator for circuit-switched service; applicable to UTRAN */
64     public static final int BARRING_SERVICE_TYPE_CS_SERVICE =
65             android.hardware.radio.V1_5.BarringInfo.ServiceType.CS_SERVICE;
66     /** Barring indicator for packet-switched service; applicable to UTRAN */
67     public static final int BARRING_SERVICE_TYPE_PS_SERVICE =
68             android.hardware.radio.V1_5.BarringInfo.ServiceType.PS_SERVICE;
69     /** Barring indicator for circuit-switched voice service; applicable to UTRAN */
70     public static final int BARRING_SERVICE_TYPE_CS_VOICE =
71             android.hardware.radio.V1_5.BarringInfo.ServiceType.CS_VOICE;
72 
73     /* Applicable to EUTRAN, NGRAN */
74     /** Barring indicator for mobile-originated signalling; applicable to EUTRAN and NGRAN */
75     public static final int BARRING_SERVICE_TYPE_MO_SIGNALLING =
76             android.hardware.radio.V1_5.BarringInfo.ServiceType.MO_SIGNALLING;
77     /** Barring indicator for mobile-originated data traffic; applicable to EUTRAN and NGRAN */
78     public static final int BARRING_SERVICE_TYPE_MO_DATA =
79             android.hardware.radio.V1_5.BarringInfo.ServiceType.MO_DATA;
80     /** Barring indicator for circuit-switched fallback for voice; applicable to EUTRAN and NGRAN */
81     public static final int BARRING_SERVICE_TYPE_CS_FALLBACK =
82             android.hardware.radio.V1_5.BarringInfo.ServiceType.CS_FALLBACK;
83     /** Barring indicator for MMTEL (IMS) voice; applicable to EUTRAN and NGRAN */
84     public static final int BARRING_SERVICE_TYPE_MMTEL_VOICE =
85             android.hardware.radio.V1_5.BarringInfo.ServiceType.MMTEL_VOICE;
86     /** Barring indicator for MMTEL (IMS) video; applicable to EUTRAN and NGRAN */
87     public static final int BARRING_SERVICE_TYPE_MMTEL_VIDEO =
88             android.hardware.radio.V1_5.BarringInfo.ServiceType.MMTEL_VIDEO;
89 
90     /* Applicable to UTRAN, EUTRAN, NGRAN */
91     /** Barring indicator for emergency services; applicable to UTRAN, EUTRAN, and NGRAN */
92     public static final int BARRING_SERVICE_TYPE_EMERGENCY =
93             android.hardware.radio.V1_5.BarringInfo.ServiceType.EMERGENCY;
94     /** Barring indicator for SMS sending; applicable to UTRAN, EUTRAN, and NGRAN */
95     public static final int BARRING_SERVICE_TYPE_SMS =
96             android.hardware.radio.V1_5.BarringInfo.ServiceType.SMS;
97 
98     //TODO: add barring constants for Operator-Specific barring codes
99 
100     /** Describe the current barring configuration of a cell */
101     public static final class BarringServiceInfo implements Parcelable {
102         /**
103          * Barring Type
104          * @hide
105          */
106         @Retention(RetentionPolicy.SOURCE)
107         @IntDef(prefix = "BARRING_TYPE_", value =
108                     {BARRING_TYPE_NONE,
109                     BARRING_TYPE_UNCONDITIONAL,
110                     BARRING_TYPE_CONDITIONAL,
111                     BARRING_TYPE_UNKNOWN})
112         public @interface BarringType {}
113 
114         /** Barring is inactive */
115         public static final int BARRING_TYPE_NONE =
116                 android.hardware.radio.V1_5.BarringInfo.BarringType.NONE;
117         /** The service is barred */
118         public static final int BARRING_TYPE_UNCONDITIONAL =
119                 android.hardware.radio.V1_5.BarringInfo.BarringType.UNCONDITIONAL;
120         /** The service may be barred based on additional factors */
121         public static final int BARRING_TYPE_CONDITIONAL =
122                 android.hardware.radio.V1_5.BarringInfo.BarringType.CONDITIONAL;
123 
124         /** If a modem does not report barring info, then the barring type will be UNKNOWN */
125         public static final int BARRING_TYPE_UNKNOWN = -1;
126 
127         private final @BarringType int mBarringType;
128 
129         private final boolean mIsConditionallyBarred;
130         private final int mConditionalBarringFactor;
131         private final int mConditionalBarringTimeSeconds;
132 
133         /** @hide */
BarringServiceInfo(@arringType int type)134         public BarringServiceInfo(@BarringType int type) {
135             this(type, false, 0, 0);
136         }
137 
138         /** @hide */
139         @TestApi
BarringServiceInfo(@arringType int barringType, boolean isConditionallyBarred, int conditionalBarringFactor, int conditionalBarringTimeSeconds)140         public BarringServiceInfo(@BarringType int barringType, boolean isConditionallyBarred,
141                 int conditionalBarringFactor, int conditionalBarringTimeSeconds) {
142             mBarringType = barringType;
143             mIsConditionallyBarred = isConditionallyBarred;
144             mConditionalBarringFactor = conditionalBarringFactor;
145             mConditionalBarringTimeSeconds = conditionalBarringTimeSeconds;
146         }
147 
getBarringType()148         public @BarringType int getBarringType() {
149             return mBarringType;
150         }
151 
152         /**
153          * @return true if the conditional barring parameters have resulted in the service being
154          *         barred; false if the service has either not been evaluated for conditional
155          *         barring or has been evaluated and isn't barred.
156          */
isConditionallyBarred()157         public boolean isConditionallyBarred() {
158             return mIsConditionallyBarred;
159         }
160 
161         /**
162          * @return the conditional barring factor as a percentage 0-100, which is the probability of
163          *         a random device being barred for the service type.
164          */
getConditionalBarringFactor()165         public int getConditionalBarringFactor() {
166             return mConditionalBarringFactor;
167         }
168 
169         /**
170          * @return the conditional barring time seconds, which is the interval between successive
171          *         evaluations for conditional barring based on the barring factor.
172          */
173         @SuppressLint("MethodNameUnits")
getConditionalBarringTimeSeconds()174         public int getConditionalBarringTimeSeconds() {
175             return mConditionalBarringTimeSeconds;
176         }
177 
178         /**
179          * Return whether a service is currently barred based on the BarringInfo
180          *
181          * @return true if the service is currently being barred, otherwise false
182          */
isBarred()183         public boolean isBarred() {
184             return mBarringType == BarringServiceInfo.BARRING_TYPE_UNCONDITIONAL
185                     || (mBarringType == BarringServiceInfo.BARRING_TYPE_CONDITIONAL
186                             && mIsConditionallyBarred);
187         }
188 
189         @Override
hashCode()190         public int hashCode() {
191             return Objects.hash(mBarringType, mIsConditionallyBarred,
192                     mConditionalBarringFactor, mConditionalBarringTimeSeconds);
193         }
194 
195         @Override
equals(Object rhs)196         public boolean equals(Object rhs) {
197             if (!(rhs instanceof BarringServiceInfo)) return false;
198 
199             BarringServiceInfo other = (BarringServiceInfo) rhs;
200             return mBarringType == other.mBarringType
201                     && mIsConditionallyBarred == other.mIsConditionallyBarred
202                     && mConditionalBarringFactor == other.mConditionalBarringFactor
203                     && mConditionalBarringTimeSeconds == other.mConditionalBarringTimeSeconds;
204         }
205 
206         /** @hide */
BarringServiceInfo(Parcel p)207         public BarringServiceInfo(Parcel p) {
208             mBarringType = p.readInt();
209             mIsConditionallyBarred = p.readBoolean();
210             mConditionalBarringFactor = p.readInt();
211             mConditionalBarringTimeSeconds = p.readInt();
212         }
213 
214         @Override
writeToParcel(@onNull Parcel dest, int flags)215         public void writeToParcel(@NonNull Parcel dest, int flags) {
216             dest.writeInt(mBarringType);
217             dest.writeBoolean(mIsConditionallyBarred);
218             dest.writeInt(mConditionalBarringFactor);
219             dest.writeInt(mConditionalBarringTimeSeconds);
220         }
221 
222         /* @inheritDoc */
223         public static final @NonNull Parcelable.Creator<BarringServiceInfo> CREATOR =
224                 new Parcelable.Creator<BarringServiceInfo>() {
225                     @Override
226                     public BarringServiceInfo createFromParcel(Parcel source) {
227                         return new BarringServiceInfo(source);
228                     }
229 
230                     @Override
231                     public BarringServiceInfo[] newArray(int size) {
232                         return new BarringServiceInfo[size];
233                     }
234                 };
235 
236         @Override
describeContents()237         public int describeContents() {
238             return 0;
239         }
240     }
241 
242     private static final BarringServiceInfo BARRING_SERVICE_INFO_UNKNOWN =
243             new BarringServiceInfo(BarringServiceInfo.BARRING_TYPE_UNKNOWN);
244 
245     private static final BarringServiceInfo BARRING_SERVICE_INFO_UNBARRED =
246             new BarringServiceInfo(BarringServiceInfo.BARRING_TYPE_NONE);
247 
248     private CellIdentity mCellIdentity;
249 
250     // A SparseArray potentially mapping each BarringService type to a BarringServiceInfo config
251     // that describes the current barring status of that particular service.
252     private SparseArray<BarringServiceInfo> mBarringServiceInfos;
253 
254     /** @hide */
255     @TestApi
256     @SystemApi
BarringInfo()257     public BarringInfo() {
258         mBarringServiceInfos = new SparseArray<>();
259     }
260 
261     /**
262      * Constructor for new BarringInfo instances.
263      *
264      * @hide
265      */
266     @TestApi
BarringInfo(@ullable CellIdentity barringCellId, @NonNull SparseArray<BarringServiceInfo> barringServiceInfos)267     public BarringInfo(@Nullable CellIdentity barringCellId,
268             @NonNull SparseArray<BarringServiceInfo> barringServiceInfos) {
269         mCellIdentity = barringCellId;
270         mBarringServiceInfos = barringServiceInfos;
271     }
272 
273     /** @hide */
create( @onNull android.hardware.radio.V1_5.CellIdentity halBarringCellId, @NonNull List<android.hardware.radio.V1_5.BarringInfo> halBarringInfos)274     public static BarringInfo create(
275             @NonNull android.hardware.radio.V1_5.CellIdentity halBarringCellId,
276             @NonNull List<android.hardware.radio.V1_5.BarringInfo> halBarringInfos) {
277         CellIdentity ci = CellIdentity.create(halBarringCellId);
278         SparseArray<BarringServiceInfo> serviceInfos = new SparseArray<>();
279 
280         for (android.hardware.radio.V1_5.BarringInfo halBarringInfo : halBarringInfos) {
281             if (halBarringInfo.barringType
282                     == android.hardware.radio.V1_5.BarringInfo.BarringType.CONDITIONAL) {
283                 if (halBarringInfo.barringTypeSpecificInfo.getDiscriminator()
284                         != android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo
285                                 .hidl_discriminator.conditional) {
286                     // this is an error case where the barring info is conditional but the
287                     // conditional barring fields weren't included
288                     continue;
289                 }
290                 android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo
291                         .Conditional conditionalInfo =
292                         halBarringInfo.barringTypeSpecificInfo.conditional();
293                 serviceInfos.put(
294                         halBarringInfo.serviceType, new BarringServiceInfo(
295                                 halBarringInfo.barringType, // will always be CONDITIONAL here
296                                 conditionalInfo.isBarred,
297                                 conditionalInfo.factor,
298                                 conditionalInfo.timeSeconds));
299             } else {
300                 // Barring type is either NONE or UNCONDITIONAL
301                 serviceInfos.put(
302                         halBarringInfo.serviceType, new BarringServiceInfo(
303                                 halBarringInfo.barringType, false, 0, 0));
304             }
305         }
306         return new BarringInfo(ci, serviceInfos);
307     }
308 
309     /**
310      * Get the BarringServiceInfo for a specified service.
311      *
312      * @return a BarringServiceInfo struct describing the current barring status for a service
313      */
getBarringServiceInfo(@arringServiceType int service)314     public @NonNull BarringServiceInfo getBarringServiceInfo(@BarringServiceType int service) {
315         BarringServiceInfo bsi = mBarringServiceInfos.get(service);
316         // If barring is reported but not for a particular service, then we report the barring
317         // type as UNKNOWN; if the modem reports barring info but doesn't report for a particular
318         // service then we can safely assume that the service isn't barred (for instance because
319         // that particular service isn't applicable to the current RAN).
320         return (bsi != null) ? bsi : mBarringServiceInfos.size() > 0
321                 ? BARRING_SERVICE_INFO_UNBARRED : BARRING_SERVICE_INFO_UNKNOWN;
322     }
323 
324     /** @hide */
325     @SystemApi
createLocationInfoSanitizedCopy()326     public @NonNull BarringInfo createLocationInfoSanitizedCopy() {
327         // The only thing that would need sanitizing is the CellIdentity
328         if (mCellIdentity == null) return this;
329 
330         return new BarringInfo(mCellIdentity.sanitizeLocationInfo(), mBarringServiceInfos);
331     }
332 
333     /** @hide */
BarringInfo(Parcel p)334     public BarringInfo(Parcel p) {
335         mCellIdentity = p.readParcelable(CellIdentity.class.getClassLoader());
336         mBarringServiceInfos = p.readSparseArray(BarringServiceInfo.class.getClassLoader());
337     }
338 
339     @Override
writeToParcel(@onNull Parcel dest, int flags)340     public void writeToParcel(@NonNull Parcel dest, int flags) {
341         dest.writeParcelable(mCellIdentity, flags);
342         dest.writeSparseArray(mBarringServiceInfos);
343     }
344 
345     public static final @NonNull Parcelable.Creator<BarringInfo> CREATOR =
346             new Parcelable.Creator<BarringInfo>() {
347                 @Override
348                 public BarringInfo createFromParcel(Parcel source) {
349                     return new BarringInfo(source);
350                 }
351 
352                 @Override
353                 public BarringInfo[] newArray(int size) {
354                     return new BarringInfo[size];
355                 }
356             };
357 
358     @Override
describeContents()359     public int describeContents() {
360         return 0;
361     }
362 
363     @Override
hashCode()364     public int hashCode() {
365         int hash = mCellIdentity != null ? mCellIdentity.hashCode() : 7;
366         for (int i = 0; i < mBarringServiceInfos.size(); i++) {
367             hash = hash + 15 * mBarringServiceInfos.keyAt(i);
368             hash = hash + 31 * mBarringServiceInfos.valueAt(i).hashCode();
369         }
370         return hash;
371     }
372 
373     @Override
equals(Object rhs)374     public boolean equals(Object rhs) {
375         if (!(rhs instanceof BarringInfo)) return false;
376 
377         BarringInfo bi = (BarringInfo) rhs;
378 
379         if (hashCode() != bi.hashCode()) return false;
380 
381         if (mBarringServiceInfos.size() != bi.mBarringServiceInfos.size()) return false;
382 
383         for (int i = 0; i < mBarringServiceInfos.size(); i++) {
384             if (mBarringServiceInfos.keyAt(i) != bi.mBarringServiceInfos.keyAt(i)) return false;
385             if (!Objects.equals(mBarringServiceInfos.valueAt(i),
386                         bi.mBarringServiceInfos.valueAt(i))) {
387                 return false;
388             }
389         }
390         return true;
391     }
392 
393     @Override
toString()394     public String toString() {
395         return "BarringInfo {mCellIdentity=" + mCellIdentity
396                + ", mBarringServiceInfos=" + mBarringServiceInfos + "}";
397     }
398 }
399