首先在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;
}
视频通话是否开启