Android Mobile Network Settings | APN 菜单加载异常

问题

从log看是有创建APN对应的Controller(功能逻辑是ok的),但是Mobile Network Settings无法显示(UI异常)。

日志分析

看似APN 菜单已经创建了,实际上并没有显示。

11-12 07:01:28.150  8773  8773 D PrefCtrlListHelper: Could not find Context-only controller for pref: com.android.settings.network.telephony.ApnPreferenceController

11-12 07:01:28.164  8773  8773 D ApnPreferenceController: init: subId = 1

Debug 1:表面原因 isGsmApn

debug打印log的时候会发现,使用平板时preference是不可见的,无法确认是不是getAvailabilityStatus影响了displayPreference。

  • Tablet Log:

11-13 17:10:46.692  7796  9288 D ApnPreferenceController: getAvailabilityStatus hideCarrierNetwork = false, isCdmaApn = false, isGsmApn = false

11-13 17:10:46.705  7796  7796 I ApnPreferenceController: displayPreference: isShow = false, isVisible = false, isEnable = true

  • Phone Log:

11-13 03:25:47.285 13222 13222 D ApnPreferenceController: init: subId = 3

11-13 03:25:47.323 13222 13401 D ApnPreferenceController: getAvailabilityStatus hideCarrierNetwork = false, isCdmaApn = false, isGsmApn = true

11-13 03:25:47.372 13222 13222 I ApnPreferenceController: displayPreference: isShow = true, isVisible = true, isEnable = true

Debug 2:根因 isGsmOptions

  • Phone Log:

11-13 05:14:30.305 15022 15022 D SatelliteSettingPreferenceController: init(), subId=3
11-13 05:14:30.305 15022 15022 D ApnPreferenceController: init: subId = 3

11-13 05:14:30.354 15022 15233 D ApnPreferenceController: isGsmOption = true
11-13 05:14:30.354 15022 15233 D ApnPreferenceController: KEY_APN_EXPAND_BOOL = true

11-13 05:14:30.355 15022 15233 D ApnPreferenceController: getAvailabilityStatus hideCarrierNetwork = false, isCdmaApn = false, isGsmApn = true

11-13 05:14:30.448 15022 15022 I ApnPreferenceController: displayPreference: isShow = true, isVisible = true, isEnable = true

11-13 05:14:31.218 15022 15022 D ApnPreferenceController: updateState: preferenceKey = telephony_apn_key

11-13 05:14:32.350 15022 15022 D ApnPreferenceController: handlePreferenceTreeClick

  • Tablet Log:

11-13 18:13:24.359 11793 11793 D ApnPreferenceController: isGsmOption = false

11-13 18:13:24.359 11793 11793 D ApnPreferenceController: KEY_APN_EXPAND_BOOL = true

11-13 18:13:24.359 11793 11793 D ApnPreferenceController: getAvailabilityStatus hideCarrierNetwork = false, isCdmaApn = false, isGsmApn = false

11-13 18:13:24.360 11793 11793 I ApnPreferenceController: displayPreference: isShow = false, isVisible = false, isEnable = true

代码解读

移动网络界面加入APN的菜单

mobile_network_settings.xml

先来看看界面设计逻辑

<!-- Copyright (C) 2019 The Android Open Source Project --><PreferenceScreenxmlns:android="http://schemas.android.com/apk/res/android"xmlns:settings="http://schemas.android.com/apk/res-auto"android:key="mobile_network_pref_screen"><com.android.settings.spa.preference.ComposePreferenceandroid:key="use_sim_switch"settings:controller="com.android.settings.network.telephony.MobileNetworkSwitchController"/><!-- 省略移动网络其他controller --><!--We want separate APN setting from reset of settings because we want user to change it with caution--><com.android.settingslib.RestrictedPreferenceandroid:key="telephony_apn_key"android:persistent="false"android:title="@string/mobile_network_apn_title"settings:keywords="@string/keywords_access_point_names"settings:controller="com.android.settings.network.telephony.ApnPreferenceController"/></PreferenceScreen>

标题定义

packages\apps\Settings\res\values\strings.xml

    <!-- Title for Apn settings in mobile network settings [CHAR LIMIT=60] --><string name="mobile_network_apn_title">Access Point Names</string>

ApnPreferenceController

    @Overridepublic int getAvailabilityStatus(int subId) {final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(subId);final boolean isCdmaApn = MobileNetworkUtils.isCdmaOptions(mContext, subId)&& carrierConfig != null&& carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_APN_SETTING_CDMA_BOOL);final boolean isGsmApn = MobileNetworkUtils.isGsmOptions(mContext, subId)&& carrierConfig != null&& carrierConfig.getBoolean(CarrierConfigManager.KEY_APN_EXPAND_BOOL);final boolean hideCarrierNetwork = carrierConfig == null|| carrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL);return !hideCarrierNetwork && (isCdmaApn || isGsmApn)? AVAILABLE: CONDITIONALLY_UNAVAILABLE;}@Overridepublic void displayPreference(PreferenceScreen screen) {super.displayPreference(screen);Log.i(TAG, "displayPreference + ");mPreference = screen.findPreference(getPreferenceKey());//For debug as belowif (mPreference != null) {Log.i(TAG, "displayPreference: isShow = " + mPreference.isShown() +", isVisible = " + mPreference.isVisible() + ", isEnable = " + mPreference.isEnabled());}mPreference.setEnabled(true);    //是否置灰mPreference.setVisible(true);    //是否显示Log.i(TAG, "displayPreference: enable and visible.");}

继续分析preference的逻辑,沿着 getAvailabilityStatus 可以看到,在 ApnPreferenceController  其父类实现的接口 TelephonyAvailabilityCallback 中会回调

packages/apps/Settings/src/com/android/settings/network/telephony/ApnPreferenceController.java

*** Preference controller for "Apn settings"*/
public class ApnPreferenceController extends TelephonyBasePreferenceController implementsLifecycleObserver, OnStart, OnStop {}
父类 TelephonyBasePreferenceController

packages/apps/Settings/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java

/*** {@link BasePreferenceController} that used by all preferences that requires subscription id.*/
public abstract class TelephonyBasePreferenceController extends BasePreferenceControllerimplements TelephonyAvailabilityCallback, TelephonyAvailabilityHandler {}

可用性接口TelephonyAvailabilityCallback

packages/apps/Settings/src/com/android/settings/network/telephony/TelephonyAvailabilityCallback.java

package com.android.settings.network.telephony;/*** Callback to decide whether preference is available based on subscription id*/
public interface TelephonyAvailabilityCallback {/*** Return availability status for a specific subId** @see TelephonyBasePreferenceController* @see TelephonyTogglePreferenceController*/int getAvailabilityStatus(int subId);
}
MobileNetworkUtils

packages/apps/Settings/src/com/android/settings/network/telephony/MobileNetworkUtils.java

    /*** Return availability for a default subscription id. If subId already been set, use it to* check, otherwise traverse all active subIds on device to check.* @param context context* @param defSubId Default subId get from telephony preference controller* @param callback Callback to check availability for a specific subId* @return Availability** @see BasePreferenceController#getAvailabilityStatus()*/public static int getAvailability(Context context, int defSubId,TelephonyAvailabilityCallback callback) {if (defSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {// If subId has been set, return the corresponding statusreturn callback.getAvailabilityStatus(defSubId);} else {// Otherwise, search whether there is one subId in device that support this preferencefinal int[] subIds = getActiveSubscriptionIdList(context);if (ArrayUtils.isEmpty(subIds)) {return callback.getAvailabilityStatus(SubscriptionManager.INVALID_SUBSCRIPTION_ID);} else {for (final int subId : subIds) {final int status = callback.getAvailabilityStatus(subId);if (status == BasePreferenceController.AVAILABLE) {return status;}}return callback.getAvailabilityStatus(subIds[0]);}}}/*** return {@code true} if we need show Gsm related settings*/public static boolean isGsmOptions(Context context, int subId) {if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {return false;}if (isGsmBasicOptions(context, subId)) {return true;}final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class).createForSubscriptionId(subId);final int networkMode = getNetworkTypeFromRaf((int) telephonyManager.getAllowedNetworkTypesForReason(TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER));if (isWorldMode(context, subId)) {if (networkMode == NETWORK_MODE_LTE_CDMA_EVDO|| networkMode == NETWORK_MODE_LTE_GSM_WCDMA|| networkMode == NETWORK_MODE_NR_LTE_CDMA_EVDO|| networkMode == NETWORK_MODE_NR_LTE_GSM_WCDMA) {return true;} else if (shouldSpeciallyUpdateGsmCdma(context, subId)) {return true;}}return false;}private static boolean isGsmBasicOptions(Context context, int subId) {final PersistableBundle carrierConfig =CarrierConfigCache.getInstance(context).getConfigForSubId(subId);if (carrierConfig != null&& !carrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)&& carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) {return true;}final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class).createForSubscriptionId(subId);if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {return true;}return false;}}

解决方案

如何更改平板上面gsm的判断?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/60458.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上海市计算机学会竞赛平台2020年4月月赛丙组永恒的生命游戏

题目背景 2020年4月11日&#xff0c;英国数学家 约翰霍顿康威&#xff08;John Horton Conway&#xff09;因为新型冠状病毒肺炎不幸逝世。他在群论、数论、代数、几何拓扑、理论物理、组合博弈论和几何等领域&#xff0c;都做出了重大贡献。他的离去是人类文明的损失。他最著…

FS8x 功能安全

fail-safe是电独立的和物理隔离的。fail-safe由自己的参考电压和电流提供,有自己的振荡器,有重复的模拟路径以最小化常见的故障,并有LBIST/ABIST来覆盖潜在故障。fail-safe根据设备部件号提供ASIL B或ASIL D遵从性。除非另有规定,fail-safe定时来自故障安全振荡器,其精度为…

项目模块十七:HttpServer模块

一、项目模块设计思路 目的&#xff1a;实现HTTP服务器搭建 思想&#xff1a;设计请求路由表&#xff0c;记录请求方法与对应业务的处理函数映射关系。用户实现请求方法和处理函数添加到路由表&#xff0c;服务器只接受请求并调用用户的处理函数即可。 处理流程&#xff1a; …

内网域环境、工作组、局域网等探针方案

1. 信息收集 1.1 网络收集 了解当前服务器的计算机基本信息&#xff0c;为后续判断服务器角色&#xff0c;网络环境做准备 systeminfo 详细信息 net start 启动服务 tasklist 进程列表 schtasks 计划任务&#xff08;受权限影响&#xff09; 了解当前服务器的网络接口信息…

什么是量化交易

课程大纲 内容初级初识量化&#xff0c;理解量化 初识量化 传统量化和AI量化的区别 量化思想挖掘 量化思想的挖掘及积累技巧 量化代码基础&#xff1a; python、pandas、SQL基础语法 金融数据分析 常用金融分析方式 常用因子分析方式 数据分析实战练习 回测及交易引擎 交易引擎…

OpenHarmony-1.启动流程

OpenHarmony启动流程 1.kernel的启动 流程图如下所示&#xff1a;   OpenHarmony(简称OH)的标准系统的底层系统是linux&#xff0c;所以调用如下代码&#xff1a; linux-5.10/init/main.c: noinline void __ref rest_init(void) {struct task_struct *tsk;int pid;rcu_sch…

【LeetCode】【算法】64. 最小路径和

LeetCode 64. 最小路径和 题目描述 给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 说明&#xff1a;每次只能向下或者向右移动一步。 思路 思路&#xff1a;这种题太典了&#xff0c;典…

1.7 JS性能优化

从输入url到页面加载完成都做了些什么 输入 URL - 资源定位符 http://www.zhaowa.com - http 协议 追问&#xff1a;http 与 TCP 1. http - 应用层 < > TCP - 传输层 2. 关联 - http基于TCP实现连接 < > UDP > 握手 & 挥手 &#xff08;传输速率上较…

Spring Task详细讲解

✨Spring Task简介 Spring Task 是 Spring 提供的轻量级定时任务工具&#xff0c;也就意味着不需要再添加第三方依赖了&#xff0c;相比其他第三方类库更加方便易用。可以按照约定的时间自动执行某个代码逻辑。 使用场景&#xff1a; 信用卡每月还款提醒银行贷款每月还款提醒…

Qt/C++ 海康SDK开发示例Demo

*** 工业相机在机器视觉中起到关键作用&#xff0c;本文基于海康 SDK 详细解读了设备连接与控制的各个步骤。内容涵盖设备枚举、句柄创建、图像采集回调以及设备异常处理&#xff0c;帮助开发者快速理解如何通过代码控制相机&#xff0c;实时采集并处理图像数据。*** 1. 搜索并…

HDLBIts习题(5):移位寄存器

&#xff08;1&#xff09;易错习题1&#xff1a;109题&#xff08;shift18&#xff09; 对算数左移和算数右移概念不清&#xff0c;不知道该如何计算。 逻辑左移和算术左移之间没有区别。&#xff08;无论是有符号位数据还是无符号位数据&#xff0c;右侧补0&#xff09; 逻辑…

想要成为独立游戏作者 :通关!游戏设计之道 2-2 关卡设计

本文通过ai辅助总结加个人微调,不喜勿喷 前篇如下&#xff1a; 想要成为独立游戏作者 &#xff1a;通关&#xff01;游戏设计之道 2-1 HUD-CSDN博客 1.关卡的多重定义 在电子游戏行业里 “关卡” 有多种含义&#xff0c;如游戏行为发生的环境、分割的游戏体验单元、量…

【深圳大学】数据结构A+攻略(计软版)

1. 考试 1.1 形式 分为平时&#xff0c;笔试&#xff0c;机试三部分。其中&#xff1a; 平时占30%&#xff0c;包含平时OJ测验和课堂练习&#xff0c;注意这个可能会因老师的不同和课题组的新策略而改变。笔试占60%&#xff0c;是分值占比的主要部分。机试占10%。 1.2 题型…

Springboot 启动端口占用如何解决

Springboot 启动端口占用如何解决 1、报错信息如下 *************************** APPLICATION FAILED TO START ***************************Description:Web server failed to start. Port 9010 was already in use.Action:Identify and stop the process thats listening o…

H.264/H.265播放器EasyPlayer.js RTSP播放器关于webcodecs硬解码H265的问题

EasyPlayer.js H5播放器&#xff0c;是一款能够同时支持HTTP、HTTP-FLV、HLS&#xff08;m3u8&#xff09;、WS视频直播与视频点播等多种协议&#xff0c;支持H.264、H.265、AAC、G711A、Mp3等多种音视频编码格式&#xff0c;支持MSE、WASM、WebCodec等多种解码方式&#xff0c…

集合类源码浅析のJDK1.8ConcurrentHashMap(上篇)

文章目录 前言一、概述二、CHM的属性1、属性 三、新增方法1、put2、initTable 四、分段计数1、addCount2、fullAddCount3、sumCount 总结 前言 本篇是JDK1.8的ConcurrentHashMap源码个人学习笔记&#xff0c;ConcurrentHashMap&#xff08;笔记中简称CHM&#xff09;是一种线程…

Linux权限和开发工具(3)

文章目录 1. 简单理解版本控制器Git1. 如何理解版本控制 2. Git的操作2.1 Git安装2.2 Git提交身份2.3 Git提交命令2.4 Git版本管理2.5 Git下的同步 3. gdb命令3.1解决gdb的难用问题3.2 gdb/cgdb的使用 1. 简单理解版本控制器Git 1. 如何理解版本控制 我们在做项目的时候可能会…

抓包工具WireShark使用记录

目录 网卡选择&#xff1a; 抓包流程&#xff1a; 捕获过滤器 常用捕获过滤器&#xff1a; 抓包数据的显示 显示过滤器&#xff1a; 常用的显示过滤器&#xff1a; 实际工作中&#xff0c;在平台对接&#xff0c;设备对接等常常需要调试接口&#xff0c;PostMan虽然可以进…

腾讯云双十一重磅福利----下一代CDN-EdgeOne

&#x1f34b;引言 随着全球互联网的快速发展和网络安全威胁的不断升级&#xff0c;传统的内容分发网络&#xff08;CDN&#xff09;已逐渐无法满足高效、安全、灵活的需求。腾讯云的下一代CDN产品—EdgeOne应运而生&#xff0c;凭借其全球化边缘节点架构&#xff0c;为客户提供…

Unity Coroutine

调用函数时&#xff0c;函数将运行到完成状态&#xff0c;然后返回。这实际上意味着在函数中发生的任何动作都必须在单帧更新内发生&#xff1b;函数调用不能用于包含程序性动画或随时间推移的一系列事件。例如&#xff0c;假设需要逐渐减少对象的 Alpha&#xff08;不透明度&a…