(M)SIM卡开机流程分析之TelephonyManager类分析

首先在PhoneFactory的makeDefaultPhone方法中,调用了TelephonyManager.getDefault方法

int numPhones = TelephonyManager.getDefault().getPhoneCount();
查看TelephonyManager的getDefault方法

// Leo, 全局变量
    private static TelephonyManager sInstance = new TelephonyManager();

    /** @hide
    /* @deprecated - use getSystemService as described above */
    public static TelephonyManager getDefault() {
        return sInstance;
    }
可以看到,就是返回了一个全局TelephonyManager对象

/**
     * Returns the number of phones available.
     * Returns 1 for Single standby mode (Single SIM functionality)
     * Returns 2 for Dual standby mode.(Dual SIM functionality)
     */
    public int getPhoneCount() {
        int phoneCount = 1;
        switch (getMultiSimConfiguration()) {
            case UNKNOWN:
                phoneCount = 1;
                break;
            case DSDS:
            case DSDA:
                phoneCount = PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
                break;
            case TSTS:
                phoneCount = PhoneConstants.MAX_PHONE_COUNT_TRI_SIM;
                break;
        }
        return phoneCount;
    }
/**
     * Returns the multi SIM variant
     * Returns DSDS for Dual SIM Dual Standby
     * Returns DSDA for Dual SIM Dual Active
     * Returns TSTS for Triple SIM Triple Standby
     * Returns UNKNOWN for others
     */
    /** {@hide} */
    public MultiSimVariants getMultiSimConfiguration() {
        String mSimConfig =
            SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
        if (mSimConfig.equals("dsds")) {
            return MultiSimVariants.DSDS;
        } else if (mSimConfig.equals("dsda")) {
            return MultiSimVariants.DSDA;
        } else if (mSimConfig.equals("tsts")) {
            return MultiSimVariants.TSTS;
        } else {
            return MultiSimVariants.UNKNOWN;
        }
    }
所以,

int numPhones = TelephonyManager.getDefault().getPhoneCount();
这个语句就是根据用户预设定的persist.radio.multisim.config值,来确定当前是单卡项目还是多卡项目,返回的是手机所支持的卡槽数量。

我们通常看到的获取TelephonyManager对象的方法,都是通过调用

TelephonyManager.from(context)
方法,而且看到上述无参构造函数中注释中说明,获取其对象一般需要使用getSystemService方法来获取,来看看TelephonyManager的from方法

/** {@hide} */
    public static TelephonyManager from(Context context) {
        return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    }
可以看到,如google原始注释,需要使用getSystemService方法来获取其对象,而从之前对于getSystemService方法分析,可以知道,其就是通过TelephonyManager(context)构造函数来生成TelephonyManager对象的

/** @hide */
    public TelephonyManager(Context context) {
        Context appContext = context.getApplicationContext();
        if (appContext != null) {
            mContext = appContext;
        } else {
            mContext = context;
        }
        mSubscriptionManager = SubscriptionManager.from(mContext);

        if (sRegistry == null) {
            sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                    "telephony.registry"));
        }
    }
同样地,SubscriptionManager的from方法

/**
     * Get an instance of the SubscriptionManager from the Context.
     * This invokes {@link android.content.Context#getSystemService
     * Context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)}.
     *
     * @param context to use.
     * @return SubscriptionManager instance
     */
    public static SubscriptionManager from(Context context) {
        return (SubscriptionManager) context.getSystemService(
                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
    }
通过查看SystemServiceRegistry.java的方法
registerService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
                new CachedServiceFetcher() {
            @Override
            public SubscriptionManager createService(ContextImpl ctx) {
                return new SubscriptionManager(ctx.getOuterContext());
            }});
其调用的是SubscriptionManager类中的SubscriptionManager(Context)构造函数

因此,mSubscriptionManager就是SubscriptionManager对象,而sRegistry就是TelephonyRegistry对象,这个不多说。

int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
这个方法不多说,获取当前卡槽的PhoneType

再来看看TelephonyManager类中的其他方法

/**
    * @hide
    */
    private ITelephony getITelephony() {
        return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
    }
这个方法是AIDL的应用,我还没搞明白,等后续分析后,再来记录下吧,其返回的是PhoneInterfaceManager对象

/**
    * @hide
    */
    private ITelecomService getTelecomService() {
        return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
    }
不多说,这个ITelephonyService应该是在TelecomServiceImpl类中实现的

/**
    * @hide
    */
    private IPhoneSubInfo getSubscriberInfo() {
        // get it each time because that process crashes a lot
        return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
    }
在PhoneSubInfoProxy类中实现

/** {@hide} */
    public boolean isMultiSimEnabled() {
        return (multiSimConfig.equals("dsds") || multiSimConfig.equals("dsda") ||
            multiSimConfig.equals("tsts"));
    }
判断是否是多卡项目

/**
     * Returns the software version number for the device, for example,
     * the IMEI/SV for GSM phones. Return null if the software version is
     * not available.
     *
     * 

Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceSoftwareVersion() { return getDeviceSoftwareVersion(getDefaultSim()); }

/**
     * Returns the software version number for the device, for example,
     * the IMEI/SV for GSM phones. Return null if the software version is
     * not available.
     *
     * 

Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * * @param slotId of which deviceID is returned */ /** {@hide} */ public String getDeviceSoftwareVersion(int slotId) { // FIXME methods taking slot id should not use subscription, instead us Uicc directly int[] subId = SubscriptionManager.getSubId(slotId); if (subId == null || subId.length == 0) { return null; } try { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getDeviceSvnUsingSubId(subId[0], mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { return null; } }

获取软件版本,调用的是PhoneSubInfoProxy类中的getDeviceSvnUsingSubId方法

/**
     * Returns the unique device ID, for example, the IMEI for GSM and the MEID
     * or ESN for CDMA phones. Return null if device ID is not available.
     *
     * 

Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceId() { try { ITelephony telephony = getITelephony(); if (telephony == null) return null; return telephony.getDeviceId(mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { return null; } }

获取设备ID,IMEI或者MEID号,调用PhoneInterfaceManager类中的getDeviceId方法,如下:

/**
     * Returns the unique device ID of phone, for example, the IMEI for
     * GSM and the MEID for CDMA phones. Return null if device ID is not available.
     *
     * 

Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ @Override public String getDeviceId(String callingPackage) { if (!canReadPhoneState(callingPackage, "getDeviceId")) { return null; } final Phone phone = PhoneFactory.getPhone(0); if (phone != null) { return phone.getDeviceId(); } else { return null; } }

调用的是Phone的getDeviceId方法,而PhoneFactory的getPhone方法

PhoneFactory.java
public static Phone getPhone(int phoneId) {
        Phone phone;
        String dbgInfo = "";

        synchronized (sLockProxyPhones) {
            if (!sMadeDefaults) {
                throw new IllegalStateException("Default phones haven't been made yet!");
                // CAF_MSIM FIXME need to introduce default phone id ?
            } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
                if (DBG) dbgInfo = "phoneId == DEFAULT_PHONE_ID return sProxyPhone";
                phone = sProxyPhone;
            } else {
                if (DBG) dbgInfo = "phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId]";
                phone = (((phoneId >= 0)
                                && (phoneId < TelephonyManager.getDefault().getPhoneCount()))
                        ? sProxyPhones[phoneId] : null);
            }
            if (DBG) {
                Rlog.d(LOG_TAG, "getPhone:- " + dbgInfo + " phoneId=" + phoneId +
                        " phone=" + phone);
            }
            return phone;
        }
    }
PhoneProxy.java
@Override
    public String getDeviceId() {
        return mActivePhone.getDeviceId();
    }
而mActivePhone是PhoneBase对象,具体实现在PhoneFactory的makeDefaultPhone中实现,应该是GSMPhone或者CDMALTEPhone对象

继续看TelephonyManager中的其他方法

/**
     * Returns the unique device ID of a subscription, for example, the IMEI for
     * GSM and the MEID for CDMA phones. Return null if device ID is not available.
     *
     * 

Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * * @param slotId of which deviceID is returned */ public String getDeviceId(int slotId) { // FIXME this assumes phoneId == slotId try { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getDeviceIdForPhone(slotId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { return null; } }

这个是调用了PhoneSubInfoProxy的getDeviceIdForPhone方法,获取设备ID,IMEI或者MEID号

/**
     * Returns the IMEI. Return null if IMEI is not available.
     *
     * 

Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ /** {@hide} */ public String getImei() { return getImei(getDefaultSim()); }

/**
     * Returns the IMEI. Return null if IMEI is not available.
     *
     * 

Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * * @param slotId of which deviceID is returned */ /** {@hide} */ public String getImei(int slotId) { int[] subId = SubscriptionManager.getSubId(slotId); try { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getImeiForSubscriber(subId[0], mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { return null; } }

获取IMEI号

/**
     * Returns the NAI. Return null if NAI is not available.
     *
     */
    /** {@hide}*/
    public String getNai() {
        return getNai(getDefaultSim());
    }
/**
     * Returns the NAI. Return null if NAI is not available.
     *
     *  @param slotId of which Nai is returned
     */
    /** {@hide}*/
    public String getNai(int slotId) {
        int[] subId = SubscriptionManager.getSubId(slotId);
        try {
            IPhoneSubInfo info = getSubscriberInfo();
            if (info == null)
                return null;
            String nai = info.getNaiForSubscriber(subId[0], mContext.getOpPackageName());
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Rlog.v(TAG, "Nai = " + nai);
            }
            return nai;
        } catch (RemoteException ex) {
            return null;
        } catch (NullPointerException ex) {
            return null;
        }
    }
获取NAI

/**
     * Returns the current location of the device.
     *

* If there is only one radio in the device and that radio has an LTE connection, * this method will return null. The implementation must not to try add LTE * identifiers into the existing cdma/gsm classes. *

* In the future this call will be deprecated. *

* @return Current location of the device or null if not available. * *

Requires Permission: * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_FINE_LOCATION}. */ public CellLocation getCellLocation() { try { ITelephony telephony = getITelephony(); if (telephony == null) { Rlog.d(TAG, "getCellLocation returning null because telephony is null"); return null; } Bundle bundle = telephony.getCellLocation(mContext.getOpPackageName()); if (bundle.isEmpty()) { Rlog.d(TAG, "getCellLocation returning null because bundle is empty"); return null; } CellLocation cl = CellLocation.newFromBundle(bundle); if (cl.isEmpty()) { Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty"); return null; } return cl; } catch (RemoteException ex) { Rlog.d(TAG, "getCellLocation returning null due to RemoteException " + ex); return null; } catch (NullPointerException ex) { Rlog.d(TAG, "getCellLocation returning null due to NullPointerException " + ex); return null; } }

获取设备的位置信息

/**
     * Enables location update notifications.  {@link PhoneStateListener#onCellLocationChanged
     * PhoneStateListener.onCellLocationChanged} will be called on location updates.
     *
     * 

Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES * CONTROL_LOCATION_UPDATES} * * @hide */ public void enableLocationUpdates() { enableLocationUpdates(getDefaultSubscription()); }

/**
     * Enables location update notifications for a subscription.
     * {@link PhoneStateListener#onCellLocationChanged
     * PhoneStateListener.onCellLocationChanged} will be called on location updates.
     *
     * 

Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES * CONTROL_LOCATION_UPDATES} * * @param subId for which the location updates are enabled */ /** @hide */ public void enableLocationUpdates(int subId) { try { ITelephony telephony = getITelephony(); if (telephony != null) telephony.enableLocationUpdatesForSubscriber(subId); } catch (RemoteException ex) { } catch (NullPointerException ex) { } }

启动设备位置信息更新通知

/**
     * Disables location update notifications.  {@link PhoneStateListener#onCellLocationChanged
     * PhoneStateListener.onCellLocationChanged} will be called on location updates.
     *
     * 

Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES * CONTROL_LOCATION_UPDATES} * * @hide */ public void disableLocationUpdates() { disableLocationUpdates(getDefaultSubscription()); } /** @hide */ public void disableLocationUpdates(int subId) { try { ITelephony telephony = getITelephony(); if (telephony != null) telephony.disableLocationUpdatesForSubscriber(subId); } catch (RemoteException ex) { } catch (NullPointerException ex) { } }

关闭设备位置更新通知

/**
     * Returns the neighboring cell information of the device.
     *
     * @return List of NeighboringCellInfo or null if info unavailable.
     *
     * 

Requires Permission: * (@link android.Manifest.permission#ACCESS_COARSE_UPDATES} * * @deprecated Use (@link getAllCellInfo} which returns a superset of the information * from NeighboringCellInfo. */ @Deprecated public List getNeighboringCellInfo() { try { ITelephony telephony = getITelephony(); if (telephony == null) return null; return telephony.getNeighboringCellInfo(mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { return null; } }

/**
     * Returns all observed cell information from all radios on the
     * device including the primary and neighboring cells. This does
     * not cause or change the rate of PhoneStateListener#onCellInfoChanged.
     *

* The list can include one or more of {@link android.telephony.CellInfoGsm CellInfoGsm}, * {@link android.telephony.CellInfoCdma CellInfoCdma}, * {@link android.telephony.CellInfoLte CellInfoLte} and * {@link android.telephony.CellInfoWcdma CellInfoWcdma} in any combination. * Specifically on devices with multiple radios it is typical to see instances of * one or more of any these in the list. In addition 0, 1 or more CellInfo * objects may return isRegistered() true. *

* This is preferred over using getCellLocation although for older * devices this may return null in which case getCellLocation should * be called. *

* This API will return valid data for registered cells on devices with * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY} *

* @return List of CellInfo or null if info unavailable. * *

Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} */ public List getAllCellInfo() { try { ITelephony telephony = getITelephony(); if (telephony == null) return null; return telephony.getAllCellInfo(getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { return null; } }

获取附近小区信息

/**
     * Returns the current phone type.
     * TODO: This is a last minute change and hence hidden.
     *
     * @see #PHONE_TYPE_NONE
     * @see #PHONE_TYPE_GSM
     * @see #PHONE_TYPE_CDMA
     * @see #PHONE_TYPE_SIP
     *
     * {@hide}
     */
    @SystemApi
    public int getCurrentPhoneType() {
        return getCurrentPhoneType(getDefaultSubscription());
    }
/**
     * Returns a constant indicating the device phone type for a subscription.
     *
     * @see #PHONE_TYPE_NONE
     * @see #PHONE_TYPE_GSM
     * @see #PHONE_TYPE_CDMA
     *
     * @param subId for which phone type is returned
     */
    /** {@hide} */
    @SystemApi
    public int getCurrentPhoneType(int subId) {
        int phoneId;
        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
            // if we don't have any sims, we don't have subscriptions, but we
            // still may want to know what type of phone we've got.
            phoneId = 0;
        } else {
            phoneId = SubscriptionManager.getPhoneId(subId);
        }
        try{
            ITelephony telephony = getITelephony();
            if (telephony != null && subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                return telephony.getActivePhoneTypeForSubscriber(subId);
            } else {
                // This can happen when the ITelephony interface is not up yet.
                return getPhoneTypeFromProperty(phoneId);
            }
        } catch (RemoteException ex) {
            // This shouldn't happen in the normal case, as a backup we
            // read from the system property.
            return getPhoneTypeFromProperty(phoneId);
        } catch (NullPointerException ex) {
            // This shouldn't happen in the normal case, as a backup we
            // read from the system property.
            return getPhoneTypeFromProperty(phoneId);
        }
    }
获取当前Phone的类型,这个地方获取的是默认的SubId


/**
     * Returns a constant indicating the device phone type.  This
     * indicates the type of radio used to transmit voice calls.
     *
     * @see #PHONE_TYPE_NONE
     * @see #PHONE_TYPE_GSM
     * @see #PHONE_TYPE_CDMA
     * @see #PHONE_TYPE_SIP
     */
    public int getPhoneType() {
        if (!isVoiceCapable()) {
            return PHONE_TYPE_NONE;
        }
        return getCurrentPhoneType();
    }

private int getPhoneTypeFromProperty() {
        return getPhoneTypeFromProperty(getDefaultPhone());
    }

    /** {@hide} */
    private int getPhoneTypeFromProperty(int phoneId) {
        String type = getTelephonyProperty(phoneId,
                TelephonyProperties.CURRENT_ACTIVE_PHONE, null);
        if (type == null || type.equals("")) {
            return getPhoneTypeFromNetworkType(phoneId);
        }
        return Integer.parseInt(type);
    }

    private int getPhoneTypeFromNetworkType() {
        return getPhoneTypeFromNetworkType(getDefaultPhone());
    }

    /** {@hide} */
    private int getPhoneTypeFromNetworkType(int phoneId) {
        // When the system property CURRENT_ACTIVE_PHONE, has not been set,
        // use the system property for default network type.
        // This is a fail safe, and can only happen at first boot.
        String mode = getTelephonyProperty(phoneId, "ro.telephony.default_network", null);
        if (mode != null) {
            return TelephonyManager.getPhoneType(Integer.parseInt(mode));
        }
        return TelephonyManager.PHONE_TYPE_NONE;
    }

这些方法全部是获取当前PHone的类型的,还有上述getPhoneType(int networkMode)方法

/**
     * The contents of the /proc/cmdline file
     */
    private static String getProcCmdLine()
    {
        String cmdline = "";
        FileInputStream is = null;
        try {
            is = new FileInputStream("/proc/cmdline");
            byte [] buffer = new byte[2048];
            int count = is.read(buffer);
            if (count > 0) {
                cmdline = new String(buffer, 0, count);
            }
        } catch (IOException e) {
            Rlog.d(TAG, "No /proc/cmdline exception=" + e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
        }
        Rlog.d(TAG, "/proc/cmdline=" + cmdline);
        return cmdline;
    }
获取当前/proc/cmdline中的数据

/**
     * Returns the alphabetic name of current registered operator.
     * 

* Availability: Only when user is registered to a network. Result may be * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if * on a CDMA network). */ public String getNetworkOperatorName() { return getNetworkOperatorName(getDefaultSubscription()); }

/**
     * Returns the alphabetic name of current registered operator
     * for a particular subscription.
     * 

* Availability: Only when user is registered to a network. Result may be * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if * on a CDMA network). * @param subId */ /** {@hide} */ public String getNetworkOperatorName(int subId) { int phoneId = SubscriptionManager.getPhoneId(subId); return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, ""); }

/**
     * Gets the telephony property.
     *
     * @hide
     */
    public static String getTelephonyProperty(int phoneId, String property, String defaultVal) {
        String propVal = null;
        String prop = SystemProperties.get(property);
        if ((prop != null) && (prop.length() > 0)) {
            String values[] = prop.split(",");
            if ((phoneId >= 0) && (phoneId < values.length) && (values[phoneId] != null)) {
                propVal = values[phoneId];
            }
        }
        return propVal == null ? defaultVal : propVal;
    }
获取运营商的名称

/**
     * Returns the numeric name (MCC+MNC) of current registered operator.
     * 

* Availability: Only when user is registered to a network. Result may be * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if * on a CDMA network). */ public String getNetworkOperator() { return getNetworkOperatorForPhone(getDefaultPhone()); }

/**
     * Returns the numeric name (MCC+MNC) of current registered operator
     * for a particular subscription.
     * 

* Availability: Only when user is registered to a network. Result may be * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if * on a CDMA network). * * @param subId */ /** {@hide} */ public String getNetworkOperatorForSubscription(int subId) { int phoneId = SubscriptionManager.getPhoneId(subId); return getNetworkOperatorForPhone(phoneId); }

/**
     * Returns the numeric name (MCC+MNC) of current registered operator
     * for a particular subscription.
     * 

* Availability: Only when user is registered to a network. Result may be * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if * on a CDMA network). * * @param phoneId * @hide **/ public String getNetworkOperatorForPhone(int phoneId) { return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, ""); }

获取MCC+MNC

/**
     * Returns true if the device is considered roaming on the current
     * network, for GSM purposes.
     * 

* Availability: Only when user registered to a network. */ public boolean isNetworkRoaming() { return isNetworkRoaming(getDefaultSubscription()); }

/**
     * Returns true if the device is considered roaming on the current
     * network for a subscription.
     * 

* Availability: Only when user registered to a network. * * @param subId */ /** {@hide} */ public boolean isNetworkRoaming(int subId) { int phoneId = SubscriptionManager.getPhoneId(subId); return Boolean.parseBoolean(getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, null)); }

是否漫游

/**
     * Returns the ISO country code equivalent of the current registered
     * operator's MCC (Mobile Country Code).
     * 

* Availability: Only when user is registered to a network. Result may be * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if * on a CDMA network). */ public String getNetworkCountryIso() { return getNetworkCountryIsoForPhone(getDefaultPhone()); }

/**
     * Returns the ISO country code equivalent of the current registered
     * operator's MCC (Mobile Country Code) of a subscription.
     * 

* Availability: Only when user is registered to a network. Result may be * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if * on a CDMA network). * * @param subId for which Network CountryIso is returned */ /** {@hide} */ public String getNetworkCountryIsoForSubscription(int subId) { int phoneId = SubscriptionManager.getPhoneId(subId); return getNetworkCountryIsoForPhone(phoneId); }

/**
     * Returns the ISO country code equivalent of the current registered
     * operator's MCC (Mobile Country Code) of a subscription.
     * 

* Availability: Only when user is registered to a network. Result may be * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if * on a CDMA network). * * @param phoneId for which Network CountryIso is returned */ /** {@hide} */ public String getNetworkCountryIsoForPhone(int phoneId) { return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); }

获取ISO国家信息

/**
     * @return the NETWORK_TYPE_xxxx for current data connection.
     */
    public int getNetworkType() {
       try {
           ITelephony telephony = getITelephony();
           if (telephony != null) {
               return telephony.getNetworkType();
            } else {
                // This can happen when the ITelephony interface is not up yet.
                return NETWORK_TYPE_UNKNOWN;
            }
        } catch(RemoteException ex) {
            // This shouldn't happen in the normal case
            return NETWORK_TYPE_UNKNOWN;
        } catch (NullPointerException ex) {
            // This could happen before phone restarts due to crashing
            return NETWORK_TYPE_UNKNOWN;
        }
    }
/**
     * Returns a constant indicating the radio technology (network type)
     * currently in use on the device for a subscription.
     * @return the network type
     *
     * @param subId for which network type is returned
     *
     * @see #NETWORK_TYPE_UNKNOWN
     * @see #NETWORK_TYPE_GPRS
     * @see #NETWORK_TYPE_EDGE
     * @see #NETWORK_TYPE_UMTS
     * @see #NETWORK_TYPE_HSDPA
     * @see #NETWORK_TYPE_HSUPA
     * @see #NETWORK_TYPE_HSPA
     * @see #NETWORK_TYPE_CDMA
     * @see #NETWORK_TYPE_EVDO_0
     * @see #NETWORK_TYPE_EVDO_A
     * @see #NETWORK_TYPE_EVDO_B
     * @see #NETWORK_TYPE_1xRTT
     * @see #NETWORK_TYPE_IDEN
     * @see #NETWORK_TYPE_LTE
     * @see #NETWORK_TYPE_EHRPD
     * @see #NETWORK_TYPE_HSPAP
     *
     * 

* Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ /** {@hide} */ public int getNetworkType(int subId) { try { ITelephony telephony = getITelephony(); if (telephony != null) { return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName()); } else { // This can happen when the ITelephony interface is not up yet. return NETWORK_TYPE_UNKNOWN; } } catch(RemoteException ex) { // This shouldn't happen in the normal case return NETWORK_TYPE_UNKNOWN; } catch (NullPointerException ex) { // This could happen before phone restarts due to crashing return NETWORK_TYPE_UNKNOWN; } }

获取数据连接网络类型,调用的是PhoneInterfaceManager的getNetworkType方法

/**
     * Return general class of network type, such as "3G" or "4G". In cases
     * where classification is contentious, this method is conservative.
     *
     * @hide
     */
    public static int getNetworkClass(int networkType) {
        switch (networkType) {
            case NETWORK_TYPE_GPRS:
            case NETWORK_TYPE_GSM:
            case NETWORK_TYPE_EDGE:
            case NETWORK_TYPE_CDMA:
            case NETWORK_TYPE_1xRTT:
            case NETWORK_TYPE_IDEN:
                return NETWORK_CLASS_2_G;
            case NETWORK_TYPE_UMTS:
            case NETWORK_TYPE_EVDO_0:
            case NETWORK_TYPE_EVDO_A:
            case NETWORK_TYPE_HSDPA:
            case NETWORK_TYPE_HSUPA:
            case NETWORK_TYPE_HSPA:
            case NETWORK_TYPE_EVDO_B:
            case NETWORK_TYPE_EHRPD:
            case NETWORK_TYPE_HSPAP:
            case NETWORK_TYPE_TD_SCDMA:
                return NETWORK_CLASS_3_G;
            case NETWORK_TYPE_LTE:
            case NETWORK_TYPE_IWLAN:
                return NETWORK_CLASS_4_G;
            default:
                return NETWORK_CLASS_UNKNOWN;
        }
    }

根据网络类型,获取网络数据等级,2G/3G/4G

/**
     * Returns a string representation of the radio technology (network type)
     * currently in use on the device.
     * @return the name of the radio technology
     *
     * @hide pending API council review
     */
    public String getNetworkTypeName() {
        return getNetworkTypeName(getNetworkType());
    }
获取网络类型名称

/**
     * @return true if a ICC card is present
     */
    public boolean hasIccCard() {
        return hasIccCard(getDefaultSim());
    }
/**
     * @return true if a ICC card is present for a subscription
     *
     * @param slotId for which icc card presence is checked
     */
    /** {@hide} */
    // FIXME Input argument slotId should be of type int
    public boolean hasIccCard(int slotId) {

        try {
            ITelephony telephony = getITelephony();
            if (telephony == null)
                return false;
            return telephony.hasIccCardUsingSlotId(slotId);
        } catch (RemoteException ex) {
            // Assume no ICC card if remote exception which shouldn't happen
            return false;
        } catch (NullPointerException ex) {
            // This could happen before phone restarts due to crashing
            return false;
        }
    }
判断是否有IccCard,即SIM卡

/**
     * Returns a constant indicating the state of the default SIM card.
     *
     * @see #SIM_STATE_UNKNOWN
     * @see #SIM_STATE_ABSENT
     * @see #SIM_STATE_PIN_REQUIRED
     * @see #SIM_STATE_PUK_REQUIRED
     * @see #SIM_STATE_NETWORK_LOCKED
     * @see #SIM_STATE_READY
     * @see #SIM_STATE_NOT_READY
     * @see #SIM_STATE_PERM_DISABLED
     * @see #SIM_STATE_CARD_IO_ERROR
     */
    public int getSimState() {
        int slotIdx = getDefaultSim();
        // slotIdx may be invalid due to sim being absent. In that case query all slots to get
        // sim state
        if (slotIdx < 0) {
            // query for all slots and return absent if all sim states are absent, otherwise
            // return unknown
            for (int i = 0; i < getPhoneCount(); i++) {
                int simState = getSimState(i);
                if (simState != SIM_STATE_ABSENT) {
                    Rlog.d(TAG, "getSimState: default sim:" + slotIdx + ", sim state for " +
                            "slotIdx=" + i + " is " + simState + ", return state as unknown");
                    return SIM_STATE_UNKNOWN;
                }
            }
            Rlog.d(TAG, "getSimState: default sim:" + slotIdx + ", all SIMs absent, return " +
                    "state as absent");
            return SIM_STATE_ABSENT;
        }
        return getSimState(slotIdx);
    }
/** {@hide} */
    public int getSimState(int slotIdx) {
        int simState = SubscriptionManager.getSimStateForSlotIdx(slotIdx);
        return simState;
    }
获取SIM卡状态

/**
     * Returns the MCC+MNC (mobile country code + mobile network code) of the
     * provider of the SIM. 5 or 6 decimal digits.
     * 

* Availability: SIM state must be {@link #SIM_STATE_READY} * * @see #getSimState */ public String getSimOperator() { return getSimOperatorNumeric(); }

public String getSimOperator(int subId) {
        return getSimOperatorNumericForSubscription(subId);
    }
public String getSimOperatorNumeric() {
        int subId = SubscriptionManager.getDefaultDataSubId();
        if (!SubscriptionManager.isUsableSubIdValue(subId)) {
            subId = SubscriptionManager.getDefaultSmsSubId();
            if (!SubscriptionManager.isUsableSubIdValue(subId)) {
                subId = SubscriptionManager.getDefaultVoiceSubId();
                if (!SubscriptionManager.isUsableSubIdValue(subId)) {
                    subId = SubscriptionManager.getDefaultSubId();
                }
            }
        }
        return getSimOperatorNumericForSubscription(subId);
    }
public String getSimOperatorNumericForSubscription(int subId) {
        int phoneId = SubscriptionManager.getPhoneId(subId);
        return getSimOperatorNumericForPhone(phoneId);
    }
public String getSimOperatorNumericForPhone(int phoneId) {
        return getTelephonyProperty(phoneId,
                TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
    }
返回IccCard的MCCMNC

public String getSimOperatorName() {
        return getSimOperatorNameForPhone(getDefaultPhone());
    }
public String getSimOperatorNameForSubscription(int subId) {
        int phoneId = SubscriptionManager.getPhoneId(subId);
        return getSimOperatorNameForPhone(phoneId);
    }
public String getSimOperatorNameForPhone(int phoneId) {
         return getTelephonyProperty(phoneId,
                TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "");
    }
返回SIM卡的SPN

public String getSimCountryIso() {
        return getSimCountryIsoForPhone(getDefaultPhone());
    }
返回SIM卡的ISO城市代码

/**
     * Returns the serial number of the SIM, if applicable. Return null if it is
     * unavailable.
     * 

* Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getSimSerialNumber() { return getSimSerialNumber(getDefaultSubscription()); }

返回SIM卡的Serial Number

public String getMsisdn() {
        return getMsisdn(getDefaultSubscription());
    }
返回MSISDN

public String getVoiceMailNumber() {
        return getVoiceMailNumber(getDefaultSubscription());
    }
返回VoiceMail Number

public boolean setVoiceMailNumber(String alphaTag, String number) {
        return setVoiceMailNumber(getDefaultSubscription(), alphaTag, number);
    }
设置VoiceMail Number

public int getVoiceMessageCount() {
        return getVoiceMessageCount(getDefaultSubscription());
    }
获取VoiceMail消息数量

public int getCallState() {
        try {
            ITelecomService telecom = getTelecomService();
            if (telecom != null) {
                return telecom.getCallState();
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelecomService#getCallState", e);
        }
        return CALL_STATE_IDLE;
    }
获取当前的通话状态

public int getDataActivity() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony == null)
                return DATA_ACTIVITY_NONE;
            return telephony.getDataActivity();
        } catch (RemoteException ex) {
            // the phone process is restarting.
            return DATA_ACTIVITY_NONE;
        } catch (NullPointerException ex) {
          // the phone process is restarting.
          return DATA_ACTIVITY_NONE;
      }
    }
获取数据连接的上下行状态

public int getDataState() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony == null)
                return DATA_DISCONNECTED;
            return telephony.getDataState();
        } catch (RemoteException ex) {
            // the phone process is restarting.
            return DATA_DISCONNECTED;
        } catch (NullPointerException ex) {
            return DATA_DISCONNECTED;
        }
    }
获取数据链接的状态

public void listen(PhoneStateListener listener, int events) {
        if (mContext == null) return;
        try {
            Boolean notifyNow = (getITelephony() != null);
            sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
                    listener.callback, events, notifyNow);
        } catch (RemoteException ex) {
            // system process dead
        } catch (NullPointerException ex) {
            // system process dead
        }
    }
注册监听,监听手机Telephony的状态变化

private static int getDefaultSubscription() {
        return SubscriptionManager.getDefaultSubId();
    }
获取默认的subId

private static int getDefaultPhone() {
        return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubId());
    }
获取默认的PhoneId,这个代表的是哪一个卡槽

/** {@hide} */
    public int getDefaultSim() {
        return SubscriptionManager.getSlotId(SubscriptionManager.getDefaultSubId());
    }
获取默认的SIM卡

/** @hide */
    public int getSimCount() {
        // FIXME Need to get it from Telephony Dev Controller when that gets implemented!
        // and then this method shouldn't be used at all!
        if(isMultiSimEnabled()) {
            return 2;
        } else {
            return 1;
        }
    }
获取当前SIM卡数量

public int getPreferredNetworkType(int subId) {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                return telephony.getPreferredNetworkType(subId);
        } catch (RemoteException ex) {
            Rlog.e(TAG, "getPreferredNetworkType RemoteException", ex);
        } catch (NullPointerException ex) {
            Rlog.e(TAG, "getPreferredNetworkType NPE", ex);
        }
        return -1;
    }
根据subId获取PreferredNetworkType

public boolean setPreferredNetworkType(int subId, int networkType) {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                return telephony.setPreferredNetworkType(subId, networkType);
        } catch (RemoteException ex) {
            Rlog.e(TAG, "setPreferredNetworkType RemoteException", ex);
        } catch (NullPointerException ex) {
            Rlog.e(TAG, "setPreferredNetworkType NPE", ex);
        }
        return false;
    }
设置subId对应的SIM卡的PreferredNetworkType

 public void dial(String number) {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                telephony.dial(number);
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#dial", e);
        }
    }
public void call(String callingPackage, String number) {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                telephony.call(callingPackage, number);
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#call", e);
        }
    }
实现拨号

public boolean endCall() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                return telephony.endCall();
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#endCall", e);
        }
        return false;
    }
实现挂断电话

public void answerRingingCall() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                telephony.answerRingingCall();
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#answerRingingCall", e);
        }
    }
实现接听通话

public void silenceRinger() {
        try {
            getTelecomService().silenceRinger(getOpPackageName());
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelecomService#silenceRinger", e);
        }
    }
实现来电静音

public boolean enableDataConnectivity() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                return telephony.enableDataConnectivity();
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#enableDataConnectivity", e);
        }
        return false;
    }
实现打开数据链接

public boolean disableDataConnectivity() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                return telephony.disableDataConnectivity();
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#disableDataConnectivity", e);
        }
        return false;
    }
实现关闭数据链接

public boolean isDataConnectivityPossible() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                return telephony.isDataConnectivityPossible();
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#isDataConnectivityPossible", e);
        }
        return false;
    }
判断数据链接使用可用

public void setDataEnabled(boolean enable) {
        setDataEnabled(SubscriptionManager.getDefaultDataSubId(), enable);
    }
打开数据连接

public boolean getDataEnabled() {
        return getDataEnabled(SubscriptionManager.getDefaultDataSubId());
    }
获取数据链接是否打开状态

public void enableVideoCalling(boolean enable) {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                telephony.enableVideoCalling(enable);
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#enableVideoCalling", e);
        }
    }
开启视频通话

public boolean isVideoCallingEnabled() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                return telephony.isVideoCallingEnabled(getOpPackageName());
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#isVideoCallingEnabled", e);
        }
        return false;
    }
视频通话是否开启










你可能感兴趣的:(SIM卡开机流程分析)