1 /*
2  * Copyright (C) 2018 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.NonNull;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 import android.telephony.RadioAccessSpecifier;
23 
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.Objects;
28 
29 /**
30  * Defines available network information which includes corresponding subscription id,
31  * network plmns and corresponding priority to be used for network selection by Opportunistic
32  * Network Service when passed through {@link TelephonyManager#updateAvailableNetworks}
33  */
34 public final class AvailableNetworkInfo implements Parcelable {
35 
36     /*
37      * Defines number of priority level high.
38      */
39     public static final int PRIORITY_HIGH = 1;
40 
41     /*
42      * Defines number of priority level medium.
43      */
44     public static final int PRIORITY_MED = 2;
45 
46     /*
47      * Defines number of priority level low.
48      */
49     public static final int PRIORITY_LOW = 3;
50 
51     /**
52      * subscription Id of the available network. This value must be one of the entry retrieved from
53      * {@link SubscriptionManager#getOpportunisticSubscriptions}
54      */
55     private int mSubId;
56 
57     /**
58      * Priority for the subscription id.
59      * Priorities are in the range of {@link AvailableNetworkInfo#PRIORITY_LOW} to
60      * {@link AvailableNetworkInfo#PRIORITY_HIGH}
61      * Among all networks available after network scan, subId with highest priority is chosen
62      * for network selection. If there are more than one subId with highest priority then the
63      * network with highest RSRP is chosen.
64      */
65     private int mPriority;
66 
67     /**
68      * Describes the List of PLMN ids (MCC-MNC) associated with mSubId.
69      * Opportunistic Network Service will scan and verify specified PLMNs are available.
70      * If this entry is left empty, then the Opportunistic Network Service will not scan the network
71      * to validate the network availability.
72      */
73     private ArrayList<String> mMccMncs;
74 
75     /**
76      * Returns the frequency bands associated with the {@link #getMccMncs() MCC/MNCs}.
77      * Opportunistic network service will use these bands to scan.
78      *
79      * When no specific bands are specified (empty array or null) CBRS band
80      * {@link AccessNetworkConstants.EutranBand.BAND_48
81      * } will be used for network scan.
82      *
83      * See {@link AccessNetworkConstants} for details.
84      *
85      * @deprecated use {@link #mRadioAccessSpecifiers} instead
86      */
87     @Deprecated
88     private ArrayList<Integer> mBands;
89 
90     /**
91      * Returns a list of {@link RadioAccessSpecifier} associated with the available network.
92      * Opportunistic network service will use this to determine which bands to scan for.
93      *
94      * If this entry is left empty, {@link RadioAcccessSpecifier}s with {@link AccessNetworkType}s
95      * of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link
96      * AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed
97      * by Opportunistic network service.
98      */
99     private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers;
100 
101     /**
102      * Return subscription Id of the available network.
103      * This value must be one of the entry retrieved from
104      * {@link SubscriptionManager#getOpportunisticSubscriptions}
105      * @return subscription id
106      */
getSubId()107     public int getSubId() {
108         return mSubId;
109     }
110 
111     /**
112      * Return priority for the subscription id.
113      * Priorities are in the range of {@link AvailableNetworkInfo#PRIORITY_LOW} to
114      * {@link AvailableNetworkInfo#PRIORITY_HIGH}
115      * Among all networks available after network scan, subId with highest priority is chosen
116      * for network selection. If there are more than one subId with highest priority then the
117      * network with highest RSRP is chosen.
118      * @return priority level
119      */
getPriority()120     public int getPriority() {
121         return mPriority;
122     }
123 
124     /**
125      * Return List of PLMN ids (MCC-MNC) associated with the sub ID.
126      * Opportunistic Network Service will scan and verify specified PLMNs are available.
127      * If this entry is left empty, then the Opportunistic Network Service will not scan the network
128      * to validate the network availability.
129      * @return list of PLMN ids
130      */
getMccMncs()131     public @NonNull List<String> getMccMncs() {
132         return (List<String>) mMccMncs.clone();
133     }
134 
135     /**
136      * Returns the frequency bands that need to be scanned by opportunistic network service
137      *
138      * The returned value is defined in either of {@link AccessNetworkConstants.GeranBand},
139      * {@link AccessNetworkConstants.UtranBand} and {@link AccessNetworkConstants.EutranBand}
140      * See {@link AccessNetworkConstants.AccessNetworkType} for details regarding different network
141      * types. When no specific bands are specified (empty array or null) CBRS band
142      * {@link AccessNetworkConstants.EutranBand#BAND_48} will be used for network scan.
143      */
getBands()144     public @NonNull List<Integer> getBands() {
145         return (List<Integer>) mBands.clone();
146     }
147 
148     /**
149      * Returns a list of {@link RadioAccessSpecifier} associated with the available network.
150      * Opportunistic network service will use this to determine which bands to scan for.
151      *
152      * the returned value is one of {@link AccessNetworkConstants.AccessNetworkType}. When no
153      * specific access network type is specified, {@link RadioAccessSpecifier}s with {@link
154      * AccessNetworkType}s of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link
155      * AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed
156      * by Opportunistic network service.
157      * @return the access network type associated with the available network.
158      * @hide
159      */
getRadioAccessSpecifiers()160     public List<RadioAccessSpecifier>  getRadioAccessSpecifiers() {
161         return (List<RadioAccessSpecifier>) mRadioAccessSpecifiers.clone();
162     }
163 
164     @Override
describeContents()165     public int describeContents() {
166         return 0;
167     }
168 
169     @Override
writeToParcel(Parcel dest, int flags)170     public void writeToParcel(Parcel dest, int flags) {
171         dest.writeInt(mSubId);
172         dest.writeInt(mPriority);
173         dest.writeStringList(mMccMncs);
174         dest.writeList(mBands);
175         dest.writeList(mRadioAccessSpecifiers);
176     }
177 
AvailableNetworkInfo(Parcel in)178     private AvailableNetworkInfo(Parcel in) {
179         mSubId = in.readInt();
180         mPriority = in.readInt();
181         mMccMncs = new ArrayList<>();
182         in.readStringList(mMccMncs);
183         mBands = new ArrayList<>();
184         in.readList(mBands, Integer.class.getClassLoader());
185         mRadioAccessSpecifiers = new ArrayList<>();
186         in.readList(mRadioAccessSpecifiers, RadioAccessSpecifier.class.getClassLoader());
187     }
188 
AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs, @NonNull List<Integer> bands)189     public AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs,
190             @NonNull List<Integer> bands) {
191         this(subId, priority, mccMncs, bands,
192                 new ArrayList<RadioAccessSpecifier>());
193     }
194 
195     /** @hide */
AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs, @NonNull List<Integer> bands, @NonNull List<RadioAccessSpecifier> radioAccessSpecifiers)196     private AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs,
197             @NonNull List<Integer> bands, @NonNull List<RadioAccessSpecifier>
198             radioAccessSpecifiers) {
199         mSubId = subId;
200         mPriority = priority;
201         mMccMncs = new ArrayList<String>(mccMncs);
202         mBands = new ArrayList<Integer>(bands);
203         mRadioAccessSpecifiers = new ArrayList<RadioAccessSpecifier>(radioAccessSpecifiers);
204     }
205 
206     @Override
equals(Object o)207     public boolean equals(Object o) {
208         AvailableNetworkInfo ani;
209 
210         try {
211             ani = (AvailableNetworkInfo) o;
212         } catch (ClassCastException ex) {
213             return false;
214         }
215 
216         if (o == null) {
217             return false;
218         }
219 
220         return (mSubId == ani.mSubId
221             && mPriority == ani.mPriority
222             && (((mMccMncs != null)
223             && mMccMncs.equals(ani.mMccMncs)))
224             && mBands.equals(ani.mBands))
225             && mRadioAccessSpecifiers.equals(ani.getRadioAccessSpecifiers());
226     }
227 
228     @Override
hashCode()229     public int hashCode() {
230         return Objects.hash(mSubId, mPriority, mMccMncs, mBands, mRadioAccessSpecifiers);
231     }
232 
233     public static final @android.annotation.NonNull Parcelable.Creator<AvailableNetworkInfo> CREATOR =
234             new Creator<AvailableNetworkInfo>() {
235                 @Override
236                 public AvailableNetworkInfo createFromParcel(Parcel in) {
237                     return new AvailableNetworkInfo(in);
238                 }
239 
240                 @Override
241                 public AvailableNetworkInfo[] newArray(int size) {
242                     return new AvailableNetworkInfo[size];
243                 }
244             };
245 
246     @Override
toString()247     public String toString() {
248         return ("AvailableNetworkInfo:"
249             + " mSubId: " + mSubId
250             + " mPriority: " + mPriority
251             + " mMccMncs: " + Arrays.toString(mMccMncs.toArray())
252             + " mBands: " + Arrays.toString(mBands.toArray())
253             + " mRadioAccessSpecifiers: " + Arrays.toString(mRadioAccessSpecifiers.toArray()));
254     }
255 
256     /**
257      * Provides a convenient way to set the fields of a {@link AvailableNetworkInfo} when
258      * creating a new instance.
259      *
260      * <p>The example below shows how you might create a new {@code AvailableNetworkInfo}:
261      *
262      * <pre><code>
263      *
264      * AvailableNetworkInfo aNI = new AvailableNetworkInfo.Builder()
265      *     .setSubId(1)
266      *     .setPriority(AvailableNetworkInfo.PRIORITY_MED)
267      *     .build();
268      * </code></pre>
269      *
270      * @hide
271      */
272     public static final class Builder {
273         private int mSubId = Integer.MIN_VALUE;
274         private int mPriority = AvailableNetworkInfo.PRIORITY_LOW;
275         private ArrayList<String> mMccMncs = new ArrayList<>();
276         private ArrayList<Integer> mBands = new ArrayList<>();
277         private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers = new ArrayList<>();
278 
setSubId(int subId)279         public @NonNull Builder setSubId(int subId) {
280             mSubId = subId;
281             return this;
282         }
283 
setPriority(int priority)284         public @NonNull Builder setPriority(int priority) {
285             if (priority > AvailableNetworkInfo.PRIORITY_LOW
286                     || priority < AvailableNetworkInfo.PRIORITY_HIGH) {
287                 throw new IllegalArgumentException("A valid priority must be set");
288             }
289             mPriority = priority;
290             return this;
291         }
292 
setMccMncs(@onNull ArrayList<String> mccMncs)293         public @NonNull Builder setMccMncs(@NonNull ArrayList<String> mccMncs) {
294             Objects.requireNonNull(mccMncs, "A non-null ArrayList of mccmncs must be set. An empty "
295                     + "list is still accepted. Please read documentation in "
296                     + "AvailableNetworkService to see consequences of an empty Arraylist.");
297             mMccMncs = mccMncs;
298             return this;
299         }
300 
setRadioAccessSpecifiers( @onNull ArrayList<RadioAccessSpecifier> radioAccessSpecifiers)301         public @NonNull Builder setRadioAccessSpecifiers(
302                 @NonNull ArrayList<RadioAccessSpecifier> radioAccessSpecifiers) {
303             Objects.requireNonNull(radioAccessSpecifiers, "A non-null ArrayList of "
304                     + "RadioAccessSpecifiers must be set. An empty list is still accepted. Please "
305                     + "read documentation in AvailableNetworkService to see consequences of an "
306                     + "empty Arraylist.");
307             mRadioAccessSpecifiers = radioAccessSpecifiers;
308             return this;
309         }
310 
build()311         public @NonNull AvailableNetworkInfo build() {
312             if (mSubId == Integer.MIN_VALUE) {
313                 throw new IllegalArgumentException("A valid subId must be set");
314             }
315 
316             return new AvailableNetworkInfo(mSubId, mPriority, mMccMncs, mBands,
317                     mRadioAccessSpecifiers);
318         }
319     }
320 }
321