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