1 /*
2  * Copyright (C) 2014 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.Nullable;
20 import android.annotation.SystemApi;
21 import android.content.Context;
22 import android.content.pm.PackageInfo;
23 import android.content.pm.PackageManager;
24 import android.graphics.Bitmap;
25 import android.graphics.Canvas;
26 import android.graphics.Color;
27 import android.graphics.Paint;
28 import android.graphics.PorterDuff;
29 import android.graphics.PorterDuffColorFilter;
30 import android.graphics.Rect;
31 import android.graphics.Typeface;
32 import android.os.Build;
33 import android.os.Parcel;
34 import android.os.Parcelable;
35 import android.util.DisplayMetrics;
36 
37 import java.util.Arrays;
38 import java.util.ArrayList;
39 import java.util.List;
40 
41 /**
42  * A Parcelable class for Subscription Information.
43  */
44 public class SubscriptionInfo implements Parcelable {
45 
46     /**
47      * Size of text to render on the icon.
48      */
49     private static final int TEXT_SIZE = 16;
50 
51     /**
52      * Subscription Identifier, this is a device unique number
53      * and not an index into an array
54      */
55     private int mId;
56 
57     /**
58      * The GID for a SIM that maybe associated with this subscription, empty if unknown
59      */
60     private String mIccId;
61 
62     /**
63      * The index of the slot that currently contains the subscription
64      * and not necessarily unique and maybe INVALID_SLOT_ID if unknown
65      */
66     private int mSimSlotIndex;
67 
68     /**
69      * The name displayed to the user that identifies this subscription
70      */
71     private CharSequence mDisplayName;
72 
73     /**
74      * String that identifies SPN/PLMN
75      * TODO : Add a new field that identifies only SPN for a sim
76      */
77     private CharSequence mCarrierName;
78 
79     /**
80      * The source of the name, NAME_SOURCE_UNDEFINED, NAME_SOURCE_DEFAULT_SOURCE,
81      * NAME_SOURCE_SIM_SOURCE or NAME_SOURCE_USER_INPUT.
82      */
83     private int mNameSource;
84 
85     /**
86      * The color to be used for tinting the icon when displaying to the user
87      */
88     private int mIconTint;
89 
90     /**
91      * A number presented to the user identify this subscription
92      */
93     private String mNumber;
94 
95     /**
96      * Data roaming state, DATA_RAOMING_ENABLE, DATA_RAOMING_DISABLE
97      */
98     private int mDataRoaming;
99 
100     /**
101      * SIM Icon bitmap
102      */
103     private Bitmap mIconBitmap;
104 
105     /**
106      * Mobile Country Code
107      */
108     private int mMcc;
109 
110     /**
111      * Mobile Network Code
112      */
113     private int mMnc;
114 
115     /**
116      * ISO Country code for the subscription's provider
117      */
118     private String mCountryIso;
119 
120     /**
121      * Whether the subscription is an embedded one.
122      */
123     private boolean mIsEmbedded;
124 
125     /**
126      * The access rules for this subscription, if it is embedded and defines any.
127      */
128     @Nullable
129     private UiccAccessRule[] mAccessRules;
130 
131     /**
132      * The ID of the SIM card. It is the ICCID of the active profile for a UICC card and the EID
133      * for an eUICC card.
134      */
135     private String mCardId;
136 
137     /**
138      * @hide
139      */
SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, int mcc, int mnc, String countryIso)140     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
141         CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
142         Bitmap icon, int mcc, int mnc, String countryIso) {
143         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
144             roaming, icon, mcc, mnc, countryIso, false /* isEmbedded */,
145             null /* accessRules */, null /* accessRules */);
146     }
147 
148     /**
149      * @hide
150      */
SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, int mcc, int mnc, String countryIso, boolean isEmbedded, @Nullable UiccAccessRule[] accessRules)151     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
152             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
153             Bitmap icon, int mcc, int mnc, String countryIso,  boolean isEmbedded,
154             @Nullable UiccAccessRule[] accessRules) {
155         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
156                 roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, null /* cardId */);
157     }
158 
159     /**
160      * @hide
161      */
SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, int mcc, int mnc, String countryIso, boolean isEmbedded, @Nullable UiccAccessRule[] accessRules, String cardId)162     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
163             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
164             Bitmap icon, int mcc, int mnc, String countryIso, boolean isEmbedded,
165             @Nullable UiccAccessRule[] accessRules, String cardId) {
166         this.mId = id;
167         this.mIccId = iccId;
168         this.mSimSlotIndex = simSlotIndex;
169         this.mDisplayName = displayName;
170         this.mCarrierName = carrierName;
171         this.mNameSource = nameSource;
172         this.mIconTint = iconTint;
173         this.mNumber = number;
174         this.mDataRoaming = roaming;
175         this.mIconBitmap = icon;
176         this.mMcc = mcc;
177         this.mMnc = mnc;
178         this.mCountryIso = countryIso;
179         this.mIsEmbedded = isEmbedded;
180         this.mAccessRules = accessRules;
181         this.mCardId = cardId;
182     }
183 
184     /**
185      * @return the subscription ID.
186      */
getSubscriptionId()187     public int getSubscriptionId() {
188         return this.mId;
189     }
190 
191     /**
192      * @return the ICC ID.
193      */
getIccId()194     public String getIccId() {
195         return this.mIccId;
196     }
197 
198     /**
199      * @return the slot index of this Subscription's SIM card.
200      */
getSimSlotIndex()201     public int getSimSlotIndex() {
202         return this.mSimSlotIndex;
203     }
204 
205     /**
206      * @return the name displayed to the user that identifies this subscription
207      */
getDisplayName()208     public CharSequence getDisplayName() {
209         return this.mDisplayName;
210     }
211 
212     /**
213      * Sets the name displayed to the user that identifies this subscription
214      * @hide
215      */
setDisplayName(CharSequence name)216     public void setDisplayName(CharSequence name) {
217         this.mDisplayName = name;
218     }
219 
220     /**
221      * @return the name displayed to the user that identifies Subscription provider name
222      */
getCarrierName()223     public CharSequence getCarrierName() {
224         return this.mCarrierName;
225     }
226 
227     /**
228      * Sets the name displayed to the user that identifies Subscription provider name
229      * @hide
230      */
setCarrierName(CharSequence name)231     public void setCarrierName(CharSequence name) {
232         this.mCarrierName = name;
233     }
234 
235     /**
236      * @return the source of the name, eg NAME_SOURCE_UNDEFINED, NAME_SOURCE_DEFAULT_SOURCE,
237      * NAME_SOURCE_SIM_SOURCE or NAME_SOURCE_USER_INPUT.
238      * @hide
239      */
getNameSource()240     public int getNameSource() {
241         return this.mNameSource;
242     }
243 
244     /**
245      * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a user
246      * interface.
247      *
248      * @param context A {@code Context} to get the {@code DisplayMetrics}s from.
249      *
250      * @return A bitmap icon for this {@code SubscriptionInfo}.
251      */
createIconBitmap(Context context)252     public Bitmap createIconBitmap(Context context) {
253         int width = mIconBitmap.getWidth();
254         int height = mIconBitmap.getHeight();
255         DisplayMetrics metrics = context.getResources().getDisplayMetrics();
256 
257         // Create a new bitmap of the same size because it will be modified.
258         Bitmap workingBitmap = Bitmap.createBitmap(metrics, width, height, mIconBitmap.getConfig());
259 
260         Canvas canvas = new Canvas(workingBitmap);
261         Paint paint = new Paint();
262 
263         // Tint the icon with the color.
264         paint.setColorFilter(new PorterDuffColorFilter(mIconTint, PorterDuff.Mode.SRC_ATOP));
265         canvas.drawBitmap(mIconBitmap, 0, 0, paint);
266         paint.setColorFilter(null);
267 
268         // Write the sim slot index.
269         paint.setAntiAlias(true);
270         paint.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL));
271         paint.setColor(Color.WHITE);
272         // Set text size scaled by density
273         paint.setTextSize(TEXT_SIZE * metrics.density);
274         // Convert sim slot index to localized string
275         final String index = String.format("%d", mSimSlotIndex + 1);
276         final Rect textBound = new Rect();
277         paint.getTextBounds(index, 0, 1, textBound);
278         final float xOffset = (width / 2.f) - textBound.centerX();
279         final float yOffset = (height / 2.f) - textBound.centerY();
280         canvas.drawText(index, xOffset, yOffset, paint);
281 
282         return workingBitmap;
283     }
284 
285     /**
286      * A highlight color to use in displaying information about this {@code PhoneAccount}.
287      *
288      * @return A hexadecimal color value.
289      */
getIconTint()290     public int getIconTint() {
291         return mIconTint;
292     }
293 
294     /**
295      * Sets the color displayed to the user that identifies this subscription
296      * @hide
297      */
setIconTint(int iconTint)298     public void setIconTint(int iconTint) {
299         this.mIconTint = iconTint;
300     }
301 
302     /**
303      * @return the number of this subscription.
304      */
getNumber()305     public String getNumber() {
306         return mNumber;
307     }
308 
309     /**
310      * @return the data roaming state for this subscription, either
311      * {@link SubscriptionManager#DATA_ROAMING_ENABLE} or {@link SubscriptionManager#DATA_ROAMING_DISABLE}.
312      */
getDataRoaming()313     public int getDataRoaming() {
314         return this.mDataRoaming;
315     }
316 
317     /**
318      * @return the MCC.
319      */
getMcc()320     public int getMcc() {
321         return this.mMcc;
322     }
323 
324     /**
325      * @return the MNC.
326      */
getMnc()327     public int getMnc() {
328         return this.mMnc;
329     }
330 
331     /**
332      * @return the ISO country code
333      */
getCountryIso()334     public String getCountryIso() {
335         return this.mCountryIso;
336     }
337 
338     /** @return whether the subscription is an eUICC one. */
isEmbedded()339     public boolean isEmbedded() {
340         return this.mIsEmbedded;
341     }
342 
343     /**
344      * Checks whether the app with the given context is authorized to manage this subscription
345      * according to its metadata. Only supported for embedded subscriptions (if {@link #isEmbedded}
346      * returns true).
347      *
348      * @param context Context of the application to check.
349      * @return whether the app is authorized to manage this subscription per its metadata.
350      * @throws UnsupportedOperationException if this subscription is not embedded.
351      * @hide
352      * @deprecated - Do not use.
353      */
354     @Deprecated
canManageSubscription(Context context)355     public boolean canManageSubscription(Context context) {
356         return canManageSubscription(context, context.getPackageName());
357     }
358 
359     /**
360      * Checks whether the given app is authorized to manage this subscription according to its
361      * metadata. Only supported for embedded subscriptions (if {@link #isEmbedded} returns true).
362      *
363      * @param context Any context.
364      * @param packageName Package name of the app to check.
365      * @return whether the app is authorized to manage this subscription per its metadata.
366      * @throws UnsupportedOperationException if this subscription is not embedded.
367      * @hide
368      * @deprecated - Do not use.
369      */
370     @Deprecated
canManageSubscription(Context context, String packageName)371     public boolean canManageSubscription(Context context, String packageName) {
372         if (!isEmbedded()) {
373             throw new UnsupportedOperationException("Not an embedded subscription");
374         }
375         if (mAccessRules == null) {
376             return false;
377         }
378         PackageManager packageManager = context.getPackageManager();
379         PackageInfo packageInfo;
380         try {
381             packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
382         } catch (PackageManager.NameNotFoundException e) {
383             throw new IllegalArgumentException("Unknown package: " + packageName, e);
384         }
385         for (UiccAccessRule rule : mAccessRules) {
386             if (rule.getCarrierPrivilegeStatus(packageInfo)
387                     == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
388                 return true;
389             }
390         }
391         return false;
392     }
393 
394     /**
395      * @return the {@link UiccAccessRule}s dictating who is authorized to manage this subscription.
396      * @throws UnsupportedOperationException if this subscription is not embedded.
397      * @hide
398      */
399     @SystemApi
getAccessRules()400     public @Nullable List<UiccAccessRule> getAccessRules() {
401         if (!isEmbedded()) {
402             throw new UnsupportedOperationException("Not an embedded subscription");
403         }
404         if (mAccessRules == null) return null;
405         return Arrays.asList(mAccessRules);
406     }
407 
408     /**
409      * @return the ID of the SIM card which contains the subscription.
410      * @hide
411      */
getCardId()412     public String getCardId() {
413         return this.mCardId;
414     }
415 
416     public static final Parcelable.Creator<SubscriptionInfo> CREATOR = new Parcelable.Creator<SubscriptionInfo>() {
417         @Override
418         public SubscriptionInfo createFromParcel(Parcel source) {
419             int id = source.readInt();
420             String iccId = source.readString();
421             int simSlotIndex = source.readInt();
422             CharSequence displayName = source.readCharSequence();
423             CharSequence carrierName = source.readCharSequence();
424             int nameSource = source.readInt();
425             int iconTint = source.readInt();
426             String number = source.readString();
427             int dataRoaming = source.readInt();
428             int mcc = source.readInt();
429             int mnc = source.readInt();
430             String countryIso = source.readString();
431             Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source);
432             boolean isEmbedded = source.readBoolean();
433             UiccAccessRule[] accessRules = source.createTypedArray(UiccAccessRule.CREATOR);
434             String cardId = source.readString();
435 
436             return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
437                     nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
438                     isEmbedded, accessRules, cardId);
439         }
440 
441         @Override
442         public SubscriptionInfo[] newArray(int size) {
443             return new SubscriptionInfo[size];
444         }
445     };
446 
447     @Override
writeToParcel(Parcel dest, int flags)448     public void writeToParcel(Parcel dest, int flags) {
449         dest.writeInt(mId);
450         dest.writeString(mIccId);
451         dest.writeInt(mSimSlotIndex);
452         dest.writeCharSequence(mDisplayName);
453         dest.writeCharSequence(mCarrierName);
454         dest.writeInt(mNameSource);
455         dest.writeInt(mIconTint);
456         dest.writeString(mNumber);
457         dest.writeInt(mDataRoaming);
458         dest.writeInt(mMcc);
459         dest.writeInt(mMnc);
460         dest.writeString(mCountryIso);
461         mIconBitmap.writeToParcel(dest, flags);
462         dest.writeBoolean(mIsEmbedded);
463         dest.writeTypedArray(mAccessRules, flags);
464         dest.writeString(mCardId);
465     }
466 
467     @Override
describeContents()468     public int describeContents() {
469         return 0;
470     }
471 
472     /**
473      * @hide
474      */
givePrintableIccid(String iccId)475     public static String givePrintableIccid(String iccId) {
476         String iccIdToPrint = null;
477         if (iccId != null) {
478             if (iccId.length() > 9 && !Build.IS_DEBUGGABLE) {
479                 iccIdToPrint = iccId.substring(0, 9) + Rlog.pii(false, iccId.substring(9));
480             } else {
481                 iccIdToPrint = iccId;
482             }
483         }
484         return iccIdToPrint;
485     }
486 
487     @Override
toString()488     public String toString() {
489         String iccIdToPrint = givePrintableIccid(mIccId);
490         String cardIdToPrint = givePrintableIccid(mCardId);
491         return "{id=" + mId + ", iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex
492                 + " displayName=" + mDisplayName + " carrierName=" + mCarrierName
493                 + " nameSource=" + mNameSource + " iconTint=" + mIconTint
494                 + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
495                 + " mnc " + mMnc + " isEmbedded " + mIsEmbedded
496                 + " accessRules " + Arrays.toString(mAccessRules)
497                 + " cardId=" + cardIdToPrint + "}";
498     }
499 }
500