Android 定制飞行模式和通话中设置菜单置灰

业务背景

定制需求实现

目标:通话中禁用移动网络设置中的网络模式和APN入口

Google原生行为分析

在原生Android中:

  1. 飞行模式

    • 无法在通话中开启:系统会自动阻止,因飞行模式会断开通话所需的射频。
    • APN/网络模式修改:通话中允许进入设置,但修改可能导致数据连接中断(取决于版本,部分版本会自动禁用)。
  2. 通话中设置菜单状态

    • 网络模式(如4G/3G切换):通常允许修改,但可能不立即生效。
    • APN配置:允许进入,但保存新APN可能导致当前数据会话重置。

原生与定制的对比

场景 Google原生行为 定制后行为
通话中修改网络模式 允许但可能中断数据连接 禁止,菜单项置灰
通话中进入APN设置 允许,保存可能重置数据 禁止,Toast提示并拦截跳转
飞行模式下的移动网络 直接隐藏或禁用整个菜单 明确置灰,提示不可用

方案分析

代码关键点

  • 通话状态判断 :通过TelephonyManager.CALL_STATE判断是否在通话中。
  • Preference动态控制 :使用setEnabled(false)置灰,并通过点击事件拦截防止跳转。
  • 广播监听飞行模式:实时响应飞行模式开关,禁用整个移动网络菜单。

方案逻辑

  1. 在相关的PreferenceFragment(如MobileNetworkSettings)中注册一个通话状态监听器。
  2. 当通话状态变为OFFHOOK(正在通话中),则禁用网络模式和APN的Preference。
  3. 当通话结束后,恢复这些Preference的可用状态。
  4. 可能需要覆盖Preference的点击事件,在通话中阻止跳转到APN设置页面。

针对代码实现的具体步骤:

首先,找到移动网络设置中的相关Preference的key,比如"network_mode"和"apn_settings"。

在MobileNetworkSettings.java中,可能需要添加如下逻辑:

  • 在onCreate()中初始化这些Preference。
  • 在onResume()中注册通话状态监听,比如通过TelephonyManager.listen()。
  • 当通话状态改变时,更新Preference的enabled状态。
  • 在onPause()中取消注册监听器,以避免资源泄漏。

另外,APN设置的入口可能是一个PreferenceScreen,点击后会跳转到ApnSettings。因此,需要禁用该Preference,或者在点击时检查通话状态,并弹出提示。

代码

实现步骤

1. 监听通话状态

在设置页面的Fragment(如MobileNetworkSettings.java)中注册通话状态监听:

java 复制代码
// 添加成员变量
private TelephonyManager mTelephonyManager;
private PhoneStateListener mPhoneStateListener;
private boolean mInCall = false;

// 在onCreate中初始化
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mTelephonyManager = getSystemService(TelephonyManager.class);
    mPhoneStateListener = new PhoneStateListener() {
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            mInCall = (state != TelephonyManager.CALL_STATE_IDLE);
            updatePreferenceStates();
        }
    };
}

// 在onResume中注册监听
@Override
public void onResume() {
    super.onResume();
    mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}

// 在onPause中取消注册
@Override
public void onPause() {
    super.onPause();
    mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
}
2. 动态控制Preference状态
java 复制代码
private void updatePreferenceStates() {
    // 获取网络模式和APN的Preference
    Preference networkModePref = findPreference("network_mode_key");
    Preference apnPref = findPreference("apn_settings_key");

    if (networkModePref != null) {
        networkModePref.setEnabled(!mInCall);
    }

    if (apnPref != null) {
        apnPref.setEnabled(!mInCall);
        // 拦截点击事件
        apnPref.setOnPreferenceClickListener(preference -> {
            if (mInCall) {
                Toast.makeText(getContext(), "Cannot modify APN during a call", 
                    Toast.LENGTH_SHORT).show();
                return true; // 阻止跳转
            }
            return false; // 允许正常跳转
        });
    }
}
3. 飞行模式下的处理

监听飞行模式变化并禁用相关菜单:

java 复制代码
// 在Fragment中添加广播接收器
private BroadcastReceiver mAirplaneModeReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        boolean isAirplaneModeOn = Settings.Global.getInt(getContentResolver(),
            Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
        updatePreferenceStatesForAirplaneMode(isAirplaneModeOn);
    }
};

// 注册广播
@Override
public void onResume() {
    super.onResume();
    // 通话状态监听...
    registerReceiver(mAirplaneModeReceiver, 
        new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
}

@Override
public void onPause() {
    super.onPause();
    unregisterReceiver(mAirplaneModeReceiver);
}

private void updatePreferenceStatesForAirplaneMode(boolean isAirplaneModeOn) {
    Preference mobileNetworkPref = findPreference("mobile_network_key");
    if (mobileNetworkPref != null) {
        mobileNetworkPref.setEnabled(!isAirplaneModeOn);
    }
}

相关类

Android提供了TelephonyManager,可以监听通话状态。例如,通过监听TelephonyManager.EXTRA_STATE,或者使用PhoneStateListener来监听通话状态的变化。

java 复制代码
package android.telephony;

public class TelephonyManager {

    public static final int CALL_COMPOSER_STATUS_BUSINESS_ONLY = 2;
    public static final int CALL_COMPOSER_STATUS_OFF = 0;
    public static final int CALL_COMPOSER_STATUS_ON = 1;
    public static final int CALL_STATE_IDLE = 0;
    public static final int CALL_STATE_OFFHOOK = 2;
    public static final int CALL_STATE_RINGING = 1;

}

当检测到通话处于活动状态时(比如,来电接通时),需要禁用相关Preference。

总结

通过监听通话状态和飞行模式,动态控制Preference的可用性及点击事件拦截,实现符合运营商需求的设置菜单逻辑。

相关推荐
数智工坊4 小时前
机器人运动控制:采样、优化与学习三大流派深度对比与实战
android·学习·机器人
故渊at6 小时前
第二板块:Android 四大组件标准化学理 | 第八篇:Service 后台执行实体与优先级
android·gitee·service·前台服务·后台服务
会Tk矩阵群控的小木6 小时前
安卓群控系统对于游戏工作室实战教程
android·运维·游戏·adb·开源软件·个人开发
qeen877 小时前
【C++】类与对象之类的默认成员函数(二)
android·c语言·开发语言·c++·笔记·学习
故渊at7 小时前
第二板块:Android 四大组件标准化学理 | 第九篇:BroadcastReceiver 事件分发与有序广播
android·gitee·broadcast·广播·动态注册·静态注册
JohnnyDeng947 小时前
【Android】Room 数据库高级用法与性能调优:从查询瓶颈到毫秒级响应
android·性能优化·kotlin·room
zeqinjie8 小时前
Flutter 折叠屏 iPad / 宽屏适配实践
android·前端·flutter
ab_dg_dp8 小时前
Android 17+ 提取 AIDL 生成 Java 文件的实用脚本
android·java·python
Arrom8 小时前
DLNA 渲染端排障实战:从 20s 卡顿到 stale subscriber 的两周追凶之旅
android·java