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