(M)SIM卡开机流程分析之TelephonyManager类分析
来源:互联网 发布:壁纸自动更换软件 编辑:程序博客网 时间:2024/05/06 17:39
首先在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<SubscriptionManager>() { @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. * * <p>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. * * <p>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. * * <p>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. * * <p>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.javapublic 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. * * <p>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. * * <p>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. * * <p>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. *<p> * 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. *<p> * In the future this call will be deprecated. *<p> * @return Current location of the device or null if not available. * * <p>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. * * <p>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. * * <p>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. * * <p>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. * * <p>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<NeighboringCellInfo> 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. *<p> * 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. *<p> * This is preferred over using getCellLocation although for older * devices this may return null in which case getCellLocation should * be called. *<p> * This API will return valid data for registered cells on devices with * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY} *<p> * @return List of CellInfo or null if info unavailable. * * <p>Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} */ public List<CellInfo> 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. * <p> * 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. * <p> * 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. * <p> * 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. * <p> * 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. * <p> * 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. * <p> * 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. * <p> * 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). * <p> * 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. * <p> * 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. * <p> * 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 * * <p> * 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. * <p> * 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. * <p> * 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; }视频通话是否开启
0 0
- (M)SIM卡开机流程分析之TelephonyManager类分析
- (M)SIM卡开机流程分析之主线分析
- (M)SIM卡开机流程分析之SPN加载
- (M)SIM卡开机流程分析之TelephonyDevController类分析
- (M)SIM卡开机流程分析之UiccController类分析
- (M)SIM卡开机流程分析之RIL类分析
- (M)SIM卡开机流程分析之DefaultPhoneNotifier类分析
- (M)SIM卡开机流程分析之SubscriptionController类分析
- (M)SIM卡开机流程分析之默认APN设置
- (M)SIM卡开机流程分析之显示名称加载
- 开机导入Sim卡联系人流程分析
- android之Sim Tool Kit流程分析
- Android4.4 Telephony流程分析——SIM卡开机时的初始化
- Android4.4 Telephony流程分析——SIM卡开机时的数据加载
- Android 4.4Telephony流程分析SIM卡开机时的数据加载
- Android 4.4Telephony流程分析SIM卡开机时的初始化
- Android4.4 Telephony流程分析——SIM卡开机时的初始化
- 联系人开机自动导入SIM卡联系人分析
- at之asynctask源码解答
- jQuery-Ajax
- linux时间操作
- linux 查看自己所在的公网ip
- Unity中判断地图上两点之间相对于正北方向的角度 c#实现
- (M)SIM卡开机流程分析之TelephonyManager类分析
- 系统音量条
- Guava学习笔记:Google Guava 类库简介
- Android架构思考(模块化、多进程)
- 最大质因数求解
- Java基础&进阶(收藏)
- 【SQLSERVER】output用法解析
- linux安装图形界面
- 正则表达式