1 手動搜網(wǎng)應(yīng)用程序
1.1 MobileNetworkSettings入口
我們首先從apk的Manifest找入口坏瞄,如下:
/packages/apps/Settings/AndroidManifest.xml
<activity android:name=".network.telephony.MobileNetworkActivity"
android:label="@string/network_settings_title"
android:exported="true"
android:launchMode="singleTask">
<intent-filter android:priority="1">
<!-- Displays the MobileNetworkActivity and opt-in dialog for capability discovery. -->
<action android:name="android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN" />
<action android:name="android.settings.NETWORK_OPERATOR_SETTINGS" />
<action android:name="android.settings.DATA_ROAMING_SETTINGS" />
<action android:name="android.settings.MMS_MESSAGE_SETTING" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
緊接著的調(diào)用關(guān)系墨吓,會使用到布局xml文件:
/packages/apps/Settings/src/com/android/settings/network/telephony/MobileNetworkActivity.java
/packages/apps/Settings/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@Override
protected int getPreferenceScreenResId() {
return R.xml.mobile_network_settings;
}
1.1.1 MobileNetworkSettings布局
從上述的R.xml.mobile_network_settings引入布局,這里摘抄部分:
/packages/apps/Settings/res/xml/mobile_network_settings.xml
<PreferenceScreen
xmlns: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.widget.SettingsMainSwitchPreference
android:key="use_sim_switch"
settings:controller="com.android.settings.network.telephony.MobileNetworkSwitchController"/>
<PreferenceCategory
android:key="enabled_state_container"
android:title="@string/summary_placeholder"
settings:controller="com.android.settings.network.telephony.DisabledSubscriptionController"
android:layout="@layout/preference_category_no_label">
<SwitchPreference
android:key="mobile_data_enable"
android:title="@string/mobile_data_settings_title"
android:summary="@string/mobile_data_settings_summary"
settings:controller="com.android.settings.network.telephony.MobileDataPreferenceController"
settings:allowDividerAbove="true"/>
<com.android.settingslib.RestrictedSwitchPreference
android:key="button_roaming_key"
android:title="@string/roaming"
android:persistent="false"
android:summaryOn="@string/roaming_enable"
android:summaryOff="@string/roaming_disable"
settings:userRestriction="no_data_roaming"
settings:controller="com.android.settings.network.telephony.RoamingPreferenceController"/>
<SwitchPreference
android:key="carrier_wifi_toggle"
android:title="@string/carrier_wifi_offload_title"
android:summary="@string/carrier_wifi_offload_summary"
settings:controller="com.android.settings.network.CarrierWifiTogglePreferenceController"/>
<Preference
android:key="carrier_wifi_network"
android:title="@string/carrier_wifi_network_title"
android:selectable="false"
settings:searchable="false"/>
<SwitchPreference
android:key="4g_calling"
android:title="@string/enhanced_4g_lte_mode_title_4g_calling"
android:persistent="false"
android:summary="@string/enhanced_4g_lte_mode_summary_4g_calling"
settings:keywords="@string/keywords_enhance_4g_lte"
settings:controller="com.android.settings.network.telephony.Enhanced4gCallingPreferenceController"/>
<ListPreference
android:key="preferred_network_mode_key"
android:title="@string/preferred_network_mode_title"
android:summary="@string/preferred_network_mode_summary"
android:entries="@array/preferred_network_mode_choices"
android:entryValues="@array/preferred_network_mode_values"
android:dialogTitle="@string/preferred_network_mode_dialogtitle"
settings:controller="com.android.settings.network.telephony.PreferredNetworkModePreferenceController"/>
<PreferenceCategory
android:key="network_operators_category_key"
android:title="@string/network_operator_category"
settings:controller="com.android.settings.network.telephony.NetworkPreferenceCategoryController">
<SwitchPreference
android:key="auto_select_key"
android:title="@string/select_automatically"
settings:controller="com.android.settings.network.telephony.gsm.AutoSelectPreferenceController"/>
<Preference
android:key="choose_network_key"
android:title="@string/choose_network_title"
android:fragment="com.android.phone.NetworkSelectSetting"
settings:controller="com.android.settings.network.telephony.gsm.OpenNetworkSelectPagePreferenceController"/>
</PreferenceCategory>
<!--We want separate APN setting from reset of settings because we want user to change it with caution-->
<com.android.settingslib.RestrictedPreference
android:key="telephony_apn_key"
android:persistent="false"
android:title="@string/mobile_network_apn_title"
settings:allowDividerAbove="true"
settings:controller="com.android.settings.network.telephony.ApnPreferenceController"/>
</PreferenceScreen>
1.1.2 MobileNetworkSettings字符串位置
通過字符串也可以快速查找一些難以確認(rèn)的界面程序入口:
/packages/apps/Settings/res/values/strings.xml
1.1.3 MobileNetworkSettings初始化
在onAttach進(jìn)行一些初步的初始化:
/packages/apps/Settings/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@Override
public void onAttach(Context context) {
super.onAttach(context);
use(MobileNetworkSwitchController.class).init(getLifecycle(), mSubId);
use(DisabledSubscriptionController.class).init(getLifecycle(), mSubId);
use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId);
use(MobileDataPreferenceController.class).setWifiPickerTrackerHelper(
new WifiPickerTrackerHelper(getSettingsLifecycle(), context,
null /* WifiPickerTrackerCallback */));
use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId);
use(ApnPreferenceController.class).init(mSubId);
use(PreferredNetworkModePreferenceController.class).init(mSubId);
use(CarrierWifiTogglePreferenceController.class).init(getLifecycle(), mSubId);
final WifiCallingPreferenceController wifiCallingPreferenceController =
use(WifiCallingPreferenceController.class).init(mSubId);
final OpenNetworkSelectPagePreferenceController openNetworkSelectPagePreferenceController =
use(OpenNetworkSelectPagePreferenceController.class).init(getLifecycle(), mSubId);
final AutoSelectPreferenceController autoSelectPreferenceController =
use(AutoSelectPreferenceController.class)
.init(getLifecycle(), mSubId)
.addListener(openNetworkSelectPagePreferenceController);
use(NetworkPreferenceCategoryController.class).init(getLifecycle(), mSubId)
.setChildren(Arrays.asList(autoSelectPreferenceController));
use(NetworkPreferenceCategoryController.class).init(getLifecycle(), mSubId)
.setChildren(Arrays.asList(autoSelectPreferenceController));
use(Enhanced4gCallingPreferenceController.class).init(mSubId)
.addListener(videoCallingPreferenceController);
1.2 手動搜網(wǎng)代碼入口
從上述分析可以得知填渠,手動搜網(wǎng)的代碼入口java文件如下:
/packages/apps/Settings/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java
1.3 手動搜網(wǎng)應(yīng)用流程
如果用戶選擇了手動搜網(wǎng),則走else流程:
/packages/apps/Settings/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java
@Override
public boolean setChecked(boolean isChecked) {
if (isChecked) {
setAutomaticSelectionMode();
return false;
} else {
final Bundle bundle = new Bundle();
bundle.putInt(Settings.EXTRA_SUB_ID, mSubId);
new SubSettingLauncher(mContext)
.setDestination(NetworkSelectSettings.class.getName())
.setSourceMetricsCategory(SettingsEnums.MOBILE_NETWORK_SELECT)
.setTitleRes(R.string.choose_network_title)
.setArguments(bundle)
.launch();
return false;
}
}
如下界面被發(fā)起鸟辅,startNetworkQuery()被調(diào)用氛什。mUseNewApi來自config_enableNewAutoSelectNetworkUI,該值為false匪凉,所以選擇了NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS:
/packages/apps/Settings/src/com/android/settings/network/telephony/NetworkSelectSettings.java
@Override
public void onStart() {
super.onStart();
updateForbiddenPlmns();
if (isProgressBarVisible()) {
return;
}
if (mWaitingForNumberOfScanResults <= 0) {
startNetworkQuery();
}
}
private void startNetworkQuery() {
setProgressBarVisible(true);
if (mNetworkScanHelper != null) {
mRequestIdManualNetworkScan = getNewRequestId();
mWaitingForNumberOfScanResults = MIN_NUMBER_OF_SCAN_REQUIRED;
mNetworkScanHelper.startNetworkScan(
mUseNewApi
? NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS
: NetworkScanHelper.NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS);
}
}
接下來通過startNetworkScan()來啟動手動搜網(wǎng)枪眉,走該代碼的if分支,逐步完成對TelephonyManager API的調(diào)用再层。這里也需要注意贸铜,對于網(wǎng)絡(luò)側(cè)返回信息,則callback函數(shù)onSuccess()或onFailure()會被調(diào)用:
/packages/apps/Settings/src/com/android/settings/network/telephony/NetworkScanHelper.java
/**
* Performs a network scan for the given type {@code type}.
* {@link #NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS} is recommended if modem supports
* {@link TelephonyManager#requestNetworkScan(
* NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}.
*
* @param type used to tell which network scan API should be used.
*/
public void startNetworkScan(@NetworkQueryType int type) {
if (type == NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS) {
mNetworkScanFuture = SettableFuture.create();
Futures.addCallback(mNetworkScanFuture, new FutureCallback<List<CellInfo>>() {
@Override
public void onSuccess(List<CellInfo> result) {
onResults(result);
onComplete();
}
@Override
public void onFailure(Throwable t) {
if (t instanceof CancellationException) {
return;
}
int errCode = Integer.parseInt(t.getMessage());
onError(errCode);
}
}, MoreExecutors.directExecutor());
mExecutor.execute(new NetworkScanSyncTask(
mTelephonyManager, (SettableFuture) mNetworkScanFuture));
} else if (type == NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS) {
if (mNetworkScanRequester != null) {
return;
}
mNetworkScanRequester = mTelephonyManager.requestNetworkScan(
createNetworkScanForPreferredAccessNetworks(),
mExecutor,
mInternalNetworkScanCallback);
if (mNetworkScanRequester == null) {
onError(NetworkScan.ERROR_RADIO_INTERFACE_ERROR);
}
}
}
private static final class NetworkScanSyncTask implements Runnable {
private final SettableFuture<List<CellInfo>> mCallback;
private final TelephonyManager mTelephonyManager;
NetworkScanSyncTask(
TelephonyManager telephonyManager, SettableFuture<List<CellInfo>> callback) {
mTelephonyManager = telephonyManager;
mCallback = callback;
}
@Override
public void run() {
final CellNetworkScanResult result = mTelephonyManager.getAvailableNetworks();
if (result.getStatus() == CellNetworkScanResult.STATUS_SUCCESS) {
final List<CellInfo> cellInfos = result.getOperators()
.stream()
.map(operatorInfo
-> CellInfoUtil.convertOperatorInfoToCellInfo(operatorInfo))
.collect(Collectors.toList());
Log.d(TAG, "Sync network scan completed, cellInfos = "
+ CellInfoUtil.cellInfoListToString(cellInfos));
mCallback.set(cellInfos);
} else {
final Throwable error = new Throwable(
Integer.toString(convertToScanErrorCode(result.getStatus())));
mCallback.setException(error);
Log.d(TAG, "Sync network scan error, ex = " + error);
}
}
}
2 手動搜網(wǎng)Framework
2.1 Framework涉及到的類
四個主要的類:
TelephonyManager : 提供API給應(yīng)用聂受。
PhoneInterfaceManager : 實現(xiàn)ITelephony接口蒿秦,實現(xiàn)對Phone的控制操作。其內(nèi)部類MainThreadHandler繼承于Handler蛋济。
GsmCdmaPhone : Phone棍鳖,其父類繼承于Handler。
RIL : RILJ碗旅,提供API給Phone
2.2 流程圖
這些類的工作流程一般如下:
Step1: 通過TelephonyManager API調(diào)用Telephony Service(PhoneInterfaceManager)
Step2: 通過Telephony Service調(diào)用控制Phone
Step3: 通過Phone調(diào)用RILJ
Step4: RILJ通過HIDL實現(xiàn)對RILD的調(diào)用
Step5: RILD通過RadioResponse把返回值反饋給Phone
Step6: Phone把返回值傳給Telephony Service
Step7: Telephony Service把返回值通知給應(yīng)用程序
3 手動搜網(wǎng)RILD
3.1 流程圖
3.2 AT Command
可參考3GPP TS 27.007之7.3 PLMN selection +COPS
如下是聯(lián)通卡搜網(wǎng)的一個結(jié)果示例:
AT> AT+COPS=?
AT< +COPS: (1,"China Unicom","CU-GSM","46001","25C7",7),(1,"China Unicom","CU-GSM","46001","A5AB",2),(2,"China Unicom","CU-GSM","46001","77B600",11),(3,"46011","46011","46011","7C06",7),(3,"China Mobile","CMCC","46000","2441",7),(3,"46011","46011","46011","77B600",11),,(0-3),(0-2)
AT< OK
界面效果如下:
China Unicom 4G (Available)
China Unicom 3G (Available)
China Unicom 5G (Current)
China Telecom 4G (Forbidden)
China Mobile 4G (Forbidden)
China Telecom 5G (Forbidden)
版權(quán)聲明:本文為 無痕1024 原創(chuàng)文章鹊杖,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明扛芽。
本文鏈接:http://www.reibang.com/p/e56e83ca520d