Android开发笔记(一百二十八)手机制式适配

查看运营商与网络类型

虽然现在4G网络很普及了,但是我国幅员辽阔,4G信号在某些地方接收不良,手机连接很容易掉到3G甚至2G网络。为了让用户在低速环境也能使用App的基础功能,而不至于还在老牛破车地缓慢下载大图,App就得判断当前所处的网络环境,从而针对不同的网络连接提供相应的访问模式;比如在4G网络下默认完整模式,在2G/3G网络下默认切换到极简模式。

查看网络类型等信息,用到了电话管理器TelephonyManager,它的对象从系统服务TELEPHONY_SERVICE中获取,相关方法说明如下:
getNetworkOperator : 获取运营商代码。返回五位数字的字符串,前三位表示移动国家代码(Mobile Country Code,简称MCC),后两位表示移动网络代码(Mobile Network Code,简称MNC)。
getNetworkOperatorName : 获取运营商名称。如中国移动、中国联通、中国电信等等。
getPhoneType : 获取电话类型。返回1表示GSM,2表示CDMA,3表示SIP。
getNetworkType : 获取网络类型。这个网络类型包含每代网络的细分类型,可表示GPRS、CDMA、EvDo、HSPA、LTE等等。
getNetworkTypeName : 获取网络类型的名称。隐藏方法,需使用反射机制调用。
getNetworkClass : 获取网络分代。隐藏方法,需使用反射技术调用。返回1表示2G,返回2表示3G,返回3表示4G。

下面是查看具体手机上网络类型的截图,第一张图片为使用移动号码的网络信息,第二张图片为使用联通号码的网络信息。
 

下面是查看网络类型的代码例子:
	private void initOperator() {
		TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
		String desc = "";
		// MCC,Mobile Country Code,移动国家代码(中国的为460);
		// MNC,Mobile Network Code,移动网络代码(中国移动为0,中国联通为1,中国电信为2);
		String operator = tm.getNetworkOperator();
		int mcc = Integer.parseInt(operator.substring(0, 3));
		int mnc = Integer.parseInt(operator.substring(3, 5)); 
		desc = String.format("%s\n 国家代码=%d", desc, mcc);
		desc = String.format("%s\n 网络代码=%d", desc, mnc);
		desc = String.format("%s\n 运营商名称=%s", desc, tm.getNetworkOperatorName());
		desc = String.format("%s\n 手机类型=%s", desc, SignalUtils.mVoiceArray[tm.getPhoneType()]);
		desc = String.format("%s\n 网络类型=%s", desc, 
				SignalUtils.getNetworkTypeName(tm, tm.getNetworkType()));
		desc = String.format("%s\n 网络分代=%s", desc, 
				SignalUtils.getClassName(tm, tm.getNetworkType()));
		tv_operator.setText(desc);
	}


查看双卡双待信息

标准的Android系统只支持一张sim卡,不支持一个手机同时插两张卡。可是许多人都希望手机插两张卡,一张卡用于工作,一张卡用于私人,所以双卡双待手机最早由山寨机厂商推出后,就大受国人追捧,使得国内各大厂商纷纷跟进推出双卡手机。时至今日,中国的智能手机市场,早已是双卡手机的天下,Android标准的单卡手机反而沦为少数群体了。

现在有些App的用户账号与手机是绑定的,一部手机只能注册一个账号,然而注册用户应该以手机号码做为唯一标识,像双卡手机同时插了两张卡,就应当允许注册两个账号,每个帐号都对应一个手机号码,才符合正常的处理逻辑。因此,App在用户注册帐号时,可先判断当前手机是否支持双卡,且是否两个卡槽都插了sim卡,如果用户手机找到两个手机卡,则允许这部手机按照号码分别注册两个账号。

既然广大用户存在双卡手机的需求,而且App也需要校验双卡信息,那么Android理当响应广大人民的呼声,顺势推出双卡功能才对。遗憾的是,原生的Android一直坚守单卡方案,反而是芯片厂商在底层对Android系统做了深度定制,使得采用这些芯片的手机也能支持双卡功能。因为双卡模块由各家芯片厂商自行定制,所以查询双卡信息没有统一的标准,开发者只有获得各厂商的私有查询API,然后在App中各显神通,想办法知道当前手机用的是哪套双卡方案,详细的双卡信息又是什么。

双卡方案的实现方式各有不同,市面上的Android智能手机,大多采用了高通芯片或者联发科芯片,于是双卡方案也形成了高通与联发科两大阵营。它们都提供了查询两个卡槽的imei和imsi信息,不过由于是隐藏方法,故而要通过反射机制来调用。

下面是查看具体手机上双卡信息的截图,第一张图片为使用高通方案的双卡信息,第二张图片为使用联发科方案的双卡信息。
 

下面是查看双卡信息的代码例子:
	public static int SINGLE_STANDARD = 0, DOUBLE_MTK = 1, DOUBLE_GC = 2;
	public static String[] mSolutionDesc = {"标准单卡", "联发科双卡", "高通双卡"};
	private void setCardInfo() {
		//读取电话信息需要授权android.permission.READ_PHONE_STATE
		tm = ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE));
		mCardInfo.imei1 = tm.getDeviceId();
		mCardInfo.imsi1 = tm.getSubscriberId();
		try {
			mCardInfo.imei1 = getByReflect(mContext, "getDeviceIdGemini", 0);
			mCardInfo.imei2 = getByReflect(mContext, "getDeviceIdGemini", 1);
			setSolutionType(DOUBLE_MTK);  //联发科方案
			mCardInfo.imsi1 = getByReflect(mContext, "getSubscriberIdGemini", 0);
			mCardInfo.imsi2 = getByReflect(mContext, "getSubscriberIdGemini", 1);
		} catch (Exception e) {
			e.printStackTrace();
			try {
				mCardInfo.imei1 = getByReflect(mContext, "getDeviceId", 0);
				mCardInfo.imei2 = getByReflect(mContext, "getDeviceId", 1);
				setSolutionType(DOUBLE_GC);  //高通方案
				mCardInfo.imsi1 = getByReflect(mContext, "getSubscriberId", 0);
				mCardInfo.imsi2 = getByReflect(mContext, "getSubscriberId", 1);
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}
	}

	private String getByReflect(Context context, String method, int seq) throws Exception {
		String inumeric = null;
		Class<?> telephonyClass = Class.forName(tm.getClass().getName());
		Class<?>[] parameter = new Class[1];
		parameter[0] = int.class;
		Method getSimID = telephonyClass.getMethod(method, parameter);
		Object[] obParameter = new Object[1];
		obParameter[0] = seq;
		Object ob_phone = getSimID.invoke(tm, obParameter);
		if (ob_phone != null) {
			inumeric = ob_phone.toString();
		}
		return inumeric;
	}

	private void setSolutionType(int solutionType) {
		mCardInfo.solutionType = solutionType;
		mCardInfo.solutionDesc = mSolutionDesc[solutionType];
		if (solutionType > 0) {
			mCardInfo.bDouble = true;
		}
	}


Android5.1增加支持多sim卡

国内的双卡手机已占市场主流,即使Android长期固守单卡,那也不能无视广大人民的呼声呀,所以从Android5.1开始,Android正式支持多张sim卡。其实也没有增加新的管理类,只是给TelephonyManager重载了几个sim卡信息获取接口,允许传入序号参数,比如传0表示获取第一个卡槽的sim卡信息,传1表示获取第二个卡槽的sim卡信息。

下面是新增的几个重载方法说明:
getDeviceId : 获取指定卡槽的imei号。如果该卡槽是cdma制式,则返回meid值。
getImei: 获取指定卡槽的imei号。
getSubscriberId: 获取指定sim卡的imsi。
getSimOperator: 获取指定sim卡的运营商名称。
getNetworkType: 获取指定sim卡的网络类型。
getCurrentPhoneType: 获取指定sim卡的手机类型。
getNetworkOperatorName: 获取指定sim卡的网络运营商名称。
isNetworkRoaming: 获取指定sim卡是否处于网络漫游。

另需注意,以上方法都是隐藏方法,不能直接调用,得通过反射机制调用才行。有关反射机制的说明参见《 Android开发笔记(六十)网络的检测与连接》。





点击下载本文用到的手机制式适配的工程代码


点此查看Android开发笔记的完整目录
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值