| /* |
| * Copyright 2020 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.server.wifi.coex; |
| |
| |
| import static android.net.wifi.WifiManager.COEX_RESTRICTION_SOFTAP; |
| import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_AWARE; |
| import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_DIRECT; |
| import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ; |
| import static android.net.wifi.WifiScanner.WIFI_BAND_5_GHZ; |
| import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; |
| |
| import static com.android.server.wifi.coex.CoexUtils.CHANNEL_SET_5_GHZ; |
| import static com.android.server.wifi.coex.CoexUtils.CHANNEL_SET_5_GHZ_20_MHZ; |
| import static com.android.server.wifi.coex.CoexUtils.CHANNEL_SET_5_GHZ_40_MHZ; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import static org.junit.Assume.assumeTrue; |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.ArgumentMatchers.anyInt; |
| import static org.mockito.ArgumentMatchers.eq; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.when; |
| |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.content.res.Resources; |
| import android.net.wifi.CoexUnsafeChannel; |
| import android.net.wifi.ICoexCallback; |
| import android.os.Handler; |
| import android.os.IBinder; |
| import android.os.Looper; |
| import android.os.PersistableBundle; |
| import android.os.RemoteException; |
| import android.telephony.AccessNetworkConstants; |
| import android.telephony.Annotation; |
| import android.telephony.CarrierConfigManager; |
| import android.telephony.PhysicalChannelConfig; |
| import android.telephony.SubscriptionInfo; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyCallback; |
| import android.telephony.TelephonyManager; |
| |
| import androidx.test.filters.SmallTest; |
| |
| import com.android.modules.utils.build.SdkLevel; |
| import com.android.server.wifi.WifiBaseTest; |
| import com.android.server.wifi.WifiNative; |
| import com.android.wifi.resources.R; |
| |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.TemporaryFolder; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.Mock; |
| import org.mockito.MockitoAnnotations; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.nio.charset.StandardCharsets; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.concurrent.Executor; |
| import java.util.stream.Collectors; |
| |
| /** |
| * Unit tests for {@link com.android.server.wifi.coex.CoexManager}. |
| */ |
| @SmallTest |
| public class CoexManagerTest extends WifiBaseTest { |
| @Rule |
| public TemporaryFolder tempFolder = new TemporaryFolder(); |
| private static final String FILEPATH_MALFORMED = "assets/coex_malformed.xml"; |
| private static final String FILEPATH_LTE_40_NEIGHBORING = "assets/coex_lte_40_neighboring.xml"; |
| private static final String FILEPATH_LTE_46_NEIGHBORING = "assets/coex_lte_46_neighboring.xml"; |
| private static final String FILEPATH_LTE_40_OVERRIDE = "assets/coex_lte_40_override.xml"; |
| private static final String FILEPATH_LTE_27_HARMONIC = "assets/coex_lte_27_harmonic.xml"; |
| private static final String FILEPATH_LTE_7_INTERMOD = "assets/coex_lte_7_intermod.xml"; |
| |
| @Mock private Context mMockContext; |
| @Mock private Resources mMockResources; |
| @Mock private WifiNative mMockWifiNative; |
| @Mock private TelephonyManager mMockDefaultTelephonyManager; |
| @Mock private SubscriptionManager mMockSubscriptionManager; |
| private List<SubscriptionInfo> mSubscriptionInfos = new ArrayList<>(); |
| @Mock private CarrierConfigManager mMockCarrierConfigManager; |
| private PersistableBundle mUnrestrictedBundle = new PersistableBundle(); |
| private PersistableBundle mRestrictedBundle = new PersistableBundle(); |
| |
| private final ArgumentCaptor<CoexManager.CoexOnSubscriptionsChangedListener> |
| mCoexSubscriptionsListenerCaptor = ArgumentCaptor.forClass( |
| CoexManager.CoexOnSubscriptionsChangedListener.class); |
| private final ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor = |
| ArgumentCaptor.forClass(BroadcastReceiver.class); |
| |
| /** |
| * Set up TelephonyManager and SubscriptionManager mocks for the given subId before creating |
| * a CoexManager. Returns the mock TelephonyManager corresponding to the given subId. |
| */ |
| private TelephonyManager setUpSubIdMocks(int subId) { |
| TelephonyManager telephonyManager = mock(TelephonyManager.class); |
| when(mMockDefaultTelephonyManager.createForSubscriptionId(subId)) |
| .thenReturn(telephonyManager); |
| SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class); |
| when(subscriptionInfo.getSubscriptionId()).thenReturn(subId); |
| mSubscriptionInfos.add(subscriptionInfo); |
| return telephonyManager; |
| } |
| |
| private CoexManager createCoexManager() { |
| Looper.prepare(); |
| final CoexManager coexManager = new CoexManager(mMockContext, mMockWifiNative, |
| mMockDefaultTelephonyManager, mMockSubscriptionManager, mMockCarrierConfigManager, |
| new Handler(Looper.myLooper())); |
| coexManager.enableVerboseLogging(true); |
| return coexManager; |
| } |
| |
| private PhysicalChannelConfig createMockPhysicalChannelConfig( |
| @Annotation.NetworkType int rat, int band, |
| int dlFreqKhz, int dlBandwidthKhz, int ulFreqKhz, int ulBandwidthKhz) { |
| PhysicalChannelConfig config = mock(PhysicalChannelConfig.class); |
| when(config.getNetworkType()).thenReturn(rat); |
| when(config.getBand()).thenReturn(band); |
| when(config.getDownlinkFrequencyKhz()).thenReturn(dlFreqKhz); |
| when(config.getCellBandwidthDownlinkKhz()).thenReturn(dlBandwidthKhz); |
| when(config.getUplinkFrequencyKhz()).thenReturn(ulFreqKhz); |
| when(config.getCellBandwidthUplinkKhz()).thenReturn(ulBandwidthKhz); |
| return config; |
| } |
| |
| private File createFileFromResource(String configFile) throws Exception { |
| InputStream in = getClass().getClassLoader().getResourceAsStream(configFile); |
| File file = tempFolder.newFile(configFile.split("/")[1]); |
| |
| BufferedReader reader = new BufferedReader(new InputStreamReader(in)); |
| FileOutputStream out = new FileOutputStream(file); |
| |
| String line; |
| |
| while ((line = reader.readLine()) != null) { |
| out.write(line.getBytes(StandardCharsets.UTF_8)); |
| } |
| |
| out.flush(); |
| out.close(); |
| return file; |
| } |
| |
| @Before |
| public void setUp() throws Exception { |
| assumeTrue(SdkLevel.isAtLeastS()); |
| MockitoAnnotations.initMocks(this); |
| when(mMockContext.getResources()).thenReturn(mMockResources); |
| when(mMockResources.getBoolean(R.bool.config_wifiDefaultCoexAlgorithmEnabled)) |
| .thenReturn(true); |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(""); |
| when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()) |
| .thenReturn(mSubscriptionInfos); |
| mUnrestrictedBundle.putBoolean(CarrierConfigManager.Wifi |
| .KEY_AVOID_5GHZ_SOFTAP_FOR_LAA_BOOL, false); |
| mUnrestrictedBundle.putBoolean(CarrierConfigManager.Wifi |
| .KEY_AVOID_5GHZ_WIFI_DIRECT_FOR_LAA_BOOL, false); |
| mRestrictedBundle.putBoolean(CarrierConfigManager.Wifi |
| .KEY_AVOID_5GHZ_SOFTAP_FOR_LAA_BOOL, true); |
| mRestrictedBundle.putBoolean(CarrierConfigManager.Wifi |
| .KEY_AVOID_5GHZ_WIFI_DIRECT_FOR_LAA_BOOL, true); |
| } |
| |
| /** |
| * Verifies that setCoexUnsafeChannels(Set, int) sets values returned in the getter methods |
| * getCoexUnsafeChannels() and getCoexRestrictions(). |
| */ |
| @Test |
| public void testSetCoexUnsafeChannels_nonNullChannels_returnedInGetters() { |
| assumeTrue(SdkLevel.isAtLeastS()); |
| CoexManager coexManager = createCoexManager(); |
| List<CoexUnsafeChannel> unsafeChannels = new ArrayList<>(); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 36)); |
| final int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP |
| | COEX_RESTRICTION_WIFI_AWARE; |
| |
| coexManager.setCoexUnsafeChannels(unsafeChannels, restrictions); |
| |
| assertThat(coexManager.getCoexUnsafeChannels()).containsExactlyElementsIn(unsafeChannels); |
| assertThat(coexManager.getCoexRestrictions()).isEqualTo(restrictions); |
| } |
| |
| /** |
| * Verifies that setCoexUnsafeChannels(Set, int) with an null set results in no change to the |
| * current CoexUnsafeChannels or restrictions |
| */ |
| @Test |
| public void testSetCoexUnsafeChannels_nullChannels_setsEmptySet() { |
| CoexManager coexManager = createCoexManager(); |
| List<CoexUnsafeChannel> unsafeChannels = new ArrayList<>(); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 36)); |
| final int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP |
| | COEX_RESTRICTION_WIFI_AWARE; |
| coexManager.setCoexUnsafeChannels(unsafeChannels, restrictions); |
| |
| coexManager.setCoexUnsafeChannels(null, 0); |
| |
| assertThat(coexManager.getCoexUnsafeChannels()).containsExactlyElementsIn(unsafeChannels); |
| assertThat(coexManager.getCoexRestrictions()).isEqualTo(restrictions); |
| } |
| |
| /** |
| * Verifies that setCoexUnsafeChannels(Set, int) with undefined restriction flags results in no |
| * change to the current CoexUnsafeChannels or restrictions |
| */ |
| @Test |
| public void testSetCoexUnsafeChannels_undefinedRestrictions_setsEmptySet() { |
| CoexManager coexManager = createCoexManager(); |
| List<CoexUnsafeChannel> unsafeChannels = new ArrayList<>(); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 36)); |
| final int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP |
| | COEX_RESTRICTION_WIFI_AWARE; |
| coexManager.setCoexUnsafeChannels(unsafeChannels, restrictions); |
| |
| coexManager.setCoexUnsafeChannels(Collections.emptyList(), ~restrictions); |
| |
| assertThat(coexManager.getCoexUnsafeChannels()).containsExactlyElementsIn(unsafeChannels); |
| assertThat(coexManager.getCoexRestrictions()).isEqualTo(restrictions); |
| } |
| |
| /** |
| * Verifies that setCoexUnsafeChannels notifies WifiNative with the set values. |
| */ |
| @Test |
| public void testSetCoexUnsafeChannels_notifiesWifiVendorHal() { |
| CoexManager coexManager = createCoexManager(); |
| List<CoexUnsafeChannel> unsafeChannels = new ArrayList<>(); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 36)); |
| final int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP |
| | COEX_RESTRICTION_WIFI_AWARE; |
| coexManager.setCoexUnsafeChannels(unsafeChannels, restrictions); |
| |
| verify(mMockWifiNative).setCoexUnsafeChannels(unsafeChannels, restrictions); |
| } |
| |
| /** |
| * Verifies that the registered CoexListeners are notified when |
| * setCoexUnsafeChannels is called. |
| */ |
| @Test |
| public void testRegisteredCoexListener_setCoexUnsafeChannels_listenerIsNotified() { |
| CoexManager.CoexListener listener1 = mock(CoexManager.CoexListener.class); |
| CoexManager.CoexListener listener2 = mock(CoexManager.CoexListener.class); |
| CoexManager coexManager = createCoexManager(); |
| coexManager.registerCoexListener(listener1); |
| coexManager.registerCoexListener(listener2); |
| List<CoexUnsafeChannel> unsafeChannels = new ArrayList<>(); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 36)); |
| int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP |
| | COEX_RESTRICTION_WIFI_AWARE; |
| |
| coexManager.setCoexUnsafeChannels(unsafeChannels, restrictions); |
| |
| verify(listener1).onCoexUnsafeChannelsChanged(); |
| verify(listener2).onCoexUnsafeChannelsChanged(); |
| } |
| |
| /** |
| * Verifies that unregistered CoexListeners are not notified when |
| * setCoexUnsafeChannels is called. |
| */ |
| @Test |
| public void testUnregisteredCoexListener_setCoexUnsafeChannels_listenerIsNotNotified() { |
| CoexManager.CoexListener listener1 = mock(CoexManager.CoexListener.class); |
| CoexManager.CoexListener listener2 = mock(CoexManager.CoexListener.class); |
| CoexManager coexManager = createCoexManager(); |
| coexManager.registerCoexListener(listener1); |
| coexManager.registerCoexListener(listener2); |
| coexManager.unregisterCoexListener(listener1); |
| coexManager.unregisterCoexListener(listener2); |
| List<CoexUnsafeChannel> unsafeChannels = new ArrayList<>(); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 36)); |
| int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP |
| | COEX_RESTRICTION_WIFI_AWARE; |
| |
| coexManager.setCoexUnsafeChannels(unsafeChannels, restrictions); |
| |
| verify(listener1, never()).onCoexUnsafeChannelsChanged(); |
| verify(listener2, never()).onCoexUnsafeChannelsChanged(); |
| } |
| |
| /** |
| * Verifies that registered remote CoexCallbacks are notified when |
| * setCoexUnsafeChannels is called. |
| */ |
| @Test |
| public void testRegisteredRemoteCoexCallback_setCoexUnsafeChannels_callbackIsNotified() |
| throws RemoteException { |
| ICoexCallback remoteCallback1 = mock(ICoexCallback.class); |
| when(remoteCallback1.asBinder()).thenReturn(mock(IBinder.class)); |
| ICoexCallback remoteCallback2 = mock(ICoexCallback.class); |
| when(remoteCallback2.asBinder()).thenReturn(mock(IBinder.class)); |
| CoexManager coexManager = createCoexManager(); |
| coexManager.registerRemoteCoexCallback(remoteCallback1); |
| coexManager.registerRemoteCoexCallback(remoteCallback2); |
| verify(remoteCallback1).onCoexUnsafeChannelsChanged(any(), anyInt()); |
| verify(remoteCallback2).onCoexUnsafeChannelsChanged(any(), anyInt()); |
| List<CoexUnsafeChannel> unsafeChannels = new ArrayList<>(); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 36)); |
| int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP |
| | COEX_RESTRICTION_WIFI_AWARE; |
| |
| coexManager.setCoexUnsafeChannels(unsafeChannels, restrictions); |
| |
| List<CoexUnsafeChannel> unsafeChannelList = new ArrayList<>(unsafeChannels); |
| verify(remoteCallback1).onCoexUnsafeChannelsChanged(unsafeChannelList, restrictions); |
| verify(remoteCallback2).onCoexUnsafeChannelsChanged(unsafeChannelList, restrictions); |
| } |
| |
| /** |
| * Verifies that unregistered remote CoexCallbacks are not notified when |
| * setCoexUnsafeChannels is called. |
| */ |
| @Test |
| public void testUnregisteredRemoteCoexCallback_setCoexUnsafeChannels_callbackIsNotNotified() |
| throws RemoteException { |
| ICoexCallback remoteCallback1 = mock(ICoexCallback.class); |
| when(remoteCallback1.asBinder()).thenReturn(mock(IBinder.class)); |
| ICoexCallback remoteCallback2 = mock(ICoexCallback.class); |
| when(remoteCallback2.asBinder()).thenReturn(mock(IBinder.class)); |
| CoexManager coexManager = createCoexManager(); |
| coexManager.registerRemoteCoexCallback(remoteCallback1); |
| coexManager.registerRemoteCoexCallback(remoteCallback2); |
| verify(remoteCallback1).onCoexUnsafeChannelsChanged(any(), anyInt()); |
| verify(remoteCallback2).onCoexUnsafeChannelsChanged(any(), anyInt()); |
| coexManager.unregisterRemoteCoexCallback(remoteCallback1); |
| coexManager.unregisterRemoteCoexCallback(remoteCallback2); |
| List<CoexUnsafeChannel> unsafeChannels = new ArrayList<>(); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 36)); |
| int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP |
| | COEX_RESTRICTION_WIFI_AWARE; |
| |
| coexManager.setCoexUnsafeChannels(unsafeChannels, restrictions); |
| |
| verify(remoteCallback1, times(1)).onCoexUnsafeChannelsChanged(any(), anyInt()); |
| verify(remoteCallback2, times(1)).onCoexUnsafeChannelsChanged(any(), anyInt()); |
| } |
| |
| /** |
| * Verifies that CoexManager does register as a TelephonyCallback if the default coex algorithm |
| * is enabled and a coex table xml file exists and could be read. |
| */ |
| @Test |
| public void testTelephonyCallback_defaultAlgorithmEnabledXmlExists_registersWithTelephony() |
| throws Exception { |
| // config_wifiDefaultCoexAlgorithm defaults to true |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_40_NEIGHBORING).getCanonicalPath()); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| |
| verify(telephonyManager, times(1)) |
| .registerTelephonyCallback(any(Executor.class), any(TelephonyCallback.class)); |
| } |
| |
| /** |
| * Verifies that CoexManager does not register as a TelephonyCallback if the default coex |
| * algorithm is disabled. |
| */ |
| @Test |
| public void testTelephonyCallback_defaultAlgorithmDisabled_doesNotRegisterWithTelephony() |
| throws Exception { |
| when(mMockResources.getBoolean(R.bool.config_wifiDefaultCoexAlgorithmEnabled)) |
| .thenReturn(false); |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_40_NEIGHBORING).getCanonicalPath()); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| createCoexManager(); |
| |
| verify(telephonyManager, never()) |
| .registerTelephonyCallback(any(Executor.class), any(TelephonyCallback.class)); |
| } |
| |
| /** |
| * Verifies that CoexManager returns the correct 2.4Ghz CoexUnsafeChannels for a cell channel |
| * in the neighboring LTE band 40. |
| */ |
| @Test |
| public void testGetCoexUnsafeChannels_neighboringLte40_returns2gNeighboringChannels() |
| throws Exception { |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_40_NEIGHBORING).getCanonicalPath()); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor.capture()); |
| |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 40, 2399_900, 10_000, 0, 0) |
| )); |
| |
| assertThat(coexManager.getCoexUnsafeChannels()).containsExactly( |
| new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 1, -50), |
| new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 2, -50), |
| new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 3, -50), |
| new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 4, -50), |
| new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 5, -50) |
| ); |
| } |
| |
| /** |
| * Verifies that CoexManager returns the correct 5Ghz CoexUnsafeChannels for a cell channel |
| * in the neighboring LTE band 46. |
| */ |
| @Test |
| public void testGetCoexUnsafeChannels_neighboringLte46_returns5gNeighboringChannels() |
| throws Exception { |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_46_NEIGHBORING).getCanonicalPath()); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor.capture()); |
| |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 46, 5150_000, 10_000, 0, 0) |
| )); |
| |
| assertThat(coexManager.getCoexUnsafeChannels()).containsExactly( |
| new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 32, -50), |
| new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 34, -50), |
| new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 36, -50), |
| new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 38, -50), |
| new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 42, -50), |
| new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 50, -50) |
| ); |
| } |
| |
| /** |
| * Verifies that CoexManager returns the correct subset of CoexUnsafeChannels caused by |
| * harmonic interference from the example channel 27065 of LTE Band 27. |
| */ |
| @Test |
| public void testGetCoexUnsafeChannels_channel27065Example_returnsCorrectWifiChannels() |
| throws Exception { |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_27_HARMONIC).getCanonicalPath()); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor.capture()); |
| |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 27, |
| 854_500, 17_000, 809_500, 17_000) |
| )); |
| |
| List<CoexUnsafeChannel> coexUnsafeChannels = new ArrayList<>(); |
| for (int channel = 2; channel <= 7; channel += 1) { |
| coexUnsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, channel, -50)); |
| } |
| assertThat(coexManager.getCoexUnsafeChannels()) |
| .containsExactlyElementsIn(coexUnsafeChannels); |
| } |
| |
| /** |
| * Verifies that CoexManager returns the correct subset of CoexUnsafeChannels caused by |
| * intermod interference with the example channel 3350 of LTE Band 7. |
| */ |
| @Test |
| public void testGetCoexUnsafeChannels_channel3350Example_returnsCorrectWifiChannels() |
| throws Exception { |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_7_INTERMOD).getCanonicalPath()); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor.capture()); |
| |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 7, |
| 2680_000, 10_000, 2560_000, 10_000) |
| )); |
| |
| List<CoexUnsafeChannel> coexUnsafeChannels = new ArrayList<>(); |
| for (int channel = 4; channel <= 9; channel += 1) { |
| coexUnsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, channel, -50)); |
| } |
| assertThat(coexManager.getCoexUnsafeChannels()) |
| .containsExactlyElementsIn(coexUnsafeChannels); |
| } |
| |
| /** |
| * Verifies that CoexManager returns the full list of 2.4GHz CoexUnsafeChannels excluding the |
| * default channel if the entire 2.4GHz band is unsafe. |
| */ |
| @Test |
| public void testGetCoexUnsafeChannels_entire2gBandUnsafe_excludesDefault2gChannel() |
| throws Exception { |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_40_NEIGHBORING).getCanonicalPath()); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor.capture()); |
| |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 40, 2399_900, 2000_000, 0, 0) |
| )); |
| |
| assertThat(coexManager.getCoexUnsafeChannels()).hasSize(13); |
| assertThat(coexManager.getCoexUnsafeChannels()).doesNotContain( |
| new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6, -50)); |
| } |
| |
| /** |
| * Verifies that CoexManager returns the full list of 5GHz CoexUnsafeChannels excluding the |
| * default channel if the entire 5GHz band is unsafe. |
| */ |
| @Test |
| public void testGetCoexUnsafeChannels_entire5gBandUnsafe_excludesDefault5gChannel() |
| throws Exception { |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_46_NEIGHBORING).getCanonicalPath()); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor.capture()); |
| |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 46, 5150_000, 2000_000, 0, 0) |
| )); |
| |
| assertThat(coexManager.getCoexUnsafeChannels()).hasSize(CHANNEL_SET_5_GHZ.size() - 1); |
| assertThat(coexManager.getCoexUnsafeChannels()).doesNotContain( |
| new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 36, -50)); |
| } |
| |
| /** |
| * Verifies that added mock cell channels are used instead of real channels to calculate unsafe |
| * channels until the mock cell channels are reset. |
| */ |
| @Test |
| public void testGetCoexUnsafeChannels_mockCellChannelsAdded_mockCellChannelsUsed() |
| throws Exception { |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_40_NEIGHBORING).getCanonicalPath()); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor.capture()); |
| |
| // Mock channels set. |
| coexManager.setMockCellChannels(Arrays.asList( |
| new CoexUtils.CoexCellChannel(NETWORK_TYPE_LTE, 40, 2399_900, 10_000, 0, 0, |
| SubscriptionManager.INVALID_SUBSCRIPTION_ID))); |
| // Real channels changed. |
| telephonyCallbackCaptor.getValue() |
| .onPhysicalChannelConfigChanged(Collections.emptyList()); |
| |
| // Real channels should be ignored while mock channels are set/ |
| assertThat(coexManager.getCoexUnsafeChannels()).containsExactly( |
| new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 1, -50), |
| new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 2, -50), |
| new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 3, -50), |
| new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 4, -50), |
| new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 5, -50) |
| ); |
| |
| coexManager.resetMockCellChannels(); |
| |
| // Real channels should be used when mock channels are reset. |
| assertThat(coexManager.getCoexUnsafeChannels()).isEmpty(); |
| } |
| |
| /** |
| * Verifies that CoexManager returns the list of channels specified in the override list of a |
| * corresponding cell band. |
| */ |
| @Test |
| public void testGetCoexUnsafeChannels_overrideExists_overrideChannelsAdded() |
| throws Exception { |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_40_OVERRIDE).getCanonicalPath()); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor.capture()); |
| |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 40, 2399_900, 10_000, 0, 0) |
| )); |
| |
| List<CoexUnsafeChannel> unsafeChannels = new ArrayList<>(); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 11)); |
| for (int channel : CHANNEL_SET_5_GHZ_20_MHZ) { |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, channel)); |
| } |
| for (int channel : CHANNEL_SET_5_GHZ_40_MHZ) { |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, channel)); |
| } |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 50)); |
| unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 114)); |
| assertThat(coexManager.getCoexUnsafeChannels()).containsExactlyElementsIn(unsafeChannels); |
| } |
| |
| /** |
| * Verifies that CoexManager returns the full list of 5GHz CoexUnsafeChannels and SoftAP and |
| * Wifi Direct restrictions if LAA is active for a subscription that has LAA restriction |
| * carrier configs set. |
| */ |
| @Test |
| public void testGetCoexUnsafeChannels_LAA_restrict5gSoftApAndWifiDirect() |
| throws Exception { |
| when(mMockCarrierConfigManager.getConfigForSubId(0)) |
| .thenReturn(mUnrestrictedBundle); |
| when(mMockCarrierConfigManager.getConfigForSubId(1)) |
| .thenReturn(mRestrictedBundle); |
| final TelephonyManager telephonyManager0 = setUpSubIdMocks(0); |
| final TelephonyManager telephonyManager1 = setUpSubIdMocks(1); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor0 = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager0).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor0.capture()); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor1 = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager1).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor1.capture()); |
| |
| // Unrestricted sub id gets an LAA channel |
| telephonyCallbackCaptor0.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig( |
| NETWORK_TYPE_LTE, AccessNetworkConstants.EutranBand.BAND_46, |
| 5150_000, 1_000, 0, 0) |
| )); |
| |
| // Unrestricted sub id LAA channel does not trigger the 5g band restriction. |
| assertThat(coexManager.getCoexUnsafeChannels()).isEmpty(); |
| assertThat(coexManager.getCoexRestrictions()).isEqualTo(0); |
| |
| // Restricted sub id gets an LAA channel |
| telephonyCallbackCaptor1.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig( |
| NETWORK_TYPE_LTE, AccessNetworkConstants.EutranBand.BAND_46, |
| 5150_000, 1_000, 0, 0) |
| )); |
| |
| // Restricted sub id LAA channel triggers 5g band restriction. |
| assertThat(coexManager.getCoexUnsafeChannels().stream() |
| .filter(unsafeChannel -> unsafeChannel.getBand() == WIFI_BAND_5_GHZ) |
| .map(unsafeChannel -> unsafeChannel.getChannel()).collect(Collectors.toList())) |
| .containsExactlyElementsIn(CHANNEL_SET_5_GHZ); |
| assertThat(coexManager.getCoexRestrictions() & COEX_RESTRICTION_SOFTAP) |
| .isNotEqualTo(0); |
| assertThat(coexManager.getCoexRestrictions() & COEX_RESTRICTION_WIFI_DIRECT) |
| .isNotEqualTo(0); |
| } |
| |
| /** |
| * Verifies that carrier configs changing will update the unsafe channels |
| */ |
| @Test |
| public void testGetCoexUnsafeChannels_carrierConfigsChanged_updatesUnsafeChannels() { |
| // Start with no restrictions in the carrier config |
| when(mMockCarrierConfigManager.getConfigForSubId(0)).thenReturn(mUnrestrictedBundle); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager).registerTelephonyCallback( |
| any(Executor.class), telephonyCallbackCaptor.capture()); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(IntentFilter.class), eq(null), any(Handler.class)); |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig( |
| NETWORK_TYPE_LTE, AccessNetworkConstants.EutranBand.BAND_46, |
| 5150_000, 1_000, 0, 0) |
| )); |
| |
| // Update the carrier config to have restrictions |
| when(mMockCarrierConfigManager.getConfigForSubId(0)).thenReturn(mRestrictedBundle); |
| Intent intent = new Intent(); |
| intent.setAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, intent); |
| |
| // New carrier config values should be reflected in the unsafe channels. |
| assertThat(coexManager.getCoexUnsafeChannels().stream() |
| .filter(unsafeChannel -> unsafeChannel.getBand() == WIFI_BAND_5_GHZ) |
| .map(unsafeChannel -> unsafeChannel.getChannel()).collect(Collectors.toList())) |
| .containsExactlyElementsIn(CHANNEL_SET_5_GHZ); |
| assertThat(coexManager.getCoexRestrictions() & COEX_RESTRICTION_SOFTAP) |
| .isNotEqualTo(0); |
| assertThat(coexManager.getCoexRestrictions() & COEX_RESTRICTION_WIFI_DIRECT) |
| .isNotEqualTo(0); |
| } |
| |
| /** |
| * Verifies that unsafe channels are calculated on the aggregated cell channels of each sub id. |
| */ |
| @Test |
| public void testGetCoexUnsafeChannels_multipleSubIds_combineUnsafeChannels() throws Exception { |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_46_NEIGHBORING).getCanonicalPath()); |
| final TelephonyManager telephonyManager0 = setUpSubIdMocks(0); |
| final TelephonyManager telephonyManager1 = setUpSubIdMocks(1); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor0 = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager0).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor0.capture()); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor1 = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager1).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor1.capture()); |
| |
| |
| // Add a PhysicalChannelConfig for one sub id to conflict with the lower half of 5g |
| telephonyCallbackCaptor0.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 46, 5000_000, 1000_000, 0, 0) |
| )); |
| // Add a PhysicalChannelConfig for another sub id to conflict with the upper half of 5g |
| telephonyCallbackCaptor1.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 46, 6000_000, 1000_000, 0, 0) |
| )); |
| |
| // The PhysicalChannelConfigs for both sub ids should cause the entire 5g to be unsafe |
| // excluding the default channel. |
| assertThat(coexManager.getCoexUnsafeChannels()).hasSize(CHANNEL_SET_5_GHZ.size() - 1); |
| assertThat(coexManager.getCoexUnsafeChannels()).doesNotContain( |
| new CoexUnsafeChannel(WIFI_BAND_5_GHZ, 36, -50)); |
| } |
| |
| /** |
| * Verifies that calling onPhysicalChannelConfigChanged with the same list more than once will |
| * only notify listeners the first time. |
| */ |
| @Test |
| public void testOnPhysicalChannelConfigChanged_sameChannels_doesNotUpdateListeners() |
| throws Exception { |
| when(mMockResources.getString(R.string.config_wifiCoexTableFilepath)) |
| .thenReturn(createFileFromResource(FILEPATH_LTE_40_NEIGHBORING).getCanonicalPath()); |
| final TelephonyManager telephonyManager = setUpSubIdMocks(0); |
| CoexManager coexManager = createCoexManager(); |
| verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( |
| any(), mCoexSubscriptionsListenerCaptor.capture()); |
| mCoexSubscriptionsListenerCaptor.getValue().onSubscriptionsChanged(); |
| final ArgumentCaptor<CoexManager.CoexTelephonyCallback> telephonyCallbackCaptor = |
| ArgumentCaptor.forClass(CoexManager.CoexTelephonyCallback.class); |
| verify(telephonyManager).registerTelephonyCallback(any(Executor.class), |
| telephonyCallbackCaptor.capture()); |
| CoexManager.CoexListener listener = mock(CoexManager.CoexListener.class); |
| coexManager.registerCoexListener(listener); |
| ICoexCallback remoteCallback = mock(ICoexCallback.class); |
| when(remoteCallback.asBinder()).thenReturn(mock(IBinder.class)); |
| coexManager.registerRemoteCoexCallback(remoteCallback); |
| |
| // Update physical channel configs three times with the same channel |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 40, 2399_900, 10_000, 0, 0) |
| )); |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 40, 2399_900, 10_000, 0, 0) |
| )); |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 40, 2399_900, 10_000, 0, 0) |
| )); |
| // Update physical channel configs with a different channel now |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 41, 2399_900, 10_000, 0, 0) |
| )); |
| // Update physical channel configs back to the first channel |
| telephonyCallbackCaptor.getValue().onPhysicalChannelConfigChanged(Arrays.asList( |
| createMockPhysicalChannelConfig(NETWORK_TYPE_LTE, 40, 2399_900, 10_000, 0, 0) |
| )); |
| |
| // Callbacks should be notified three times: |
| // 1) no list -> list 1 |
| // 2) list 1 -> list 2 |
| // 3) list 2 -> list 1 |
| verify(mMockWifiNative, times(3)).setCoexUnsafeChannels(any(), anyInt()); |
| verify(listener, times(3)).onCoexUnsafeChannelsChanged(); |
| // The remote callback has an extra call since it was notified on registration. |
| verify(remoteCallback, times(4)).onCoexUnsafeChannelsChanged(any(), anyInt()); |
| } |
| } |