Special-case backup/restore of replaced settings
Bug: 153940088
Test: atest SettingsProviderTest:SettingsHelperTest
Values for some settings might be changed temporarily. If a backup happens at that moment, we want to backup the real values instead of the temporary ones. If a restore happens at that moment, we don't want to restore values for modified settings. See https://b.corp.google.com/issues/153940088#comment2 for context.
Change-Id: I4866f56376ffa393220bbef828a4b876d586146b
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index d67bd8d..9d042a4 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -34,6 +34,7 @@
],
static_libs: [
"androidx.test.rules",
+ "mockito-target-minus-junit4",
"SettingsLibDisplayDensityUtils",
"platform-test-annotations",
"truth-prebuilt",
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index b6e31d2..d023d98 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -48,6 +48,8 @@
public class SettingsHelper {
private static final String TAG = "SettingsHelper";
private static final String SILENT_RINGTONE = "_silent";
+ private static final String SETTINGS_REPLACED_KEY = "backup_skip_user_facing_data";
+ private static final String SETTING_ORIGINAL_KEY_SUFFIX = "_original";
private static final float FLOAT_TOLERANCE = 0.01f;
private Context mContext;
@@ -121,6 +123,10 @@
*/
public void restoreValue(Context context, ContentResolver cr, ContentValues contentValues,
Uri destination, String name, String value, int restoredFromSdkInt) {
+ if (isReplacedSystemSetting(name)) {
+ return;
+ }
+
// Will we need a post-restore broadcast for this element?
String oldValue = null;
boolean sendBroadcast = false;
@@ -203,7 +209,32 @@
}
}
// Return the original value
- return value;
+ return isReplacedSystemSetting(name) ? getRealValueForSystemSetting(name) : value;
+ }
+
+ /**
+ * The setting value might have been replaced temporarily. If that's the case, return the real
+ * value instead of the temporary one.
+ */
+ @VisibleForTesting
+ public String getRealValueForSystemSetting(String setting) {
+ return Settings.System.getString(mContext.getContentResolver(),
+ setting + SETTING_ORIGINAL_KEY_SUFFIX);
+ }
+
+ @VisibleForTesting
+ public boolean isReplacedSystemSetting(String setting) {
+ // This list should not be modified.
+ if (!Settings.System.MASTER_MONO.equals(setting)
+ && !Settings.System.SCREEN_OFF_TIMEOUT.equals(setting)) {
+ return false;
+ }
+ // If this flag is set, values for the system settings from the list above have been
+ // temporarily replaced. We don't want to back up the temporary value or run restore for
+ // such settings.
+ // TODO(154822946): Remove this logic in the next release.
+ return Settings.Secure.getInt(mContext.getContentResolver(), SETTINGS_REPLACED_KEY,
+ /* def */ 0) != 0;
}
/**
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
index d112fac..7baa226 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
@@ -18,18 +18,79 @@
import static junit.framework.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.media.AudioManager;
+import android.net.Uri;
import android.os.LocaleList;
+import android.telephony.TelephonyManager;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
/**
* Tests for the SettingsHelperTest
*/
@RunWith(AndroidJUnit4.class)
public class SettingsHelperTest {
+ private static final String SETTING_KEY = "setting_key";
+ private static final String SETTING_VALUE = "setting_value";
+ private static final String SETTING_REAL_VALUE = "setting_real_value";
+
+ private SettingsHelper mSettingsHelper;
+
+ @Mock private Context mContext;
+ @Mock private ContentResolver mContentResolver;
+ @Mock private AudioManager mAudioManager;
+ @Mock private TelephonyManager mTelephonyManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(eq(Context.AUDIO_SERVICE))).thenReturn(mAudioManager);
+ when(mContext.getSystemService(eq(Context.TELEPHONY_SERVICE))).thenReturn(
+ mTelephonyManager);
+
+ mSettingsHelper = spy(new SettingsHelper(mContext));
+ }
+
+ @Test
+ public void testOnBackupValue_settingReplaced_returnsRealValue() {
+ when(mSettingsHelper.isReplacedSystemSetting(eq(SETTING_KEY))).thenReturn(true);
+ doReturn(SETTING_REAL_VALUE).when(mSettingsHelper).getRealValueForSystemSetting(
+ eq(SETTING_KEY));
+
+ assertEquals(SETTING_REAL_VALUE, mSettingsHelper.onBackupValue(SETTING_KEY, SETTING_VALUE));
+ }
+
+ @Test
+ public void testGetRealValue_settingNotReplaced_returnsSameValue() {
+ when(mSettingsHelper.isReplacedSystemSetting(eq(SETTING_KEY))).thenReturn(false);
+
+ assertEquals(SETTING_VALUE, mSettingsHelper.onBackupValue(SETTING_KEY, SETTING_VALUE));
+ }
+
+ @Test
+ public void testRestoreValue_settingReplaced_doesNotRestore() {
+ when(mSettingsHelper.isReplacedSystemSetting(eq(SETTING_KEY))).thenReturn(true);
+ mSettingsHelper.restoreValue(mContext, mContentResolver, new ContentValues(), Uri.EMPTY,
+ SETTING_KEY, SETTING_VALUE, /* restoredFromSdkInt */ 0);
+
+ verifyZeroInteractions(mContentResolver);
+ }
+
@Test
public void testResolveLocales() throws Exception {
// Empty string from backup server