From b2dd2e320318e6d6365d3498ea77890829303cca Mon Sep 17 00:00:00 2001 From: Geoffrey Boullanger Date: Fri, 11 Oct 2024 16:02:59 +0000 Subject: [PATCH] Updated toggles in Date and time settings page Design doc: go/dd-android-settings-time-2024 Changes: - toggling off "automatic time zone" now sets "use location" off and makes it unmodifiable - removing "use locale default" for time format Bug: 296835792 Test: on-device and atest Flag: com.android.settings.flags.revamp_toggles Change-Id: I31744f104fed06ee9980a6a0160501325175a02d --- ...ettings_datetime_flag_declarations.aconfig | 8 ++ res/values/strings.xml | 2 +- res/xml/date_time_prefs_revamped.xml | 104 ++++++++++++++++++ .../AutoTimeZonePreferenceController.java | 32 ++++-- .../settings/datetime/DateTimeSettings.java | 7 +- ...TimeZoneDetectionPreferenceController.java | 35 +++++- .../TimeFormatPreferenceController.java | 11 +- .../AutoTimeZonePreferenceControllerTest.java | 59 +++++++++- ...ZoneDetectionPreferenceControllerTest.java | 36 +++++- .../TimeFormatPreferenceControllerTest.java | 9 ++ 10 files changed, 282 insertions(+), 21 deletions(-) create mode 100644 res/xml/date_time_prefs_revamped.xml diff --git a/aconfig/settings_datetime_flag_declarations.aconfig b/aconfig/settings_datetime_flag_declarations.aconfig index 3d9d8b317a5..93d41d6d5cb 100644 --- a/aconfig/settings_datetime_flag_declarations.aconfig +++ b/aconfig/settings_datetime_flag_declarations.aconfig @@ -9,3 +9,11 @@ flag { bug: "283239837" } +flag { + name: "revamp_toggles" + # "location" is used by the Android System Time team for feature flags. + namespace: "location" + description: "Makes the use location toggle dependent on automatic time zone detection" + bug: "296835792" +} + diff --git a/res/values/strings.xml b/res/values/strings.xml index a11acb09586..50c50a19299 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -579,7 +579,7 @@ Set automatically based on mobile networks near you - Set automatically using your device location, if available. An active Wifi connection may also be required. + Set automatically using your device location, if available Use locale default diff --git a/res/xml/date_time_prefs_revamped.xml b/res/xml/date_time_prefs_revamped.xml new file mode 100644 index 00000000000..fe0fd7e2c52 --- /dev/null +++ b/res/xml/date_time_prefs_revamped.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java index 2f062897b48..3d8f8011dda 100644 --- a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java +++ b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java @@ -32,6 +32,7 @@ import androidx.preference.Preference; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; +import com.android.settings.flags.Flags; public class AutoTimeZonePreferenceController extends TogglePreferenceController { @@ -46,7 +47,7 @@ public class AutoTimeZonePreferenceController extends TogglePreferenceController // setTimeAndDateCallback() isn't called, e.g. for slices and other cases where the // controller is instantiated outside of the context of the real Date & Time settings // screen. - mCallback = (c) -> {}; + mCallback = (c) -> {}; } /** @@ -103,10 +104,25 @@ public class AutoTimeZonePreferenceController extends TogglePreferenceController @Override public boolean setChecked(boolean isChecked) { - TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder() - .setAutoDetectionEnabled(isChecked) - .build(); - boolean result = mTimeManager.updateTimeZoneConfiguration(configuration); + TimeZoneConfiguration.Builder configuration = new TimeZoneConfiguration.Builder() + .setAutoDetectionEnabled(isChecked); + + if (Flags.revampToggles()) { + // "Use location for time zone" is only used if "Automatic time zone" is enabled. If + // the user toggles off automatic time zone, set the toggle off and disable the toggle. + int geoDetectionCapability = mTimeManager + .getTimeZoneCapabilitiesAndConfig() + .getCapabilities() + .getConfigureGeoDetectionEnabledCapability(); + + if (!isChecked + && (geoDetectionCapability == CAPABILITY_NOT_APPLICABLE + || geoDetectionCapability == CAPABILITY_POSSESSED)) { + configuration.setGeoDetectionEnabled(false); + } + } + + boolean result = mTimeManager.updateTimeZoneConfiguration(configuration.build()); mCallback.updateTimeAndDateDisplay(mContext); return result; @@ -138,8 +154,10 @@ public class AutoTimeZonePreferenceController extends TogglePreferenceController @VisibleForTesting boolean isEnabled() { - TimeZoneConfiguration config = getTimeZoneCapabilitiesAndConfig().getConfiguration(); - return config.isAutoDetectionEnabled(); + return mTimeManager + .getTimeZoneCapabilitiesAndConfig() + .getConfiguration() + .isAutoDetectionEnabled(); } private TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig() { diff --git a/src/com/android/settings/datetime/DateTimeSettings.java b/src/com/android/settings/datetime/DateTimeSettings.java index f3c11d43ac3..e5c13bfec18 100644 --- a/src/com/android/settings/datetime/DateTimeSettings.java +++ b/src/com/android/settings/datetime/DateTimeSettings.java @@ -23,6 +23,7 @@ import android.content.Context; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.flags.Flags; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.search.SearchIndexable; @@ -49,6 +50,9 @@ public class DateTimeSettings extends DashboardFragment implements @Override protected int getPreferenceScreenResId() { + if (Flags.revampToggles()) { + return R.xml.date_time_prefs_revamped; + } return R.xml.date_time_prefs; } @@ -119,5 +123,6 @@ public class DateTimeSettings extends DashboardFragment implements } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.date_time_prefs); + new BaseSearchIndexProvider( + Flags.revampToggles() ? R.xml.date_time_prefs_revamped : R.xml.date_time_prefs); } diff --git a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java index a50ce4c3c22..52d49ac8b78 100644 --- a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java +++ b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java @@ -32,6 +32,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.core.TogglePreferenceController; +import com.android.settings.flags.Flags; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; @@ -64,8 +65,10 @@ public class LocationTimeZoneDetectionPreferenceController @Override public boolean isChecked() { + // forceRefresh set to true as the location toggle may have been turned off by switching off + // automatic time zone TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = - getTimeZoneCapabilitiesAndConfig(/*forceRefresh=*/false); + getTimeZoneCapabilitiesAndConfig(/*forceRefresh=*/ Flags.revampToggles()); TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration(); return configuration.isGeoDetectionEnabled(); } @@ -73,7 +76,7 @@ public class LocationTimeZoneDetectionPreferenceController @Override public boolean setChecked(boolean isChecked) { TimeZoneCapabilitiesAndConfig timeZoneCapabilitiesAndConfig = - getTimeZoneCapabilitiesAndConfig(/*forceRefresh=*/false); + getTimeZoneCapabilitiesAndConfig(/*forceRefresh=*/ false); boolean isLocationEnabled = timeZoneCapabilitiesAndConfig.getCapabilities().isUseLocationEnabled(); if (isChecked && !isLocationEnabled) { @@ -130,17 +133,30 @@ public class LocationTimeZoneDetectionPreferenceController getTimeZoneCapabilitiesAndConfig(/* forceRefresh= */ false).getCapabilities(); int capability = timeZoneCapabilities.getConfigureGeoDetectionEnabledCapability(); - // The preference only has two states: present and not present. The preference is never - // present but disabled. + // The preference can be present and enabled, present and disabled or not present. if (capability == CAPABILITY_NOT_SUPPORTED || capability == CAPABILITY_NOT_ALLOWED) { return UNSUPPORTED_ON_DEVICE; } else if (capability == CAPABILITY_NOT_APPLICABLE || capability == CAPABILITY_POSSESSED) { - return AVAILABLE; + if (Flags.revampToggles()) { + return isAutoTimeZoneEnabled() ? AVAILABLE : DISABLED_DEPENDENT_SETTING; + } else { + return AVAILABLE; + } } else { throw new IllegalStateException("Unknown capability=" + capability); } } + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + if (Flags.revampToggles()) { + // enable / disable the toggle based on automatic time zone being enabled or not + preference.setEnabled(isAutoTimeZoneEnabled()); + } + } + @Override public CharSequence getSummary() { TimeZoneCapabilitiesAndConfig timeZoneCapabilitiesAndConfig = @@ -212,4 +228,13 @@ public class LocationTimeZoneDetectionPreferenceController } return mTimeZoneCapabilitiesAndConfig; } + + /** + * Returns whether the user can select this preference or not, as it is a sub toggle of + * automatic time zone. + */ + private boolean isAutoTimeZoneEnabled() { + return mTimeManager.getTimeZoneCapabilitiesAndConfig().getConfiguration() + .isAutoDetectionEnabled(); + } } diff --git a/src/com/android/settings/datetime/TimeFormatPreferenceController.java b/src/com/android/settings/datetime/TimeFormatPreferenceController.java index 19805ad03dd..2dee76e9fbd 100644 --- a/src/com/android/settings/datetime/TimeFormatPreferenceController.java +++ b/src/com/android/settings/datetime/TimeFormatPreferenceController.java @@ -25,6 +25,7 @@ import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; +import com.android.settings.flags.Flags; import java.util.Calendar; import java.util.Date; @@ -72,8 +73,10 @@ public class TimeFormatPreferenceController extends TogglePreferenceController { if (mIsFromSUW) { return DISABLED_DEPENDENT_SETTING; } - if (AutoTimeFormatPreferenceController.isAutoTimeFormatSelection(mContext)) { - return DISABLED_DEPENDENT_SETTING; + if (!Flags.revampToggles()) { + if (AutoTimeFormatPreferenceController.isAutoTimeFormatSelection(mContext)) { + return DISABLED_DEPENDENT_SETTING; + } } return AVAILABLE; } @@ -130,7 +133,7 @@ public class TimeFormatPreferenceController extends TogglePreferenceController { timeFormatPreference = Intent.EXTRA_TIME_PREF_VALUE_USE_LOCALE_DEFAULT; } else { timeFormatPreference = is24Hour ? Intent.EXTRA_TIME_PREF_VALUE_USE_24_HOUR - : Intent.EXTRA_TIME_PREF_VALUE_USE_12_HOUR; + : Intent.EXTRA_TIME_PREF_VALUE_USE_12_HOUR; } timeChanged.putExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, timeFormatPreference); context.sendBroadcast(timeChanged); @@ -138,7 +141,7 @@ public class TimeFormatPreferenceController extends TogglePreferenceController { static void set24Hour(Context context, Boolean is24Hour) { String value = is24Hour == null ? null : - is24Hour ? HOURS_24 : HOURS_12; + is24Hour ? HOURS_24 : HOURS_12; Settings.System.putString(context.getContentResolver(), Settings.System.TIME_12_24, value); } diff --git a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java index 651915b4cab..7bf8d52543e 100644 --- a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java @@ -40,12 +40,17 @@ import android.app.time.TimeZoneConfiguration; import android.app.time.TimeZoneDetectorStatus; import android.content.Context; import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import androidx.preference.Preference; import com.android.settings.R; +import com.android.settings.flags.Flags; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -57,6 +62,9 @@ import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class AutoTimeZonePreferenceControllerTest { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Mock private UpdateTimeAndDateCallback mCallback; private Context mContext; @@ -238,8 +246,53 @@ public class AutoTimeZonePreferenceControllerTest { mContext.getString(R.string.auto_zone_requires_location_summary)); } + @Test + @EnableFlags({Flags.FLAG_REVAMP_TOGGLES}) + public void toggleOff_revampFlagOn_shouldToggleOffUseLocation() { + TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig( + /* autoSupported= */ true, + /* autoEnabled= */ true, + /* telephonySupported= */ true, + /* locationSupported= */ true); + when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig); + + mController.setChecked(false); + + TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder() + .setAutoDetectionEnabled(false) + .setGeoDetectionEnabled(false) + .build(); + + verify(mTimeManager).updateTimeZoneConfiguration(configuration); + } + + @Test + @DisableFlags({Flags.FLAG_REVAMP_TOGGLES}) + public void toggleOff_revampFlagOff_shouldToggleOffUseLocation() { + TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig( + /* autoSupported= */ true, + /* autoEnabled= */ true, + /* telephonySupported= */ true, + /* locationSupported= */ true); + when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig); + + mController.setChecked(false); + + TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder() + .setAutoDetectionEnabled(false) + .build(); + + verify(mTimeManager).updateTimeZoneConfiguration(configuration); + } + private static TimeZoneCapabilitiesAndConfig createCapabilitiesAndConfig( boolean autoSupported, boolean autoEnabled, boolean telephonySupported) { + return createCapabilitiesAndConfig(autoSupported, autoEnabled, telephonySupported, false); + } + + private static TimeZoneCapabilitiesAndConfig createCapabilitiesAndConfig( + boolean autoSupported, boolean autoEnabled, boolean telephonySupported, + boolean locationSupported) { TimeZoneDetectorStatus status = new TimeZoneDetectorStatus(DETECTOR_STATUS_RUNNING, new TelephonyTimeZoneAlgorithmStatus( telephonySupported ? DETECTION_ALGORITHM_STATUS_RUNNING @@ -253,12 +306,14 @@ public class AutoTimeZonePreferenceControllerTest { TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder(UserHandle.SYSTEM) .setConfigureAutoDetectionEnabledCapability(configureAutoDetectionEnabledCapability) .setUseLocationEnabled(true) - .setConfigureGeoDetectionEnabledCapability(Capabilities.CAPABILITY_NOT_SUPPORTED) + .setConfigureGeoDetectionEnabledCapability( + locationSupported ? Capabilities.CAPABILITY_POSSESSED + : Capabilities.CAPABILITY_NOT_SUPPORTED) .setSetManualTimeZoneCapability(Capabilities.CAPABILITY_POSSESSED) .build(); TimeZoneConfiguration config = new TimeZoneConfiguration.Builder() .setAutoDetectionEnabled(autoEnabled) - .setGeoDetectionEnabled(false) + .setGeoDetectionEnabled(locationSupported) .build(); return new TimeZoneCapabilitiesAndConfig(status, capabilities, config); } diff --git a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java index cd89c0c2d22..40794d217ee 100644 --- a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java @@ -25,6 +25,8 @@ import static android.app.time.DetectorStatusTypes.DETECTOR_STATUS_RUNNING; import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT; import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_READY; +import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -43,11 +45,17 @@ import android.app.time.TimeZoneConfiguration; import android.app.time.TimeZoneDetectorStatus; import android.content.Context; import android.os.UserHandle; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; + +import androidx.preference.SwitchPreference; import com.android.settings.R; import com.android.settings.core.InstrumentedPreferenceFragment; +import com.android.settings.flags.Flags; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -62,9 +70,14 @@ import org.robolectric.annotation.Config; com.android.settings.testutils.shadow.ShadowFragment.class, }) public class LocationTimeZoneDetectionPreferenceControllerTest { + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Mock private TimeManager mTimeManager; private Context mContext; + private SwitchPreference mPreference; private LocationTimeZoneDetectionPreferenceController mController; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private InstrumentedPreferenceFragment mFragment; @@ -76,6 +89,9 @@ public class LocationTimeZoneDetectionPreferenceControllerTest { when(mContext.getSystemService(TimeManager.class)).thenReturn(mTimeManager); mController = new LocationTimeZoneDetectionPreferenceController(mContext); mController.setFragment(mFragment); + + mPreference = new SwitchPreference(mContext); + mPreference.setKey("location_time_zone_detection"); } @Test @@ -114,6 +130,17 @@ public class LocationTimeZoneDetectionPreferenceControllerTest { verify(mTimeManager, never()).updateTimeZoneConfiguration(any()); } + @Test + @EnableFlags({Flags.FLAG_REVAMP_TOGGLES}) + public void flagRevampTogglesOn_toggleOff_automaticTimeZone_disablesLocationToggle() { + TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = + createTimeZoneCapabilitiesAndConfig(/* useLocationEnabled= */ true, + CAPABILITY_POSSESSED, /* setAutoDetectionEnabled= */ false); + when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + @Test public void setChecked_withFalse_shouldUpdateSetting() { boolean useLocationEnabled = false; @@ -181,7 +208,14 @@ public class LocationTimeZoneDetectionPreferenceControllerTest { private static TimeZoneCapabilitiesAndConfig createTimeZoneCapabilitiesAndConfig( boolean useLocationEnabled, @CapabilityState int configureGeoDetectionEnabledCapability) { + return createTimeZoneCapabilitiesAndConfig(useLocationEnabled, + configureGeoDetectionEnabledCapability, /* setAutoDetectionEnabled= */ true); + } + private static TimeZoneCapabilitiesAndConfig createTimeZoneCapabilitiesAndConfig( + boolean useLocationEnabled, + @CapabilityState int configureGeoDetectionEnabledCapability, + boolean setAutoDetectionEnabled) { // Create a status that matches the user's capability state. LocationTimeZoneAlgorithmStatus locationAlgorithmStatus; switch (configureGeoDetectionEnabledCapability) { @@ -213,7 +247,7 @@ public class LocationTimeZoneDetectionPreferenceControllerTest { .build(); TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder() - .setAutoDetectionEnabled(true) + .setAutoDetectionEnabled(setAutoDetectionEnabled) .setGeoDetectionEnabled(true) .build(); diff --git a/tests/robotests/src/com/android/settings/datetime/TimeFormatPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/TimeFormatPreferenceControllerTest.java index e1ea8f9e0fa..c5aac843018 100644 --- a/tests/robotests/src/com/android/settings/datetime/TimeFormatPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datetime/TimeFormatPreferenceControllerTest.java @@ -23,11 +23,16 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.content.Intent; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import androidx.preference.SwitchPreference; +import com.android.settings.flags.Flags; + import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -41,6 +46,9 @@ import java.util.List; @RunWith(RobolectricTestRunner.class) public class TimeFormatPreferenceControllerTest { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Mock private UpdateTimeAndDateCallback mCallback; @@ -97,6 +105,7 @@ public class TimeFormatPreferenceControllerTest { } @Test + @DisableFlags({Flags.FLAG_REVAMP_TOGGLES}) public void updateState_autoSet_shouldNotEnablePreference() { Settings.System.putString(mContext.getContentResolver(), Settings.System.TIME_12_24, null);