diff --git a/res/values/strings.xml b/res/values/strings.xml index 73a3b557ede..afd0ac47bc6 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2125,6 +2125,14 @@ IP settings Privacy + + MAC + + Device name + + Send device name + + Share this device\u0027s name with the network Subscription diff --git a/res/xml/wifi_network_details_fragment2.xml b/res/xml/wifi_network_details_fragment2.xml index daff20f5a28..598f9d86173 100644 --- a/res/xml/wifi_network_details_fragment2.xml +++ b/res/xml/wifi_network_details_fragment2.xml @@ -97,6 +97,11 @@ android:entries="@array/wifi_privacy_entries" android:entryValues="@array/wifi_privacy_values"/> + + () /** @@ -99,11 +97,6 @@ class AutoSelectPreferenceController @JvmOverloads constructor( if (MobileNetworkUtils.shouldDisplayNetworkSelectOptions(mContext, subId)) AVAILABLE else CONDITIONALLY_UNAVAILABLE - override fun displayPreference(screen: PreferenceScreen) { - super.displayPreference(screen) - preference = screen.findPreference(preferenceKey)!! - } - @Composable override fun Content() { val coroutineScope = rememberCoroutineScope() diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt index 7a1d91571ad..568188fa862 100644 --- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt +++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt @@ -56,6 +56,7 @@ import com.android.settings.spa.notification.NotificationMainPageProvider import com.android.settings.spa.system.AppLanguagesPageProvider import com.android.settings.spa.system.LanguageAndInputPageProvider import com.android.settings.spa.system.SystemMainPageProvider +import com.android.settings.wifi.details2.WifiPrivacyPageProvider import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository import com.android.settingslib.spa.framework.common.SpaEnvironment import com.android.settingslib.spa.framework.common.SpaLogger @@ -122,6 +123,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { SimOnboardingPageProvider, BatteryOptimizationModeAppListPageProvider, NetworkCellularGroupProvider, + WifiPrivacyPageProvider, ) override val logger = if (FeatureFlagUtils.isEnabled( diff --git a/src/com/android/settings/spa/preference/ComposePreferenceController.kt b/src/com/android/settings/spa/preference/ComposePreferenceController.kt index 9dd82824fd9..5ba1d24583d 100644 --- a/src/com/android/settings/spa/preference/ComposePreferenceController.kt +++ b/src/com/android/settings/spa/preference/ComposePreferenceController.kt @@ -24,7 +24,7 @@ import com.android.settings.core.BasePreferenceController abstract class ComposePreferenceController(context: Context, preferenceKey: String) : BasePreferenceController(context, preferenceKey) { - private lateinit var preference: ComposePreference + protected lateinit var preference: ComposePreference override fun displayPreference(screen: PreferenceScreen) { super.displayPreference(screen) diff --git a/src/com/android/settings/wifi/WepNetworksPreferenceController.kt b/src/com/android/settings/wifi/WepNetworksPreferenceController.kt index 6263bfdafbf..c84e79aa597 100644 --- a/src/com/android/settings/wifi/WepNetworksPreferenceController.kt +++ b/src/com/android/settings/wifi/WepNetworksPreferenceController.kt @@ -39,15 +39,8 @@ import kotlinx.coroutines.flow.callbackFlow class WepNetworksPreferenceController(context: Context, preferenceKey: String) : ComposePreferenceController(context, preferenceKey) { - private lateinit var preference: Preference - var wifiManager = context.getSystemService(WifiManager::class.java)!! - override fun displayPreference(screen: PreferenceScreen) { - super.displayPreference(screen) - preference = screen.findPreference(preferenceKey)!! - } - override fun getAvailabilityStatus() = if (Flags.androidVWifiApi()) AVAILABLE else UNSUPPORTED_ON_DEVICE diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java index 0384f0d6c8c..e1774e3f1a2 100644 --- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java +++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java @@ -58,6 +58,7 @@ import com.android.settings.wifi.details2.AddDevicePreferenceController2; import com.android.settings.wifi.details2.WifiAutoConnectPreferenceController2; import com.android.settings.wifi.details2.WifiDetailPreferenceController2; import com.android.settings.wifi.details2.WifiMeteredPreferenceController2; +import com.android.settings.wifi.details2.WifiPrivacyPreferenceController; import com.android.settings.wifi.details2.WifiPrivacyPreferenceController2; import com.android.settings.wifi.details2.WifiSecondSummaryController2; import com.android.settings.wifi.details2.WifiSubscriptionDetailPreferenceController2; @@ -118,6 +119,13 @@ public class WifiNetworkDetailsFragment extends RestrictedDashboardFragment impl super(UserManager.DISALLOW_CONFIG_WIFI); } + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + use(WifiPrivacyPreferenceController.class) + .setWifiEntryKey(getArguments().getString(KEY_CHOSEN_WIFIENTRY_KEY)); + } + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); diff --git a/src/com/android/settings/wifi/details2/WifiPrivacyPageProvider.kt b/src/com/android/settings/wifi/details2/WifiPrivacyPageProvider.kt new file mode 100644 index 00000000000..e41863cd5b8 --- /dev/null +++ b/src/com/android/settings/wifi/details2/WifiPrivacyPageProvider.kt @@ -0,0 +1,203 @@ +/* + * 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.wifi.details2 + +import android.content.Context +import android.net.wifi.WifiConfiguration +import android.net.wifi.WifiManager +import android.os.Bundle +import android.os.Handler +import android.os.HandlerThread +import android.os.Looper +import android.os.Process +import android.os.SimpleClock +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.res.stringArrayResource +import androidx.compose.ui.res.stringResource +import androidx.navigation.NavType +import androidx.navigation.navArgument +import com.android.settings.R +import com.android.settings.overlay.FeatureFactory.Companion.featureFactory +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.widget.preference.ListPreferenceModel +import com.android.settingslib.spa.widget.preference.ListPreferenceOption +import com.android.settingslib.spa.widget.preference.RadioPreferences +import com.android.settingslib.spa.widget.preference.SwitchPreference +import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel +import com.android.settingslib.spa.widget.scaffold.RegularScaffold +import com.android.settingslib.spa.widget.ui.CategoryTitle +import com.android.wifitrackerlib.WifiEntry +import java.time.Clock +import java.time.ZoneOffset + +const val WIFI_ENTRY_KEY = "wifiEntryKey" + +object WifiPrivacyPageProvider : SettingsPageProvider { + override val name = "WifiPrivacy" + const val TAG = "WifiPrivacyPageProvider" + + override val parameter = listOf( + navArgument(WIFI_ENTRY_KEY) { type = NavType.StringType }, + ) + + @Composable + override fun Page(arguments: Bundle?) { + val wifiEntryKey = arguments!!.getString(WIFI_ENTRY_KEY) + if (wifiEntryKey != null) { + val context = LocalContext.current + val lifecycle = LocalLifecycleOwner.current.lifecycle + val wifiEntry = remember { + getWifiEntry(context, wifiEntryKey, lifecycle) + } + WifiPrivacyPage(wifiEntry) + } + } + + fun getRoute( + wifiEntryKey: String, + ): String = "${name}/$wifiEntryKey" +} + +@Composable +fun WifiPrivacyPage(wifiEntry: WifiEntry) { + val isSelectable: Boolean = wifiEntry.canSetPrivacy() + RegularScaffold( + title = stringResource(id = R.string.wifi_privacy_settings) + ) { + Column { + val title = stringResource(id = R.string.wifi_privacy_mac_settings) + val wifiPrivacyEntries = stringArrayResource(R.array.wifi_privacy_entries) + val wifiPrivacyValues = stringArrayResource(R.array.wifi_privacy_values) + val textsSelectedId = rememberSaveable { mutableIntStateOf(wifiEntry.privacy) } + val dataList = remember { + wifiPrivacyEntries.mapIndexed { index, text -> + ListPreferenceOption(id = wifiPrivacyValues[index].toInt(), text = text) + } + } + RadioPreferences(remember { + object : ListPreferenceModel { + override val title = title + override val options = dataList + override val selectedId = textsSelectedId + override val onIdSelected: (Int) -> Unit = { + textsSelectedId.intValue = it + onSelectedChange(wifiEntry, it) + } + override val enabled = { isSelectable } + } + }) + wifiEntry.wifiConfiguration?.let { + DeviceNameSwitchPreference(it) + } + } + } +} + +@Composable +fun DeviceNameSwitchPreference(wifiConfiguration: WifiConfiguration){ + Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight)) + CategoryTitle(title = stringResource(R.string.wifi_privacy_device_name_settings)) + Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight)) + var checked by remember { + mutableStateOf(wifiConfiguration.isSendDhcpHostnameEnabled) + } + val context = LocalContext.current + val wifiManager = context.getSystemService(WifiManager::class.java)!! + SwitchPreference(object : SwitchPreferenceModel { + override val title = + context.resources.getString( + R.string.wifi_privacy_send_device_name_toggle_title + ) + override val summary = + { + context.resources.getString( + R.string.wifi_privacy_send_device_name_toggle_summary + ) + } + override val checked = { checked } + override val onCheckedChange: (Boolean) -> Unit = { newChecked -> + wifiConfiguration.isSendDhcpHostnameEnabled = newChecked + wifiManager.save(wifiConfiguration, null /* listener */) + checked = newChecked + } + }) +} + +fun onSelectedChange(wifiEntry: WifiEntry, privacy: Int) { + if (wifiEntry.privacy == privacy) { + // Prevent disconnection + reconnection if settings not changed. + return + } + wifiEntry.setPrivacy(privacy) + + // To activate changing, we need to reconnect network. WiFi will auto connect to + // current network after disconnect(). Only needed when this is connected network. + + // To activate changing, we need to reconnect network. WiFi will auto connect to + // current network after disconnect(). Only needed when this is connected network. + if (wifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) { + wifiEntry.disconnect(null /* callback */) + wifiEntry.connect(null /* callback */) + } +} + +fun getWifiEntry( + context: Context, + wifiEntryKey: String, + liftCycle: androidx.lifecycle.Lifecycle +): WifiEntry { + // Max age of tracked WifiEntries + val MAX_SCAN_AGE_MILLIS: Long = 15000 + // Interval between initiating SavedNetworkTracker scans + val SCAN_INTERVAL_MILLIS: Long = 10000 + val mWorkerThread = HandlerThread( + WifiPrivacyPageProvider.TAG, + Process.THREAD_PRIORITY_BACKGROUND + ) + mWorkerThread.start() + val elapsedRealtimeClock: Clock = object : SimpleClock(ZoneOffset.UTC) { + override fun millis(): Long { + return android.os.SystemClock.elapsedRealtime() + } + } + val mNetworkDetailsTracker = featureFactory + .wifiTrackerLibProvider + .createNetworkDetailsTracker( + liftCycle, + context, + Handler(Looper.getMainLooper()), + mWorkerThread.getThreadHandler(), + elapsedRealtimeClock, + MAX_SCAN_AGE_MILLIS, + SCAN_INTERVAL_MILLIS, + wifiEntryKey + ) + return mNetworkDetailsTracker.wifiEntry +} diff --git a/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController.kt b/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController.kt new file mode 100644 index 00000000000..42741e311c2 --- /dev/null +++ b/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController.kt @@ -0,0 +1,66 @@ +/* + * 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.wifi.details2 + +import android.content.Context +import android.net.wifi.WifiManager +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource +import com.android.settings.R +import com.android.settings.spa.SpaActivity.Companion.startSpaActivity +import com.android.settings.spa.preference.ComposePreferenceController +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.wifi.flags.Flags + +class WifiPrivacyPreferenceController(context: Context, preferenceKey: String) : + ComposePreferenceController(context, preferenceKey) { + + private var wifiEntryKey: String? = null + + var wifiManager = context.getSystemService(WifiManager::class.java)!! + + fun setWifiEntryKey(key: String?) { + wifiEntryKey = key + } + + override fun getAvailabilityStatus() = + if (Flags.androidVWifiApi() && wifiManager.isConnectedMacRandomizationSupported) AVAILABLE + else CONDITIONALLY_UNAVAILABLE + + @Composable + override fun Content() { + Preference(object : PreferenceModel { + override val title = stringResource(R.string.wifi_privacy_settings) + override val icon = @Composable { + Icon( + ImageVector.vectorResource(R.drawable.ic_wifi_privacy_24dp), + contentDescription = null + ) + } + override val onClick: () -> Unit = + { + wifiEntryKey?.let { + mContext.startSpaActivity(WifiPrivacyPageProvider.getRoute(it)) + } + } + }) + } +} \ No newline at end of file diff --git a/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController2.java index 8c78e805d69..5d393e54a21 100644 --- a/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController2.java +++ b/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController2.java @@ -26,6 +26,7 @@ import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +import com.android.wifi.flags.Flags; import com.android.wifitrackerlib.WifiEntry; /** @@ -50,7 +51,7 @@ public class WifiPrivacyPreferenceController2 extends BasePreferenceController i @Override public int getAvailabilityStatus() { - return mWifiManager.isConnectedMacRandomizationSupported() + return (!Flags.androidVWifiApi() && mWifiManager.isConnectedMacRandomizationSupported()) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } diff --git a/tests/spa_unit/src/com/android/settings/wifi/details2/WifiPrivacyPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/wifi/details2/WifiPrivacyPageProviderTest.kt new file mode 100644 index 00000000000..5c9a1a4a932 --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/wifi/details2/WifiPrivacyPageProviderTest.kt @@ -0,0 +1,179 @@ +/* + * 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.wifi.details2 + +import android.content.Context +import android.net.wifi.WifiConfiguration +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsNotEnabled +import androidx.compose.ui.test.assertIsOff +import androidx.compose.ui.test.assertIsOn +import androidx.compose.ui.test.assertIsSelectable +import androidx.compose.ui.test.assertIsSelected +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performClick +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.wifitrackerlib.WifiEntry +import com.google.common.truth.Truth +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.stub + +@RunWith(AndroidJUnit4::class) +class WifiPrivacyPageProviderTest { + @get:Rule + val composeTestRule = createComposeRule() + + private val context: Context = ApplicationProvider.getApplicationContext() + private var mockWifiConfiguration = mock() { + on { isSendDhcpHostnameEnabled } doReturn true + } + private var mockWifiEntry = mock() { + on { canSetPrivacy() } doReturn true + on { privacy } doReturn 0 + on { wifiConfiguration } doReturn mockWifiConfiguration + } + + @Test + fun apnEditPageProvider_name() { + Truth.assertThat(WifiPrivacyPageProvider.name).isEqualTo("WifiPrivacy") + } + + @Test + fun title_displayed() { + composeTestRule.setContent { + WifiPrivacyPage(mockWifiEntry) + } + composeTestRule.onNodeWithText( + context.getString(R.string.wifi_privacy_settings) + ).assertIsDisplayed() + } + + @Test + fun category_mac_title_displayed() { + composeTestRule.setContent { + WifiPrivacyPage(mockWifiEntry) + } + composeTestRule.onNodeWithText( + context.getString(R.string.wifi_privacy_mac_settings) + ).assertIsDisplayed() + } + + @Test + fun category_mac_list_displayed() { + composeTestRule.setContent { + WifiPrivacyPage(mockWifiEntry) + } + val wifiPrivacyEntries = context.resources.getStringArray(R.array.wifi_privacy_entries) + for (entry in wifiPrivacyEntries) { + composeTestRule.onNodeWithText( + entry + ).assertIsDisplayed() + } + } + + @Test + fun category_mac_list_selectable() { + composeTestRule.setContent { + WifiPrivacyPage(mockWifiEntry) + } + val wifiPrivacyEntries = context.resources.getStringArray(R.array.wifi_privacy_entries) + for (entry in wifiPrivacyEntries) { + composeTestRule.onNodeWithText( + entry + ).assertIsSelectable() + } + } + + @Test + fun category_mac_list_default_selected() { + composeTestRule.setContent { + WifiPrivacyPage(mockWifiEntry) + } + val wifiPrivacyEntries = context.resources.getStringArray(R.array.wifi_privacy_entries) + val wifiPrivacyValues = context.resources.getStringArray(R.array.wifi_privacy_values) + composeTestRule.onNodeWithText( + wifiPrivacyEntries[wifiPrivacyValues.indexOf("0")] + ).assertIsSelected() + } + + @Test + fun category_mac_list_not_enabled() { + mockWifiEntry.stub { + on { canSetPrivacy() } doReturn false + } + composeTestRule.setContent { + WifiPrivacyPage(mockWifiEntry) + } + val wifiPrivacyEntries = context.resources.getStringArray(R.array.wifi_privacy_entries) + for (entry in wifiPrivacyEntries) { + composeTestRule.onNodeWithText(entry).assertIsNotEnabled() + } + } + + @Test + fun category_send_device_name_title_displayed() { + composeTestRule.setContent { + WifiPrivacyPage(mockWifiEntry) + } + composeTestRule.onNodeWithText( + context.getString(R.string.wifi_privacy_device_name_settings) + ).assertIsDisplayed() + } + + @Test + fun toggle_send_device_name_title_displayed() { + composeTestRule.setContent { + WifiPrivacyPage(mockWifiEntry) + } + composeTestRule.onNodeWithText( + context.getString(R.string.wifi_privacy_send_device_name_toggle_title) + ).assertIsDisplayed() + } + + @Test + fun send_device_name_turnOn() { + composeTestRule.setContent { + WifiPrivacyPage(mockWifiEntry) + } + composeTestRule.onNodeWithText( + context.getString(R.string.wifi_privacy_send_device_name_toggle_title) + ).assertIsOn() + } + + @Test + fun onClick_turnOff() { + composeTestRule.setContent { + WifiPrivacyPage(mockWifiEntry) + } + + composeTestRule.onNodeWithText( + context.getString(R.string.wifi_privacy_send_device_name_toggle_title) + ).performClick() + + composeTestRule.onNodeWithText( + context.getString(R.string.wifi_privacy_send_device_name_toggle_title) + ).assertIsOff() + } +} \ No newline at end of file diff --git a/tests/spa_unit/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceControllerTest.kt new file mode 100644 index 00000000000..98997e4ff8c --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceControllerTest.kt @@ -0,0 +1,96 @@ +/* + * 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.wifi.details2 + +import android.content.Context +import android.content.Intent +import android.net.wifi.WifiManager +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.core.os.bundleOf +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.settingslib.spa.framework.util.KEY_DESTINATION +import com.google.common.truth.Truth +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.doNothing +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.spy +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@RunWith(AndroidJUnit4::class) +class WifiPrivacyPreferenceControllerTest { + @get:Rule + val composeTestRule = createComposeRule() + + private val mockWifiManager = mock { + on { isConnectedMacRandomizationSupported } doReturn true + } + + private val context: Context = spy(ApplicationProvider.getApplicationContext()) { + on { getSystemService(WifiManager::class.java) } doReturn mockWifiManager + doNothing().whenever(mock).startActivity(any()) + } + + private val controller = WifiPrivacyPreferenceController(context, TEST_KEY) + + @Test + fun title_isDisplayed() { + composeTestRule.setContent { + CompositionLocalProvider(LocalContext provides context) { + controller.Content() + } + } + + composeTestRule.onNodeWithText(context.getString(R.string.wifi_privacy_settings)) + .assertIsDisplayed() + } + + @Test + fun onClick_startWifiPrivacyPage() { + composeTestRule.setContent { + CompositionLocalProvider(LocalContext provides context) { + controller.setWifiEntryKey("") + controller.Content() + } + } + + composeTestRule.onNodeWithText(context.getString(R.string.wifi_privacy_settings)) + .performClick() + + val intent = argumentCaptor { + verify(context).startActivity(capture()) + }.firstValue + Truth.assertThat(intent.getStringExtra(KEY_DESTINATION)) + .isEqualTo(WifiPrivacyPageProvider.getRoute("")) + } + + private companion object { + const val TEST_KEY = "test_key" + } +} \ No newline at end of file