文章目录
需求
当安卓手机插入多张卡时,会弹出窗口提示用户对默认卡进行选择,这里的需求是不弹出窗口,默认选择其中一张卡为默认的卡。

原生弹窗源码分析
在 Android 系统里,SimSelectNotification.java 这个类主要负责处理与 SIM 卡选择相关的通知,而 startSimSelectDialogIfNeeded 方法的用途是在有必要时启动 SIM 卡选择对话框。当设备存在多张 SIM 卡,并且系统需要用户选择使用哪张 SIM 卡来执行某些操作(如拨打电话、发送短信、使用数据流量等)时,这个方法就会发挥作用。
packages/apps/Settings/src/com/android/settings/sim/SimSelectNotification.java
MTK可能会定制,存放在
vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/sim/SimSelectNotification.java
startSimSelectDialogIfNeeded函数用于启动SIM卡选择对话框
java
/**
* 该方法用于在必要时启动 SIM 卡选择对话框。
* 它会根据传入的 Intent 中的信息判断是否需要弹出对话框,以及弹出何种类型的对话框。
*
* @param context 上下文对象,用于启动活动、发送通知等操作。
* @param intent 包含 SIM 卡选择相关信息的 Intent 对象。
*/
private void startSimSelectDialogIfNeeded(Context context, Intent intent) {
// 从 Intent 中获取默认 SIM 卡选择类型,若未找到则使用默认值 EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE
int dialogType = intent.getIntExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE,
EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE);
// 如果对话框类型为 EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE,表示不需要进行任何选择操作,直接返回
if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE) {
return;
}
// 取消之前可能存在的 SIM 卡选择通知
// 这一步是为了避免多个通知同时显示造成混淆
cancelSimSelectNotification(context);
// 创建一个通知,告知用户某些默认设置缺失
// 当需要用户进行 SIM 卡选择时,先通过通知提醒用户
createSimSelectNotification(context);
// 如果对话框类型是 EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL,即需要选择所有默认设置
if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL) {
// 从 Intent 中获取订阅 ID,若未找到则使用默认值 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID
int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_ID,
SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
// 根据订阅 ID 获取对应的 SIM 卡槽索引
int slotIndex = SubscriptionManager.getSlotIndex(subId);
// 如果设备中只有一个 SIM 卡订阅,询问用户是否希望将其用于所有操作
// 创建一个新的 Intent,用于启动 SimDialogActivity 活动
Intent newIntent = new Intent(context, SimDialogActivity.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 向 Intent 中添加对话框类型信息,这里设置为 SimDialogActivity.PREFERRED_PICK,表示选择首选 SIM 卡
newIntent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY,
SimDialogActivity.PREFERRED_PICK);
// 向 Intent 中添加首选 SIM 卡的卡槽索引
newIntent.putExtra(SimDialogActivity.PREFERRED_SIM, slotIndex);
// 使用传入的上下文启动 SimDialogActivity 活动
context.startActivity(newIntent);
}
// 如果对话框类型是 EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA,即需要选择默认数据 SIM 卡
else if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA) {
// 如果设备中有多个 SIM 卡订阅,确保用户选择默认的数据 SIM 卡
// 创建一个新的 Intent,用于启动 SimDialogActivity 活动
Intent newIntent = new Intent(context, SimDialogActivity.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 向 Intent 中添加对话框类型信息,这里设置为 SimDialogActivity.DATA_PICK,表示选择数据 SIM 卡
newIntent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.DATA_PICK);
// 使用传入的上下文启动 SimDialogActivity 活动
context.startActivity(newIntent);
}
}
修改代码实现
如果要设置默认的SIM卡,可以修改startSimSelectDialogIfNeeded实现。假设要屏蔽掉数据卡的选择弹窗,直接默认选择SIM卡2,核心思路是:删除 / 注释掉启动弹窗的代码,替换为 "直接设置 SIM 卡 2 为默认数据卡" 的逻辑,改成如下这样:
java
import java.util.List;
private void startSimSelectDialogIfNeeded(Context context, Intent intent) {
int dialogType = intent.getIntExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE,
EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE);
if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE) {
return;
}
cancelSimSelectNotification(context);
createSimSelectNotification(context);
if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL) {
int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_ID,
SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
int slotIndex = SubscriptionManager.getSlotIndex(subId);
Intent newIntent = new Intent(context, SimDialogActivity.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
newIntent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY,
SimDialogActivity.PREFERRED_PICK);
newIntent.putExtra(SimDialogActivity.PREFERRED_SIM, slotIndex);
context.startActivity(newIntent);
}
else if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA) {
/*
Intent newIntent = new Intent(context, SimDialogActivity.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
newIntent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.DATA_PICK);
context.startActivity(newIntent);
*/
// 1. 获取SubscriptionManager(SIM卡管理核心类)
SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
// 2. 获取所有激活的SIM卡信息
List<SubscriptionInfo> activeSubs = subscriptionManager.getActiveSubscriptionInfoList();
if (activeSubs != null && activeSubs.size() >= 2) {
// 3. 定位SIM卡2(卡槽索引1,AOSP卡槽索引从0开始:0=卡1,1=卡2)
SubscriptionInfo sim2Info = subscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(1);
if (sim2Info != null) {
// 4. 强制设置SIM卡2为默认数据卡
subscriptionManager.setDefaultDataSubId(sim2Info.getSubscriptionId());
// 可选:标记数据卡已设置,避免系统重复触发弹窗
Settings.Secure.putInt(context.getContentResolver(), "def_preferred_network_mode", sim2Info.getSubscriptionId());
}
}
}
验证效果
- 重新编译 Settings 模块:
bash
mmm packages/apps/Settings/
- 刷入编译后的Settings.apk到设备(或全编译系统镜像);
- 重启设备,插入双 SIM 卡后:
3.1 不再弹出 "选择默认数据卡" 的弹窗;
3.2 进入 "设置 - 移动网络/蜂窝网络 - 默认数据卡",确认已自动选中 SIM 卡 2;
3.3 测试数据网络,确认流量走 SIM 卡 2。


Android Framework专栏
部分内容如下:


作者:帅得不敢出门