当前位置: 代码迷 >> Android >> Android 双卡双待判别
  详细解决方案

Android 双卡双待判别

热度:94   发布时间:2016-04-28 06:00:49.0
Android 双卡双待识别
简介

Android双卡双待已经越来越普及了,解决双卡双待管理是广大手机开发人员必须得面对的问题,为实现Android平台的双卡双待操作,笔者研究了Android 应用层操作双卡双待的机制。


机制

获取基于ITelephony接口实现phone应用中的“phone服务”,通过TelephonyManager接口获取不同的卡(GSMPhone /CDMAPhone)进行不同的操作(拨号、接通、挂断、保持通话等)。

Android平台是一个多样型的平台,不同的手机获取ITelephony接口不同,用一种方法实现双卡双待管理是不可取的。那怎么办呢?只有针对不同的手机分析出一套管理的方案,该方案实现难度大,因为需要各个厂家的SDK的资料。为了实现该功能,笔者做了大量工作,整合各个厂家的SDK的资料。


实现

为了更好的管理双卡双待的问题,新建一个双卡双待模块静态库,其它项目引用便是,项目如图:



AbsSim是抽象类,负责实现手机操作的类。不同的厂家继承该类实现各自的接口。AbsSim信息如下:

public abstract class AbsSim implements IDualDetector { //抽象基类	protected final String TAG = getClass().getSimpleName();	protected ArrayList<SimSlot> mSimSlots = new ArrayList<SimSlot>();	protected boolean mIsDualSimPhone = false;	protected String mCallLogExtraField = "";	public abstract String getSimPhoneNumber(int paramInt); // 返回手机号码	public abstract int getDataState(int paramInt);// 返回数据状态	public abstract String getIMSI(int paramInt);// 返回手机标识	public abstract String getIMSI(int paramInt, Context paramContext);// 返回手机标识	public abstract int getPhoneState(int paramInt);// 返回手机状态	public abstract boolean isServiceAvaliable(int paramInt);// 服务是否可用	public abstract boolean isSimStateIsReady(int paramInt);// 卡是否在使用	public abstract int getSimOperator(int paramInt);// 服务商(电信、移动、联通)	protected abstract Object getITelephonyMSim(int paramInt);// 获取操作接口	protected abstract Object getMSimTelephonyManager(int paramInt);// 获取操作接口	@Override	public AbsSim detect() { // 根据手机信息匹配		if ((getITelephonyMSim(0) != null) && (getITelephonyMSim(1) != null)		// && (getmMSimSmsManager(0) != null)		// && (getmMSimSmsManager(1) != null)		// && (detectSms(paramContext, paramBoolean))		// && (detectCallLog(paramContext, paramBoolean))		)			return this;		return null;	}	public boolean directCall(String paramString, int paramInt) { // 拨打电话(根据不同卡拨打电话)		Intent localIntent = new Intent("android.intent.action.CALL",				Uri.fromParts("tel", paramString, null));		localIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);		try {			getContext().startActivity(localIntent);			return true;		} catch (Throwable localThrowable) {			localThrowable.printStackTrace();		}		return false;	}	protected boolean detectCallLog() { // 通过通话记录信息匹配		return false;	}	protected boolean detectSms() {// 通过短信记录信息匹配		return false;	}	protected Context getContext() { // 返回句柄		return SimManager.getInstance().getContext();	}	protected int getSimSlotNum() { // 返回插槽个数(默认2)		return 2;	}	public void init() { // 初始化		for (int i = 0; i < getSimSlotNum(); i++) {			try {				String imsi = getIMSI(i);				boolean isUsing = isSimStateIsReady(i);				if (imsi != null || isUsing) {					if (imsi == null || hasSimSlotByIMSI(imsi))						continue;					SimSlot simSlot = new SimSlot();					mSimSlots.add(simSlot);					simSlot.setUsing(isUsing);					simSlot.setIMSI(imsi);					simSlot.setSimOperator(getSimOperator(i));				}			} catch (Exception e) {				e.printStackTrace();			}		}	}	public boolean hasSimPhone() {// 是否有sd卡在使用		if (mSimSlots.isEmpty())			return false;		for (SimSlot simslot : mSimSlots) {			if (simslot.isUsing())				return true;		}		return false;	}	public boolean isDualSimPhone() {// 是否为双卡		if (getSimSlots().isEmpty() || getSimSlots().size() < 2)			return false;		for (SimSlot simSlot : getSimSlots()) {			if (!simSlot.isUsing())				return false;		}		return true;	}	public ArrayList<SimSlot> getSimSlots() { // 返回已确认的卡		return mSimSlots;	}	protected boolean delSimSlotByIMSI(String imsi) { // 删除相同的卡的信息		for (SimSlot simSlot : getSimSlots()) {			if (simSlot.getIMSI() != null && simSlot.getIMSI().equals(imsi)) {				getSimSlots().remove(simSlot);			}		}		return false;	}	protected boolean hasSimSlotByIMSI(String imsi) {		for (SimSlot simSlot : getSimSlots()) {			if (simSlot.getIMSI() != null && simSlot.getIMSI().equals(imsi)) {				return true;			}		}		return false;	}}

现在列举一款实现MTK方案:

public class MTKDualSim extends AbsSim {// 采用MTK方案的类(根据厂家SDK实现不同的接口)	private Object mMSimTelephonyManager = null;	private Object mTelephonyMSim = null;	public MTKDualSim() {		mCallLogExtraField = "simid";		String str1 = SimManager.getModel();		String str2 = SimManager.getManufaturer();		if ((str1 != null) && (str2 != null)) {			String str3 = str1.toLowerCase();			String str4 = str2.toLowerCase();			if ((str4.indexOf("huawei") > -1) && (str3.indexOf("h30-t00") > -1))				mCallLogExtraField = "subscription";			if ((str4.indexOf("hisense") > -1)					&& (str3.indexOf("hs-u970") > -1)) {				mCallLogExtraField = "subtype";			}		}	}	@Override	public boolean directCall(String paramString, int paramInt) {		if (SimManager.isSDKVersionMore4_1()) {			Intent localIntent1 = new Intent("android.intent.action.CALL",					Uri.fromParts("tel", paramString, null));			localIntent1.putExtra("simId", paramInt);			localIntent1.putExtra("com.android.phone.extra.slot", paramInt);			localIntent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);			try {				getContext().startActivity(localIntent1);				return true;			} catch (Throwable localThrowable1) {				localThrowable1.printStackTrace();			}		} else if (SimManager.isSDKVersionMore4_0()) {			Intent localIntent2 = new Intent(					"com.android.phone.OutgoingCallReceiver");			localIntent2.putExtra("com.android.phone.extra.slot", paramInt);			localIntent2.putExtra("simId", paramInt);			localIntent2.putExtra("com.android.phone.force.slot", true);			localIntent2.setClassName("com.android.phone",					"com.android.phone.OutgoingCallReceiver");			localIntent2.setData(Uri.fromParts("tel", paramString, null));			try {				getContext().sendBroadcast(localIntent2);				return true;			} catch (Throwable localThrowable2) {				localThrowable2.printStackTrace();			}		}		try {			Intent localIntent3 = new Intent();			localIntent3.setAction("out_going_call_to_phone_app");			localIntent3.putExtra("number", paramString);			localIntent3.putExtra("simId", paramInt);			localIntent3.putExtra("com.android.phone.extra.slot", paramInt);			localIntent3.putExtra("launch_from_dialer", 1);			localIntent3.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);			getContext().sendBroadcast(localIntent3);			return true;		} catch (Throwable localThrowable3) {			localThrowable3.printStackTrace();		}		return false;	}	@Override	public AbsSim detect() {		String imsi = getIMSI(0);		if (imsi != null && !TextUtils.isEmpty(imsi)) {			return this;		}		return super.detect();	}	@Override	public String getSimPhoneNumber(int paramInt) {		Object[] arrayOfObject2 = new Object[1];		try {			Object localObject = getMSimTelephonyManager(paramInt);			arrayOfObject2[0] = Integer.valueOf(paramInt);			String result = (String) ReflecterHelper.invokeMethod(localObject,					"getLine1NumberGemini", arrayOfObject2);			arrayOfObject2 = null;			return result;		} catch (Throwable localThrowable) {			localThrowable.printStackTrace();		}		return "";	}	@Override	public int getDataState(int paramInt) {		Object[] arrayOfObject2 = new Object[1];		try {			Object localObject = getMSimTelephonyManager(paramInt);			arrayOfObject2[0] = Integer.valueOf(paramInt);			int result = ((Integer) ReflecterHelper.invokeMethod(localObject,					"getDataStateGemini", arrayOfObject2)).intValue();			arrayOfObject2 = null;			return result;		} catch (Throwable localThrowable) {			localThrowable.printStackTrace();		}		arrayOfObject2 = null;		return -1;	}	@Override	public String getIMSI(int paramInt) {		return getIMSI(paramInt, null);	}	@Override	public String getIMSI(int paramInt, Context paramContext) {		Object localObject = getMSimTelephonyManager(paramInt);		Object[] arrayOfObject2 = new Object[1];		try {			arrayOfObject2[0] = Integer.valueOf(paramInt);			String result = (String) ReflecterHelper.invokeMethod(localObject,					"getSubscriberIdGemini", arrayOfObject2);			arrayOfObject2 = null;			return result;		} catch (Throwable localThrowable) {			localThrowable.printStackTrace();		}		arrayOfObject2 = null;		return null;	}	@Override	public int getPhoneState(int paramInt) {		Object localObject = getMSimTelephonyManager(paramInt);		Object[] arrayOfObject2 = new Object[1];		try {			arrayOfObject2[0] = Integer.valueOf(paramInt);			int result = ((Integer) ReflecterHelper.invokeMethod(localObject,					"getCallStateGemini", arrayOfObject2)).intValue();			arrayOfObject2 = null;			return result;		} catch (Throwable localThrowable) {			localThrowable.printStackTrace();		}		arrayOfObject2 = null;		return 0;	}	@Override	public boolean isServiceAvaliable(int paramInt) {		Object localObject = getITelephonyMSim(paramInt);		if (localObject == null)			return false;		Object[] arrayOfObject2 = new Object[1];		try {			arrayOfObject2[0] = Integer.valueOf(paramInt);			boolean result = ((Boolean) ReflecterHelper.invokeMethod(					localObject, "isRadioOnGemini", arrayOfObject2))					.booleanValue();			arrayOfObject2 = null;			return result;		} catch (Throwable localThrowable) {			localThrowable.printStackTrace();		}		arrayOfObject2 = null;		return false;	}	@Override	public boolean isSimStateIsReady(int paramInt) {		Object localObject = getMSimTelephonyManager(paramInt);		if (localObject != null) {			Object[] arrayOfObject2 = new Object[1];			try {				arrayOfObject2[0] = Integer.valueOf(paramInt);				int result = ((Integer) ReflecterHelper.invokeMethod(						localObject, "getSimStateGemini", arrayOfObject2))						.intValue();				arrayOfObject2 = null;				return result == 5;			} catch (Throwable localThrowable) {				localThrowable.printStackTrace();			}			arrayOfObject2 = null;		}		return false;	}	@Override	public int getSimOperator(int paramInt) { // 注意		Object localObject = getMSimTelephonyManager(paramInt);		Object[] arrayOfObject2 = new Object[1];		try {			arrayOfObject2[0] = Integer.valueOf(paramInt);			String result = ((String) ReflecterHelper.invokeMethod(localObject,					"getSimOperatorGemini", arrayOfObject2));			arrayOfObject2 = null;			return Integer.valueOf(result);		} catch (Throwable localThrowable) {			localThrowable.printStackTrace();		}		arrayOfObject2 = null;		return 0;	}	@Override	protected Object getITelephonyMSim(int paramInt) {		if (mTelephonyMSim == null)			mTelephonyMSim = ITelephony.Stub.asInterface(ServiceManager					.getService("phone"));		return mTelephonyMSim;	}	@Override	protected Object getMSimTelephonyManager(int paramInt) {		if (mMSimTelephonyManager != null)			return mMSimTelephonyManager;		Object[] arrayOfObject3 = new Object[1];		try {			mMSimTelephonyManager = SimManager.getInstance()					.getTelephonyManagerByPhone();			try {				Object localObject = mMSimTelephonyManager;				arrayOfObject3[0] = Integer.valueOf(0);				ReflecterHelper.invokeMethod(localObject,						"getSubscriberIdGemini", arrayOfObject3);				arrayOfObject3 = null;				return mMSimTelephonyManager;			} catch (Throwable localThrowable2) {				localThrowable2.printStackTrace();			}		} catch (Throwable localThrowable1) {			localThrowable1.printStackTrace();		}		arrayOfObject3 = null;		return null;	}}

再列举一款单卡的方案:

public class SingleSim extends AbsSim implements IDualDetector {// 单卡方案	private final String TAG = getClass().getSimpleName();	private HashMap<String, Byte> mCallLogExtraFields = new SingleSim$1(this);	@Override	public boolean hasSimPhone() {		return false;	}	@Override	public AbsSim detect() {// 根据某些字段判是否为双卡(有可能误判)		if (mIsDualSimPhone)			return null;		Cursor localSafeCursor = null;		String[] arrayOfString;		try {			localSafeCursor = SimManager					.getInstance()					.getContext()					.getContentResolver()					.query(CallLog.Calls.CONTENT_URI, null, null, null,							"_id limit 0,1");			if (localSafeCursor != null && localSafeCursor.moveToFirst()) {				arrayOfString = localSafeCursor.getColumnNames();				for (int i = 0; i < arrayOfString.length; i++) {					String str = arrayOfString[i];					if (mCallLogExtraFields.containsKey(str.toLowerCase())) {						mIsDualSimPhone = true;						mCallLogExtraField = str;					}				}			}		} catch (Exception e) {			e.printStackTrace();		}		return this;	}	@Override	public boolean isDualSimPhone() {		return mIsDualSimPhone;	}	@Override	public int getSimSlotNum() {		return 1;	}	@Override	public String getSimPhoneNumber(int paramInt) {		return ((TelephonyManager) getMSimTelephonyManager(0)).getLine1Number();	}	@Override	public int getDataState(int paramInt) {		return ((TelephonyManager) getMSimTelephonyManager(0)).getDataState();	}	@Override	public String getIMSI(int paramInt) {		return ((TelephonyManager) getMSimTelephonyManager(0)).getDeviceId();	}	@Override	public String getIMSI(int paramInt, Context paramContext) {		return ((TelephonyManager) getMSimTelephonyManager(0))				.getSubscriberId();	}	@Override	public int getPhoneState(int paramInt) {		return ((TelephonyManager) getMSimTelephonyManager(0)).getCallState();	}	@Override	public boolean isServiceAvaliable(int paramInt) {		ITelephony localITelephony = (ITelephony) getITelephonyMSim(0);		if (localITelephony == null)			return false;		try {			boolean bool = localITelephony.isRadioOn();			return bool;		} catch (Throwable localThrowable) {			localThrowable.printStackTrace();		}		return false;	}	@Override	public boolean isSimStateIsReady(int paramInt) {		return ((TelephonyManager) getMSimTelephonyManager(0)).getSimState() == 5;	}	@Override	public int getSimOperator(int paramInt) {		TelephonyManager localTelephonyManager = (TelephonyManager) getMSimTelephonyManager(paramInt);		return Integer.parseInt(localTelephonyManager.getSimOperator());	}	@Override	protected Object getITelephonyMSim(int paramInt) {		return SimManager.getInstance().getITelephonyByPhone();	}	@Override	protected Object getMSimTelephonyManager(int paramInt) {		return SimManager.getInstance().getTelephonyManagerByPhone();	}}

总结

利用java 反射机制操作Android隐藏的类,很好的解决了双卡双待的问题。
Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。


项目下载

2楼sara_loveyou46分钟前
楼主的精神可嘉,不知道是否能够覆盖市面上80%以上的设备
Re: banketree30分钟前
回复sara_loveyoun写该项目就是冲着广大用户而来。
1楼flxue昨天 23:49
赞一个,java reflection是没法直接获取API时候比较长想到的方式,不过会不会遇到permission check虽然知道的接口但实际没法跑?
Re: banketree59分钟前
回复flxuen测试截至此刻,未检测到任何问题。
  相关解决方案