背景描述
- sdk支持的流量管理功能需要配置運營商省份和品牌兩個信息后才可以生效
- 在雙卡的場景下,由于sdk的問題,假如卡槽1上的卡做過配置,卡槽2的卡在未正確配置的情況下,sdk會自動分配卡槽1的運營商配置信息給卡槽2,導致卡槽2出現(xiàn)無法通過短信校準流量的問題
- 假如兩張卡都進行過運營商配置,用戶手工交換兩張卡的位置,sdk無法自動檢查這種情況,不能及時更新sim卡配置信息,導致流量校驗等功能失效
監(jiān)聽sim卡插拔并且提醒用戶發(fā)生配置變更的解決方案
<receiver android:name="com.oneplus.security.network.simcard.SimcardStateChangeReceiver"
android:exported="true"
android:enabled="true" >
<intent-filter>
<action android:name="android.intent.action.SIM_STATE_CHANGED"/>
</intent-filter>
</receiver>
@Override
public void onReceive (Context context, Intent intent) {
String action = intent.getAction();
if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
String state = intent.getStringExtra(SimStateListener.SIM_STATE_KEY);
if (SimStateListener.SS_ABSENT.equals(state)) {
SimcardStateManager.setShouldAlertSimcardHasPopedOut(context, true,
SimcardDataModelInterface.SIM_CARD_ONE_INDEX);
SimcardStateManager.setShouldAlertSimcardHasPopedOut(context, true,
SimcardDataModelInterface.SIM_CARD_TWO_INDEX);
}
}
}
- 注冊靜態(tài)廣播,監(jiān)聽sim卡插拔狀態(tài)的變化,發(fā)生sim卡absent事件時,設置需要提醒用戶配置流量標識(alert_data_change_flag)為true,每次啟動流量管理界面時,都彈出對話框提示,假如用戶跟隨對話框提示的指引進入配置頁面,則認為用戶已經正確做完配置,重置標志位alert_data_change_flag為false
- 這個方案的問題
- 假如用戶曾經做過正確的配置,只是因為某些原因重插拔卡,提示會造成干擾
- 監(jiān)聽SS_ABSENT的方法不合適,因為手機重新開機時,sim卡會走一遍從SS_ABSENT過渡到SS_READY的過程,因為我們注冊了靜態(tài)廣播,即使用戶沒做過任何插拔卡動作,也會觸發(fā)提醒
- 這個問題根本上是解決怎么保存用戶配置問題,而不是插拔卡的問題,以監(jiān)聽插拔卡來設置標記的方式,只是針對現(xiàn)象做補救,而不解決根本問題
怎么保存用戶的配置信息
找到唯一標識sim卡的id信息
咨詢其他同事,可以用sim卡的subId來做標識,在一臺手機上,每次插入一張新的sim卡,手機會給這張卡一個遞增的subId,即便以后發(fā)生過換卡等操作,再次使用這張卡時,也會使用之前保存過的subId來標識舊的sim卡,所以方案演變成
以sim卡的subId為key做永久存儲,通過檢查一個subId對應的value有效性的方式決定要不要提示用戶重新配置
- 在用戶配置運營商信息時,獲取被設置卡的subId,以之為key做永久存儲,參考CarrierConfigFragment.java
@Override
public boolean onPreferenceChange (Preference preference, Object newValue) {
if (preference == mProvinceSelection) {
String newProvince = String.valueOf(newValue);
if (null != mOperatorPrefModel) {
mOperatorPrefModel.setProvince(newProvince);
SimcardInfoSaver.saveSimcardProvinceBySubId(getActivity(), mSubId, newProvince);
}
return true;
} else if (preference == mBrandSelection) {
String newBrand = String.valueOf(newValue);
if (null != mOperatorPrefModel) {
mOperatorPrefModel.setBrand(newBrand);
SimcardInfoSaver.saveSimcardBrandBySubId(getActivity(), mSubId, newBrand);
}
return true;
}
return false;
}
- 依舊監(jiān)聽sim卡插拔狀態(tài)的監(jiān)聽,避免做不必要的更新檢查
- 在需要檢查的時候,根據(jù)卡槽上某張卡的subId獲取province和brand等信息,做有效性檢查,有效重新設置,無效發(fā)出警告,以下代碼在流量管理的主界面管理代碼中
private boolean alertSimcardOneIfNecessary () {
return getShouldAlertSimcardChange(SimcardDataModelInterface.SIM_CARD_ONE_INDEX, new SimcardProvinceAndBrandSetter() {
@Override
public void setProvinceAndBrand (String province, String brand) {
if (null != mOperatorDataModelSimOne) {
mOperatorDataModelSimOne.setProvince(SimcardDataModelInterface
.SIM_CARD_ONE_INDEX, province);
mOperatorDataModelSimOne.setOperatorBrand(SimcardDataModelInterface
.SIM_CARD_ONE_INDEX, brand);
}
}
});
}
private boolean alertSimcardTwoIfNecessary() {
return getShouldAlertSimcardChange(SimcardDataModelInterface.SIM_CARD_TWO_INDEX, new SimcardProvinceAndBrandSetter() {
@Override
public void setProvinceAndBrand (String province, String brand) {
if (null != mOperatorDataModelSimTwo) {
mOperatorDataModelSimTwo.setProvince(SimcardDataModelInterface
.SIM_CARD_TWO_INDEX, province);
mOperatorDataModelSimTwo.setOperatorBrand(SimcardDataModelInterface
.SIM_CARD_TWO_INDEX, brand);
}
}
});
}
private boolean getShouldAlertSimcardChange (int slotId, final SimcardProvinceAndBrandSetter
setter) {
if (null == mSimcardDataModel) {
return false;
}
final Context c = getActivity();
if (mCurrentDataSlotId == SimcardDataModelInterface.INVALID_SIM_SLOT_ID) {
return false;
}
if (!SimcardStateManager.getShouldAlertSimcardHasPopedOut(getActivity(), slotId)) {
return false;
}
boolean shouldAlertSimcardChangeDialog = false;
if (mSimcardDataModel.isSlotSimInserted(slotId)
&& mSimcardDataModel.isSlotOperatorSupportedBySdk(slotId)) {
int subId = SimcardDataModel.staticGetSubIdBySlotId(slotId);
String province = SimcardInfoSaver.getSimcardProvinceBySubId(getActivity(), subId);
String brand = SimcardInfoSaver.getSimcardBrandBySubId(getActivity(), subId);
if (SimcardInfoSaver.SIMCARD_BRAND_INVALID_VALUE.equals(brand)
|| SimcardInfoSaver.SIMCARD_PROVINCE_INVALID_VALUE.equals(province)) {
LogUtils.LogD(TAG, "alert slot1 error " + brand + " " + province);
if (SimcardStateManager.getShouldAlertSimcardHasPopedOut(getActivity(), slotId)) {
showReconfigSimcardAlert(c, slotId);
shouldAlertSimcardChangeDialog = true;
} else {
shouldAlertSimcardChangeDialog = false;
}
} else {
LogUtils.LogD(TAG, "detect simcard change and reset sdk information on slot 1.");
setter.setProvinceAndBrand(province, brand);
}
}
return shouldAlertSimcardChangeDialog;
}
private interface SimcardProvinceAndBrandSetter {
void setProvinceAndBrand(String province, String brand);
}
private void showReconfigSimcardAlert (final Context c, final int slotId) {
AlertDialog.Builder builder = new AlertDialog.Builder(c);
builder.setCancelable(true);
StringBuilder sb = new StringBuilder();
sb.append(getSimCardDescriptions(slotId));
sb.append("\r\n");
sb.append(c.getText(R.string.detect_simcard_change_please_confirm_config));
builder.setMessage(sb.toString());
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick (DialogInterface dialog, int which) {
startSpecificTrafficConfigSettingsActivity(slotId);
}
});
builder.create().show();
}
- 代碼的觸發(fā)點有兩個位置,一個是進入流量管理界面的動畫結束之后,另一個是點擊流量校準按鈕的時候
@Override
public void pageInAnim () {
super.pageInAnim();
mDataTopView.animtionCircle(true);
if (null != mOperatorDataModel) {
mOperatorDataModel.requesetPkgMonthlyUsageAndTotalInByte(mCurrentDataSlotId);
}
alertSimcardOneIfNecessary();
alertSimcardTwoIfNecessary();
}
mSimDataUsageQueryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick (View v) {
...
if (SimcardDataModelInterface.SIM_CARD_ONE_INDEX == mCurrentDataSlotId) {
if (alertSimcardOneIfNecessary()) {
return;
}
} else if (SimcardDataModelInterface.SIM_CARD_TWO_INDEX == mCurrentDataSlotId) {
if (alertSimcardTwoIfNecessary()) {
return;
}
} else {
// CurrentDataSlotId is invalid, should do nothing but return. actually, in
// this circumstances, data calibrate button is invisible.
return;
}
...
}
};
測試建議及其他
- 非sdk支持的運營商卡,不會產生自動配置省份和品牌的行為,因為本身就不需要設置 比如小米卡
- 單張卡插入 從未配置過的sim卡 活動到流量頁或者點擊流量校準按鈕
- 會彈出需要配置的提示框 點擊邊緣可以退出提示框使用其他功能 但是重復步驟2會繼續(xù)提示
- 有兩種方法可以終止提示 a.點擊提示框的確定跳轉到設置界面 b.點擊流量套餐配置跳轉到設置界面
- 已經配置過的sim卡,如果沒有做過清除用戶數(shù)據(jù)的操作,即使交換卡位,預期可以自動完成sim卡配置,不會彈出提示框,手工進入 流量套餐配置預期可以查看到正確的配置,流量校準使用正常
- 雙卡的情況下,如果兩張卡都配置過,無論是否交換卡位,預期不會彈提示框,進入對應卡槽的配置界面,預期省份及品牌信息顯示正確,功能正常
- 雙卡情況下,兩張卡均未配置過,會提示用戶進行配置
- 雙卡,一張配置、一張未配置,且都被sdk支持,即使交換卡位,預期已配置的卡顯示正確,功能正常,未配置過的卡會按照2的邏輯彈出提示
- 已配置過的卡且或者未配置過的卡進行過4中操作,重啟手機不會重復彈框
- 未配置過的卡并且未進行過4中操作,重啟手機,滑動到流量界面,點擊校準按鈕,都會彈框提示
最終效果
已經配置過的sim卡,可以正常識別并進行重新設置,不會頻繁騷擾用戶