From 7acd13f3e463575e6338dada36c1bf9d188aade3 Mon Sep 17 00:00:00 2001 From: Matthew Fritze Date: Thu, 12 Apr 2018 16:40:07 -0700 Subject: [PATCH] Update a Slice Uri when unavailable When a slice becomes unavailable, it should not update the underlying data even if the view has not changed. When we receive a change from an unavailable slice, notifychange on the Uri and do not change the underlying data. Change-Id: I91851ab668e4aece669fd65c14e0dc4ec2edefdf Fixes: 77980406 Test: robotests --- .../slices/SliceBroadcastReceiver.java | 16 +++- .../slices/SliceBroadcastReceiverTest.java | 85 ++++++++++++++++++- .../slices/SliceBuilderUtilsTest.java | 10 +-- .../testutils/FakeSliderController.java | 6 +- .../testutils/FakeToggleController.java | 5 +- .../FakeUnavailablePreferenceController.java | 4 +- 6 files changed, 111 insertions(+), 15 deletions(-) rename tests/robotests/src/com/android/settings/{slices => testutils}/FakeUnavailablePreferenceController.java (82%) diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java index 80b7519430a..d2a6d101052 100644 --- a/src/com/android/settings/slices/SliceBroadcastReceiver.java +++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java @@ -54,16 +54,16 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); final String key = intent.getStringExtra(EXTRA_SLICE_KEY); - final boolean isPlatformDefined = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED, + final boolean isPlatformSlice = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED, false /* default */); switch (action) { case ACTION_TOGGLE_CHANGED: - handleToggleAction(context, key, isPlatformDefined); + handleToggleAction(context, key, isPlatformSlice); break; case ACTION_SLIDER_CHANGED: int newPosition = intent.getIntExtra(Slice.EXTRA_RANGE_VALUE, -1); - handleSliderAction(context, key, newPosition); + handleSliderAction(context, key, newPosition, isPlatformSlice); break; case ACTION_WIFI_CHANGED: WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); @@ -95,6 +95,7 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { if (!controller.isAvailable()) { Log.w(TAG, "Can't update " + key + " since the setting is unavailable"); updateUri(context, key, isPlatformSlice); + return; } // TODO post context.getContentResolver().notifyChanged(uri, null) in the Toggle controller @@ -107,7 +108,8 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { updateUri(context, key, isPlatformSlice); } - private void handleSliderAction(Context context, String key, int newPosition) { + private void handleSliderAction(Context context, String key, int newPosition, + boolean isPlatformSlice) { if (TextUtils.isEmpty(key)) { throw new IllegalArgumentException( "No key passed to Intent for slider controller. Use extra: " + EXTRA_SLICE_KEY); @@ -123,6 +125,12 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { throw new IllegalArgumentException("Slider action passed for a non-slider key: " + key); } + if (!controller.isAvailable()) { + Log.w(TAG, "Can't update " + key + " since the setting is unavailable"); + updateUri(context, key, isPlatformSlice); + return; + } + final SliderPreferenceController sliderController = (SliderPreferenceController) controller; final int maxSteps = sliderController.getMaxSteps(); if (newPosition < 0 || newPosition > maxSteps) { diff --git a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java index 0cdb2f43d59..0b6e4b5bb32 100644 --- a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java +++ b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java @@ -18,17 +18,28 @@ package com.android.settings.slices; import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.app.slice.Slice; +import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; +import android.database.ContentObserver; import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.provider.Settings; +import android.provider.SettingsSlicesContract; import android.util.Pair; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.core.BasePreferenceController; import com.android.settings.search.FakeIndexProvider; import com.android.settings.search.SearchFeatureProvider; import com.android.settings.search.SearchFeatureProviderImpl; @@ -36,6 +47,7 @@ import com.android.settings.testutils.DatabaseTestUtils; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeSliderController; import com.android.settings.testutils.FakeToggleController; +import com.android.settings.testutils.FakeUnavailablePreferenceController; import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.After; @@ -65,7 +77,7 @@ public class SliceBroadcastReceiverTest { @Before public void setUp() { - mContext = RuntimeEnvironment.application; + mContext = spy(RuntimeEnvironment.application); mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase(); mReceiver = new SliceBroadcastReceiver(); SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext); @@ -192,6 +204,77 @@ public class SliceBroadcastReceiverTest { mReceiver.onReceive(mContext, intent); } + @Test + public void toggleUpdate_unavailableUriNotified() { + // Monitor the ContentResolver + final ContentResolver resolver = spy(mContext.getContentResolver()); + doReturn(resolver).when(mContext).getContentResolver(); + + // Disable Setting + Settings.Global.putInt(mContext.getContentResolver(), + FakeToggleController.AVAILABILITY_KEY, + BasePreferenceController.DISABLED_UNSUPPORTED); + + // Insert Fake Toggle into Database + final String key = "key"; + mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear(); + insertSpecialCase(FakeToggleController.class, key); + + // Turn on toggle setting + final FakeToggleController fakeToggleController = new FakeToggleController(mContext, key); + fakeToggleController.setChecked(true); + + // Build Action + final Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED); + intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key); + + // Trigger Slice change + mReceiver.onReceive(mContext, intent); + + // Check the value is the same and the Uri has been notified. + assertThat(fakeToggleController.isChecked()).isTrue(); + final Uri expectedUri = SliceBuilderUtils.getUri( + SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key, false); + verify(resolver).notifyChange(eq(expectedUri), eq(null)); + } + + @Test + public void sliderUpdate_unavailableUriNotified() { + // Monitor the ContentResolver + final ContentResolver resolver = spy(mContext.getContentResolver()); + doReturn(resolver).when(mContext).getContentResolver(); + + // Disable Setting + Settings.Global.putInt(mContext.getContentResolver(), + FakeSliderController.AVAILABILITY_KEY, + BasePreferenceController.DISABLED_UNSUPPORTED); + + // Insert Fake Slider into Database + final String key = "key"; + final int position = FakeSliderController.MAX_STEPS - 1; + final int oldPosition = FakeSliderController.MAX_STEPS; + mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear(); + insertSpecialCase(FakeSliderController.class, key); + + // Set slider setting + final FakeSliderController fakeSliderController = new FakeSliderController(mContext, key); + fakeSliderController.setSliderPosition(oldPosition); + + // Build action + final Intent intent = new Intent(SettingsSliceProvider.ACTION_SLIDER_CHANGED); + intent.putExtra(Slice.EXTRA_RANGE_VALUE, position); + intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key); + + // Trigger Slice change + mReceiver.onReceive(mContext, intent); + + // Check position is the same and the Uri has been notified. + assertThat(fakeSliderController.getSliderPosition()).isEqualTo(oldPosition); + final Uri expectedUri = SliceBuilderUtils.getUri( + SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key, false); + verify(resolver).notifyChange(eq(expectedUri), eq(null)); + } + private void insertSpecialCase(String key) { insertSpecialCase(fakeControllerName, key); } diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java index 59eb7ceceaf..0672c8679ea 100644 --- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java +++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java @@ -24,7 +24,6 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import android.app.PendingIntent; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -40,6 +39,7 @@ import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeSliderController; import com.android.settings.testutils.FakeToggleController; +import com.android.settings.testutils.FakeUnavailablePreferenceController; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SliceTester; @@ -324,7 +324,7 @@ public class SliceBuilderUtilsTest { public void testUnsupportedSlice_validTitleSummary() { final SliceData data = getDummyData(FakeUnavailablePreferenceController.class, SliceData.SliceType.SWITCH); - Settings.System.putInt(mContext.getContentResolver(), + Settings.Global.putInt(mContext.getContentResolver(), FakeUnavailablePreferenceController.AVAILABILITY_KEY, BasePreferenceController.DISABLED_UNSUPPORTED); @@ -337,7 +337,7 @@ public class SliceBuilderUtilsTest { public void testDisabledForUserSlice_validTitleSummary() { final SliceData data = getDummyData(FakeUnavailablePreferenceController.class, SliceData.SliceType.SWITCH); - Settings.System.putInt(mContext.getContentResolver(), + Settings.Global.putInt(mContext.getContentResolver(), FakeUnavailablePreferenceController.AVAILABILITY_KEY, BasePreferenceController.DISABLED_FOR_USER); @@ -350,7 +350,7 @@ public class SliceBuilderUtilsTest { public void testDisabledDependentSettingSlice_validTitleSummary() { final SliceData data = getDummyData(FakeUnavailablePreferenceController.class, SliceData.SliceType.INTENT); - Settings.System.putInt(mContext.getContentResolver(), + Settings.Global.putInt(mContext.getContentResolver(), FakeUnavailablePreferenceController.AVAILABILITY_KEY, BasePreferenceController.DISABLED_DEPENDENT_SETTING); @@ -372,7 +372,7 @@ public class SliceBuilderUtilsTest { public void testUnavailableUnknownSlice_validTitleSummary() { final SliceData data = getDummyData(FakeUnavailablePreferenceController.class, SliceData.SliceType.SWITCH); - Settings.System.putInt(mContext.getContentResolver(), + Settings.Global.putInt(mContext.getContentResolver(), FakeUnavailablePreferenceController.AVAILABILITY_KEY, BasePreferenceController.UNAVAILABLE_UNKNOWN); diff --git a/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java b/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java index f4f91ed2382..530bdee97f3 100644 --- a/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java +++ b/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java @@ -19,13 +19,14 @@ package com.android.settings.testutils; import android.content.Context; import android.provider.Settings; -import com.android.settings.core.BasePreferenceController; import com.android.settings.core.SliderPreferenceController; public class FakeSliderController extends SliderPreferenceController { private final String settingKey = "fake_slider_key"; + public static final String AVAILABILITY_KEY = "fake_slider_availability_key"; + public static final int MAX_STEPS = 9; public FakeSliderController(Context context, String key) { @@ -49,6 +50,7 @@ public class FakeSliderController extends SliderPreferenceController { @Override public int getAvailabilityStatus() { - return BasePreferenceController.AVAILABLE; + return Settings.Global.getInt(mContext.getContentResolver(), + AVAILABILITY_KEY, AVAILABLE); } } diff --git a/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java b/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java index c984c6ceca4..d0ce76fe60a 100644 --- a/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java +++ b/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java @@ -26,6 +26,8 @@ public class FakeToggleController extends TogglePreferenceController { private String settingKey = "toggle_key"; + public static final String AVAILABILITY_KEY = "fake_toggle_availability_key"; + private final int ON = 1; private final int OFF = 0; @@ -47,6 +49,7 @@ public class FakeToggleController extends TogglePreferenceController { @Override public int getAvailabilityStatus() { - return AVAILABLE; + return Settings.Global.getInt(mContext.getContentResolver(), + AVAILABILITY_KEY, AVAILABLE); } } diff --git a/tests/robotests/src/com/android/settings/slices/FakeUnavailablePreferenceController.java b/tests/robotests/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java similarity index 82% rename from tests/robotests/src/com/android/settings/slices/FakeUnavailablePreferenceController.java rename to tests/robotests/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java index a7e5d7562aa..1ceaad864e1 100644 --- a/tests/robotests/src/com/android/settings/slices/FakeUnavailablePreferenceController.java +++ b/tests/robotests/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java @@ -1,4 +1,4 @@ -package com.android.settings.slices; +package com.android.settings.testutils; import android.content.Context; import android.provider.Settings; @@ -15,7 +15,7 @@ public class FakeUnavailablePreferenceController extends BasePreferenceControlle @Override public int getAvailabilityStatus() { - return Settings.System.getInt(mContext.getContentResolver(), + return Settings.Global.getInt(mContext.getContentResolver(), AVAILABILITY_KEY, 0); } }