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

相关推荐
JhonKI8 小时前
【MySQL】存储引擎 - CSV详解
android·数据库·mysql
开开心心_Every8 小时前
手机隐私数据彻底删除工具:回收或弃用手机前防数据恢复
android·windows·python·搜索引擎·智能手机·pdf·音视频
大G哥9 小时前
Kotlin Lambda语法错误修复
android·java·开发语言·kotlin
鸿蒙布道师12 小时前
鸿蒙NEXT开发动画案例2
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
androidwork12 小时前
Kotlin Android工程Mock数据方法总结
android·开发语言·kotlin
xiangxiongfly91514 小时前
Android setContentView()源码分析
android·setcontentview
人间有清欢15 小时前
Android开发补充内容
android·okhttp·rxjava·retrofit·hilt·jetpack compose
人间有清欢16 小时前
Android开发报错解决
android
每次的天空18 小时前
Android学习总结之kotlin协程面试篇
android·学习·kotlin
每次的天空19 小时前
Android学习总结之Binder篇
android·学习·binder