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
|
@JvmStatic
|
||||||
fun cellInfoListToString(cellInfos: List<CellInfo>): String =
|
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.
|
* 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;
|
package com.android.settings.network.telephony;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -39,6 +38,7 @@ import android.util.Log;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.Keep;
|
import androidx.annotation.Keep;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -49,14 +49,21 @@ import com.android.internal.telephony.OperatorInfo;
|
|||||||
import com.android.internal.telephony.flags.Flags;
|
import com.android.internal.telephony.flags.Flags;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
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.settings.overlay.FeatureFactory;
|
||||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
|
import kotlin.Unit;
|
||||||
|
import kotlin.jvm.functions.Function1;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@@ -71,12 +78,8 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
private static final String TAG = "NetworkSelectSettings";
|
private static final String TAG = "NetworkSelectSettings";
|
||||||
|
|
||||||
private static final int EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE = 1;
|
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 String PREF_KEY_NETWORK_OPERATORS = "network_operators_preference";
|
||||||
private static final int MIN_NUMBER_OF_SCAN_REQUIRED = 2;
|
|
||||||
|
|
||||||
private PreferenceCategory mPreferenceCategory;
|
private PreferenceCategory mPreferenceCategory;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -91,18 +94,14 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
private CarrierConfigManager mCarrierConfigManager;
|
private CarrierConfigManager mCarrierConfigManager;
|
||||||
private List<String> mForbiddenPlmns;
|
private List<String> mForbiddenPlmns;
|
||||||
private boolean mShow4GForLTE = false;
|
private boolean mShow4GForLTE = false;
|
||||||
private NetworkScanHelper mNetworkScanHelper;
|
|
||||||
private final ExecutorService mNetworkScanExecutor = Executors.newFixedThreadPool(1);
|
private final ExecutorService mNetworkScanExecutor = Executors.newFixedThreadPool(1);
|
||||||
private MetricsFeatureProvider mMetricsFeatureProvider;
|
private MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
private boolean mUseNewApi;
|
|
||||||
private long mRequestIdManualNetworkSelect;
|
|
||||||
private long mRequestIdManualNetworkScan;
|
|
||||||
private long mWaitingForNumberOfScanResults;
|
|
||||||
@VisibleForTesting
|
|
||||||
boolean mIsAggregationEnabled = false;
|
|
||||||
private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener;
|
private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener;
|
||||||
private AtomicBoolean mShouldFilterOutSatellitePlmn = new AtomicBoolean();
|
private AtomicBoolean mShouldFilterOutSatellitePlmn = new AtomicBoolean();
|
||||||
|
|
||||||
|
private NetworkScanRepository mNetworkScanRepository;
|
||||||
|
private boolean mUpdateScanResult = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
@@ -114,7 +113,6 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
@Initializer
|
@Initializer
|
||||||
protected void onCreateInitialization() {
|
protected void onCreateInitialization() {
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
mUseNewApi = enableNewAutoSelectNetworkUI(context);
|
|
||||||
mSubId = getSubId();
|
mSubId = getSubId();
|
||||||
|
|
||||||
mPreferenceCategory = getPreferenceCategory(PREF_KEY_NETWORK_OPERATORS);
|
mPreferenceCategory = getPreferenceCategory(PREF_KEY_NETWORK_OPERATORS);
|
||||||
@@ -124,8 +122,6 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
mTelephonyManager = getTelephonyManager(context, mSubId);
|
mTelephonyManager = getTelephonyManager(context, mSubId);
|
||||||
mSatelliteManager = getSatelliteManager(context);
|
mSatelliteManager = getSatelliteManager(context);
|
||||||
mCarrierConfigManager = getCarrierConfigManager(context);
|
mCarrierConfigManager = getCarrierConfigManager(context);
|
||||||
mNetworkScanHelper = new NetworkScanHelper(
|
|
||||||
mTelephonyManager, mCallback, mNetworkScanExecutor);
|
|
||||||
PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(mSubId,
|
PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(mSubId,
|
||||||
CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL,
|
CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL,
|
||||||
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL);
|
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL);
|
||||||
@@ -136,30 +132,13 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
true));
|
true));
|
||||||
|
|
||||||
mMetricsFeatureProvider = getMetricsFeatureProvider(context);
|
mMetricsFeatureProvider = getMetricsFeatureProvider(context);
|
||||||
mIsAggregationEnabled = enableAggregation(context);
|
|
||||||
Log.d(TAG, "init: mUseNewApi:" + mUseNewApi
|
|
||||||
+ " ,mIsAggregationEnabled:" + mIsAggregationEnabled + " ,mSubId:" + mSubId);
|
|
||||||
|
|
||||||
mCarrierConfigChangeListener =
|
mCarrierConfigChangeListener =
|
||||||
(slotIndex, subId, carrierId, specificCarrierId) -> handleCarrierConfigChanged(
|
(slotIndex, subId, carrierId, specificCarrierId) -> handleCarrierConfigChanged(
|
||||||
subId);
|
subId);
|
||||||
mCarrierConfigManager.registerCarrierConfigChangeListener(mNetworkScanExecutor,
|
mCarrierConfigManager.registerCarrierConfigChangeListener(mNetworkScanExecutor,
|
||||||
mCarrierConfigChangeListener);
|
mCarrierConfigChangeListener);
|
||||||
|
mNetworkScanRepository = new NetworkScanRepository(context, mSubId);
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
@@ -218,17 +197,42 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
final Activity activity = getActivity();
|
mProgressHeader = setPinnedHeaderView(
|
||||||
if (activity != null) {
|
com.android.settingslib.widget.progressbar.R.layout.progress_header
|
||||||
mProgressHeader = setPinnedHeaderView(
|
).findViewById(com.android.settingslib.widget.progressbar.R.id.progress_bar_animation);
|
||||||
com.android.settingslib.widget.progressbar.R.layout.progress_header)
|
|
||||||
.findViewById(com.android.settingslib.widget.progressbar.R.id.progress_bar_animation);
|
|
||||||
setProgressBarVisible(false);
|
|
||||||
}
|
|
||||||
forceUpdateConnectedPreferenceCategory();
|
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
|
@Override
|
||||||
@@ -236,12 +240,8 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
super.onStart();
|
super.onStart();
|
||||||
|
|
||||||
updateForbiddenPlmns();
|
updateForbiddenPlmns();
|
||||||
if (isProgressBarVisible()) {
|
setProgressBarVisible(true);
|
||||||
return;
|
mUpdateScanResult = true;
|
||||||
}
|
|
||||||
if (mWaitingForNumberOfScanResults <= 0) {
|
|
||||||
startNetworkQuery();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -256,14 +256,6 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
: new ArrayList<>();
|
: new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStop() {
|
|
||||||
if (mWaitingForNumberOfScanResults <= 0) {
|
|
||||||
stopNetworkQuery();
|
|
||||||
}
|
|
||||||
super.onStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceTreeClick(Preference preference) {
|
public boolean onPreferenceTreeClick(Preference preference) {
|
||||||
if (preference == mSelectedPreference) {
|
if (preference == mSelectedPreference) {
|
||||||
@@ -275,7 +267,7 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
stopNetworkQuery();
|
mUpdateScanResult = false;
|
||||||
|
|
||||||
// Refresh the last selected item in case users reselect network.
|
// Refresh the last selected item in case users reselect network.
|
||||||
clearPreferenceSummary();
|
clearPreferenceSummary();
|
||||||
@@ -294,8 +286,6 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
// Disable the screen until network is manually set
|
// Disable the screen until network is manually set
|
||||||
enablePreferenceScreen(false);
|
enablePreferenceScreen(false);
|
||||||
|
|
||||||
mRequestIdManualNetworkSelect = getNewRequestId();
|
|
||||||
mWaitingForNumberOfScanResults = MIN_NUMBER_OF_SCAN_REQUIRED;
|
|
||||||
final OperatorInfo operator = mSelectedPreference.getOperatorInfo();
|
final OperatorInfo operator = mSelectedPreference.getOperatorInfo();
|
||||||
ThreadUtils.postOnBackgroundThread(() -> {
|
ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
final Message msg = mHandler.obtainMessage(
|
final Message msg = mHandler.obtainMessage(
|
||||||
@@ -329,7 +319,6 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE:
|
case EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE:
|
||||||
final boolean isSucceed = (boolean) msg.obj;
|
final boolean isSucceed = (boolean) msg.obj;
|
||||||
stopNetworkQuery();
|
|
||||||
setProgressBarVisible(false);
|
setProgressBarVisible(false);
|
||||||
enablePreferenceScreen(true);
|
enablePreferenceScreen(true);
|
||||||
|
|
||||||
@@ -341,86 +330,15 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
Log.e(TAG, "No preference to update!");
|
Log.e(TAG, "No preference to update!");
|
||||||
}
|
}
|
||||||
break;
|
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
|
/* 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
|
cellular network. Therefore, it is needed to filter out satellite plmns from current cell
|
||||||
info list */
|
info list */
|
||||||
private List<CellInfo> filterOutSatellitePlmn(List<CellInfo> cellInfoList) {
|
@VisibleForTesting
|
||||||
|
List<CellInfo> filterOutSatellitePlmn(List<CellInfo> cellInfoList) {
|
||||||
List<String> aggregatedSatellitePlmn = getSatellitePlmnsForCarrierWrapper();
|
List<String> aggregatedSatellitePlmn = getSatellitePlmnsForCarrierWrapper();
|
||||||
if (!mShouldFilterOutSatellitePlmn.get() || aggregatedSatellitePlmn.isEmpty()) {
|
if (!mShouldFilterOutSatellitePlmn.get() || aggregatedSatellitePlmn.isEmpty()) {
|
||||||
return cellInfoList;
|
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
|
@Keep
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected void scanResultHandler(List<CellInfo> results) {
|
protected void scanResultHandler(List<CellInfo> results) {
|
||||||
if (mRequestIdManualNetworkScan < mRequestIdManualNetworkSelect) {
|
mCellInfoList = filterOutSatellitePlmn(results);
|
||||||
Log.d(TAG, "CellInfoList (drop): "
|
|
||||||
+ CellInfoUtil.cellInfoListToString(new ArrayList<>(results)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mWaitingForNumberOfScanResults--;
|
|
||||||
if ((mWaitingForNumberOfScanResults <= 0) && (!isResumed())) {
|
|
||||||
stopNetworkQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
mCellInfoList = doAggregation(results);
|
|
||||||
Log.d(TAG, "CellInfoList: " + CellInfoUtil.cellInfoListToString(mCellInfoList));
|
Log.d(TAG, "CellInfoList: " + CellInfoUtil.cellInfoListToString(mCellInfoList));
|
||||||
if (mCellInfoList != null && mCellInfoList.size() != 0) {
|
if (mCellInfoList != null && mCellInfoList.size() != 0) {
|
||||||
final NetworkOperatorPreference connectedPref = updateAllPreferenceCategory();
|
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() {
|
private boolean isProgressBarVisible() {
|
||||||
if (mProgressHeader == null) {
|
if (mProgressHeader == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -671,29 +555,8 @@ public class NetworkSelectSettings extends DashboardFragment {
|
|||||||
mPreferenceCategory.addPreference(mStatusMessagePreference);
|
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
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
stopNetworkQuery();
|
|
||||||
mNetworkScanExecutor.shutdown();
|
mNetworkScanExecutor.shutdown();
|
||||||
super.onDestroy();
|
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 Context mContext;
|
||||||
public PreferenceCategory mPreferenceCategory;
|
public PreferenceCategory mPreferenceCategory;
|
||||||
public boolean mIsAggregationEnabled = true;
|
|
||||||
|
|
||||||
private TargetClass mNetworkSelectSettings;
|
private TargetClass mNetworkSelectSettings;
|
||||||
|
|
||||||
@@ -104,12 +103,13 @@ public class NetworkSelectSettingsTest {
|
|||||||
doReturn(mCellId2).when(mCellInfo2).getCellIdentity();
|
doReturn(mCellId2).when(mCellInfo2).getCellIdentity();
|
||||||
doReturn(mock(CellSignalStrength.class)).when(mCellInfo2).getCellSignalStrength();
|
doReturn(mock(CellSignalStrength.class)).when(mCellInfo2).getCellSignalStrength();
|
||||||
doReturn(CARRIER_NAME2).when(mCellId2).getOperatorAlphaLong();
|
doReturn(CARRIER_NAME2).when(mCellId2).getOperatorAlphaLong();
|
||||||
mIsAggregationEnabled = true;
|
|
||||||
mNetworkSelectSettings = spy(new TargetClass(this));
|
mNetworkSelectSettings = spy(new TargetClass(this));
|
||||||
|
|
||||||
PersistableBundle config = new PersistableBundle();
|
PersistableBundle config = new PersistableBundle();
|
||||||
config.putBoolean(CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, true);
|
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();
|
doReturn(TelephonyManager.DATA_CONNECTED).when(mTelephonyManager).getDataState();
|
||||||
}
|
}
|
||||||
@@ -174,11 +174,6 @@ public class NetworkSelectSettingsTest {
|
|||||||
return pref;
|
return pref;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean enableAggregation(Context context) {
|
|
||||||
return mTestEnv.mIsAggregationEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getSubId() {
|
protected int getSubId() {
|
||||||
return SUB_ID;
|
return SUB_ID;
|
||||||
@@ -210,77 +205,7 @@ public class NetworkSelectSettingsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doAggregation_hasDuplicateItemsDiffCellIdCase1_removeSamePlmnRatItem() {
|
public void filterOutSatellitePlmn_filterOutSatellitePlmn_whenKeyIsTrue() {
|
||||||
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() {
|
|
||||||
PersistableBundle config = new PersistableBundle();
|
PersistableBundle config = new PersistableBundle();
|
||||||
config.putBoolean(
|
config.putBoolean(
|
||||||
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true);
|
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true);
|
||||||
@@ -304,11 +229,11 @@ public class NetworkSelectSettingsTest {
|
|||||||
List<CellInfo> expected = Arrays.asList(
|
List<CellInfo> expected = Arrays.asList(
|
||||||
createGsmCellInfo(false, 123, "123", "233", "CarrierB"),
|
createGsmCellInfo(false, 123, "123", "233", "CarrierB"),
|
||||||
createLteCellInfo(false, 1234, "123", "234", "CarrierC"));
|
createLteCellInfo(false, 1234, "123", "234", "CarrierC"));
|
||||||
assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected);
|
assertThat(mNetworkSelectSettings.filterOutSatellitePlmn(testList)).isEqualTo(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doAggregation_filterOutSatellitePlmn_whenNoSatellitePlmnIsAvailable() {
|
public void filterOutSatellitePlmn_filterOutSatellitePlmn_whenNoSatellitePlmnIsAvailable() {
|
||||||
PersistableBundle config = new PersistableBundle();
|
PersistableBundle config = new PersistableBundle();
|
||||||
config.putBoolean(
|
config.putBoolean(
|
||||||
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true);
|
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true);
|
||||||
@@ -336,17 +261,17 @@ public class NetworkSelectSettingsTest {
|
|||||||
createGsmCellInfo(false, 123, "123", "233", "CarrierB"),
|
createGsmCellInfo(false, 123, "123", "233", "CarrierB"),
|
||||||
createLteCellInfo(false, 1234, "123", "234", "CarrierC"),
|
createLteCellInfo(false, 1234, "123", "234", "CarrierC"),
|
||||||
createGsmCellInfo(false, 12345, "123", "235", "CarrierD"));
|
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.
|
// Expect no filter out when KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL is false.
|
||||||
config.putBoolean(
|
config.putBoolean(
|
||||||
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, false);
|
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, false);
|
||||||
mNetworkSelectSettings.onCreateInitialization();
|
mNetworkSelectSettings.onCreateInitialization();
|
||||||
assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected);
|
assertThat(mNetworkSelectSettings.filterOutSatellitePlmn(testList)).isEqualTo(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doAggregation_filterOutSatellitePlmn_whenKeyIsFalse() {
|
public void filterOutSatellitePlmn_filterOutSatellitePlmn_whenKeyIsFalse() {
|
||||||
PersistableBundle config = new PersistableBundle();
|
PersistableBundle config = new PersistableBundle();
|
||||||
config.putBoolean(
|
config.putBoolean(
|
||||||
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true);
|
CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true);
|
||||||
@@ -372,7 +297,7 @@ public class NetworkSelectSettingsTest {
|
|||||||
createGsmCellInfo(false, 123, "123", "233", "CarrierB"),
|
createGsmCellInfo(false, 123, "123", "233", "CarrierB"),
|
||||||
createLteCellInfo(false, 1234, "123", "234", "CarrierC"),
|
createLteCellInfo(false, 1234, "123", "234", "CarrierC"),
|
||||||
createGsmCellInfo(false, 12345, "123", "235", "CarrierD"));
|
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,
|
private CellInfoLte createLteCellInfo(boolean registered, int cellId, String mcc, String mnc,
|
||||||
|
Reference in New Issue
Block a user