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     @SystemApi
BarringInfo()256     public BarringInfo() {
257         mBarringServiceInfos = new SparseArray<>();
258     }
259 
260     /**
261      * Constructor for new BarringInfo instances.
262      *
263      * @hide
264      */
265     @TestApi
BarringInfo(@ullable CellIdentity barringCellId, @NonNull SparseArray<BarringServiceInfo> barringServiceInfos)266     public BarringInfo(@Nullable CellIdentity barringCellId,
267             @NonNull SparseArray<BarringServiceInfo> barringServiceInfos) {
268         mCellIdentity = barringCellId;
269         mBarringServiceInfos = barringServiceInfos;
270     }
271 
272     /** @hide */
create( @onNull android.hardware.radio.V1_5.CellIdentity halBarringCellId, @NonNull List<android.hardware.radio.V1_5.BarringInfo> halBarringInfos)273     public static BarringInfo create(
274             @NonNull android.hardware.radio.V1_5.CellIdentity halBarringCellId,
275             @NonNull List<android.hardware.radio.V1_5.BarringInfo> halBarringInfos) {
276         CellIdentity ci = CellIdentity.create(halBarringCellId);
277         SparseArray<BarringServiceInfo> serviceInfos = new SparseArray<>();
278 
279         for (android.hardware.radio.V1_5.BarringInfo halBarringInfo : halBarringInfos) {
280             if (halBarringInfo.barringType
281                     == android.hardware.radio.V1_5.BarringInfo.BarringType.CONDITIONAL) {
282                 if (halBarringInfo.barringTypeSpecificInfo.getDiscriminator()
283                         != android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo
284                                 .hidl_discriminator.conditional) {
285                     // this is an error case where the barring info is conditional but the
286                     // conditional barring fields weren't included
287                     continue;
288                 }
289                 android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo
290                         .Conditional conditionalInfo =
291                         halBarringInfo.barringTypeSpecificInfo.conditional();
292                 serviceInfos.put(
293                         halBarringInfo.serviceType, new BarringServiceInfo(
294                                 halBarringInfo.barringType, // will always be CONDITIONAL here
295                                 conditionalInfo.isBarred,
296                                 conditionalInfo.factor,
297                                 conditionalInfo.timeSeconds));
298             } else {
299                 // Barring type is either NONE or UNCONDITIONAL
300                 serviceInfos.put(
301                         halBarringInfo.serviceType, new BarringServiceInfo(
302                                 halBarringInfo.barringType, false, 0, 0));
303             }
304         }
305         return new BarringInfo(ci, serviceInfos);
306     }
307 
308     /**
309      * Get the BarringServiceInfo for a specified service.
310      *
311      * @return a BarringServiceInfo struct describing the current barring status for a service
312      */
getBarringServiceInfo(@arringServiceType int service)313     public @NonNull BarringServiceInfo getBarringServiceInfo(@BarringServiceType int service) {
314         BarringServiceInfo bsi = mBarringServiceInfos.get(service);
315         // If barring is reported but not for a particular service, then we report the barring
316         // type as UNKNOWN; if the modem reports barring info but doesn't report for a particular
317         // service then we can safely assume that the service isn't barred (for instance because
318         // that particular service isn't applicable to the current RAN).
319         return (bsi != null) ? bsi : mBarringServiceInfos.size() > 0
320                 ? BARRING_SERVICE_INFO_UNBARRED : BARRING_SERVICE_INFO_UNKNOWN;
321     }
322 
323     /** @hide */
324     @SystemApi
createLocationInfoSanitizedCopy()325     public @NonNull BarringInfo createLocationInfoSanitizedCopy() {
326         // The only thing that would need sanitizing is the CellIdentity
327         if (mCellIdentity == null) return this;
328 
329         return new BarringInfo(mCellIdentity.sanitizeLocationInfo(), mBarringServiceInfos);
330     }
331 
332     /** @hide */
BarringInfo(Parcel p)333     public BarringInfo(Parcel p) {
334         mCellIdentity = p.readParcelable(CellIdentity.class.getClassLoader());
335         mBarringServiceInfos = p.readSparseArray(BarringServiceInfo.class.getClassLoader());
336     }
337 
338     @Override
writeToParcel(@onNull Parcel dest, int flags)339     public void writeToParcel(@NonNull Parcel dest, int flags) {
340         dest.writeParcelable(mCellIdentity, flags);
341         dest.writeSparseArray(mBarringServiceInfos);
342     }
343 
344     public static final @NonNull Parcelable.Creator<BarringInfo> CREATOR =
345             new Parcelable.Creator<BarringInfo>() {
346                 @Override
347                 public BarringInfo createFromParcel(Parcel source) {
348                     return new BarringInfo(source);
349                 }
350 
351                 @Override
352                 public BarringInfo[] newArray(int size) {
353                     return new BarringInfo[size];
354                 }
355             };
356 
357     @Override
describeContents()358     public int describeContents() {
359         return 0;
360     }
361 
362     @Override
hashCode()363     public int hashCode() {
364         int hash = mCellIdentity != null ? mCellIdentity.hashCode() : 7;
365         for (int i = 0; i < mBarringServiceInfos.size(); i++) {
366             hash = hash + 15 * mBarringServiceInfos.keyAt(i);
367             hash = hash + 31 * mBarringServiceInfos.valueAt(i).hashCode();
368         }
369         return hash;
370     }
371 
372     @Override
equals(Object rhs)373     public boolean equals(Object rhs) {
374         if (!(rhs instanceof BarringInfo)) return false;
375 
376         BarringInfo bi = (BarringInfo) rhs;
377 
378         if (hashCode() != bi.hashCode()) return false;
379 
380         if (mBarringServiceInfos.size() != bi.mBarringServiceInfos.size()) return false;
381 
382         for (int i = 0; i < mBarringServiceInfos.size(); i++) {
383             if (mBarringServiceInfos.keyAt(i) != bi.mBarringServiceInfos.keyAt(i)) return false;
384             if (!Objects.equals(mBarringServiceInfos.valueAt(i),
385                         bi.mBarringServiceInfos.valueAt(i))) {
386                 return false;
387             }
388         }
389         return true;
390     }
391 
392     @Override
toString()393     public String toString() {
394         return "BarringInfo {mCellIdentity=" + mCellIdentity
395                + ", mBarringServiceInfos=" + mBarringServiceInfos + "}";
396     }
397 }
398