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的可用性及点击事件拦截,实现符合运营商需求的设置菜单逻辑。

相关推荐
AD钙奶-lalala2 小时前
某车企面试备忘
android
我爱拉臭臭3 小时前
kotlin音乐app之自定义点击缩放组件Shrink Layout
android·java·kotlin
匹马夕阳4 小时前
(二十五)安卓开发一个完整的登录页面-支持密码登录和手机验证码登录
android·智能手机
吃饭了呀呀呀4 小时前
🐳 深度解析:Android 下拉选择控件优化方案——NiceSpinner 实践指南
android·java
吃饭了呀呀呀5 小时前
🐳 《Android》 安卓开发教程 - 三级地区联动
android·java·后端
_祝你今天愉快6 小时前
深入剖析Java中ThreadLocal原理
android
张力尹7 小时前
谈谈 kotlin 和 java 中的锁!你是不是在协程中使用 synchronized?
android
流浪汉kylin7 小时前
Android 斜切图片
android
PuddingSama8 小时前
Android 视图转换工具 Matrix
android·前端·面试
RichardLai888 小时前
[Flutter学习之Dart基础] - 控制语句
android·flutter