一、参数说明

(一)APN配置结构对比

平台AndroidKaiOS文件类型xmljson结构每个标签是一条APN,包含完成的信息层级数组结构,使用JSON格式的数据。最外层是mcc,其次mnc,最后APN用数组形式配置(每个APN都是一个对象,不含mccmnc属性)。

Android: apns-conf.xml 文件

KaiOS: apn.json 文件

gaia/apps/settings/elements/apn_editor.html at master · mozilla-b2g/gaia · GitHub

特别需要注意格式(很容易出错),数组最后不用加逗号,注意大/中括号的首位一致性。

{

"202": {

"10": [

{"carrier":"Wind Internet","apn":"gint.b-online.gr","type":["default","supl"]},

{"voicemail":"122","type":["operatorvariant"]},

{"carrier":"Wind MMS","apn":"mnet.b-online.gr","mmsc":"http://192.168.200.95/servlets/mms","mmsproxy":"192.168.200.11","mmsport":"9401","type":["mms"]}

],

"01": [

{"carrier":"Cosmote Wireless Internet","apn":"","type":["ia"]},

{"voicemail":"123","type":["operatorvariant"]},

{"carrier":"Cosmote Wireless Internet","apn":"internet","type":["default","supl"]},

{"carrier":"Cosmote Mms","apn":"mms","mmsc":"http://mmsc.cosmote.gr:8002","mmsproxy":"10.10.10.20","mmsport":"8080","type":["mms"]}

],

"09": [

{"carrier":"Q Internet","apn":"myq","type":["default","supl"]},

{"voicemail":"122","type":["operatorvariant"]},

{"carrier":"Q-Telecom MMS GPRS","apn":"q-mms.myq.gr","mmsc":"http://mms.myq.gr","mmsproxy":"192.168.80.134","mmsport":"8080","type":["mms"]}

]

},

"001": {

"01": [

{"carrier":"Testing SIM default","apn":"test","type":["default"],"protocol":"IPV4V6","roaming_protocol":"IPV4V6","user_visible":"true"},

{"carrier":"IMS","apn":"ims","type":["ims"],"protocol":"IPV4V6","roaming_protocol":"IPV4V6","user_visible":"true"},

{"carrier":"XCAP","apn":"xcap","type":["xcap"],"protocol":"IPV4V6","roaming_protocol":"IPV4V6","user_visible":"true","authtype":"0"}

]

}

}

(二)bearer配置值对比

1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20 (The original bearer value in Android,位运算)1048575(The original bearer value in KaiOS using decimalism)

(三)authtype 映射关系

kaios

"authtype":"1" ——PAP

二、代码解析

(一)Android

待完善

(二)KaiOS

DataCallManager.jsmapn_editor_const.js

1、bitmask的进制转换

可以参考PDN建立逻辑,gecko/dom/system/gonk/radio/DataCallManager.jsm

//DataCallManager.jsm

//检查对应的rat是否包含在此APN bearer 配置中

// Check rat value include in the bit map or not.

function bitmaskHasTech(aBearerBitmask, aRadioTech) {

if (aBearerBitmask == 0) {

return true;

} else if (aRadioTech > 0) {

return (aBearerBitmask & (1 << (aRadioTech - 1))) != 0;

}

return false;

}

//bearer十进制转成二进制

// Show the detail rat type.

function bitmaskToString(aBearerBitmask) {

if (aBearerBitmask == 0 || aBearerBitmask === undefined) {

return 0;

}

let val = "";

for (let i = 1; i < RIL.GECKO_RADIO_TECH.length; i++) {

if ((aBearerBitmask & (1 << (i - 1))) != 0) {

val = val.concat(i + "|");

}

}

return val;

}

function bearerBitmapHasCdma(aBearerBitmask) {

return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK & aBearerBitmask) != 0;

}

在bitmaskToString接口中,将bitmask转化成String时,循环RIL.GECKO_RADIO_TECH的长度次,经过位运算转换成与Android原始配置的bearer_bitmask相同格式的bearer位符,用“|”间隔rat类型位。

是如何通过RIL调用ril_consts.js内的GECKO_RADIO_TECH?

在DataCallManager.jsm 中定义RIL对象,并使用XPCOMUtils.defineLazyGetter()方法来实现懒加载,即在要使用时才加载和初始化对象(只有在第一次访问该对象时才会进行初始化和加载),避免不必要的性能开销和资源浪费。 RIL对象是通过ChromeUtils.import 方法从ril_consts.js文件中导入的,该对象由ril_consts.js文件中的代码创建和初始化的。

//DataCallManaer.jsm

"use strict";

//XPCOM 是一个用于 实现跨语言组件的技术框架。

//导入XPCOMUtils对象(工具库),简化和封装XPCOM组件的开发和使用。

//使用常量const来定义 XPCOMUtils 对象,以确保在运行时不会发生对象被重新赋值的情况。

const { XPCOMUtils } = ChromeUtils.import(

"resource://gre/modules/XPCOMUtils.jsm"

);

//定义RIL对象,后续调用 RIL.GECKO_RADIO_TECH

XPCOMUtils.defineLazyGetter(this, "RIL", function() {

return ChromeUtils.import("resource://gre/modules/ril_consts.js");

});

//ref RIL.GECKO_RADIO_TECH

const TCP_BUFFER_SIZES = [

null,

"4092,8760,48000,4096,8760,48000", // gprs

"4093,26280,70800,4096,16384,70800", // edge

"58254,349525,1048576,58254,349525,1048576", // umts

"16384,32768,131072,4096,16384,102400", // is95a = 1xrtt

"16384,32768,131072,4096,16384,102400", // is95b = 1xrtt

"16384,32768,131072,4096,16384,102400", // 1xrtt

"4094,87380,262144,4096,16384,262144", // evdo0

"4094,87380,262144,4096,16384,262144", // evdoa

"61167,367002,1101005,8738,52429,262114", // hsdpa

"40778,244668,734003,16777,100663,301990", // hsupa = hspa

"40778,244668,734003,16777,100663,301990", // hspa

"4094,87380,262144,4096,16384,262144", // evdob

"131072,262144,1048576,4096,16384,524288", // ehrpd

"524288,1048576,2097152,262144,524288,1048576", // lte

"122334,734003,2202010,32040,192239,576717", // hspa+

"4096,87380,110208,4096,16384,110208", // gsm (using default value)

"4096,87380,110208,4096,16384,110208", // tdscdma (using default value)

"122334,734003,2202010,32040,192239,576717", // iwlan

"122334,734003,2202010,32040,192239,576717", // ca

];

//定义了一个常量RIL_RADIO_CDMA_TECHNOLOGY_BITMASK,用于表示CDMA射频技术类型的掩码值。

//RIL.GECKO_RADIO_TECH.indexOf 查找各个CDMA技术类型在GECKO_RADIO_TECH数组中的下标值,

//-1 的目的是得到对应的掩码位数,并将此转换成掩码值,

//使用按位左移(<<)运算符得到掩码值,

//各个掩码值按位或(|)操作得到最终的掩码值。

const RIL_RADIO_CDMA_TECHNOLOGY_BITMASK =

(1 << (RIL.GECKO_RADIO_TECH.indexOf("is95a") - 1)) |

(1 << (RIL.GECKO_RADIO_TECH.indexOf("is95b") - 1)) |

(1 << (RIL.GECKO_RADIO_TECH.indexOf("1xrtt") - 1)) |

(1 << (RIL.GECKO_RADIO_TECH.indexOf("evdo0") - 1)) |

(1 << (RIL.GECKO_RADIO_TECH.indexOf("evdoa") - 1)) |

(1 << (RIL.GECKO_RADIO_TECH.indexOf("evdob") - 1)) |

(1 << (RIL.GECKO_RADIO_TECH.indexOf("ehrpd") - 1));

// set to true in ril_consts.js to see debug messages

var DEBUG = RIL_DEBUG.DEBUG_RIL; //调试用的log打印标识符

如上代码,CDMA技术类型对应的掩码值RIL_RADIO_CDMA_TECHNO如下:

is95a: 1 << (5-1) = 0x10 is95b: 1 << (6-1) = 0x20 1xrtt: 1 << (7-1) = 0x40 evdo0: 1 << (8-1) = 0x80 evdoa: 1 << (9-1) = 0x100 evdob: 1 << (14-1) = 0x2000 ehrpd: 1 << (15-1) = 0x4000

2、GECKO_RADIO_TECH 定义网络制式 (ril_consts.js)

在KaiOS中,RIL.GECKO_RADIO_TECH数组是在Gecko内核的代码中定义的,其实现位于Gecko代码库的"gecko/dom/system/gonk/radio/ril_consts.js"文件中。该文件定义了一系列RIL层的常量,包括射频技术类型、消息ID等。在该文件中,可以找到以下代码片段,其中定义了RIL.GECKO_RADIO_TECH数组的元素和顺序:

//GECKO_RADIO_TECH 数组定义射频技术(网络连接)

this.GECKO_RADIO_TECH = [

null,

"gprs", //1 GPRS

"edge", //2 EDGE

"umts", //3 UMTS,3G

"is95a", //4 IS-95A

"is95b", //5 IS-95B

"1xrtt", //6 cdma1x?一种CDMA2000射频技术,是CDMAOne技术的升级版(1x Radio Transmission Technology)

"evdo0", //7 EVDO-0

"evdoa", //8 EVDO-A

"hsdpa", //9

"hsupa", //10

"hspa", //11

"evdob", //12 EVDO-B

"ehrpd", //13 EVDO-D

"lte", //14 LTE

"hspa+", //15 HSPA+

"gsm", //16 GSM

"tdscdma", //17 TD-SCDMA

"iwlan", //18 iWLAN(wifi)

"lte_ca", //19 LTE_CA

];

//定义遵循的协议类型

this.GECKO_PROFILE_INFO_TYPE_COMMON = 0;

this.GECKO_PROFILE_INFO_TYPE_3GPP = 1;

this.GECKO_PROFILE_INFO_TYPE_3GPP2 = 2;

3、DataCall 对 rat 的使用案例

dataRegistrationChanged(aRadioTech) {

let targetBearer;

if (this.apnSetting.bearer === undefined) {

targetBearer = 0;

} else {

targetBearer = this.apnSetting.bearer;

}

if (DEBUG) {

this.debug(

"dataRegistrationChanged: targetBearer: " +

bitmaskToString(targetBearer)

);

}

if (bitmaskHasTech(targetBearer, aRadioTech)) {

// Ignore same rat type. Let handler process the retry.

} else {

if (DEBUG) {

this.debug(

"dataRegistrationChanged: current APN do not support this rat reset DC. APN:" +

JSON.stringify(this.apnSetting)

);

// Clean the requestedNetworkInterfaces due to current DC can not support this rat under DC retrying state.

// Let handler process the retry.

let targetRequestedNetworkInterfaces = this.requestedNetworkInterfaces.slice();

for (let networkInterface of targetRequestedNetworkInterfaces) {

this.disconnect(networkInterface);

}

}

},

gecko/koost/telephony/TelephonyBinderService.h

// Cover the GECKO_RADIO_TECH to NETWORK_TYPE_*

int32_t convertRadioTech(const nsAString& rat);

4、apn_editor_const.js 原始数据和 UI显示转换

KaiOS 基线提供了VALUE_CONVERTERS 常量对象,包含两个属性:TO_STRING和TO_DATA,每个属性包含了转换方法。

TO_STRING:将一个字符串数组转换成一个用逗号分隔的字符串

apn_editor.js 界面显示用TO_DATA :将一个用逗号分隔的字符串转换为一个字符串数组

apn_editor_session.js 保存数据库用

源码如下,可参考APN Type显示的内容,对数组进行显示和配置数据存储。

/**

* The apn editor const

*/

define([],() => {

const APN_PROPERTY_DEFAULTS = {

//省略大部分原生属性

apn: '',

types: ['default'],

roaming_protocol: 'notDefined',

//自定义

mvno_type: 'notDefined',

mvno_match_data: '',

bearer:['unspecified']

};

const APN_PROPERTIES = Object.keys(APN_PROPERTY_DEFAULTS);

//数据转换工具接口

const VALUE_CONVERTERS = {

TO_STRING: { //TO_STRING属性

types(types) {

//判断 types参数存在、是一个数组、且数组非空,就将字符串数组转换成用逗号分隔的字符串

// types :参数是否存在

// Array.isArray(types):是否为一个数组

// types.length:数组是否非空

if (types && Array.isArray(types) && types.length) {

return types.join(', ');

}

return 'default'; //默认返回“default”

}

},

TO_DATA: { //TO_DATA属性

types(string) {

//将用逗号分隔的字符串转换为字符串数组

return string.split(',').map(str => str.trim());

}

}

};

//在apn_editor.js中定义了常量调用方法,APN_PROPERTIES、APN_PROPERTY_DEFAULTS、VALUE_CONVERTERS

return { //一个对象,三个只读get属性?外部访问但不能修改他们的值?

get APN_PROPERTIES() {

return APN_PROPERTIES;

},

get APN_PROPERTY_DEFAULTS() {

return APN_PROPERTY_DEFAULTS;

},

get VALUE_CONVERTERS() {

return VALUE_CONVERTERS;

}

};

});

(1)测试代码

 对以上接口VALUE_CONVERTERS的测试代码和解析,输出案例 :

const types = ['gprs', 'edge', 'umts'];

const str = VALUE_CONVERTERS.TO_STRING.types(types);

console.log(str); // 输出 'gprs, edge, umts'

const str = 'gprs, edge, umts';

const types = VALUE_CONVERTERS.TO_DATA.types(str);

console.log(types); // 输出 ['gprs', 'edge', 'umts']

(2)apn_editor.js 调用TO_STRING 界面显示

外部模块调用源码实现

/**

* The apn editor module

*/

'use strict';

define(function(require) { //eslint-disable-line

const ApnEditorConst = require('panels/apn_editor/apn_editor_const');

const ApnEditorSession = require('panels/apn_editor/apn_editor_session');

//引用apn_editor_const.js 定义常量

const { APN_PROPERTIES } = ApnEditorConst;

const { APN_PROPERTY_DEFAULTS } = ApnEditorConst;

const { VALUE_CONVERTERS } = ApnEditorConst;

ApnEditor.prototype = {

convertValue(value, converter) {

if (converter) {

return converter(value);

}

return value;

},

fillInputElements(inputElements, apn) {

APN_PROPERTIES.forEach(function input(name) {

const inputElement = inputElements[name];

if (inputElement) {

//数据处理,调用VALUE_CONVERTERS 转成字符串

inputElement.value = this.convertValue(

value,

VALUE_CONVERTERS.TO_STRING[name]

);

} //if inputElement

}, this);

},

});

(3)apn_editor_session.js 保存信息到APN数据库

在commit 中保存APN到,通过apn manager执行addApn或 updateApn

/**

* The apn editor session module

*/

define(['require','modules/apn/apn_settings_manager','panels/apn_editor/apn_editor_const','modules/apn/apn_utils'],function(require) { //eslint-disable-line

const ApnSettingsManager = require('modules/apn/apn_settings_manager');

const ApnEditorConst = require('panels/apn_editor/apn_editor_const');

const ApnUtils = require('modules/apn/apn_utils');

const { APN_PROPERTIES } = ApnEditorConst;

const { VALUE_CONVERTERS } = ApnEditorConst;

function ApnEditorSession(obj, inputElements, apnItem) {

this.serviceId = obj.serviceId;

this.apnMode = obj.mode;

this.inputElements = inputElements;

this.apnItem = apnItem;

}

ApnEditorSession.prototype = {

convertValue(value, converter) {

if (converter) {

return converter(value);

}

return value;

},

exportApnSetting(inputElements) {

const newApnSetting = {};

APN_PROPERTIES.forEach(function input(name) {

const inputElement = inputElements[name];

if (inputElement && !inputElement.hidden) {

newApnSetting[name.toLowerCase()] = this.convertValue(

inputElement.value,

VALUE_CONVERTERS.TO_DATA[name]

);

}

}, this);

return newApnSetting;

},

//保存新增APN数据,调用addApn

commitNew() {

const promises = [];

const newApnSetting = this.exportApnSetting(this.inputElements);

promises.push(ApnSettingsManager.addApn(this.serviceId, newApnSetting));

return Promise.all(promises);

},

//保存编辑APN数据,调用updateApn

commitEdit() {

const promises = [];

const newApnSetting = this.exportApnSetting(this.inputElements);

promises.push(ApnSettingsManager.updateApn(this.serviceId,

this.apnItem.id, newApnSetting));

return Promise.all(promises);

},

//在apn_editor.js中传递 new/edit选择执行新增/编辑APN

commit() {

switch (this.apnMode) {

case 'new':

return this.commitNew();

case 'edit':

return this.commitEdit();

default:

console.error('invalid mode');

return Promise.resolve();

}

},

//取消,不保存任何数据

cancel() {

APN_PROPERTIES.forEach(function input(name) {

this.inputElements[name].value = '';

}, this);

this.apnItem = null;

},

//还没找到mode的用法

get mode() {

return this.apnMode;

}

};

return function apnEditorSession(obj, inputElements, apnItem) {

return new ApnEditorSession(obj, inputElements, apnItem);

};

});

三、日志分析

追溯在PDN建立过程中,读取apn配置的bearer参数到DataCall使用的radio类型的bearer值变化情况。

四、方案开发

相关介绍:KaiOS 新增APN信息字段的代码实现-CSDN博客

在 APN Editor中实现bearer显示

代码模块:gaia/apps/settings/js/panels/apn_editor/apn_editor.js

/**

* The apn editor module

*/

'use strict';

define(function(require) { //eslint-disable-line

const ApnEditorConst = require('panels/apn_editor_tct/apn_editor_const');

const ApnEditorSession = require('panels/apn_editor_tct/apn_editor_session');

const ApnUtils = require('modules/apn_tct/apn_utils');

//以下三个常量都是从ApnEditorConst模块中导入的

const { APN_PROPERTIES } = ApnEditorConst;

const { APN_PROPERTY_DEFAULTS } = ApnEditorConst;

const { VALUE_CONVERTERS } = ApnEditorConst;

return function apnEditor(rootElement) {

return new ApnEditor(rootElement);

};

});

(一)KaiOS

1、十进制bearer -> bitmask位码 & networkType字符

将kaios中十进制的bearer转换同Android原始配置的bitmask及映射网络类型字符串

// 功能:将十进制bearer转换成1-20字符串(同Android)

function bitmaskToString(aBearerBitmask) {

if (aBearerBitmask == 0 || aBearerBitmask === undefined) {

return 0;

}

let val = "";

for (let i = 1; i < 20; i++) {

if ((aBearerBitmask & (1 << (i - 1))) != 0) {

val = val.concat(i + "|");

}

}

return val;

}

//常量数组,定义rat。

//最后一个数据到底要不要逗号?源码有,参考代码可以不用 —— 兼容性问题,新的会支持 ,

const GECKO_RADIO_TECH = [

null,

"gprs",

"edge",

"umts",

"is95a",

"is95b",

"1xrtt",

"evdo0",

"evdoa",

"hsdpa",

"hsupa",

"hspa",

"evdob",

"ehrpd",

"lte",

"hspa+",

"gsm",

"tdscdma",

"iwlan",

"lte_ca",

];

//将1-20的bitmask转换成对应的网络制式

function bitmaskToRatString(aBitmask) {

if (aBitmask == 0 || aBitmask === undefined) {

return "unspecified";

}

let rat = "";

let splitResult = aBitmask.split("|");

console.log('splitResult = '+ splitResult);

rat = splitResult.map(x => GECKO_RADIO_TECH[x]).join(",").slice(0,-1);

//slice(startIndex,endIndex) 用于去掉最后一个逗号

return rat;

}

// 测试代码

let apnBearer = '312312'; //apn.json原始配置值

let targetBearer; //1-20转换目标值

let bearerString = '';

if (apnBearer === undefined) {

targetBearer = 0;

} else {

targetBearer = apnBearer;

}

bearerString = bitmaskToString(targetBearer);

let ratString = bitmaskToRatString(bearerString);

// 输出结果

console.log('targetBearer = ' + targetBearer);

console.log('bearerString = '+ bearerString);

console.log('ratString = ' + ratString);

存在一个问题 ,在UI显示了rat的字符串,那么 commitEdit() 的时候会保存bearer为字符串,应该需要在apn_editor_session.js 中处理ApnSettings内容。

难点在于如何将gprs,edge,is95b,1xrtt 转换成bearer数值 ( bitmask=1|2|5|6 甚至是 十进制原文)

2、networktype字符 -> bitmask 位码

convertNetworkTypeToBitmask,将networktype字符串转换成bitmask(1|18|20格式)

//映射表,包含了不同的网络类型和对应的数字码。

const networkTypeMap = {

"unspecified": "0",

"gprs": "1",

"edge": "2",

"umts": "3",

"is95a": "4",

"is95b": "5",

"1xrtt": "6",

"evdo0": "7",

"evdoa": "8",

"hsdpa": "9",

"hsupa": "10",

"hspa": "11",

"evdob": "12",

"ehrpd": "13",

"lte": "14",

"hspa+": "15",

"gsm": "16",

"tdscdma": "17",

"iwlan": "18",

"lte_ca": "19"

};

//测试代码

//一、简单程序

let bearerString = "gprs,edge,umts,hsdpa,hsupa,hspa,lte,hspa+"; //界面显示字符串包含多个网络类型,使用逗号分隔

let networkTypes = bearerString.split(","); //string转换成字符串数组

let bitCode = Array.from(networkTypes, bearerString => networkTypeMap[bearerString]); //将字符串数组转换成数字码数组

let bitmask = bitCode.join("|");

console.log("networkTypes = " + networkTypes);

console.log("bitCode = " + bitCode);

//二、改善,封装成接口调用

//参数类型:字符串 "gprs,edge,umts,hsdpa,hsupa,hspa,lte,hspa+"

//let bearerString = "gprs,edge,umts,hsdpa,hsupa,hspa,lte,hspa+";

function convertNetworkTypeToBitmask(aNetworkTypes) {

let bitmask = '0'; //初始化为0和"0"的区别?

if (aNetworkTypes == 0 || aNetworkTypes === undefined) {

return 0;

}

//networkTypesArray是一个字符串数组,存储着多个网络类型的字符串,例如 ['gprs', 'edge']

let networkTypesArray = aNetworkTypes.split(","); //字符串转成字符串数组

//networkTypesBitCode是一个数字码数组,如[ '1', '2', '3' ]

//映射函数对每个字符串进行转换,函数参数是每个字符串,它在映射表中对应的值就是所需bit位数字码

//映射函数的代码为 aNetworkTypes => networkTypeMap[aNetworkTypes]

let networkTypesBitCode = Array.from(networkTypesArray, aNetworkTypes => networkTypeMap[aNetworkTypes]); //字符串数组转换成功数字码

bitmask = networkTypesBitCode.join("|");

return bitmask;

}

console.log("bitmask(api) = " + convertNetworkTypeToBitmask(bearerString));

//如果传参是数组,就更简单的封装接口了

//接受一个包含网络类型的数组作为参数,并将这个数组中的每种网络类型转换为对应的数字码,

//返回一个由数字码组成的字符串,使用"|"符号分隔,即bitmask

//通过map()方法遍历这个数组,将每种网络类型转换为对应的数字码,存在codes数组

//通过join()方法将codes数字码连接成字符串 ,用“|”符号分隔。

function convertNetworkTypes(networkTypes) {

const codes = networkTypes.map(type => networkTypeMap[type]);

return codes.join("|");

}

const types = ["gprs", "edge", "is95b", "1xrtt"];

const codeString = convertNetworkTypes(types); // "1|2|5|6"

3、networktype字符 -> 十进制bearer

用如下bitcode数组能便于转换成 bitmask位码和十进制,不能直接通过bitmask转换成十进制,即bitmask 位码 -> 十进制bearer

 bitcode = 1,2,3,9,10,11,14,15

const NETWORK_TYPE_MAP = {

"unspecified": "0",

"gprs": "1",

"edge": "2",

"umts": "3",

"is95a": "4",

"is95b": "5",

"1xrtt": "6",

"evdo0": "7",

"evdoa": "8",

"hsdpa": "9",

"hsupa": "10",

"hspa": "11",

"evdob": "12",

"ehrpd": "13",

"lte": "14",

"hspa+": "15",

"gsm": "16",

"tdscdma": "17",

"iwlan": "18",

"lte_ca": "19"

};

//参数类型:字符串 "gprs,edge,umts,hsdpa,hsupa,hspa,lte,hspa+"

//let bearerString = "gprs,edge,umts,hsdpa,hsupa,hspa,lte,hspa+";

function convertNetworkTypeToBitCode(aNetworkTypes) {

console.log("convertBitcodeToBearer: aNetworkTypes = " + aNetworkTypes);

let bitcode = '0';

if (aNetworkTypes == 0 || aNetworkTypes === undefined) {

return 0;

}

let networkTypesArray = aNetworkTypes.split(","); //字符串转成字符串数组

bitcode = Array.from(networkTypesArray, aNetworkTypes => NETWORK_TYPE_MAP[aNetworkTypes]); //

console.log("convertNetworkTypeToBitCode: bitcode = " + bitcode);

return bitcode;

}

function convertBitCodeToBitmask(aBitCode) {

let bitmask = aBitCode.join("|");

console.log("convertBitCodeToBitmask: bitmask = " + bitmask);

return bitmask;

}

function convertBitcodeToBearer(aBitCode) {

let bearerDec = 0;

let bearerBin =0;

if (aBitCode == 0 || aBitCode === undefined) {

return 0;

}

//parseInt((code).toString(2)) 是将数字 code转成二进制字符串

bearerBin = aBitCode.map(code => parseInt(code).toString(2)).join(""); //转成二进制

console.log("convertBitcodeToBearer: bearerBin = " + bearerBin);

bearerDec = parseInt(bearerBin,2);//将二进制转换成十进制 。

console.log("convertBitcodeToBearer: bearerDec = " + bearerDec);

return bearerDec;

}

let bearerString = "gprs,edge,umts,hsdpa,hsupa,hspa,lte,hspa+"; //界面显示字符串包含多个网络类型,使用逗号分隔

convertBitCodeToBitmask(convertNetworkTypeToBitCode(bearerString));

convertBitcodeToBearer(convertNetworkTypeToBitCode(bearerString));

bearerBin  存在问题,在bitcode 转成20位二进制数的时候,输出的bearerBin 不正确

优化以上代码:

function convertNetworkTypeToBearer(aNetworkTypes) {

dump('apn_editor_session: StringToBearer aNetworkTypes = ' + aNetworkTypes);

if (aNetworkTypes == 0 || aNetworkTypes === undefined) {

return 0;

}

let bitcode = '0';

let bearerBin = "";

let bearer = 0;

let networkTypesArray = aNetworkTypes.split(",");

bitcode = Array.from(networkTypesArray, aNetworkTypes => NETWORK_TYPE_MAP[aNetworkTypes]); //bitcode array like [18,14]

bitcode = bitcode.sort(function(a, b) {

return a - b;

});

dump('apn_editor_session: StringToBearer bitcode = ' + bitcode);

let bearerArray = new Array(20).fill(0);

for (let i = 0; i < bitcode.length; i++) {

bearerArray[bitcode[i]-1] = 1;

dump('apn_editor: StringToBearer bitcode[i] = ' + bitcode[i]);

}

dump('apn_editor_session: StringToBearer bearerArray = ' + bearerArray);

bearerBin = bearerArray.reverse().join("");

bearer = parseInt(bearerBin,2);

dump('apn_editor_session: StringToBearer bearer = ' + bearer);

return bearer;

}

参考阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。