diff --git a/res/layout/wifi_dialog.xml b/res/layout/wifi_dialog.xml index 233072745b8..72eb011befb 100644 --- a/res/layout/wifi_dialog.xml +++ b/res/layout/wifi_dialog.xml @@ -483,6 +483,27 @@ + + + + + + + + Treat as unmetered + + Default (use randomized MAC) + Trusted + + No Yes @@ -1092,6 +1097,11 @@ 2 + + 0 + 1 + + Automatic (based on time of day) diff --git a/res/values/strings.xml b/res/values/strings.xml index b52bfea6481..344cc5636dc 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2052,6 +2052,8 @@ Choose at least one band for Wi\u2011Fi hotspot: IP settings + + Privacy Share with other device users diff --git a/res/xml/wifi_network_details_fragment.xml b/res/xml/wifi_network_details_fragment.xml index 5e2745a6e51..7c8d9a00aa2 100644 --- a/res/xml/wifi_network_details_fragment.xml +++ b/res/xml/wifi_network_details_fragment.xml @@ -56,6 +56,12 @@ android:title="@string/data_usage_metered_yes" android:entries="@array/wifi_metered_entries" android:entryValues="@array/wifi_metered_values"/> + + diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java index 0fe37e91027..567bd121898 100644 --- a/src/com/android/settings/core/FeatureFlags.java +++ b/src/com/android/settings/core/FeatureFlags.java @@ -26,4 +26,5 @@ public class FeatureFlags { public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid"; public static final String MOBILE_NETWORK_V2 = "settings_mobile_network_v2"; public static final String DATA_USAGE_V2 = "settings_data_usage_v2"; + public static final String WIFI_MAC_RANDOMIZATION = "settings_wifi_mac_randomization"; } diff --git a/src/com/android/settings/wifi/WifiDialog.java b/src/com/android/settings/wifi/WifiDialog.java index 2b8fb2d3236..b5bd32068de 100644 --- a/src/com/android/settings/wifi/WifiDialog.java +++ b/src/com/android/settings/wifi/WifiDialog.java @@ -19,6 +19,7 @@ package com.android.settings.wifi; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; +import android.util.FeatureFlagUtils; import android.view.View; import android.widget.Button; @@ -93,6 +94,14 @@ public class WifiDialog extends AlertDialog implements WifiConfigUiBase, if (mAccessPoint == null) { mController.hideForgetButton(); } + + if (FeatureFlagUtils.isEnabled(getContext(), + com.android.settings.core.FeatureFlags.WIFI_MAC_RANDOMIZATION)) { + View view = mView.findViewById(R.id.privacy_settings_fields); + if (view != null) { + view.setVisibility(View.VISIBLE); + } + } } public void onRestoreInstanceState(Bundle savedInstanceState) { diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java index c29ad60a5e4..7f0e8ee5677 100644 --- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java +++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java @@ -135,6 +135,10 @@ public class WifiNetworkDetailsFragment extends DashboardFragment { controllers.add(mWifiDetailPreferenceController); controllers.add(new WifiMeteredPreferenceController(context, mAccessPoint.getConfig())); + WifiPrivacyPreferenceController preferenceController = new WifiPrivacyPreferenceController( + context); + preferenceController.setWifiConfiguration(mAccessPoint.getConfig()); + controllers.add(preferenceController); return controllers; } diff --git a/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java b/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java new file mode 100644 index 00000000000..2afe35bf2d4 --- /dev/null +++ b/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.wifi.details; + +import android.content.Context; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.util.FeatureFlagUtils; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.DropDownPreference; +import androidx.preference.Preference; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.core.FeatureFlags; +import com.android.settingslib.core.AbstractPreferenceController; + +/** + * {@link AbstractPreferenceController} that controls whether the wifi network is mac randomized + * or not + */ +public class WifiPrivacyPreferenceController extends BasePreferenceController implements + Preference.OnPreferenceChangeListener { + + private static final String KEY_WIFI_PRIVACY = "privacy"; + private WifiConfiguration mWifiConfiguration; + private WifiManager mWifiManager; + + public WifiPrivacyPreferenceController(Context context) { + super(context, KEY_WIFI_PRIVACY); + mWifiConfiguration = null; + mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + } + + public void setWifiConfiguration(WifiConfiguration wifiConfiguration) { + mWifiConfiguration = wifiConfiguration; + } + + @Override + public int getAvailabilityStatus() { + return FeatureFlagUtils.isEnabled(mContext, FeatureFlags.WIFI_MAC_RANDOMIZATION) + ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void updateState(Preference preference) { + final DropDownPreference dropDownPreference = (DropDownPreference) preference; + final int randomizationLevel = getRandomizationValue(); + dropDownPreference.setValue(Integer.toString(randomizationLevel)); + updateSummary((DropDownPreference) preference, randomizationLevel); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (mWifiConfiguration != null) { + //TODO(b/117957974): update MAC randomization level to WifiManager + mWifiManager.updateNetwork(mWifiConfiguration); + } + updateSummary((DropDownPreference) preference, Integer.parseInt((String) newValue)); + return true; + } + + @VisibleForTesting + int getRandomizationValue() { + if (mWifiConfiguration != null) { + //TODO(b/117957974): get real MAC randomization level from WifiManager + return 0; + } + return 0; + } + + private void updateSummary(DropDownPreference preference, int macRandomized) { + preference.setSummary(preference.getEntries()[macRandomized]); + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiPrivacyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiPrivacyPreferenceControllerTest.java new file mode 100644 index 00000000000..a4bcfff9b88 --- /dev/null +++ b/tests/robotests/src/com/android/settings/wifi/details/WifiPrivacyPreferenceControllerTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.wifi.details; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; +import android.net.wifi.WifiConfiguration; + +import androidx.preference.DropDownPreference; + +import com.android.settings.R; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class WifiPrivacyPreferenceControllerTest { + + private static final int PRIVACY_RANDOMIZED = 0; + private static final int PRIVACY_TRUSTED = 1; + + @Mock + private WifiConfiguration mWifiConfiguration; + + private WifiPrivacyPreferenceController mPreferenceController; + private Context mContext; + private DropDownPreference mDropDownPreference; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + + WifiPrivacyPreferenceController preferenceController = new WifiPrivacyPreferenceController( + mContext); + preferenceController.setWifiConfiguration(mWifiConfiguration); + mPreferenceController = spy(preferenceController); + mDropDownPreference = new DropDownPreference(mContext); + mDropDownPreference.setEntries(R.array.wifi_privacy_entries); + mDropDownPreference.setEntryValues(R.array.wifi_privacy_values); + } + + @Test + public void testUpdateState_wifiPrivacy_setCorrectValue() { + doReturn(PRIVACY_TRUSTED).when(mPreferenceController).getRandomizationValue(); + + mPreferenceController.updateState(mDropDownPreference); + + assertThat(mDropDownPreference.getEntry()).isEqualTo("Trusted"); + } + + @Test + public void testUpdateState_wifiNotMetered_setCorrectValue() { + doReturn(PRIVACY_RANDOMIZED).when(mPreferenceController).getRandomizationValue(); + + mPreferenceController.updateState(mDropDownPreference); + + assertThat(mDropDownPreference.getEntry()).isEqualTo("Default (use randomized MAC)"); + } + + @Test + public void testController_resilientToNullConfig() { + mPreferenceController = spy(new WifiPrivacyPreferenceController(mContext)); + + mPreferenceController.getRandomizationValue(); + mPreferenceController.onPreferenceChange(mDropDownPreference, new String("1")); + } +}