Create NetworkScanRepository
And migrate network scan to flow for better maintenance and prevent ANR. Fix: 323105271 Test: manual - Choose network Test: unit test Change-Id: I5c49d195fc202143c0131ffd78bc3adc168b119c Merged-In: I5c49d195fc202143c0131ffd78bc3adc168b119c
This commit is contained in:
@@ -82,7 +82,7 @@ object CellInfoUtil {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun cellInfoListToString(cellInfos: List<CellInfo>): String =
|
||||
cellInfos.joinToString { cellInfo -> cellInfo.readableString() }
|
||||
cellInfos.joinToString(System.lineSeparator()) { cellInfo -> cellInfo.readableString() }
|
||||
|
||||
/**
|
||||
* Convert [CellInfo] to a readable string without sensitive info.
|
||||
|
@@ -1,346 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.network.telephony;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.content.Context;
|
||||
import android.telephony.AccessNetworkConstants.AccessNetworkType;
|
||||
import android.telephony.CellInfo;
|
||||
import android.telephony.NetworkScan;
|
||||
import android.telephony.NetworkScanRequest;
|
||||
import android.telephony.PhoneCapability;
|
||||
import android.telephony.RadioAccessSpecifier;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.telephony.TelephonyScanManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.internal.telephony.CellNetworkScanResult;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A helper class that builds the common interface and performs the network scan for two different
|
||||
* network scan APIs.
|
||||
*/
|
||||
public class NetworkScanHelper {
|
||||
public static final String TAG = "NetworkScanHelper";
|
||||
|
||||
/**
|
||||
* Callbacks interface to inform the network scan results.
|
||||
*/
|
||||
public interface NetworkScanCallback {
|
||||
/**
|
||||
* Called when the results is returned from {@link TelephonyManager}. This method will be
|
||||
* called at least one time if there is no error occurred during the network scan.
|
||||
*
|
||||
* <p> This method can be called multiple times in one network scan, until
|
||||
* {@link #onComplete()} or {@link #onError(int)} is called.
|
||||
*
|
||||
* @param results
|
||||
*/
|
||||
void onResults(List<CellInfo> results);
|
||||
|
||||
/**
|
||||
* Called when the current network scan process is finished. No more
|
||||
* {@link #onResults(List)} will be called for the current network scan after this method is
|
||||
* called.
|
||||
*/
|
||||
void onComplete();
|
||||
|
||||
/**
|
||||
* Called when an error occurred during the network scan process.
|
||||
*
|
||||
* <p> There is no more result returned from {@link TelephonyManager} if an error occurred.
|
||||
*
|
||||
* <p> {@link #onComplete()} will not be called if an error occurred.
|
||||
*
|
||||
* @see {@link NetworkScan.ScanErrorCode}
|
||||
*/
|
||||
void onError(int errorCode);
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS, NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS})
|
||||
public @interface NetworkQueryType {}
|
||||
|
||||
/**
|
||||
* Performs the network scan using {@link TelephonyManager#getAvailableNetworks()}. The network
|
||||
* scan results won't be returned to the caller until the network scan is completed.
|
||||
*
|
||||
* <p> This is typically used when the modem doesn't support the new network scan api
|
||||
* {@link TelephonyManager#requestNetworkScan(
|
||||
* NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}.
|
||||
*/
|
||||
public static final int NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS = 1;
|
||||
|
||||
/**
|
||||
* Performs the network scan using {@link TelephonyManager#requestNetworkScan(
|
||||
* NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)} The network scan
|
||||
* results will be returned to the caller periodically in a small time window until the network
|
||||
* scan is completed. The complete results should be returned in the last called of
|
||||
* {@link NetworkScanCallback#onResults(List)}.
|
||||
*
|
||||
* <p> This is recommended to be used if modem supports the new network scan api
|
||||
* {@link TelephonyManager#requestNetworkScan(
|
||||
* NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}
|
||||
*/
|
||||
public static final int NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS = 2;
|
||||
|
||||
/** The constants below are used in the async network scan. */
|
||||
@VisibleForTesting
|
||||
static final boolean INCREMENTAL_RESULTS = true;
|
||||
@VisibleForTesting
|
||||
static final int SEARCH_PERIODICITY_SEC = 5;
|
||||
@VisibleForTesting
|
||||
static final int MAX_SEARCH_TIME_SEC = 300;
|
||||
@VisibleForTesting
|
||||
static final int INCREMENTAL_RESULTS_PERIODICITY_SEC = 3;
|
||||
|
||||
private final NetworkScanCallback mNetworkScanCallback;
|
||||
private final TelephonyManager mTelephonyManager;
|
||||
private final TelephonyScanManager.NetworkScanCallback mInternalNetworkScanCallback;
|
||||
private final Executor mExecutor;
|
||||
|
||||
private int mMaxSearchTimeSec = MAX_SEARCH_TIME_SEC;
|
||||
private NetworkScan mNetworkScanRequester;
|
||||
|
||||
/** Callbacks for sync network scan */
|
||||
private ListenableFuture<List<CellInfo>> mNetworkScanFuture;
|
||||
|
||||
public NetworkScanHelper(TelephonyManager tm, NetworkScanCallback callback, Executor executor) {
|
||||
mTelephonyManager = tm;
|
||||
mNetworkScanCallback = callback;
|
||||
mInternalNetworkScanCallback = new NetworkScanCallbackImpl();
|
||||
mExecutor = executor;
|
||||
}
|
||||
|
||||
public NetworkScanHelper(Context context, TelephonyManager tm, NetworkScanCallback callback,
|
||||
Executor executor) {
|
||||
this(tm, callback, executor);
|
||||
mMaxSearchTimeSec = context.getResources().getInteger(
|
||||
R.integer.config_network_scan_helper_max_search_time_sec);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
NetworkScanRequest createNetworkScanForPreferredAccessNetworks() {
|
||||
long networkTypeBitmap3gpp = mTelephonyManager.getPreferredNetworkTypeBitmask()
|
||||
& TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP;
|
||||
|
||||
List<RadioAccessSpecifier> radioAccessSpecifiers = new ArrayList<>();
|
||||
// If the allowed network types are unknown or if they are of the right class, scan for
|
||||
// them; otherwise, skip them to save scan time and prevent users from being shown networks
|
||||
// that they can't connect to.
|
||||
if (networkTypeBitmap3gpp == 0
|
||||
|| (networkTypeBitmap3gpp & TelephonyManager.NETWORK_CLASS_BITMASK_2G) != 0) {
|
||||
radioAccessSpecifiers.add(
|
||||
new RadioAccessSpecifier(AccessNetworkType.GERAN, null, null));
|
||||
}
|
||||
if (networkTypeBitmap3gpp == 0
|
||||
|| (networkTypeBitmap3gpp & TelephonyManager.NETWORK_CLASS_BITMASK_3G) != 0) {
|
||||
radioAccessSpecifiers.add(
|
||||
new RadioAccessSpecifier(AccessNetworkType.UTRAN, null, null));
|
||||
}
|
||||
if (networkTypeBitmap3gpp == 0
|
||||
|| (networkTypeBitmap3gpp & TelephonyManager.NETWORK_CLASS_BITMASK_4G) != 0) {
|
||||
radioAccessSpecifiers.add(
|
||||
new RadioAccessSpecifier(AccessNetworkType.EUTRAN, null, null));
|
||||
}
|
||||
// If a device supports 5G stand-alone then the code below should be re-enabled; however
|
||||
// a device supporting only non-standalone mode cannot perform PLMN selection and camp on
|
||||
// a 5G network, which means that it shouldn't scan for 5G at the expense of battery as
|
||||
// part of the manual network selection process.
|
||||
//
|
||||
if (networkTypeBitmap3gpp == 0
|
||||
|| (hasNrSaCapability()
|
||||
&& (networkTypeBitmap3gpp & TelephonyManager.NETWORK_CLASS_BITMASK_5G) != 0)) {
|
||||
radioAccessSpecifiers.add(
|
||||
new RadioAccessSpecifier(AccessNetworkType.NGRAN, null, null));
|
||||
Log.d(TAG, "radioAccessSpecifiers add NGRAN.");
|
||||
}
|
||||
|
||||
return new NetworkScanRequest(
|
||||
NetworkScanRequest.SCAN_TYPE_ONE_SHOT,
|
||||
radioAccessSpecifiers.toArray(
|
||||
new RadioAccessSpecifier[radioAccessSpecifiers.size()]),
|
||||
SEARCH_PERIODICITY_SEC,
|
||||
mMaxSearchTimeSec,
|
||||
INCREMENTAL_RESULTS,
|
||||
INCREMENTAL_RESULTS_PERIODICITY_SEC,
|
||||
null /* List of PLMN ids (MCC-MNC) */);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The network scan of type {@link #NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS} can't be stopped,
|
||||
* however, the result of the current network scan won't be returned to the callback after
|
||||
* calling this method.
|
||||
*/
|
||||
public void stopNetworkQuery() {
|
||||
if (mNetworkScanRequester != null) {
|
||||
mNetworkScanRequester.stopScan();
|
||||
mNetworkScanRequester = null;
|
||||
}
|
||||
|
||||
if (mNetworkScanFuture != null) {
|
||||
mNetworkScanFuture.cancel(true /* mayInterruptIfRunning */);
|
||||
mNetworkScanFuture = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void onResults(List<CellInfo> cellInfos) {
|
||||
mNetworkScanCallback.onResults(cellInfos);
|
||||
}
|
||||
|
||||
private void onComplete() {
|
||||
mNetworkScanCallback.onComplete();
|
||||
}
|
||||
|
||||
private void onError(int errCode) {
|
||||
mNetworkScanCallback.onError(errCode);
|
||||
}
|
||||
|
||||
private boolean hasNrSaCapability() {
|
||||
return Arrays.stream(
|
||||
mTelephonyManager.getPhoneCapability().getDeviceNrCapabilities())
|
||||
.anyMatch(i -> i == PhoneCapability.DEVICE_NR_CAPABILITY_SA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the status code of {@link CellNetworkScanResult} to one of the
|
||||
* {@link NetworkScan.ScanErrorCode}.
|
||||
* @param errCode status code from {@link CellNetworkScanResult}.
|
||||
*
|
||||
* @return one of the scan error code from {@link NetworkScan.ScanErrorCode}.
|
||||
*/
|
||||
private static int convertToScanErrorCode(int errCode) {
|
||||
switch (errCode) {
|
||||
case CellNetworkScanResult.STATUS_RADIO_NOT_AVAILABLE:
|
||||
return NetworkScan.ERROR_RADIO_INTERFACE_ERROR;
|
||||
case CellNetworkScanResult.STATUS_RADIO_GENERIC_FAILURE:
|
||||
default:
|
||||
return NetworkScan.ERROR_MODEM_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
private final class NetworkScanCallbackImpl extends TelephonyScanManager.NetworkScanCallback {
|
||||
public void onResults(List<CellInfo> results) {
|
||||
Log.d(TAG, "Async scan onResults() results = "
|
||||
+ CellInfoUtil.cellInfoListToString(results));
|
||||
NetworkScanHelper.this.onResults(results);
|
||||
}
|
||||
|
||||
public void onComplete() {
|
||||
Log.d(TAG, "async scan onComplete()");
|
||||
NetworkScanHelper.this.onComplete();
|
||||
}
|
||||
|
||||
public void onError(@NetworkScan.ScanErrorCode int errCode) {
|
||||
Log.d(TAG, "async scan onError() errorCode = " + errCode);
|
||||
NetworkScanHelper.this.onError(errCode);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.settings.network.telephony;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -39,6 +38,7 @@ import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
@@ -49,14 +49,21 @@ import com.android.internal.telephony.OperatorInfo;
|
||||
import com.android.internal.telephony.flags.Flags;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.network.telephony.scan.NetworkScanRepository;
|
||||
import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanCellInfos;
|
||||
import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanComplete;
|
||||
import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanError;
|
||||
import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanResult;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -71,12 +78,8 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
private static final String TAG = "NetworkSelectSettings";
|
||||
|
||||
private static final int EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE = 1;
|
||||
private static final int EVENT_NETWORK_SCAN_RESULTS = 2;
|
||||
private static final int EVENT_NETWORK_SCAN_ERROR = 3;
|
||||
private static final int EVENT_NETWORK_SCAN_COMPLETED = 4;
|
||||
|
||||
private static final String PREF_KEY_NETWORK_OPERATORS = "network_operators_preference";
|
||||
private static final int MIN_NUMBER_OF_SCAN_REQUIRED = 2;
|
||||
|
||||
private PreferenceCategory mPreferenceCategory;
|
||||
@VisibleForTesting
|
||||
@@ -91,18 +94,14 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
private CarrierConfigManager mCarrierConfigManager;
|
||||
private List<String> mForbiddenPlmns;
|
||||
private boolean mShow4GForLTE = false;
|
||||
private NetworkScanHelper mNetworkScanHelper;
|
||||
private final ExecutorService mNetworkScanExecutor = Executors.newFixedThreadPool(1);
|
||||
private MetricsFeatureProvider mMetricsFeatureProvider;
|
||||
private boolean mUseNewApi;
|
||||
private long mRequestIdManualNetworkSelect;
|
||||
private long mRequestIdManualNetworkScan;
|
||||
private long mWaitingForNumberOfScanResults;
|
||||
@VisibleForTesting
|
||||
boolean mIsAggregationEnabled = false;
|
||||
private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener;
|
||||
private AtomicBoolean mShouldFilterOutSatellitePlmn = new AtomicBoolean();
|
||||
|
||||
private NetworkScanRepository mNetworkScanRepository;
|
||||
private boolean mUpdateScanResult = false;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
@@ -114,7 +113,6 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
@Initializer
|
||||
protected void onCreateInitialization() {
|
||||
Context context = getContext();
|
||||
mUseNewApi = enableNewAutoSelectNetworkUI(context);
|
||||
mSubId = getSubId();
|
||||
|
||||
mPreferenceCategory = getPreferenceCategory(PREF_KEY_NETWORK_OPERATORS);
|
||||
@@ -124,8 +122,6 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
mTelephonyManager = getTelephonyManager(context, mSubId);
|
||||
mSatelliteManager = getSatelliteManager(context);
|
||||
mCarrierConfigManager = getCarrierConfigManager(context);
|
||||
mNetworkScanHelper = new NetworkScanHelper(
|
||||
mTelephonyManager, mCallback, mNetworkScanExecutor);
|
||||
PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(mSubId,
|
||||
CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL,
|
||||
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL);
|
||||
@@ -136,30 +132,13 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
true));
|
||||
|
||||
mMetricsFeatureProvider = getMetricsFeatureProvider(context);
|
||||
mIsAggregationEnabled = enableAggregation(context);
|
||||
Log.d(TAG, "init: mUseNewApi:" + mUseNewApi
|
||||
+ " ,mIsAggregationEnabled:" + mIsAggregationEnabled + " ,mSubId:" + mSubId);
|
||||
|
||||
mCarrierConfigChangeListener =
|
||||
(slotIndex, subId, carrierId, specificCarrierId) -> handleCarrierConfigChanged(
|
||||
subId);
|
||||
mCarrierConfigManager.registerCarrierConfigChangeListener(mNetworkScanExecutor,
|
||||
mCarrierConfigChangeListener);
|
||||
|
||||
}
|
||||
|
||||
@Keep
|
||||
@VisibleForTesting
|
||||
protected boolean enableNewAutoSelectNetworkUI(Context context) {
|
||||
return context.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_enableNewAutoSelectNetworkUI);
|
||||
}
|
||||
|
||||
@Keep
|
||||
@VisibleForTesting
|
||||
protected boolean enableAggregation(Context context) {
|
||||
return context.getResources().getBoolean(
|
||||
R.bool.config_network_selection_list_aggregation_enabled);
|
||||
mNetworkScanRepository = new NetworkScanRepository(context, mSubId);
|
||||
}
|
||||
|
||||
@Keep
|
||||
@@ -218,17 +197,42 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
final Activity activity = getActivity();
|
||||
if (activity != null) {
|
||||
mProgressHeader = setPinnedHeaderView(
|
||||
com.android.settingslib.widget.progressbar.R.layout.progress_header)
|
||||
.findViewById(com.android.settingslib.widget.progressbar.R.id.progress_bar_animation);
|
||||
setProgressBarVisible(false);
|
||||
}
|
||||
com.android.settingslib.widget.progressbar.R.layout.progress_header
|
||||
).findViewById(com.android.settingslib.widget.progressbar.R.id.progress_bar_animation);
|
||||
forceUpdateConnectedPreferenceCategory();
|
||||
launchNetworkScan();
|
||||
}
|
||||
|
||||
private void launchNetworkScan() {
|
||||
mNetworkScanRepository.launchNetworkScan(getViewLifecycleOwner(), new Function1<>() {
|
||||
@Override
|
||||
public Unit invoke(@NonNull NetworkScanResult networkScanResult) {
|
||||
if (!mUpdateScanResult) {
|
||||
// Not update UI if not in scan mode.
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
if (networkScanResult instanceof NetworkScanCellInfos networkScanCellInfos) {
|
||||
scanResultHandler(networkScanCellInfos.getCellInfos());
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
if (!isPreferenceScreenEnabled()) {
|
||||
clearPreferenceSummary();
|
||||
enablePreferenceScreen(true);
|
||||
} else if (networkScanResult instanceof NetworkScanComplete
|
||||
&& mCellInfoList == null) {
|
||||
// In case the scan timeout before getting any results
|
||||
addMessagePreference(R.string.empty_networks_list);
|
||||
} else if (networkScanResult instanceof NetworkScanError) {
|
||||
addMessagePreference(R.string.network_query_error);
|
||||
}
|
||||
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -236,12 +240,8 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
super.onStart();
|
||||
|
||||
updateForbiddenPlmns();
|
||||
if (isProgressBarVisible()) {
|
||||
return;
|
||||
}
|
||||
if (mWaitingForNumberOfScanResults <= 0) {
|
||||
startNetworkQuery();
|
||||
}
|
||||
setProgressBarVisible(true);
|
||||
mUpdateScanResult = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,14 +256,6 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
: new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
if (mWaitingForNumberOfScanResults <= 0) {
|
||||
stopNetworkQuery();
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(Preference preference) {
|
||||
if (preference == mSelectedPreference) {
|
||||
@@ -275,7 +267,7 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
return false;
|
||||
}
|
||||
|
||||
stopNetworkQuery();
|
||||
mUpdateScanResult = false;
|
||||
|
||||
// Refresh the last selected item in case users reselect network.
|
||||
clearPreferenceSummary();
|
||||
@@ -294,8 +286,6 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
// Disable the screen until network is manually set
|
||||
enablePreferenceScreen(false);
|
||||
|
||||
mRequestIdManualNetworkSelect = getNewRequestId();
|
||||
mWaitingForNumberOfScanResults = MIN_NUMBER_OF_SCAN_REQUIRED;
|
||||
final OperatorInfo operator = mSelectedPreference.getOperatorInfo();
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
final Message msg = mHandler.obtainMessage(
|
||||
@@ -329,7 +319,6 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
switch (msg.what) {
|
||||
case EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE:
|
||||
final boolean isSucceed = (boolean) msg.obj;
|
||||
stopNetworkQuery();
|
||||
setProgressBarVisible(false);
|
||||
enablePreferenceScreen(true);
|
||||
|
||||
@@ -341,86 +330,15 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
Log.e(TAG, "No preference to update!");
|
||||
}
|
||||
break;
|
||||
case EVENT_NETWORK_SCAN_RESULTS:
|
||||
scanResultHandler((List<CellInfo>) msg.obj);
|
||||
break;
|
||||
|
||||
case EVENT_NETWORK_SCAN_ERROR:
|
||||
stopNetworkQuery();
|
||||
Log.i(TAG, "Network scan failure " + msg.arg1 + ":"
|
||||
+ " scan request 0x" + Long.toHexString(mRequestIdManualNetworkScan)
|
||||
+ ", waiting for scan results = " + mWaitingForNumberOfScanResults
|
||||
+ ", select request 0x"
|
||||
+ Long.toHexString(mRequestIdManualNetworkSelect));
|
||||
if (mRequestIdManualNetworkScan < mRequestIdManualNetworkSelect) {
|
||||
break;
|
||||
}
|
||||
if (!isPreferenceScreenEnabled()) {
|
||||
clearPreferenceSummary();
|
||||
enablePreferenceScreen(true);
|
||||
} else {
|
||||
addMessagePreference(R.string.network_query_error);
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_NETWORK_SCAN_COMPLETED:
|
||||
stopNetworkQuery();
|
||||
Log.d(TAG, "Network scan complete:"
|
||||
+ " scan request 0x" + Long.toHexString(mRequestIdManualNetworkScan)
|
||||
+ ", waiting for scan results = " + mWaitingForNumberOfScanResults
|
||||
+ ", select request 0x"
|
||||
+ Long.toHexString(mRequestIdManualNetworkSelect));
|
||||
if (mRequestIdManualNetworkScan < mRequestIdManualNetworkSelect) {
|
||||
break;
|
||||
}
|
||||
if (!isPreferenceScreenEnabled()) {
|
||||
clearPreferenceSummary();
|
||||
enablePreferenceScreen(true);
|
||||
} else if (mCellInfoList == null) {
|
||||
// In case the scan timeout before getting any results
|
||||
addMessagePreference(R.string.empty_networks_list);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
@VisibleForTesting
|
||||
List<CellInfo> doAggregation(List<CellInfo> cellInfoListInput) {
|
||||
if (!mIsAggregationEnabled) {
|
||||
Log.d(TAG, "no aggregation");
|
||||
return new ArrayList<>(cellInfoListInput);
|
||||
}
|
||||
ArrayList<CellInfo> aggregatedList = new ArrayList<>();
|
||||
for (CellInfo cellInfo : cellInfoListInput) {
|
||||
String plmn = CellInfoUtil.getNetworkTitle(cellInfo.getCellIdentity());
|
||||
Class className = cellInfo.getClass();
|
||||
|
||||
Optional<CellInfo> itemInTheList = aggregatedList.stream().filter(
|
||||
item -> {
|
||||
String itemPlmn = CellInfoUtil.getNetworkTitle(item.getCellIdentity());
|
||||
return itemPlmn.equals(plmn) && item.getClass().equals(className);
|
||||
})
|
||||
.findFirst();
|
||||
if (itemInTheList.isPresent()) {
|
||||
if (cellInfo.isRegistered() && !itemInTheList.get().isRegistered()) {
|
||||
// Adding the registered cellinfo item into list. If there are two registered
|
||||
// cellinfo items, then select first one from source list.
|
||||
aggregatedList.set(aggregatedList.indexOf(itemInTheList.get()), cellInfo);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
aggregatedList.add(cellInfo);
|
||||
}
|
||||
|
||||
return filterOutSatellitePlmn(aggregatedList);
|
||||
}
|
||||
|
||||
/* We do not want to expose carrier satellite plmns to the user when manually scan the
|
||||
cellular network. Therefore, it is needed to filter out satellite plmns from current cell
|
||||
info list */
|
||||
private List<CellInfo> filterOutSatellitePlmn(List<CellInfo> cellInfoList) {
|
||||
@VisibleForTesting
|
||||
List<CellInfo> filterOutSatellitePlmn(List<CellInfo> cellInfoList) {
|
||||
List<String> aggregatedSatellitePlmn = getSatellitePlmnsForCarrierWrapper();
|
||||
if (!mShouldFilterOutSatellitePlmn.get() || aggregatedSatellitePlmn.isEmpty()) {
|
||||
return cellInfoList;
|
||||
@@ -455,39 +373,10 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
}
|
||||
}
|
||||
|
||||
private final NetworkScanHelper.NetworkScanCallback mCallback =
|
||||
new NetworkScanHelper.NetworkScanCallback() {
|
||||
public void onResults(List<CellInfo> results) {
|
||||
final Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_RESULTS, results);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
|
||||
public void onComplete() {
|
||||
final Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_COMPLETED);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
|
||||
public void onError(int error) {
|
||||
final Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_ERROR, error,
|
||||
0 /* arg2 */);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
};
|
||||
|
||||
@Keep
|
||||
@VisibleForTesting
|
||||
protected void scanResultHandler(List<CellInfo> results) {
|
||||
if (mRequestIdManualNetworkScan < mRequestIdManualNetworkSelect) {
|
||||
Log.d(TAG, "CellInfoList (drop): "
|
||||
+ CellInfoUtil.cellInfoListToString(new ArrayList<>(results)));
|
||||
return;
|
||||
}
|
||||
mWaitingForNumberOfScanResults--;
|
||||
if ((mWaitingForNumberOfScanResults <= 0) && (!isResumed())) {
|
||||
stopNetworkQuery();
|
||||
}
|
||||
|
||||
mCellInfoList = doAggregation(results);
|
||||
mCellInfoList = filterOutSatellitePlmn(results);
|
||||
Log.d(TAG, "CellInfoList: " + CellInfoUtil.cellInfoListToString(mCellInfoList));
|
||||
if (mCellInfoList != null && mCellInfoList.size() != 0) {
|
||||
final NetworkOperatorPreference connectedPref = updateAllPreferenceCategory();
|
||||
@@ -646,11 +535,6 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
}
|
||||
}
|
||||
|
||||
private long getNewRequestId() {
|
||||
return Math.max(mRequestIdManualNetworkSelect,
|
||||
mRequestIdManualNetworkScan) + 1;
|
||||
}
|
||||
|
||||
private boolean isProgressBarVisible() {
|
||||
if (mProgressHeader == null) {
|
||||
return false;
|
||||
@@ -671,29 +555,8 @@ public class NetworkSelectSettings extends DashboardFragment {
|
||||
mPreferenceCategory.addPreference(mStatusMessagePreference);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopNetworkQuery() {
|
||||
setProgressBarVisible(false);
|
||||
if (mNetworkScanHelper != null) {
|
||||
mWaitingForNumberOfScanResults = 0;
|
||||
mNetworkScanHelper.stopNetworkQuery();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
stopNetworkQuery();
|
||||
mNetworkScanExecutor.shutdown();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.network.telephony.scan
|
||||
|
||||
import android.content.Context
|
||||
import android.telephony.AccessNetworkConstants.AccessNetworkType
|
||||
import android.telephony.CellInfo
|
||||
import android.telephony.NetworkScanRequest
|
||||
import android.telephony.PhoneCapability
|
||||
import android.telephony.RadioAccessSpecifier
|
||||
import android.telephony.TelephonyManager
|
||||
import android.telephony.TelephonyScanManager
|
||||
import android.util.Log
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.android.settings.network.telephony.CellInfoUtil
|
||||
import com.android.settings.network.telephony.CellInfoUtil.getNetworkTitle
|
||||
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.asExecutor
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
|
||||
class NetworkScanRepository(context: Context, subId: Int) {
|
||||
sealed interface NetworkScanResult
|
||||
|
||||
data class NetworkScanCellInfos(val cellInfos: List<CellInfo>) : NetworkScanResult
|
||||
data object NetworkScanComplete : NetworkScanResult
|
||||
data class NetworkScanError(val error: Int) : NetworkScanResult
|
||||
|
||||
private val telephonyManager =
|
||||
context.getSystemService(TelephonyManager::class.java)!!.createForSubscriptionId(subId)
|
||||
|
||||
/** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
|
||||
fun launchNetworkScan(lifecycleOwner: LifecycleOwner, onResult: (NetworkScanResult) -> Unit) {
|
||||
networkScanFlow().collectLatestWithLifecycle(lifecycleOwner, action = onResult)
|
||||
}
|
||||
|
||||
data class CellInfoScanKey(
|
||||
val title: String?,
|
||||
val className: String,
|
||||
val isRegistered: Boolean,
|
||||
) {
|
||||
constructor(cellInfo: CellInfo) : this(
|
||||
title = cellInfo.cellIdentity.getNetworkTitle(),
|
||||
className = cellInfo.javaClass.name,
|
||||
isRegistered = cellInfo.isRegistered,
|
||||
)
|
||||
}
|
||||
|
||||
fun networkScanFlow(): Flow<NetworkScanResult> = callbackFlow {
|
||||
val callback = object : TelephonyScanManager.NetworkScanCallback() {
|
||||
override fun onResults(results: List<CellInfo>) {
|
||||
val cellInfos = results.distinctBy { CellInfoScanKey(it) }
|
||||
trySend(NetworkScanCellInfos(cellInfos))
|
||||
Log.d(TAG, "CellInfoList: ${CellInfoUtil.cellInfoListToString(cellInfos)}")
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
trySend(NetworkScanComplete)
|
||||
close()
|
||||
Log.d(TAG, "onComplete")
|
||||
}
|
||||
|
||||
override fun onError(error: Int) {
|
||||
trySend(NetworkScanError(error))
|
||||
close()
|
||||
Log.d(TAG, "onError: $error")
|
||||
}
|
||||
}
|
||||
|
||||
val networkScan = telephonyManager.requestNetworkScan(
|
||||
createNetworkScan(),
|
||||
Dispatchers.Default.asExecutor(),
|
||||
callback,
|
||||
)
|
||||
|
||||
awaitClose { networkScan.stopScan() }
|
||||
}.flowOn(Dispatchers.Default)
|
||||
|
||||
/** Create network scan for allowed network types. */
|
||||
private fun createNetworkScan(): NetworkScanRequest {
|
||||
val allowedNetworkTypes = getAllowedNetworkTypes()
|
||||
Log.d(TAG, "createNetworkScan: allowedNetworkTypes = $allowedNetworkTypes")
|
||||
val radioAccessSpecifiers = allowedNetworkTypes
|
||||
.map { RadioAccessSpecifier(it, null, null) }
|
||||
.toTypedArray()
|
||||
return NetworkScanRequest(
|
||||
NetworkScanRequest.SCAN_TYPE_ONE_SHOT,
|
||||
radioAccessSpecifiers,
|
||||
NetworkScanRequest.MIN_SEARCH_PERIODICITY_SEC, // one shot, not used
|
||||
MAX_SEARCH_TIME_SEC,
|
||||
true,
|
||||
INCREMENTAL_RESULTS_PERIODICITY_SEC,
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getAllowedNetworkTypes(): List<Int> {
|
||||
val networkTypeBitmap3gpp: Long =
|
||||
telephonyManager.getAllowedNetworkTypesBitmask() and
|
||||
TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP
|
||||
return buildList {
|
||||
// If the allowed network types are unknown or if they are of the right class, scan for
|
||||
// them; otherwise, skip them to save scan time and prevent users from being shown
|
||||
// networks that they can't connect to.
|
||||
if (networkTypeBitmap3gpp == 0L
|
||||
|| networkTypeBitmap3gpp and TelephonyManager.NETWORK_CLASS_BITMASK_2G != 0L
|
||||
) {
|
||||
add(AccessNetworkType.GERAN)
|
||||
}
|
||||
if (networkTypeBitmap3gpp == 0L
|
||||
|| networkTypeBitmap3gpp and TelephonyManager.NETWORK_CLASS_BITMASK_3G != 0L
|
||||
) {
|
||||
add(AccessNetworkType.UTRAN)
|
||||
}
|
||||
if (networkTypeBitmap3gpp == 0L
|
||||
|| networkTypeBitmap3gpp and TelephonyManager.NETWORK_CLASS_BITMASK_4G != 0L
|
||||
) {
|
||||
add(AccessNetworkType.EUTRAN)
|
||||
}
|
||||
// If a device supports 5G stand-alone then the code below should be re-enabled; however
|
||||
// a device supporting only non-standalone mode cannot perform PLMN selection and camp
|
||||
// on a 5G network, which means that it shouldn't scan for 5G at the expense of battery
|
||||
// as part of the manual network selection process.
|
||||
//
|
||||
if (networkTypeBitmap3gpp == 0L
|
||||
|| (networkTypeBitmap3gpp and TelephonyManager.NETWORK_CLASS_BITMASK_5G != 0L &&
|
||||
hasNrSaCapability())
|
||||
) {
|
||||
add(AccessNetworkType.NGRAN)
|
||||
Log.d(TAG, "radioAccessSpecifiers add NGRAN.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasNrSaCapability(): Boolean {
|
||||
val phoneCapability = telephonyManager.getPhoneCapability()
|
||||
return PhoneCapability.DEVICE_NR_CAPABILITY_SA in phoneCapability.deviceNrCapabilities
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "NetworkScanRepository"
|
||||
|
||||
@VisibleForTesting
|
||||
val MAX_SEARCH_TIME_SEC = 300
|
||||
|
||||
@VisibleForTesting
|
||||
val INCREMENTAL_RESULTS_PERIODICITY_SEC = 3
|
||||
}
|
||||
}
|
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.network.telephony.scan
|
||||
|
||||
import android.content.Context
|
||||
import android.telephony.AccessNetworkConstants.AccessNetworkType
|
||||
import android.telephony.CellIdentityCdma
|
||||
import android.telephony.CellIdentityGsm
|
||||
import android.telephony.CellIdentityLte
|
||||
import android.telephony.CellInfoCdma
|
||||
import android.telephony.CellInfoGsm
|
||||
import android.telephony.CellInfoLte
|
||||
import android.telephony.NetworkScan
|
||||
import android.telephony.NetworkScanRequest
|
||||
import android.telephony.PhoneCapability
|
||||
import android.telephony.TelephonyManager
|
||||
import android.telephony.TelephonyManager.NETWORK_CLASS_BITMASK_5G
|
||||
import android.telephony.TelephonyScanManager
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanCellInfos
|
||||
import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanComplete
|
||||
import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanError
|
||||
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
|
||||
import com.android.settingslib.spa.testutils.toListWithTimeout
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.argThat
|
||||
import org.mockito.kotlin.doAnswer
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.stub
|
||||
import org.mockito.kotlin.verify
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class NetworkScanRepositoryTest {
|
||||
|
||||
private var callback: TelephonyScanManager.NetworkScanCallback? = null
|
||||
|
||||
private val mockTelephonyManager = mock<TelephonyManager> {
|
||||
on { createForSubscriptionId(SUB_ID) } doReturn mock
|
||||
on { requestNetworkScan(any(), any(), any()) } doAnswer {
|
||||
callback = it.arguments[2] as TelephonyScanManager.NetworkScanCallback
|
||||
mock<NetworkScan>()
|
||||
}
|
||||
}
|
||||
|
||||
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
|
||||
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
|
||||
}
|
||||
|
||||
private val repository = NetworkScanRepository(context, SUB_ID)
|
||||
|
||||
@Test
|
||||
fun networkScanFlow_initial() = runBlocking {
|
||||
val result = repository.networkScanFlow().firstWithTimeoutOrNull()
|
||||
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun networkScanFlow_onResults(): Unit = runBlocking {
|
||||
val cellInfos = listOf(CellInfoCdma().apply { cellIdentity = CELL_IDENTITY_CDMA })
|
||||
val listDeferred = async {
|
||||
repository.networkScanFlow().toListWithTimeout()
|
||||
}
|
||||
delay(100)
|
||||
|
||||
callback?.onResults(cellInfos)
|
||||
|
||||
assertThat(listDeferred.await()).containsExactly(NetworkScanCellInfos(cellInfos))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun networkScanFlow_onComplete(): Unit = runBlocking {
|
||||
val listDeferred = async {
|
||||
repository.networkScanFlow().toListWithTimeout()
|
||||
}
|
||||
delay(100)
|
||||
|
||||
callback?.onComplete()
|
||||
|
||||
assertThat(listDeferred.await()).containsExactly(NetworkScanComplete)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun networkScanFlow_onError(): Unit = runBlocking {
|
||||
val listDeferred = async {
|
||||
repository.networkScanFlow().toListWithTimeout()
|
||||
}
|
||||
delay(100)
|
||||
|
||||
callback?.onError(1)
|
||||
|
||||
assertThat(listDeferred.await()).containsExactly(NetworkScanError(1))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun networkScanFlow_hasDuplicateItems(): Unit = runBlocking {
|
||||
val cellInfos = listOf(
|
||||
createCellInfoLte("123", false),
|
||||
createCellInfoLte("123", false),
|
||||
createCellInfoLte("124", true),
|
||||
createCellInfoLte("124", true),
|
||||
createCellInfoGsm("123", false),
|
||||
createCellInfoGsm("123", false),
|
||||
)
|
||||
val listDeferred = async {
|
||||
repository.networkScanFlow().toListWithTimeout()
|
||||
}
|
||||
delay(100)
|
||||
|
||||
callback?.onResults(cellInfos)
|
||||
|
||||
assertThat(listDeferred.await()).containsExactly(
|
||||
NetworkScanCellInfos(
|
||||
listOf(
|
||||
createCellInfoLte("123", false),
|
||||
createCellInfoLte("124", true),
|
||||
createCellInfoGsm("123", false),
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun networkScanFlow_noDuplicateItems(): Unit = runBlocking {
|
||||
val cellInfos = listOf(
|
||||
createCellInfoLte("123", false),
|
||||
createCellInfoLte("123", true),
|
||||
createCellInfoLte("124", false),
|
||||
createCellInfoLte("124", true),
|
||||
createCellInfoGsm("456", false),
|
||||
createCellInfoGsm("456", true),
|
||||
)
|
||||
val listDeferred = async {
|
||||
repository.networkScanFlow().toListWithTimeout()
|
||||
}
|
||||
delay(100)
|
||||
|
||||
callback?.onResults(cellInfos)
|
||||
|
||||
assertThat(listDeferred.await()).containsExactly(
|
||||
NetworkScanCellInfos(
|
||||
listOf(
|
||||
createCellInfoLte("123", false),
|
||||
createCellInfoLte("123", true),
|
||||
createCellInfoLte("124", false),
|
||||
createCellInfoLte("124", true),
|
||||
createCellInfoGsm("456", false),
|
||||
createCellInfoGsm("456", true),
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createNetworkScan_deviceHasNrSa_requestNgran(): Unit = runBlocking {
|
||||
mockTelephonyManager.stub {
|
||||
on { getAllowedNetworkTypesBitmask() } doReturn NETWORK_CLASS_BITMASK_5G
|
||||
on { getPhoneCapability() } doReturn
|
||||
createPhoneCapability(intArrayOf(PhoneCapability.DEVICE_NR_CAPABILITY_SA))
|
||||
}
|
||||
|
||||
repository.networkScanFlow().firstWithTimeoutOrNull()
|
||||
|
||||
verify(mockTelephonyManager).requestNetworkScan(argThat<NetworkScanRequest> {
|
||||
specifiers.any { it.radioAccessNetwork == AccessNetworkType.NGRAN }
|
||||
}, any(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createNetworkScan_deviceNoNrSa_noNgran(): Unit = runBlocking {
|
||||
mockTelephonyManager.stub {
|
||||
on { getAllowedNetworkTypesBitmask() } doReturn NETWORK_CLASS_BITMASK_5G
|
||||
on { getPhoneCapability() } doReturn
|
||||
createPhoneCapability(intArrayOf(PhoneCapability.DEVICE_NR_CAPABILITY_NSA))
|
||||
}
|
||||
|
||||
repository.networkScanFlow().firstWithTimeoutOrNull()
|
||||
|
||||
verify(mockTelephonyManager).requestNetworkScan(argThat<NetworkScanRequest> {
|
||||
specifiers.none { it.radioAccessNetwork == AccessNetworkType.NGRAN }
|
||||
}, any(), any())
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val SUB_ID = 1
|
||||
const val LONG = "Long"
|
||||
const val SHORT = "Short"
|
||||
|
||||
val CELL_IDENTITY_CDMA = CellIdentityCdma(
|
||||
/* nid = */ 1,
|
||||
/* sid = */ 2,
|
||||
/* bid = */ 3,
|
||||
/* lon = */ 4,
|
||||
/* lat = */ 5,
|
||||
/* alphal = */ LONG,
|
||||
/* alphas = */ SHORT,
|
||||
)
|
||||
|
||||
private fun createCellInfoLte(alphaLong: String, registered: Boolean): CellInfoLte {
|
||||
val cellIdentityLte = CellIdentityLte(
|
||||
/* ci = */ 1,
|
||||
/* pci = */ 2,
|
||||
/* tac = */ 3,
|
||||
/* earfcn = */ 4,
|
||||
/* bands = */ intArrayOf(1, 2),
|
||||
/* bandwidth = */ 10000,
|
||||
/* mccStr = */ null,
|
||||
/* mncStr = */ null,
|
||||
/* alphal = */ alphaLong,
|
||||
/* alphas = */ null,
|
||||
/* additionalPlmns = */ emptyList(),
|
||||
/* csgInfo = */ null,
|
||||
)
|
||||
return CellInfoLte().apply {
|
||||
cellIdentity = cellIdentityLte
|
||||
isRegistered = registered
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCellInfoGsm(alphaLong: String, registered: Boolean): CellInfoGsm {
|
||||
val cellIdentityGsm = CellIdentityGsm(
|
||||
/* lac = */ 1,
|
||||
/* cid = */ 2,
|
||||
/* arfcn = */ 3,
|
||||
/* bsic = */ 4,
|
||||
/* mccStr = */ "123",
|
||||
/* mncStr = */ "01",
|
||||
/* alphal = */ alphaLong,
|
||||
/* alphas = */ null,
|
||||
/* additionalPlmns = */ emptyList(),
|
||||
)
|
||||
return CellInfoGsm().apply {
|
||||
cellIdentity = cellIdentityGsm
|
||||
isRegistered = registered
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPhoneCapability(deviceNrCapabilities: IntArray) =
|
||||
PhoneCapability.Builder().setDeviceNrCapabilities(deviceNrCapabilities).build()
|
||||
}
|
||||
}
|
@@ -1,260 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.network.telephony;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.telephony.AccessNetworkConstants;
|
||||
import android.telephony.CellInfo;
|
||||
import android.telephony.ModemInfo;
|
||||
import android.telephony.NetworkScan;
|
||||
import android.telephony.NetworkScanRequest;
|
||||
import android.telephony.PhoneCapability;
|
||||
import android.telephony.RadioAccessSpecifier;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.telephony.TelephonyScanManager;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NetworkScanHelperTest {
|
||||
|
||||
@Mock
|
||||
private TelephonyManager mTelephonyManager;
|
||||
@Mock
|
||||
private List<CellInfo> mCellInfos;
|
||||
@Mock
|
||||
private NetworkScanHelper.NetworkScanCallback mNetworkScanCallback;
|
||||
|
||||
private static final long THREAD_EXECUTION_TIMEOUT_MS = 3000L;
|
||||
|
||||
private ExecutorService mNetworkScanExecutor;
|
||||
private NetworkScanHelper mNetworkScanHelper;
|
||||
|
||||
private static final int SCAN_ID = 1234;
|
||||
private static final int SUB_ID = 1;
|
||||
|
||||
private NetworkScan mNetworkScan;
|
||||
|
||||
public class NetworkScanMock extends NetworkScan {
|
||||
NetworkScanMock(int scanId, int subId) {
|
||||
super(scanId, subId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopScan() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mNetworkScanExecutor = Executors.newFixedThreadPool(1);
|
||||
|
||||
mNetworkScanHelper = new NetworkScanHelper(mTelephonyManager,
|
||||
mNetworkScanCallback, mNetworkScanExecutor);
|
||||
|
||||
mNetworkScan = spy(new NetworkScanMock(SCAN_ID, SUB_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startNetworkScan_incrementalAndSuccess_completionWithResult() {
|
||||
when(mCellInfos.size()).thenReturn(1);
|
||||
|
||||
doAnswer(new Answer() {
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
TelephonyScanManager.NetworkScanCallback callback =
|
||||
(TelephonyScanManager.NetworkScanCallback)
|
||||
(invocation.getArguments()[2]);
|
||||
callback.onResults(mCellInfos);
|
||||
callback.onComplete();
|
||||
return mNetworkScan;
|
||||
}
|
||||
}).when(mTelephonyManager).requestNetworkScan(
|
||||
any(NetworkScanRequest.class), any(Executor.class),
|
||||
any(TelephonyScanManager.NetworkScanCallback.class));
|
||||
|
||||
ArgumentCaptor<List<CellInfo>> argument = ArgumentCaptor.forClass(List.class);
|
||||
|
||||
startNetworkScan_incremental(true);
|
||||
|
||||
verify(mNetworkScanCallback, times(1)).onResults(argument.capture());
|
||||
List<CellInfo> actualResult = argument.getValue();
|
||||
assertThat(actualResult.size()).isEqualTo(mCellInfos.size());
|
||||
verify(mNetworkScanCallback, times(1)).onComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startNetworkScan_incrementalAndImmediateFailure_failureWithErrorCode() {
|
||||
doReturn(null).when(mTelephonyManager).requestNetworkScan(
|
||||
any(NetworkScanRequest.class), any(Executor.class),
|
||||
any(TelephonyScanManager.NetworkScanCallback.class));
|
||||
|
||||
startNetworkScan_incremental(true);
|
||||
|
||||
verify(mNetworkScanCallback, times(1)).onError(anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startNetworkScan_incrementalAndFailure_failureWithErrorCode() {
|
||||
doAnswer(new Answer() {
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
TelephonyScanManager.NetworkScanCallback callback =
|
||||
(TelephonyScanManager.NetworkScanCallback)
|
||||
(invocation.getArguments()[2]);
|
||||
callback.onError(NetworkScan.ERROR_MODEM_ERROR);
|
||||
return mNetworkScan;
|
||||
}
|
||||
}).when(mTelephonyManager).requestNetworkScan(
|
||||
any(NetworkScanRequest.class), any(Executor.class),
|
||||
any(TelephonyScanManager.NetworkScanCallback.class));
|
||||
|
||||
startNetworkScan_incremental(true);
|
||||
|
||||
verify(mNetworkScanCallback, times(1)).onError(anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startNetworkScan_incrementalAndAbort_doStop() {
|
||||
doReturn(mNetworkScan).when(mTelephonyManager).requestNetworkScan(
|
||||
any(NetworkScanRequest.class), any(Executor.class),
|
||||
any(TelephonyScanManager.NetworkScanCallback.class));
|
||||
|
||||
startNetworkScan_incremental(false);
|
||||
|
||||
verify(mNetworkScan, times(1)).stopScan();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createNetworkScanForPreferredAccessNetworks_deviceNoNrSa_noNgran() {
|
||||
int[] deviceNrCapabilities = new int[]{PhoneCapability.DEVICE_NR_CAPABILITY_NSA};
|
||||
PhoneCapability phoneCapability = createPhoneCapability(deviceNrCapabilities);
|
||||
doReturn(TelephonyManager.NETWORK_CLASS_BITMASK_2G
|
||||
| TelephonyManager.NETWORK_CLASS_BITMASK_3G
|
||||
| TelephonyManager.NETWORK_CLASS_BITMASK_4G
|
||||
| TelephonyManager.NETWORK_CLASS_BITMASK_5G).when(
|
||||
mTelephonyManager).getPreferredNetworkTypeBitmask();
|
||||
doReturn(phoneCapability).when(mTelephonyManager).getPhoneCapability();
|
||||
List<RadioAccessSpecifier> radioAccessSpecifiers = new ArrayList<>();
|
||||
radioAccessSpecifiers.add(
|
||||
new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, null,
|
||||
null));
|
||||
radioAccessSpecifiers.add(
|
||||
new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.UTRAN, null,
|
||||
null));
|
||||
radioAccessSpecifiers.add(
|
||||
new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.EUTRAN, null,
|
||||
null));
|
||||
NetworkScanRequest expectedNetworkScanRequest = createNetworkScanRequest(
|
||||
radioAccessSpecifiers);
|
||||
|
||||
assertEquals(expectedNetworkScanRequest,
|
||||
mNetworkScanHelper.createNetworkScanForPreferredAccessNetworks());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createNetworkScanForPreferredAccessNetworks_deviceHasNrSa_hasNgran() {
|
||||
int[] deviceNrCapabilities = new int[]{PhoneCapability.DEVICE_NR_CAPABILITY_NSA,
|
||||
PhoneCapability.DEVICE_NR_CAPABILITY_SA};
|
||||
PhoneCapability phoneCapability = createPhoneCapability(deviceNrCapabilities);
|
||||
doReturn(TelephonyManager.NETWORK_CLASS_BITMASK_2G
|
||||
| TelephonyManager.NETWORK_CLASS_BITMASK_3G
|
||||
| TelephonyManager.NETWORK_CLASS_BITMASK_4G
|
||||
| TelephonyManager.NETWORK_CLASS_BITMASK_5G).when(
|
||||
mTelephonyManager).getPreferredNetworkTypeBitmask();
|
||||
doReturn(phoneCapability).when(mTelephonyManager).getPhoneCapability();
|
||||
List<RadioAccessSpecifier> radioAccessSpecifiers = new ArrayList<>();
|
||||
radioAccessSpecifiers.add(
|
||||
new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, null,
|
||||
null));
|
||||
radioAccessSpecifiers.add(
|
||||
new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.UTRAN, null,
|
||||
null));
|
||||
radioAccessSpecifiers.add(
|
||||
new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.EUTRAN, null,
|
||||
null));
|
||||
radioAccessSpecifiers.add(
|
||||
new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.NGRAN, null,
|
||||
null));
|
||||
NetworkScanRequest expectedNetworkScanRequest = createNetworkScanRequest(
|
||||
radioAccessSpecifiers);
|
||||
|
||||
assertEquals(expectedNetworkScanRequest,
|
||||
mNetworkScanHelper.createNetworkScanForPreferredAccessNetworks());
|
||||
}
|
||||
|
||||
private PhoneCapability createPhoneCapability(int[] deviceNrCapabilities) {
|
||||
int maxActiveVoiceCalls = 1;
|
||||
int maxActiveData = 2;
|
||||
ModemInfo modemInfo = new ModemInfo(1, 2, true, false);
|
||||
List<ModemInfo> logicalModemList = new ArrayList<>();
|
||||
logicalModemList.add(modemInfo);
|
||||
return new PhoneCapability(maxActiveVoiceCalls, maxActiveData,
|
||||
logicalModemList, false, deviceNrCapabilities);
|
||||
}
|
||||
|
||||
private NetworkScanRequest createNetworkScanRequest(
|
||||
List<RadioAccessSpecifier> radioAccessSpecifiers) {
|
||||
return new NetworkScanRequest(
|
||||
NetworkScanRequest.SCAN_TYPE_ONE_SHOT,
|
||||
radioAccessSpecifiers.toArray(
|
||||
new RadioAccessSpecifier[radioAccessSpecifiers.size()]),
|
||||
mNetworkScanHelper.SEARCH_PERIODICITY_SEC,
|
||||
mNetworkScanHelper.MAX_SEARCH_TIME_SEC,
|
||||
mNetworkScanHelper.INCREMENTAL_RESULTS,
|
||||
mNetworkScanHelper.INCREMENTAL_RESULTS_PERIODICITY_SEC,
|
||||
null /* List of PLMN ids (MCC-MNC) */);
|
||||
}
|
||||
|
||||
private void startNetworkScan_incremental(boolean waitForCompletion) {
|
||||
mNetworkScanHelper.startNetworkScan(
|
||||
NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS);
|
||||
if (!waitForCompletion) {
|
||||
mNetworkScanHelper.stopNetworkQuery();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -83,7 +83,6 @@ public class NetworkSelectSettingsTest {
|
||||
|
||||
public Context mContext;
|
||||
public PreferenceCategory mPreferenceCategory;
|
||||
public boolean mIsAggregationEnabled = true;
|
||||
|
||||
private TargetClass mNetworkSelectSettings;
|
||||
|
||||
@@ -104,12 +103,13 @@ public class NetworkSelectSettingsTest {
|
||||
doReturn(mCellId2).when(mCellInfo2).getCellIdentity();
|
||||
doReturn(mock(CellSignalStrength.class)).when(mCellInfo2).getCellSignalStrength();
|
||||
doReturn(CARRIER_NAME2).when(mCellId2).getOperatorAlphaLong();
|
||||
mIsAggregationEnabled = true;
|
||||
mNetworkSelectSettings = spy(new TargetClass(this));
|
||||
|
||||
PersistableBundle config = new PersistableBundle();
|
||||
config.putBoolean(CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, true);
|
||||
doReturn(config).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
|
||||
doReturn(config).when(mCarrierConfigManager).getConfigForSubId(SUB_ID,
|
||||
CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL,
|
||||
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL);
|
||||
|
||||
doReturn(TelephonyManager.DATA_CONNECTED).when(mTelephonyManager).getDataState();
|
||||
}
|
||||
@@ -174,11 +174,6 @@ public class NetworkSelectSettingsTest {
|
||||
return pref;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean enableAggregation(Context context) {
|
||||
return mTestEnv.mIsAggregationEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSubId() {
|
||||
return SUB_ID;
|
||||
@@ -210,77 +205,7 @@ public class NetworkSelectSettingsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doAggregation_hasDuplicateItemsDiffCellIdCase1_removeSamePlmnRatItem() {
|
||||
mNetworkSelectSettings.onCreateInitialization();
|
||||
List<CellInfo> testList = Arrays.asList(
|
||||
createLteCellInfo(true, 123, "123", "232", "CarrierA"),
|
||||
createLteCellInfo(true, 1234, "123", "232", "CarrierA"),
|
||||
createGsmCellInfo(false, 123, "123", "232", "CarrierB"));
|
||||
List<CellInfo> expected = Arrays.asList(
|
||||
createLteCellInfo(true, 123, "123", "232", "CarrierA"),
|
||||
createGsmCellInfo(false, 123, "123", "232", "CarrierB"));
|
||||
assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doAggregation_hasDuplicateItemsDiffCellIdCase2_removeSamePlmnRatItem() {
|
||||
mNetworkSelectSettings.onCreateInitialization();
|
||||
List<CellInfo> testList = Arrays.asList(
|
||||
createLteCellInfo(true, 123, "123", "232", "CarrierA"),
|
||||
createGsmCellInfo(false, 123, "123", "232", "CarrierB"),
|
||||
createLteCellInfo(false, 1234, "123", "232", "CarrierB"),
|
||||
createGsmCellInfo(false, 1234, "123", "232", "CarrierB"));
|
||||
List<CellInfo> expected = Arrays.asList(
|
||||
createLteCellInfo(true, 123, "123", "232", "CarrierA"),
|
||||
createGsmCellInfo(false, 123, "123", "232", "CarrierB"),
|
||||
createLteCellInfo(false, 1234, "123", "232", "CarrierB"));
|
||||
assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doAggregation_hasDuplicateItemsDiffMccMncCase1_removeSamePlmnRatItem() {
|
||||
mNetworkSelectSettings.onCreateInitialization();
|
||||
List<CellInfo> testList = Arrays.asList(
|
||||
createLteCellInfo(true, 123, "123", "232", "CarrierA"),
|
||||
createLteCellInfo(true, 123, "456", "232", "CarrierA"),
|
||||
createGsmCellInfo(false, 123, "123", "232", "CarrierB"));
|
||||
List<CellInfo> expected = Arrays.asList(
|
||||
createLteCellInfo(true, 123, "123", "232", "CarrierA"),
|
||||
createGsmCellInfo(false, 123, "123", "232", "CarrierB"));
|
||||
assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doAggregation_hasDuplicateItemsDiffMccMncCase2_removeSamePlmnRatItem() {
|
||||
mNetworkSelectSettings.onCreateInitialization();
|
||||
List<CellInfo> testList = Arrays.asList(
|
||||
createLteCellInfo(true, 123, "123", "232", "CarrierA"),
|
||||
createGsmCellInfo(false, 123, "123", "232", "CarrierB"),
|
||||
createLteCellInfo(false, 1234, "123", "232", "CarrierB"),
|
||||
createGsmCellInfo(false, 123, "456", "232", "CarrierB"));
|
||||
List<CellInfo> expected = Arrays.asList(
|
||||
createLteCellInfo(true, 123, "123", "232", "CarrierA"),
|
||||
createGsmCellInfo(false, 123, "123", "232", "CarrierB"),
|
||||
createLteCellInfo(false, 1234, "123", "232", "CarrierB"));
|
||||
assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doAggregation_hasDuplicateItemsDiffMccMncCase3_removeSamePlmnRatItem() {
|
||||
mNetworkSelectSettings.onCreateInitialization();
|
||||
List<CellInfo> testList = Arrays.asList(
|
||||
createLteCellInfo(false, 123, "123", "232", "CarrierA"),
|
||||
createLteCellInfo(false, 124, "123", "233", "CarrierA"),
|
||||
createLteCellInfo(true, 125, "123", "234", "CarrierA"),
|
||||
createGsmCellInfo(false, 126, "456", "232", "CarrierA"));
|
||||
List<CellInfo> expected = Arrays.asList(
|
||||
createLteCellInfo(true, 125, "123", "234", "CarrierA"),
|
||||
createGsmCellInfo(false, 126, "456", "232", "CarrierA"));
|
||||
assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doAggregation_filterOutSatellitePlmn_whenKeyIsTrue() {
|
||||
public void filterOutSatellitePlmn_filterOutSatellitePlmn_whenKeyIsTrue() {
|
||||
PersistableBundle config = new PersistableBundle();
|
||||
config.putBoolean(
|
||||
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true);
|
||||
@@ -304,11 +229,11 @@ public class NetworkSelectSettingsTest {
|
||||
List<CellInfo> expected = Arrays.asList(
|
||||
createGsmCellInfo(false, 123, "123", "233", "CarrierB"),
|
||||
createLteCellInfo(false, 1234, "123", "234", "CarrierC"));
|
||||
assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected);
|
||||
assertThat(mNetworkSelectSettings.filterOutSatellitePlmn(testList)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doAggregation_filterOutSatellitePlmn_whenNoSatellitePlmnIsAvailable() {
|
||||
public void filterOutSatellitePlmn_filterOutSatellitePlmn_whenNoSatellitePlmnIsAvailable() {
|
||||
PersistableBundle config = new PersistableBundle();
|
||||
config.putBoolean(
|
||||
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true);
|
||||
@@ -336,17 +261,17 @@ public class NetworkSelectSettingsTest {
|
||||
createGsmCellInfo(false, 123, "123", "233", "CarrierB"),
|
||||
createLteCellInfo(false, 1234, "123", "234", "CarrierC"),
|
||||
createGsmCellInfo(false, 12345, "123", "235", "CarrierD"));
|
||||
assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected);
|
||||
assertThat(mNetworkSelectSettings.filterOutSatellitePlmn(testList)).isEqualTo(expected);
|
||||
|
||||
// Expect no filter out when KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL is false.
|
||||
config.putBoolean(
|
||||
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, false);
|
||||
mNetworkSelectSettings.onCreateInitialization();
|
||||
assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected);
|
||||
assertThat(mNetworkSelectSettings.filterOutSatellitePlmn(testList)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doAggregation_filterOutSatellitePlmn_whenKeyIsFalse() {
|
||||
public void filterOutSatellitePlmn_filterOutSatellitePlmn_whenKeyIsFalse() {
|
||||
PersistableBundle config = new PersistableBundle();
|
||||
config.putBoolean(
|
||||
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true);
|
||||
@@ -372,7 +297,7 @@ public class NetworkSelectSettingsTest {
|
||||
createGsmCellInfo(false, 123, "123", "233", "CarrierB"),
|
||||
createLteCellInfo(false, 1234, "123", "234", "CarrierC"),
|
||||
createGsmCellInfo(false, 12345, "123", "235", "CarrierD"));
|
||||
assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected);
|
||||
assertThat(mNetworkSelectSettings.filterOutSatellitePlmn(testList)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
private CellInfoLte createLteCellInfo(boolean registered, int cellId, String mcc, String mnc,
|
||||
|
Reference in New Issue
Block a user