Home | History | Annotate | Download | only in model
      1 /*
      2  * Copyright (C) 2016 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 package com.android.contacts.model;
     17 
     18 import android.os.Build;
     19 import android.support.annotation.RequiresApi;
     20 import android.telephony.PhoneNumberUtils;
     21 import android.telephony.SubscriptionInfo;
     22 import android.telephony.TelephonyManager;
     23 import android.util.Log;
     24 
     25 import java.util.ArrayList;
     26 import java.util.Arrays;
     27 import java.util.List;
     28 import java.util.Locale;
     29 import java.util.Objects;
     30 
     31 /**
     32  * Holds data for a SIM card in the device.
     33  */
     34 public class SimCard {
     35 
     36     private static final String TAG = "SimCard";
     37 
     38     public static final int NO_SUBSCRIPTION_ID = -1;
     39 
     40     // This state is created from the info we get from the system
     41     private final String mSimId;
     42     private final int mSubscriptionId;
     43     private final CharSequence mCarrierName;
     44     private final CharSequence mDisplayName;
     45     private final String mPhoneNumber;
     46     private final String mCountryCode;
     47 
     48     // This is our own state that we associate with SIM cards. Currently these are only used
     49     // in the GoogleContacts app.
     50     // Note: these are logically immutable but are not final to reduce required constructor
     51     // parameters
     52     private boolean mDismissed = false;
     53     private boolean mImported = false;
     54 
     55     private List<SimContact> mContacts;
     56 
     57     public SimCard(SimCard other) {
     58         mSimId = other.mSimId;
     59         mSubscriptionId = other.mSubscriptionId;
     60         mCarrierName = other.mCarrierName;
     61         mDisplayName = other.mDisplayName;
     62         mPhoneNumber = other.mPhoneNumber;
     63         mCountryCode = other.mCountryCode;
     64         mDismissed = other.mDismissed;
     65         mImported = other.mImported;
     66         if (other.mContacts != null) {
     67             mContacts = new ArrayList<>(other.mContacts);
     68         }
     69     }
     70 
     71     public SimCard(String simId, int subscriptionId, CharSequence carrierName,
     72             CharSequence displayName, String phoneNumber, String countryCode) {
     73         mSimId = simId;
     74         mSubscriptionId = subscriptionId;
     75         mCarrierName = carrierName;
     76         mDisplayName = displayName;
     77         mPhoneNumber = phoneNumber;
     78         mCountryCode = countryCode != null ? countryCode.toUpperCase(Locale.US) : null;
     79     }
     80 
     81     public SimCard(String simId, CharSequence carrierName,
     82             CharSequence displayName, String phoneNumber, String countryCode) {
     83         this(simId, NO_SUBSCRIPTION_ID, carrierName, displayName, phoneNumber, countryCode);
     84     }
     85 
     86     public String getSimId() {
     87         return mSimId;
     88     }
     89 
     90     public int getSubscriptionId() {
     91         return mSubscriptionId;
     92     }
     93 
     94     public boolean hasValidSubscriptionId() {
     95         return mSubscriptionId != NO_SUBSCRIPTION_ID;
     96     }
     97 
     98     public CharSequence getDisplayName() {
     99         return mDisplayName;
    100     }
    101 
    102     public String getPhone() {
    103         return mPhoneNumber;
    104     }
    105 
    106     public CharSequence getFormattedPhone() {
    107         if (mPhoneNumber == null) {
    108             return null;
    109         }
    110         return PhoneNumberUtils.formatNumber(mPhoneNumber, mCountryCode);
    111     }
    112 
    113     public boolean hasPhone() {
    114         return mPhoneNumber != null;
    115     }
    116 
    117     public String getCountryCode() {
    118         return mCountryCode;
    119     }
    120 
    121     /**
    122      * Returns whether the contacts for this SIM card have been initialized.
    123      */
    124     public boolean areContactsAvailable() {
    125         return mContacts != null;
    126     }
    127 
    128     /**
    129      * Returns whether this SIM card has any SIM contacts.
    130      *
    131      * A precondition of this method is that the contacts have been initialized.
    132      */
    133     public boolean hasContacts() {
    134         if (mContacts == null) {
    135             throw new IllegalStateException("Contacts not loaded.");
    136         }
    137         return !mContacts.isEmpty();
    138     }
    139 
    140     /**
    141      * Returns the number of contacts stored on this SIM card.
    142      *
    143      * A precondition of this method is that the contacts have been initialized.
    144      */
    145     public int getContactCount() {
    146         if (mContacts == null) {
    147             throw new IllegalStateException("Contacts not loaded.");
    148         }
    149         return mContacts.size();
    150     }
    151 
    152     public boolean isDismissed() {
    153         return mDismissed;
    154     }
    155 
    156     public boolean isImported() {
    157         return mImported;
    158     }
    159 
    160     public boolean isImportable() {
    161         if (Log.isLoggable(TAG, Log.DEBUG)) {
    162             Log.d(TAG, "isImportable: isDismissed? " + isDismissed() +
    163                     " isImported? " + isImported() + " contacts=" + mContacts);
    164         }
    165         return !isDismissed() && !isImported() && hasContacts();
    166     }
    167 
    168     /**
    169      * Returns the contacts for this SIM card or null if the contacts have not been initialized.
    170      */
    171     public List<SimContact> getContacts() {
    172         return mContacts;
    173     }
    174 
    175     public SimCard withImportAndDismissStates(boolean imported, boolean dismissed) {
    176         SimCard copy = new SimCard(this);
    177         copy.mImported = imported;
    178         copy.mDismissed = dismissed;
    179         return copy;
    180     }
    181 
    182     public SimCard withImportedState(boolean imported) {
    183         return withImportAndDismissStates(imported, mDismissed);
    184     }
    185 
    186     public SimCard withDismissedState(boolean dismissed) {
    187         return withImportAndDismissStates(mImported, dismissed);
    188     }
    189 
    190     public SimCard withContacts(List<SimContact> contacts) {
    191         final SimCard copy = new SimCard(this);
    192         copy.mContacts = contacts;
    193         return copy;
    194     }
    195 
    196     public SimCard withContacts(SimContact... contacts) {
    197         final SimCard copy = new SimCard(this);
    198         copy.mContacts = Arrays.asList(contacts);
    199         return copy;
    200     }
    201 
    202     @Override
    203     public boolean equals(Object o) {
    204         if (this == o) return true;
    205         if (o == null || getClass() != o.getClass()) return false;
    206 
    207         SimCard simCard = (SimCard) o;
    208 
    209         return mSubscriptionId == simCard.mSubscriptionId && mDismissed == simCard.mDismissed &&
    210                 mImported == simCard.mImported && Objects.equals(mSimId, simCard.mSimId) &&
    211                 Objects.equals(mPhoneNumber, simCard.mPhoneNumber) &&
    212                 Objects.equals(mCountryCode, simCard.mCountryCode);
    213     }
    214 
    215     @Override
    216     public int hashCode() {
    217         int result = Objects.hash(mSimId, mPhoneNumber, mCountryCode);
    218         result = 31 * result + mSubscriptionId;
    219         result = 31 * result + (mDismissed ? 1 : 0);
    220         result = 31 * result + (mImported ? 1 : 0);
    221         return result;
    222     }
    223 
    224     @Override
    225     public String toString() {
    226         return "SimCard{" +
    227                 "mSimId='" + mSimId + '\'' +
    228                 ", mSubscriptionId=" + mSubscriptionId +
    229                 ", mCarrierName=" + mCarrierName +
    230                 ", mDisplayName=" + mDisplayName +
    231                 ", mPhoneNumber='" + mPhoneNumber + '\'' +
    232                 ", mCountryCode='" + mCountryCode + '\'' +
    233                 ", mDismissed=" + mDismissed +
    234                 ", mImported=" + mImported +
    235                 ", mContacts=" + mContacts +
    236                 '}';
    237     }
    238 
    239     @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
    240     public static SimCard create(SubscriptionInfo info) {
    241         return new SimCard(info.getIccId(), info.getSubscriptionId(),
    242                 info.getCarrierName(), info.getDisplayName(), info.getNumber(),
    243                 info.getCountryIso());
    244     }
    245 
    246     public static SimCard create(TelephonyManager telephony, String displayLabel) {
    247         if (telephony.getSimState() == TelephonyManager.SIM_STATE_READY) {
    248             return new SimCard(telephony.getSimSerialNumber(),
    249                     telephony.getSimOperatorName(), displayLabel, telephony.getLine1Number(),
    250                     telephony.getSimCountryIso());
    251         } else {
    252             // This should never happen but in case it does just fallback to an "empty" instance
    253             return new SimCard(/* SIM id */ "", /* operator name */ null, displayLabel,
    254                     /* phone number */ "", /* Country code */ null);
    255         }
    256     }
    257 }
    258