1. 程式人生 > >Android 雙卡雙待識別

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);// 獲取操作介面

}

現在列舉一款實現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) {
……
		return false;
	}

	@Override
	public AbsSim detect() {
		return super.detect();
	}

	@Override
	public String getSimPhoneNumber(int paramInt) {
		return "";
	}

	@Override
	public int getDataState(int paramInt) {
		return -1;
	}

	@Override
	public String getIMSI(int paramInt) {
		return getIMSI(paramInt, null);
	}

	@Override
	public String getIMSI(int paramInt, Context paramContext) {
		return null;
	}

	@Override
	public int getPhoneState(int paramInt) {
		return 0;
	}

	@Override
	public boolean isServiceAvaliable(int paramInt) {
		return false;
	}

	@Override
	public boolean isSimStateIsReady(int paramInt) {
		return false;
	}

	@Override
	public int getSimOperator(int paramInt) { // 注意
		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) {
		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() {// 根據某些欄位判是否為雙卡(有可能誤判)
		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) {
		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。

專案下載