blob: 1c9df67bcd2b050038dd446ffa3000a5dae74169 [file] [log] [blame]
/*
* Copyright (C) 2019 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;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.net.wifi.WifiConfiguration;
import android.os.Handler;
import android.os.Process;
import android.os.test.TestLooper;
import androidx.test.filters.SmallTest;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
* Unit tests for {@link ConnectionFailureNotifier}.
*/
@SmallTest
public class ConnectionFailureNotifierTest extends WifiBaseTest {
@Mock private Context mContext;
@Mock private WifiInjector mWifiInjector;
@Mock private Resources mResources;
@Mock private FrameworkFacade mFrameworkFacade;
@Mock private WifiConfigManager mWifiConfigManager;
@Mock private WifiConnectivityManager mWifiConnectivityManager;
@Mock private NotificationManager mNotificationManager;
@Mock private ConnectionFailureNotificationBuilder mConnectionFailureNotificationBuilder;
@Mock private Notification mNotification;
@Mock private AlertDialog mAlertDialog;
final ArgumentCaptor<BroadcastReceiver> mBroadCastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
private ConnectionFailureNotifier mConnectionFailureNotifier;
TestLooper mLooper;
/** Initialize objects before each test run. */
@Before
public void setUp() throws Exception {
// Ensure looper exists
mLooper = new TestLooper();
MockitoAnnotations.initMocks(this);
when(mContext.getResources()).thenReturn(mResources);
when(mWifiInjector.getNotificationManager()).thenReturn(mNotificationManager);
when(mWifiInjector.getConnectionFailureNotificationBuilder())
.thenReturn(mConnectionFailureNotificationBuilder);
when(mConnectionFailureNotificationBuilder
.buildNoMacRandomizationSupportNotification(any())).thenReturn(mNotification);
when(mConnectionFailureNotificationBuilder.buildChangeMacRandomizationSettingDialog(any(),
any())).thenReturn(mAlertDialog);
mConnectionFailureNotifier = new ConnectionFailureNotifier(mContext, mWifiInjector,
mFrameworkFacade, mWifiConfigManager, mWifiConnectivityManager,
new Handler(mLooper.getLooper()));
verify(mContext).registerReceiver(mBroadCastReceiverCaptor.capture(), any());
}
private class DisableMacRandomizationMatcher implements ArgumentMatcher<WifiConfiguration> {
@Override
public boolean matches(WifiConfiguration config) {
return config.macRandomizationSetting == WifiConfiguration.RANDOMIZATION_NONE;
}
}
// Returns an intent that simulates the broadcast which is received when the user tap
// on the notification to change MAC randomization settings.
private Intent buildBroadcastForRandomizationSettingsDialog(WifiConfiguration config) {
Intent intent = mock(Intent.class);
when(intent.getAction()).thenReturn(ConnectionFailureNotificationBuilder
.ACTION_SHOW_SET_RANDOMIZATION_DETAILS);
when(intent.getIntExtra(eq(ConnectionFailureNotificationBuilder
.RANDOMIZATION_SETTINGS_NETWORK_ID), anyInt())).thenReturn(config.networkId);
when(intent.getStringExtra(
eq(ConnectionFailureNotificationBuilder.RANDOMIZATION_SETTINGS_NETWORK_SSID)))
.thenReturn(config.getSsidAndSecurityTypeString());
return intent;
}
/**
* Verify that a notification is posted when a connection failure happens on a network
* in the hotlist. Then verify that tapping on the notification launches an dialog, which
* could be used to set the randomization setting for a network to "Trusted".
*/
@Test
public void testConnectionFailureSendRandomizationSettingsNotification() {
// Verify that the network is using randomized MAC at the start.
WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
when(mWifiConfigManager.getConfiguredNetwork(config.networkId)).thenReturn(config);
assertEquals(WifiConfiguration.RANDOMIZATION_PERSISTENT, config.macRandomizationSetting);
mConnectionFailureNotifier.showFailedToConnectDueToNoRandomizedMacSupportNotification(
config.networkId);
// verify that a notification is sent
verify(mNotificationManager).notify(
eq(SystemMessage.NOTE_NETWORK_NO_MAC_RANDOMIZATION_SUPPORT), eq(mNotification));
// sets up the intent that simulates the user tapping on the notification.
Intent intent = buildBroadcastForRandomizationSettingsDialog(config);
// simulate the user tapping on the notification, then verify the dialog shows up, and
// the appropriate callback is registered
ArgumentCaptor<DialogInterface.OnClickListener> onClickListenerArgumentCaptor =
ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
mBroadCastReceiverCaptor.getValue().onReceive(mContext, intent);
verify(mConnectionFailureNotificationBuilder).buildChangeMacRandomizationSettingDialog(
eq(config.SSID), onClickListenerArgumentCaptor.capture());
// simulate the user tapping on the option to reset MAC address to factory MAC
onClickListenerArgumentCaptor.getValue().onClick(null, 0);
mLooper.dispatchAll();
// verify the WifiConfiguration is updated properly.
verify(mWifiConfigManager).addOrUpdateNetwork(
argThat(new DisableMacRandomizationMatcher()), eq(Process.SYSTEM_UID));
// verify that we try to connect to the updated network.
verify(mWifiConnectivityManager).forceConnectivityScan(any());
}
/**
* Verify that if the WifiConfiguration if not found (may have been deleted by the timed the
* notification is tapped), then the AlertDialog does not show up.
*/
@Test
public void testWifiConfigurationMismatch() {
WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
when(mWifiConfigManager.getConfiguredNetwork(config.networkId)).thenReturn(config);
mConnectionFailureNotifier.showFailedToConnectDueToNoRandomizedMacSupportNotification(
config.networkId);
// verify that a notification is sent
verify(mNotificationManager).notify(
eq(SystemMessage.NOTE_NETWORK_NO_MAC_RANDOMIZATION_SUPPORT), any());
// sets up the intent that simulates the user tapping on the notification.
Intent intent = buildBroadcastForRandomizationSettingsDialog(config);
// the WifiConfiguration that is found doesn't match with the one received from broadcast.
when(mWifiConfigManager.getConfiguredNetwork(anyInt()))
.thenReturn(WifiConfigurationTestUtil.createOpenNetwork());
mBroadCastReceiverCaptor.getValue().onReceive(mContext, intent);
// verify that the AlertDialog is not launched in this case
verify(mConnectionFailureNotificationBuilder, never())
.buildChangeMacRandomizationSettingDialog(any(), any());
verify(mFrameworkFacade, never()).makeAlertDialogBuilder(any());
// instead we are showings a toast due to failing to find the network
verify(mFrameworkFacade).showToast(any(), any());
}
}