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.compat.annotation.UnsupportedAppUsage;
22 import android.content.Context;
23 import android.content.pm.PackageInfo;
24 import android.content.pm.PackageManager;
25 import android.graphics.Bitmap;
26 import android.graphics.Canvas;
27 import android.graphics.Color;
28 import android.graphics.Paint;
29 import android.graphics.PorterDuff;
30 import android.graphics.PorterDuffColorFilter;
31 import android.graphics.Rect;
32 import android.graphics.Typeface;
33 import android.os.Parcel;
34 import android.os.ParcelUuid;
35 import android.os.Parcelable;
36 import android.text.TextUtils;
37 import android.util.DisplayMetrics;
38 import android.util.Log;
39 
40 import com.android.internal.telephony.util.TelephonyUtils;
41 import com.android.telephony.Rlog;
42 
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collections;
46 import java.util.List;
47 import java.util.Objects;
48 
49 /**
50  * A Parcelable class for Subscription Information.
51  */
52 public class SubscriptionInfo implements Parcelable {
53 
54     /**
55      * Size of text to render on the icon.
56      */
57     private static final int TEXT_SIZE = 16;
58 
59     /**
60      * Subscription Identifier, this is a device unique number
61      * and not an index into an array
62      */
63     private int mId;
64 
65     /**
66      * The GID for a SIM that maybe associated with this subscription, empty if unknown
67      */
68     private String mIccId;
69 
70     /**
71      * The index of the slot that currently contains the subscription
72      * and not necessarily unique and maybe INVALID_SLOT_ID if unknown
73      */
74     private int mSimSlotIndex;
75 
76     /**
77      * The name displayed to the user that identifies this subscription
78      */
79     private CharSequence mDisplayName;
80 
81     /**
82      * String that identifies SPN/PLMN
83      * TODO : Add a new field that identifies only SPN for a sim
84      */
85     private CharSequence mCarrierName;
86 
87     /**
88      * The subscription carrier id.
89      * @see TelephonyManager#getSimCarrierId()
90      */
91     private int mCarrierId;
92 
93     /**
94      * The source of the name, NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SPN,
95      * NAME_SOURCE_SIM_PNN, or NAME_SOURCE_USER_INPUT.
96      */
97     private int mNameSource;
98 
99     /**
100      * The color to be used for tinting the icon when displaying to the user
101      */
102     private int mIconTint;
103 
104     /**
105      * A number presented to the user identify this subscription
106      */
107     private String mNumber;
108 
109     /**
110      * Data roaming state, DATA_ROAMING_ENABLE, DATA_ROAMING_DISABLE
111      */
112     private int mDataRoaming;
113 
114     /**
115      * SIM Icon bitmap
116      */
117     private Bitmap mIconBitmap;
118 
119     /**
120      * Mobile Country Code
121      */
122     private String mMcc;
123 
124     /**
125      * Mobile Network Code
126      */
127     private String mMnc;
128 
129     /**
130      * EHPLMNs associated with the subscription
131      */
132     private String[] mEhplmns;
133 
134     /**
135      * HPLMNs associated with the subscription
136      */
137     private String[] mHplmns;
138 
139     /**
140      * ISO Country code for the subscription's provider
141      */
142     private String mCountryIso;
143 
144     /**
145      * Whether the subscription is an embedded one.
146      */
147     private boolean mIsEmbedded;
148 
149     /**
150      * The access rules for this subscription, if it is embedded and defines any.
151      */
152     @Nullable
153     private UiccAccessRule[] mNativeAccessRules;
154 
155     /**
156      * The carrier certificates for this subscription that are saved in carrier configs.
157      * The other carrier certificates are embedded on Uicc and stored as part of mNativeAccessRules.
158      */
159     @Nullable
160     private UiccAccessRule[] mCarrierConfigAccessRules;
161 
162     /**
163      * The string ID of the SIM card. It is the ICCID of the active profile for a UICC card and the
164      * EID for an eUICC card.
165      */
166     private String mCardString;
167 
168     /**
169      * The card ID of the SIM card. This maps uniquely to the card string.
170      */
171     private int mCardId;
172 
173     /**
174      * Whether the subscription is opportunistic.
175      */
176     private boolean mIsOpportunistic;
177 
178     /**
179      * A UUID assigned to the subscription group. It returns null if not assigned.
180      * Check {@link SubscriptionManager#createSubscriptionGroup(List)} for more details.
181      */
182     @Nullable
183     private ParcelUuid mGroupUUID;
184 
185     /**
186      * A package name that specifies who created the group. Null if mGroupUUID is null.
187      */
188     private String mGroupOwner;
189 
190     /**
191      * Whether group of the subscription is disabled.
192      * This is only useful if it's a grouped opportunistic subscription. In this case, if all
193      * primary (non-opportunistic) subscriptions in the group are deactivated (unplugged pSIM
194      * or deactivated eSIM profile), we should disable this opportunistic subscription.
195      */
196     private boolean mIsGroupDisabled = false;
197 
198     /**
199      * Profile class, PROFILE_CLASS_TESTING, PROFILE_CLASS_OPERATIONAL
200      * PROFILE_CLASS_PROVISIONING, or PROFILE_CLASS_UNSET.
201      * A profile on the eUICC can be defined as test, operational, provisioning, or unset.
202      * The profile class will be populated from the profile metadata if present. Otherwise,
203      * the profile class defaults to unset if there is no profile metadata or the subscription
204      * is not on an eUICC ({@link #isEmbedded} returns false).
205      */
206     private int mProfileClass;
207 
208     /**
209      * Type of subscription
210      */
211     private int mSubscriptionType;
212 
213     /**
214      * Whether uicc applications are configured to enable or disable.
215      * By default it's true.
216      */
217     private boolean mAreUiccApplicationsEnabled = true;
218 
219     /**
220      * @hide
221      */
SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, @Nullable UiccAccessRule[] nativeAccessRules, String cardString)222     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
223             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
224             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
225             @Nullable UiccAccessRule[] nativeAccessRules, String cardString) {
226         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
227                 roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, -1,
228                 false, null, false, TelephonyManager.UNKNOWN_CARRIER_ID,
229                 SubscriptionManager.PROFILE_CLASS_UNSET,
230                 SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true);
231     }
232 
233     /**
234      * @hide
235      */
SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, @Nullable UiccAccessRule[] nativeAccessRules, String cardString, boolean isOpportunistic, @Nullable String groupUUID, int carrierId, int profileClass)236     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
237             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
238             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
239             @Nullable UiccAccessRule[] nativeAccessRules, String cardString,
240             boolean isOpportunistic, @Nullable String groupUUID, int carrierId, int profileClass) {
241         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
242                 roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, -1,
243                 isOpportunistic, groupUUID, false, carrierId, profileClass,
244                 SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true);
245     }
246 
247     /**
248      * @hide
249      */
SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, @Nullable UiccAccessRule[] nativeAccessRules, String cardString, int cardId, boolean isOpportunistic, @Nullable String groupUUID, boolean isGroupDisabled, int carrierId, int profileClass, int subType, @Nullable String groupOwner, @Nullable UiccAccessRule[] carrierConfigAccessRules, boolean areUiccApplicationsEnabled)250     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
251             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
252             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
253             @Nullable UiccAccessRule[] nativeAccessRules, String cardString, int cardId,
254             boolean isOpportunistic, @Nullable String groupUUID, boolean isGroupDisabled,
255             int carrierId, int profileClass, int subType, @Nullable String groupOwner,
256             @Nullable UiccAccessRule[] carrierConfigAccessRules,
257             boolean areUiccApplicationsEnabled) {
258         this.mId = id;
259         this.mIccId = iccId;
260         this.mSimSlotIndex = simSlotIndex;
261         this.mDisplayName = displayName;
262         this.mCarrierName = carrierName;
263         this.mNameSource = nameSource;
264         this.mIconTint = iconTint;
265         this.mNumber = number;
266         this.mDataRoaming = roaming;
267         this.mIconBitmap = icon;
268         this.mMcc = mcc;
269         this.mMnc = mnc;
270         this.mCountryIso = countryIso;
271         this.mIsEmbedded = isEmbedded;
272         this.mNativeAccessRules = nativeAccessRules;
273         this.mCardString = cardString;
274         this.mCardId = cardId;
275         this.mIsOpportunistic = isOpportunistic;
276         this.mGroupUUID = groupUUID == null ? null : ParcelUuid.fromString(groupUUID);
277         this.mIsGroupDisabled = isGroupDisabled;
278         this.mCarrierId = carrierId;
279         this.mProfileClass = profileClass;
280         this.mSubscriptionType = subType;
281         this.mGroupOwner = groupOwner;
282         this.mCarrierConfigAccessRules = carrierConfigAccessRules;
283         this.mAreUiccApplicationsEnabled = areUiccApplicationsEnabled;
284     }
285 
286     /**
287      * @return the subscription ID.
288      */
getSubscriptionId()289     public int getSubscriptionId() {
290         return this.mId;
291     }
292 
293     /**
294      * @return the ICC ID.
295      */
getIccId()296     public String getIccId() {
297         return this.mIccId;
298     }
299 
300     /**
301      * @return the slot index of this Subscription's SIM card.
302      */
getSimSlotIndex()303     public int getSimSlotIndex() {
304         return this.mSimSlotIndex;
305     }
306 
307     /**
308      * @return the carrier id of this Subscription carrier.
309      * @see TelephonyManager#getSimCarrierId()
310      */
getCarrierId()311     public int getCarrierId() {
312         return this.mCarrierId;
313     }
314 
315     /**
316      * @return the name displayed to the user that identifies this subscription
317      */
getDisplayName()318     public CharSequence getDisplayName() {
319         return this.mDisplayName;
320     }
321 
322     /**
323      * Sets the name displayed to the user that identifies this subscription
324      * @hide
325      */
326     @UnsupportedAppUsage
setDisplayName(CharSequence name)327     public void setDisplayName(CharSequence name) {
328         this.mDisplayName = name;
329     }
330 
331     /**
332      * @return the name displayed to the user that identifies Subscription provider name
333      */
getCarrierName()334     public CharSequence getCarrierName() {
335         return this.mCarrierName;
336     }
337 
338     /**
339      * Sets the name displayed to the user that identifies Subscription provider name
340      * @hide
341      */
setCarrierName(CharSequence name)342     public void setCarrierName(CharSequence name) {
343         this.mCarrierName = name;
344     }
345 
346     /**
347      * @return the source of the name, eg NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SPN or
348      * NAME_SOURCE_USER_INPUT.
349      * @hide
350      */
351     @UnsupportedAppUsage
getNameSource()352     public int getNameSource() {
353         return this.mNameSource;
354     }
355 
356     /**
357      * @hide
358      */
setAssociatedPlmns(String[] ehplmns, String[] hplmns)359     public void setAssociatedPlmns(String[] ehplmns, String[] hplmns) {
360         mEhplmns = ehplmns;
361         mHplmns = hplmns;
362     }
363 
364     /**
365      * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a
366      * user interface.
367      *
368      * @param context A {@code Context} to get the {@code DisplayMetrics}s from.
369      *
370      * @return A bitmap icon for this {@code SubscriptionInfo}.
371      */
createIconBitmap(Context context)372     public Bitmap createIconBitmap(Context context) {
373         int width = mIconBitmap.getWidth();
374         int height = mIconBitmap.getHeight();
375         DisplayMetrics metrics = context.getResources().getDisplayMetrics();
376 
377         // Create a new bitmap of the same size because it will be modified.
378         Bitmap workingBitmap = Bitmap.createBitmap(metrics, width, height, mIconBitmap.getConfig());
379 
380         Canvas canvas = new Canvas(workingBitmap);
381         Paint paint = new Paint();
382 
383         // Tint the icon with the color.
384         paint.setColorFilter(new PorterDuffColorFilter(mIconTint, PorterDuff.Mode.SRC_ATOP));
385         canvas.drawBitmap(mIconBitmap, 0, 0, paint);
386         paint.setColorFilter(null);
387 
388         // Write the sim slot index.
389         paint.setAntiAlias(true);
390         paint.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL));
391         paint.setColor(Color.WHITE);
392         // Set text size scaled by density
393         paint.setTextSize(TEXT_SIZE * metrics.density);
394         // Convert sim slot index to localized string
395         final String index = String.format("%d", mSimSlotIndex + 1);
396         final Rect textBound = new Rect();
397         paint.getTextBounds(index, 0, 1, textBound);
398         final float xOffset = (width / 2.f) - textBound.centerX();
399         final float yOffset = (height / 2.f) - textBound.centerY();
400         canvas.drawText(index, xOffset, yOffset, paint);
401 
402         return workingBitmap;
403     }
404 
405     /**
406      * A highlight color to use in displaying information about this {@code PhoneAccount}.
407      *
408      * @return A hexadecimal color value.
409      */
getIconTint()410     public int getIconTint() {
411         return mIconTint;
412     }
413 
414     /**
415      * Sets the color displayed to the user that identifies this subscription
416      * @hide
417      */
418     @UnsupportedAppUsage
setIconTint(int iconTint)419     public void setIconTint(int iconTint) {
420         this.mIconTint = iconTint;
421     }
422 
423     /**
424      * @return the number of this subscription.
425      */
getNumber()426     public String getNumber() {
427         return mNumber;
428     }
429 
430     /**
431      * @return the data roaming state for this subscription, either
432      * {@link SubscriptionManager#DATA_ROAMING_ENABLE} or {@link SubscriptionManager#DATA_ROAMING_DISABLE}.
433      */
getDataRoaming()434     public int getDataRoaming() {
435         return this.mDataRoaming;
436     }
437 
438     /**
439      * @return the MCC.
440      * @deprecated Use {@link #getMccString()} instead.
441      */
442     @Deprecated
getMcc()443     public int getMcc() {
444         try {
445             return this.mMcc == null ? 0 : Integer.valueOf(this.mMcc);
446         } catch (NumberFormatException e) {
447             Log.w(SubscriptionInfo.class.getSimpleName(), "MCC string is not a number");
448             return 0;
449         }
450     }
451 
452     /**
453      * @return the MNC.
454      * @deprecated Use {@link #getMncString()} instead.
455      */
456     @Deprecated
getMnc()457     public int getMnc() {
458         try {
459             return this.mMnc == null ? 0 : Integer.valueOf(this.mMnc);
460         } catch (NumberFormatException e) {
461             Log.w(SubscriptionInfo.class.getSimpleName(), "MNC string is not a number");
462             return 0;
463         }
464     }
465 
466     /**
467      * @return The MCC, as a string.
468      */
getMccString()469     public @Nullable String getMccString() {
470         return this.mMcc;
471     }
472 
473     /**
474      * @return The MNC, as a string.
475      */
getMncString()476     public @Nullable String getMncString() {
477         return this.mMnc;
478     }
479 
480     /**
481      * @return the ISO country code
482      */
getCountryIso()483     public String getCountryIso() {
484         return this.mCountryIso;
485     }
486 
487     /** @return whether the subscription is an eUICC one. */
isEmbedded()488     public boolean isEmbedded() {
489         return this.mIsEmbedded;
490     }
491 
492     /**
493      * An opportunistic subscription connects to a network that is
494      * limited in functionality and / or coverage.
495      *
496      * @return whether subscription is opportunistic.
497      */
isOpportunistic()498     public boolean isOpportunistic() {
499         return mIsOpportunistic;
500     }
501 
502     /**
503      * Used in scenarios where different subscriptions are bundled as a group.
504      * It's typically a primary and an opportunistic subscription. (see {@link #isOpportunistic()})
505      * Such that those subscriptions will have some affiliated behaviors such as opportunistic
506      * subscription may be invisible to the user.
507      *
508      * @return group UUID a String of group UUID if it belongs to a group. Otherwise
509      * it will return null.
510      */
getGroupUuid()511     public @Nullable ParcelUuid getGroupUuid() {
512         return mGroupUUID;
513     }
514 
515     /**
516      * @hide
517      */
getEhplmns()518     public List<String> getEhplmns() {
519         return mEhplmns == null ? Collections.emptyList() : Arrays.asList(mEhplmns);
520     }
521 
522     /**
523      * @hide
524      */
getHplmns()525     public List<String> getHplmns() {
526         return mHplmns == null ? Collections.emptyList() : Arrays.asList(mHplmns);
527     }
528 
529     /**
530      * Return owner package of group the subscription belongs to.
531      *
532      * @hide
533      */
getGroupOwner()534     public @Nullable String getGroupOwner() {
535         return mGroupOwner;
536     }
537 
538     /**
539      * @return the profile class of this subscription.
540      * @hide
541      */
542     @SystemApi
getProfileClass()543     public @SubscriptionManager.ProfileClass int getProfileClass() {
544         return this.mProfileClass;
545     }
546 
547     /**
548      * This method returns the type of a subscription. It can be
549      * {@link SubscriptionManager#SUBSCRIPTION_TYPE_LOCAL_SIM} or
550      * {@link SubscriptionManager#SUBSCRIPTION_TYPE_REMOTE_SIM}.
551      * @return the type of subscription
552      */
getSubscriptionType()553     public @SubscriptionManager.SubscriptionType int getSubscriptionType() {
554         return mSubscriptionType;
555     }
556 
557     /**
558      * Checks whether the app with the given context is authorized to manage this subscription
559      * according to its metadata. Only supported for embedded subscriptions (if {@link #isEmbedded}
560      * returns true).
561      *
562      * @param context Context of the application to check.
563      * @return whether the app is authorized to manage this subscription per its metadata.
564      * @hide
565      * @deprecated - Do not use.
566      */
567     @Deprecated
canManageSubscription(Context context)568     public boolean canManageSubscription(Context context) {
569         return canManageSubscription(context, context.getPackageName());
570     }
571 
572     /**
573      * Checks whether the given app is authorized to manage this subscription according to its
574      * metadata. Only supported for embedded subscriptions (if {@link #isEmbedded} returns true).
575      *
576      * @param context Any context.
577      * @param packageName Package name of the app to check.
578      * @return whether the app is authorized to manage this subscription per its metadata.
579      * @hide
580      * @deprecated - Do not use.
581      */
582     @Deprecated
canManageSubscription(Context context, String packageName)583     public boolean canManageSubscription(Context context, String packageName) {
584         List<UiccAccessRule> allAccessRules = getAllAccessRules();
585         if (allAccessRules == null) {
586             return false;
587         }
588         PackageManager packageManager = context.getPackageManager();
589         PackageInfo packageInfo;
590         try {
591             packageInfo = packageManager.getPackageInfo(packageName,
592                 PackageManager.GET_SIGNING_CERTIFICATES);
593         } catch (PackageManager.NameNotFoundException e) {
594             Log.d("SubscriptionInfo", "canManageSubscription: Unknown package: " + packageName, e);
595             return false;
596         }
597         for (UiccAccessRule rule : allAccessRules) {
598             if (rule.getCarrierPrivilegeStatus(packageInfo)
599                     == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
600                 return true;
601             }
602         }
603         return false;
604     }
605 
606     /**
607      * @return the {@link UiccAccessRule}s that are stored in Uicc, dictating who
608      * is authorized to manage this subscription.
609      * TODO and fix it properly in R / master: either deprecate this and have 3 APIs
610      *  native + carrier + all, or have this return all by default.
611      * @throws UnsupportedOperationException if this subscription is not embedded.
612      * @hide
613      */
614     @SystemApi
getAccessRules()615     public @Nullable List<UiccAccessRule> getAccessRules() {
616         if (mNativeAccessRules == null) return null;
617         return Arrays.asList(mNativeAccessRules);
618     }
619 
620     /**
621      * @return the {@link UiccAccessRule}s that are both stored on Uicc and in carrierConfigs
622      * dictating who is authorized to manage this subscription.
623      * @hide
624      */
getAllAccessRules()625     public @Nullable List<UiccAccessRule> getAllAccessRules() {
626         List<UiccAccessRule> merged = new ArrayList<>();
627         if (mNativeAccessRules != null) {
628             merged.addAll(getAccessRules());
629         }
630         if (mCarrierConfigAccessRules != null) {
631             merged.addAll(Arrays.asList(mCarrierConfigAccessRules));
632         }
633         return merged.isEmpty() ? null : merged;
634     }
635 
636     /**
637      * @return the card string of the SIM card which contains the subscription. The card string is
638      * the ICCID for UICCs or the EID for eUICCs.
639      * @hide
640      * //TODO rename usages in LPA: UiccSlotUtil.java, UiccSlotsManager.java, UiccSlotInfoTest.java
641      */
getCardString()642     public String getCardString() {
643         return this.mCardString;
644     }
645 
646     /**
647      * Returns the card ID of the SIM card which contains the subscription (see
648      * {@link UiccCardInfo#getCardId()}.
649      * @return the cardId
650      */
getCardId()651     public int getCardId() {
652         return this.mCardId;
653     }
654 
655     /**
656      * Set whether the subscription's group is disabled.
657      * @hide
658      */
setGroupDisabled(boolean isGroupDisabled)659     public void setGroupDisabled(boolean isGroupDisabled) {
660         this.mIsGroupDisabled = isGroupDisabled;
661     }
662 
663     /**
664      * Return whether the subscription's group is disabled.
665      * @hide
666      */
667     @SystemApi
isGroupDisabled()668     public boolean isGroupDisabled() {
669         return mIsGroupDisabled;
670     }
671 
672     /**
673      * Return whether uicc applications are set to be enabled or disabled.
674      * @hide
675      */
676     @SystemApi
areUiccApplicationsEnabled()677     public boolean areUiccApplicationsEnabled() {
678         return mAreUiccApplicationsEnabled;
679     }
680 
681     public static final @android.annotation.NonNull Parcelable.Creator<SubscriptionInfo> CREATOR = new Parcelable.Creator<SubscriptionInfo>() {
682         @Override
683         public SubscriptionInfo createFromParcel(Parcel source) {
684             int id = source.readInt();
685             String iccId = source.readString();
686             int simSlotIndex = source.readInt();
687             CharSequence displayName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
688             CharSequence carrierName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
689             int nameSource = source.readInt();
690             int iconTint = source.readInt();
691             String number = source.readString();
692             int dataRoaming = source.readInt();
693             String mcc = source.readString();
694             String mnc = source.readString();
695             String countryIso = source.readString();
696             Bitmap iconBitmap = source.readParcelable(Bitmap.class.getClassLoader());
697             boolean isEmbedded = source.readBoolean();
698             UiccAccessRule[] nativeAccessRules = source.createTypedArray(UiccAccessRule.CREATOR);
699             String cardString = source.readString();
700             int cardId = source.readInt();
701             boolean isOpportunistic = source.readBoolean();
702             String groupUUID = source.readString();
703             boolean isGroupDisabled = source.readBoolean();
704             int carrierid = source.readInt();
705             int profileClass = source.readInt();
706             int subType = source.readInt();
707             String[] ehplmns = source.createStringArray();
708             String[] hplmns = source.createStringArray();
709             String groupOwner = source.readString();
710             UiccAccessRule[] carrierConfigAccessRules = source.createTypedArray(
711                 UiccAccessRule.CREATOR);
712             boolean areUiccApplicationsEnabled = source.readBoolean();
713 
714             SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName,
715                     carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc,
716                     countryIso, isEmbedded, nativeAccessRules, cardString, cardId, isOpportunistic,
717                     groupUUID, isGroupDisabled, carrierid, profileClass, subType, groupOwner,
718                     carrierConfigAccessRules, areUiccApplicationsEnabled);
719             info.setAssociatedPlmns(ehplmns, hplmns);
720             return info;
721         }
722 
723         @Override
724         public SubscriptionInfo[] newArray(int size) {
725             return new SubscriptionInfo[size];
726         }
727     };
728 
729     @Override
writeToParcel(Parcel dest, int flags)730     public void writeToParcel(Parcel dest, int flags) {
731         dest.writeInt(mId);
732         dest.writeString(mIccId);
733         dest.writeInt(mSimSlotIndex);
734         TextUtils.writeToParcel(mDisplayName, dest, 0);
735         TextUtils.writeToParcel(mCarrierName, dest, 0);
736         dest.writeInt(mNameSource);
737         dest.writeInt(mIconTint);
738         dest.writeString(mNumber);
739         dest.writeInt(mDataRoaming);
740         dest.writeString(mMcc);
741         dest.writeString(mMnc);
742         dest.writeString(mCountryIso);
743         dest.writeParcelable(mIconBitmap, flags);
744         dest.writeBoolean(mIsEmbedded);
745         dest.writeTypedArray(mNativeAccessRules, flags);
746         dest.writeString(mCardString);
747         dest.writeInt(mCardId);
748         dest.writeBoolean(mIsOpportunistic);
749         dest.writeString(mGroupUUID == null ? null : mGroupUUID.toString());
750         dest.writeBoolean(mIsGroupDisabled);
751         dest.writeInt(mCarrierId);
752         dest.writeInt(mProfileClass);
753         dest.writeInt(mSubscriptionType);
754         dest.writeStringArray(mEhplmns);
755         dest.writeStringArray(mHplmns);
756         dest.writeString(mGroupOwner);
757         dest.writeTypedArray(mCarrierConfigAccessRules, flags);
758         dest.writeBoolean(mAreUiccApplicationsEnabled);
759     }
760 
761     @Override
describeContents()762     public int describeContents() {
763         return 0;
764     }
765 
766     /**
767      * @hide
768      */
givePrintableIccid(String iccId)769     public static String givePrintableIccid(String iccId) {
770         String iccIdToPrint = null;
771         if (iccId != null) {
772             if (iccId.length() > 9 && !TelephonyUtils.IS_DEBUGGABLE) {
773                 iccIdToPrint = iccId.substring(0, 9) + Rlog.pii(false, iccId.substring(9));
774             } else {
775                 iccIdToPrint = iccId;
776             }
777         }
778         return iccIdToPrint;
779     }
780 
781     @Override
toString()782     public String toString() {
783         String iccIdToPrint = givePrintableIccid(mIccId);
784         String cardStringToPrint = givePrintableIccid(mCardString);
785         return "{id=" + mId + " iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex
786                 + " carrierId=" + mCarrierId + " displayName=" + mDisplayName
787                 + " carrierName=" + mCarrierName + " nameSource=" + mNameSource
788                 + " iconTint=" + mIconTint
789                 + " mNumber=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumber)
790                 + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
791                 + " mnc " + mMnc + "mCountryIso=" + mCountryIso + " isEmbedded " + mIsEmbedded
792                 + " nativeAccessRules " + Arrays.toString(mNativeAccessRules)
793                 + " cardString=" + cardStringToPrint + " cardId=" + mCardId
794                 + " isOpportunistic=" + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
795                 + " mIsGroupDisabled=" + mIsGroupDisabled
796                 + " profileClass=" + mProfileClass
797                 + " ehplmns=" + Arrays.toString(mEhplmns)
798                 + " hplmns=" + Arrays.toString(mHplmns)
799                 + " subscriptionType=" + mSubscriptionType
800                 + " mGroupOwner=" + mGroupOwner
801                 + " carrierConfigAccessRules=" + Arrays.toString(mCarrierConfigAccessRules)
802                 + " mAreUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled + "}";
803     }
804 
805     @Override
hashCode()806     public int hashCode() {
807         return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
808                 mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc, mCountryIso, mCardString,
809                 mCardId, mDisplayName, mCarrierName, mNativeAccessRules, mIsGroupDisabled,
810                 mCarrierId, mProfileClass, mGroupOwner, mAreUiccApplicationsEnabled);
811     }
812 
813     @Override
equals(Object obj)814     public boolean equals(Object obj) {
815         if (obj == null) return false;
816         if (obj == this) return true;
817 
818         SubscriptionInfo toCompare;
819         try {
820             toCompare = (SubscriptionInfo) obj;
821         } catch (ClassCastException ex) {
822             return false;
823         }
824 
825         return mId == toCompare.mId
826                 && mSimSlotIndex == toCompare.mSimSlotIndex
827                 && mNameSource == toCompare.mNameSource
828                 && mIconTint == toCompare.mIconTint
829                 && mDataRoaming == toCompare.mDataRoaming
830                 && mIsEmbedded == toCompare.mIsEmbedded
831                 && mIsOpportunistic == toCompare.mIsOpportunistic
832                 && mIsGroupDisabled == toCompare.mIsGroupDisabled
833                 && mAreUiccApplicationsEnabled == toCompare.mAreUiccApplicationsEnabled
834                 && mCarrierId == toCompare.mCarrierId
835                 && Objects.equals(mGroupUUID, toCompare.mGroupUUID)
836                 && Objects.equals(mIccId, toCompare.mIccId)
837                 && Objects.equals(mNumber, toCompare.mNumber)
838                 && Objects.equals(mMcc, toCompare.mMcc)
839                 && Objects.equals(mMnc, toCompare.mMnc)
840                 && Objects.equals(mCountryIso, toCompare.mCountryIso)
841                 && Objects.equals(mCardString, toCompare.mCardString)
842                 && Objects.equals(mCardId, toCompare.mCardId)
843                 && Objects.equals(mGroupOwner, toCompare.mGroupOwner)
844                 && TextUtils.equals(mDisplayName, toCompare.mDisplayName)
845                 && TextUtils.equals(mCarrierName, toCompare.mCarrierName)
846                 && Arrays.equals(mNativeAccessRules, toCompare.mNativeAccessRules)
847                 && mProfileClass == toCompare.mProfileClass
848                 && Arrays.equals(mEhplmns, toCompare.mEhplmns)
849                 && Arrays.equals(mHplmns, toCompare.mHplmns);
850     }
851 }
852