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