From 8b8a16bc7c8d6697bb42b2822775be2f5076e1dd Mon Sep 17 00:00:00 2001 From: Charlotte Lu Date: Tue, 6 Feb 2024 17:46:20 +0800 Subject: [PATCH 1/9] Change Privacy into full page. Test: Visual Test Fix: 324020620 Change-Id: Ifacbf7eef3b56774c5f891c8cd60ddee2d380632 --- res/values/strings.xml | 8 + res/xml/wifi_network_details_fragment2.xml | 5 + .../gsm/AutoSelectPreferenceController.kt | 7 - .../settings/spa/SettingsSpaEnvironment.kt | 2 + .../preference/ComposePreferenceController.kt | 2 +- .../wifi/WepNetworksPreferenceController.kt | 7 - .../details/WifiNetworkDetailsFragment.java | 8 + .../wifi/details2/WifiPrivacyPageProvider.kt | 203 ++++++++++++++++++ .../WifiPrivacyPreferenceController.kt | 66 ++++++ .../WifiPrivacyPreferenceController2.java | 3 +- .../details2/WifiPrivacyPageProviderTest.kt | 179 +++++++++++++++ .../WifiPrivacyPreferenceControllerTest.kt | 96 +++++++++ 12 files changed, 570 insertions(+), 16 deletions(-) create mode 100644 src/com/android/settings/wifi/details2/WifiPrivacyPageProvider.kt create mode 100644 src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController.kt create mode 100644 tests/spa_unit/src/com/android/settings/wifi/details2/WifiPrivacyPageProviderTest.kt create mode 100644 tests/spa_unit/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceControllerTest.kt 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 From dd7626f55bfb0bf2bd8abe015e8ad3c8e1c96d15 Mon Sep 17 00:00:00 2001 From: Yiyi Shen Date: Mon, 26 Feb 2024 11:29:59 +0800 Subject: [PATCH 2/9] [Audiosharing] Clean up audio sharing from Settings Bug: 324023639 Test: atest Change-Id: Ie73790442f39af60b125bbd48182a700bb0b290a --- res/drawable/audio_sharing_guidance.png | Bin 3109 -> 0 bytes res/drawable/audio_sharing_rounded_bg.xml | 22 - .../audio_sharing_rounded_bg_ripple.xml | 21 - res/drawable/ic_audio_calls_and_alarms.xml | 32 - res/drawable/ic_audio_play_sample.xml | 32 - res/layout/audio_sharing_device_item.xml | 33 - res/layout/dialog_audio_sharing.xml | 82 --- .../dialog_audio_sharing_disconnect.xml | 51 -- res/layout/dialog_audio_sharing_join.xml | 53 -- .../dialog_custom_title_audio_sharing.xml | 41 -- res/values/strings.xml | 15 - res/xml/bluetooth_audio_sharing.xml | 80 --- res/xml/bluetooth_audio_streams.xml | 48 -- res/xml/connected_devices.xml | 13 - res/xml/connected_devices_advanced.xml | 9 - .../AudioSharingBasePreferenceController.java | 89 --- .../AudioSharingBluetoothDeviceUpdater.java | 91 --- ...ringCompatibilityPreferenceController.java | 177 ----- .../AudioSharingDashboardFragment.java | 107 --- .../AudioSharingDeviceAdapter.java | 86 --- .../audiosharing/AudioSharingDeviceItem.java | 75 -- ...udioSharingDevicePreferenceController.java | 677 ------------------ ...udioSharingDeviceVolumeControlUpdater.java | 142 ---- ...dioSharingDeviceVolumeGroupController.java | 345 --------- .../AudioSharingDeviceVolumePreference.java | 56 -- .../AudioSharingDialogFragment.java | 154 ---- .../AudioSharingDisconnectDialogFragment.java | 173 ----- .../AudioSharingJoinDialogFragment.java | 175 ----- .../AudioSharingNamePreference.java | 110 --- .../AudioSharingNamePreferenceController.java | 223 ------ .../AudioSharingNameTextValidator.java | 44 -- ...ioSharingPasswordPreferenceController.java | 130 ---- .../AudioSharingPasswordValidator.java | 51 -- ...oSharingPlaySoundPreferenceController.java | 98 --- .../AudioSharingPreferenceController.java | 138 ---- .../AudioSharingStopDialogFragment.java | 138 ---- .../AudioSharingSwitchBarController.java | 395 ---------- .../audiosharing/AudioSharingUtils.java | 408 ----------- .../CallsAndAlarmsDialogFragment.java | 103 --- .../CallsAndAlarmsPreferenceController.java | 261 ------- .../StreamSettingsCategoryController.java | 98 --- .../AudioStreamButtonController.java | 197 ----- .../AudioStreamConfirmDialog.java | 128 ---- .../AudioStreamDetailsFragment.java | 59 -- .../AudioStreamHeaderController.java | 171 ----- .../audiostreams/AudioStreamPreference.java | 195 ----- .../AudioStreamsActiveDeviceController.java | 67 -- ...udioStreamsActiveDeviceSummaryUpdater.java | 100 --- ...udioStreamsBroadcastAssistantCallback.java | 132 ---- .../AudioStreamsCategoryController.java | 110 --- .../AudioStreamsDashboardFragment.java | 134 ---- .../AudioStreamsDialogFragment.java | 151 ---- .../audiostreams/AudioStreamsHelper.java | 166 ----- .../AudioStreamsProgressCategoryCallback.java | 117 --- ...udioStreamsProgressCategoryController.java | 641 ----------------- ...udioStreamsProgressCategoryPreference.java | 89 --- .../AudioStreamsQrCodeFragment.java | 124 ---- .../audiostreams/AudioStreamsRepository.java | 160 ----- .../AudioStreamsScanQrCodeController.java | 132 ---- .../qrcode/QrCodeScanModeActivity.java | 113 --- .../qrcode/QrCodeScanModeBaseActivity.java | 64 -- .../qrcode/QrCodeScanModeFragment.java | 269 ------- .../core/gateway/SettingsGateway.java | 2 - .../ConnectedDeviceDashboardFragmentTest.java | 7 +- .../AudioSharingDialogFragmentTest.java | 232 ------ ...ioSharingDisconnectDialogFragmentTest.java | 224 ------ .../AudioSharingJoinDialogFragmentTest.java | 190 ----- .../AudioSharingPreferenceControllerTest.java | 160 ----- .../AudioSharingStopDialogFragmentTest.java | 151 ---- .../AudioSharingSwitchBarControllerTest.java | 85 --- .../CallsAndAlarmsDialogFragmentTest.java | 110 --- ...allsAndAlarmsPreferenceControllerTest.java | 248 ------- 72 files changed, 1 insertion(+), 9803 deletions(-) delete mode 100644 res/drawable/audio_sharing_guidance.png delete mode 100644 res/drawable/audio_sharing_rounded_bg.xml delete mode 100644 res/drawable/audio_sharing_rounded_bg_ripple.xml delete mode 100644 res/drawable/ic_audio_calls_and_alarms.xml delete mode 100644 res/drawable/ic_audio_play_sample.xml delete mode 100644 res/layout/audio_sharing_device_item.xml delete mode 100644 res/layout/dialog_audio_sharing.xml delete mode 100644 res/layout/dialog_audio_sharing_disconnect.xml delete mode 100644 res/layout/dialog_audio_sharing_join.xml delete mode 100644 res/layout/dialog_custom_title_audio_sharing.xml delete mode 100644 res/xml/bluetooth_audio_sharing.xml delete mode 100644 res/xml/bluetooth_audio_streams.xml delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingCompatibilityPreferenceController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceAdapter.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceItem.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdater.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumePreference.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingNameTextValidator.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingPasswordPreferenceController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingPasswordValidator.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingPlaySoundPreferenceController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingPreferenceController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsDialogFragment.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/StreamSettingsCategoryController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamDetailsFragment.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreference.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsBroadcastAssistantCallback.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsCategoryController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragment.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDialogFragment.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelper.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryCallback.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryPreference.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsRepository.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsScanQrCodeController.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/qrcode/QrCodeScanModeActivity.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/qrcode/QrCodeScanModeBaseActivity.java delete mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/qrcode/QrCodeScanModeFragment.java delete mode 100644 tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java delete mode 100644 tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragmentTest.java delete mode 100644 tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragmentTest.java delete mode 100644 tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingPreferenceControllerTest.java delete mode 100644 tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragmentTest.java delete mode 100644 tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java delete mode 100644 tests/robotests/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsDialogFragmentTest.java delete mode 100644 tests/robotests/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceControllerTest.java diff --git a/res/drawable/audio_sharing_guidance.png b/res/drawable/audio_sharing_guidance.png deleted file mode 100644 index c0ab6377019b3d1a85b14f502c54eecb3f80eb2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3109 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 diff --git a/res/drawable/audio_sharing_rounded_bg.xml b/res/drawable/audio_sharing_rounded_bg.xml deleted file mode 100644 index db1e1bbe3fb..00000000000 --- a/res/drawable/audio_sharing_rounded_bg.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/res/drawable/audio_sharing_rounded_bg_ripple.xml b/res/drawable/audio_sharing_rounded_bg_ripple.xml deleted file mode 100644 index 18696c627ec..00000000000 --- a/res/drawable/audio_sharing_rounded_bg_ripple.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/res/drawable/ic_audio_calls_and_alarms.xml b/res/drawable/ic_audio_calls_and_alarms.xml deleted file mode 100644 index 5da27c69ca5..00000000000 --- a/res/drawable/ic_audio_calls_and_alarms.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - diff --git a/res/drawable/ic_audio_play_sample.xml b/res/drawable/ic_audio_play_sample.xml deleted file mode 100644 index 3666c22ce96..00000000000 --- a/res/drawable/ic_audio_play_sample.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - diff --git a/res/layout/audio_sharing_device_item.xml b/res/layout/audio_sharing_device_item.xml deleted file mode 100644 index 04ecdd758af..00000000000 --- a/res/layout/audio_sharing_device_item.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - -