Merge "DO NOT MERGE Create a key value settings observer for backup parameters" into pi-dev
diff --git a/core/java/android/util/KeyValueSettingObserver.java b/core/java/android/util/KeyValueSettingObserver.java
new file mode 100644
index 0000000..9fca8b2
--- /dev/null
+++ b/core/java/android/util/KeyValueSettingObserver.java
@@ -0,0 +1,97 @@
+/*
+ * 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 android.util;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+
+/**
+ * Abstract class for observing changes to a specified setting stored as a comma-separated key value
+ * list of parameters. Registers and unregisters a {@link ContentObserver} and handles updates when
+ * the setting changes.
+ *
+ * <p>Subclasses should pass in the relevant setting's {@link Uri} in the constructor and implement
+ * {@link #update(KeyValueListParser)} to receive updates when the value changes.
+ * Calls to {@link #update(KeyValueListParser)} only trigger after calling {@link
+ * #start()}.
+ *
+ * <p>To get the most up-to-date parameter values, first call {@link #start()} before accessing the
+ * values to start observing changes, and then call {@link #stop()} once finished.
+ *
+ * @hide
+ */
+public abstract class KeyValueSettingObserver {
+ private static final String TAG = "KeyValueSettingObserver";
+
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+ private final ContentObserver mObserver;
+ private final ContentResolver mResolver;
+ private final Uri mSettingUri;
+
+ public KeyValueSettingObserver(Handler handler, ContentResolver resolver,
+ Uri uri) {
+ mObserver = new SettingObserver(handler);
+ mResolver = resolver;
+ mSettingUri = uri;
+ }
+
+ /** Starts observing changes for the setting. Pair with {@link #stop()}. */
+ public void start() {
+ mResolver.registerContentObserver(mSettingUri, false, mObserver);
+ setParserValue();
+ update(mParser);
+ }
+
+ /** Stops observing changes for the setting. */
+ public void stop() {
+ mResolver.unregisterContentObserver(mObserver);
+ }
+
+ /**
+ * Returns the {@link String} representation of the setting. Subclasses should implement this
+ * for their setting.
+ */
+ public abstract String getSettingValue(ContentResolver resolver);
+
+ /** Updates the parser with the current setting value. */
+ private void setParserValue() {
+ String setting = getSettingValue(mResolver);
+ try {
+ mParser.setString(setting);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Malformed setting: " + setting);
+ }
+ }
+
+ /** Subclasses should implement this to update references to their parameters. */
+ public abstract void update(KeyValueListParser parser);
+
+ private class SettingObserver extends ContentObserver {
+ private SettingObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ setParserValue();
+ update(mParser);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/backup/LocalTransportParameters.java b/core/java/com/android/internal/backup/LocalTransportParameters.java
index 390fae9..154e79d 100644
--- a/core/java/com/android/internal/backup/LocalTransportParameters.java
+++ b/core/java/com/android/internal/backup/LocalTransportParameters.java
@@ -16,62 +16,32 @@
package com.android.internal.backup;
+import android.util.KeyValueSettingObserver;
import android.content.ContentResolver;
-import android.database.ContentObserver;
import android.os.Handler;
import android.provider.Settings;
import android.util.KeyValueListParser;
-import android.util.Slog;
-class LocalTransportParameters {
+class LocalTransportParameters extends KeyValueSettingObserver {
private static final String TAG = "LocalTransportParams";
private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS;
private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag";
- private final KeyValueListParser mParser = new KeyValueListParser(',');
- private final ContentObserver mObserver;
- private final ContentResolver mResolver;
private boolean mFakeEncryptionFlag;
LocalTransportParameters(Handler handler, ContentResolver resolver) {
- mObserver = new Observer(handler);
- mResolver = resolver;
- }
-
- /** Observes for changes in the setting. This method MUST be paired with {@link #stop()}. */
- void start() {
- mResolver.registerContentObserver(Settings.Secure.getUriFor(SETTING), false, mObserver);
- update();
- }
-
- /** Stop observing for changes in the setting. */
- void stop() {
- mResolver.unregisterContentObserver(mObserver);
+ super(handler, resolver, Settings.Secure.getUriFor(SETTING));
}
boolean isFakeEncryptionFlag() {
return mFakeEncryptionFlag;
}
- private void update() {
- String parameters = "";
- try {
- parameters = Settings.Secure.getString(mResolver, SETTING);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Malformed " + SETTING + " setting: " + e.getMessage());
- }
- mParser.setString(parameters);
- mFakeEncryptionFlag = mParser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
+ public String getSettingValue(ContentResolver resolver) {
+ return Settings.Secure.getString(resolver, SETTING);
}
- private class Observer extends ContentObserver {
- private Observer(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- update();
- }
+ public void update(KeyValueListParser parser) {
+ mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
}
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerConstants.java b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
index 99160c2..dd6e6ab 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerConstants.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
@@ -18,53 +18,76 @@
import android.app.AlarmManager;
import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.KeyValueListParser;
+import android.util.KeyValueSettingObserver;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
/**
* Class to access backup manager constants.
*
- * The backup manager constants are encoded as a key value list separated by commas
- * and stored as a Settings.Secure.
+ * <p>The backup manager constants are encoded as a key value list separated by commas and stored as
+ * a Settings.Secure.
*/
-class BackupManagerConstants extends ContentObserver {
+class BackupManagerConstants extends KeyValueSettingObserver {
private static final String TAG = "BackupManagerConstants";
+ private static final String SETTING = Settings.Secure.BACKUP_MANAGER_CONSTANTS;
// Key names stored in the secure settings value.
- private static final String KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS =
+ @VisibleForTesting
+ public static final String KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS =
"key_value_backup_interval_milliseconds";
- private static final String KEY_VALUE_BACKUP_FUZZ_MILLISECONDS =
+
+ @VisibleForTesting
+ public static final String KEY_VALUE_BACKUP_FUZZ_MILLISECONDS =
"key_value_backup_fuzz_milliseconds";
- private static final String KEY_VALUE_BACKUP_REQUIRE_CHARGING =
+
+ @VisibleForTesting
+ public static final String KEY_VALUE_BACKUP_REQUIRE_CHARGING =
"key_value_backup_require_charging";
- private static final String KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE =
+
+ @VisibleForTesting
+ public static final String KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE =
"key_value_backup_required_network_type";
- private static final String FULL_BACKUP_INTERVAL_MILLISECONDS =
+
+ @VisibleForTesting
+ public static final String FULL_BACKUP_INTERVAL_MILLISECONDS =
"full_backup_interval_milliseconds";
- private static final String FULL_BACKUP_REQUIRE_CHARGING =
- "full_backup_require_charging";
- private static final String FULL_BACKUP_REQUIRED_NETWORK_TYPE =
+
+ @VisibleForTesting
+ public static final String FULL_BACKUP_REQUIRE_CHARGING = "full_backup_require_charging";
+
+ @VisibleForTesting
+ public static final String FULL_BACKUP_REQUIRED_NETWORK_TYPE =
"full_backup_required_network_type";
- private static final String BACKUP_FINISHED_NOTIFICATION_RECEIVERS =
+
+ @VisibleForTesting
+ public static final String BACKUP_FINISHED_NOTIFICATION_RECEIVERS =
"backup_finished_notification_receivers";
// Hard coded default values.
- private static final long DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS =
+ @VisibleForTesting
+ public static final long DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS =
4 * AlarmManager.INTERVAL_HOUR;
- private static final long DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS =
- 10 * 60 * 1000;
- private static final boolean DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING = true;
- private static final int DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE = 1;
- private static final long DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS =
+
+ @VisibleForTesting
+ public static final long DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS = 10 * 60 * 1000;
+
+ @VisibleForTesting public static final boolean DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING = true;
+ @VisibleForTesting public static final int DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE = 1;
+
+ @VisibleForTesting
+ public static final long DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS =
24 * AlarmManager.INTERVAL_HOUR;
- private static final boolean DEFAULT_FULL_BACKUP_REQUIRE_CHARGING = true;
- private static final int DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE = 2;
- private static final String DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS = "";
+
+ @VisibleForTesting public static final boolean DEFAULT_FULL_BACKUP_REQUIRE_CHARGING = true;
+ @VisibleForTesting public static final int DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE = 2;
+
+ @VisibleForTesting
+ public static final String DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS = "";
// Backup manager constants.
private long mKeyValueBackupIntervalMilliseconds;
@@ -76,49 +99,46 @@
private int mFullBackupRequiredNetworkType;
private String[] mBackupFinishedNotificationReceivers;
- private ContentResolver mResolver;
- private final KeyValueListParser mParser = new KeyValueListParser(',');
-
public BackupManagerConstants(Handler handler, ContentResolver resolver) {
- super(handler);
- mResolver = resolver;
- updateSettings();
- mResolver.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.BACKUP_MANAGER_CONSTANTS), false, this);
+ super(handler, resolver, Settings.Secure.getUriFor(SETTING));
}
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- updateSettings();
+ public String getSettingValue(ContentResolver resolver) {
+ return Settings.Secure.getString(resolver, SETTING);
}
- private synchronized void updateSettings() {
- try {
- mParser.setString(Settings.Secure.getString(mResolver,
- Settings.Secure.BACKUP_MANAGER_CONSTANTS));
- } catch (IllegalArgumentException e) {
- // Failed to parse the settings string. Use defaults.
- Slog.e(TAG, "Bad backup manager constants: " + e.getMessage());
- }
-
- mKeyValueBackupIntervalMilliseconds = mParser.getLong(
- KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS,
- DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS);
- mKeyValueBackupFuzzMilliseconds = mParser.getLong(KEY_VALUE_BACKUP_FUZZ_MILLISECONDS,
- DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS);
- mKeyValueBackupRequireCharging = mParser.getBoolean(KEY_VALUE_BACKUP_REQUIRE_CHARGING,
- DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING);
- mKeyValueBackupRequiredNetworkType = mParser.getInt(KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE,
- DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE);
- mFullBackupIntervalMilliseconds = mParser.getLong(FULL_BACKUP_INTERVAL_MILLISECONDS,
- DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS);
- mFullBackupRequireCharging = mParser.getBoolean(FULL_BACKUP_REQUIRE_CHARGING,
- DEFAULT_FULL_BACKUP_REQUIRE_CHARGING);
- mFullBackupRequiredNetworkType = mParser.getInt(FULL_BACKUP_REQUIRED_NETWORK_TYPE,
- DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE);
- String backupFinishedNotificationReceivers = mParser.getString(
- BACKUP_FINISHED_NOTIFICATION_RECEIVERS,
- DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS);
+ public synchronized void update(KeyValueListParser parser) {
+ mKeyValueBackupIntervalMilliseconds =
+ parser.getLong(
+ KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS,
+ DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS);
+ mKeyValueBackupFuzzMilliseconds =
+ parser.getLong(
+ KEY_VALUE_BACKUP_FUZZ_MILLISECONDS,
+ DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS);
+ mKeyValueBackupRequireCharging =
+ parser.getBoolean(
+ KEY_VALUE_BACKUP_REQUIRE_CHARGING,
+ DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING);
+ mKeyValueBackupRequiredNetworkType =
+ parser.getInt(
+ KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE,
+ DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE);
+ mFullBackupIntervalMilliseconds =
+ parser.getLong(
+ FULL_BACKUP_INTERVAL_MILLISECONDS,
+ DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS);
+ mFullBackupRequireCharging =
+ parser.getBoolean(
+ FULL_BACKUP_REQUIRE_CHARGING, DEFAULT_FULL_BACKUP_REQUIRE_CHARGING);
+ mFullBackupRequiredNetworkType =
+ parser.getInt(
+ FULL_BACKUP_REQUIRED_NETWORK_TYPE,
+ DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE);
+ String backupFinishedNotificationReceivers =
+ parser.getString(
+ BACKUP_FINISHED_NOTIFICATION_RECEIVERS,
+ DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS);
if (backupFinishedNotificationReceivers.isEmpty()) {
mBackupFinishedNotificationReceivers = new String[] {};
} else {
@@ -132,40 +152,50 @@
// a reference of this object.
public synchronized long getKeyValueBackupIntervalMilliseconds() {
if (BackupManagerService.DEBUG_SCHEDULING) {
- Slog.v(TAG, "getKeyValueBackupIntervalMilliseconds(...) returns "
- + mKeyValueBackupIntervalMilliseconds);
+ Slog.v(
+ TAG,
+ "getKeyValueBackupIntervalMilliseconds(...) returns "
+ + mKeyValueBackupIntervalMilliseconds);
}
return mKeyValueBackupIntervalMilliseconds;
}
public synchronized long getKeyValueBackupFuzzMilliseconds() {
if (BackupManagerService.DEBUG_SCHEDULING) {
- Slog.v(TAG, "getKeyValueBackupFuzzMilliseconds(...) returns "
- + mKeyValueBackupFuzzMilliseconds);
+ Slog.v(
+ TAG,
+ "getKeyValueBackupFuzzMilliseconds(...) returns "
+ + mKeyValueBackupFuzzMilliseconds);
}
return mKeyValueBackupFuzzMilliseconds;
}
public synchronized boolean getKeyValueBackupRequireCharging() {
if (BackupManagerService.DEBUG_SCHEDULING) {
- Slog.v(TAG, "getKeyValueBackupRequireCharging(...) returns "
- + mKeyValueBackupRequireCharging);
+ Slog.v(
+ TAG,
+ "getKeyValueBackupRequireCharging(...) returns "
+ + mKeyValueBackupRequireCharging);
}
return mKeyValueBackupRequireCharging;
}
public synchronized int getKeyValueBackupRequiredNetworkType() {
if (BackupManagerService.DEBUG_SCHEDULING) {
- Slog.v(TAG, "getKeyValueBackupRequiredNetworkType(...) returns "
- + mKeyValueBackupRequiredNetworkType);
+ Slog.v(
+ TAG,
+ "getKeyValueBackupRequiredNetworkType(...) returns "
+ + mKeyValueBackupRequiredNetworkType);
}
return mKeyValueBackupRequiredNetworkType;
}
public synchronized long getFullBackupIntervalMilliseconds() {
if (BackupManagerService.DEBUG_SCHEDULING) {
- Slog.v(TAG, "getFullBackupIntervalMilliseconds(...) returns "
- + mFullBackupIntervalMilliseconds);
+ Slog.v(
+ TAG,
+ "getFullBackupIntervalMilliseconds(...) returns "
+ + mFullBackupIntervalMilliseconds);
}
return mFullBackupIntervalMilliseconds;
}
@@ -179,19 +209,21 @@
public synchronized int getFullBackupRequiredNetworkType() {
if (BackupManagerService.DEBUG_SCHEDULING) {
- Slog.v(TAG, "getFullBackupRequiredNetworkType(...) returns "
- + mFullBackupRequiredNetworkType);
+ Slog.v(
+ TAG,
+ "getFullBackupRequiredNetworkType(...) returns "
+ + mFullBackupRequiredNetworkType);
}
return mFullBackupRequiredNetworkType;
}
- /**
- * Returns an array of package names that should be notified whenever a backup finishes.
- */
+ /** Returns an array of package names that should be notified whenever a backup finishes. */
public synchronized String[] getBackupFinishedNotificationReceivers() {
if (BackupManagerService.DEBUG_SCHEDULING) {
- Slog.v(TAG, "getBackupFinishedNotificationReceivers(...) returns "
- + TextUtils.join(", ", mBackupFinishedNotificationReceivers));
+ Slog.v(
+ TAG,
+ "getBackupFinishedNotificationReceivers(...) returns "
+ + TextUtils.join(", ", mBackupFinishedNotificationReceivers));
}
return mBackupFinishedNotificationReceivers;
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 6469091..b6e2dca 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -851,6 +851,10 @@
mJournal = null; // will be created on first use
mConstants = new BackupManagerConstants(mBackupHandler, mContext.getContentResolver());
+ // We are observing changes to the constants throughout the lifecycle of BMS. This is
+ // because we reference the constants in multiple areas of BMS, which otherwise would
+ // require frequent starting and stopping.
+ mConstants.start();
// Set up the various sorts of package tracking we do
mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index aed57e3..3d7fdbdd 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -62,7 +62,8 @@
$(call all-java-files-under, ../../core/java/android/app/backup) \
$(call all-Iaidl-files-under, ../../core/java/android/app/backup) \
../../core/java/android/content/pm/PackageInfo.java \
- ../../core/java/android/app/IBackupAgent.aidl
+ ../../core/java/android/app/IBackupAgent.aidl \
+ ../../core/java/android/util/KeyValueSettingObserver.java
LOCAL_AIDL_INCLUDES := \
$(call all-Iaidl-files-under, $(INTERNAL_BACKUP)) \
diff --git a/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java b/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java
index 0752537..2a32c2e 100644
--- a/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java
+++ b/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java
@@ -18,79 +18,218 @@
import static com.google.common.truth.Truth.assertThat;
-import android.app.AlarmManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.os.Handler;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
-
+import android.util.KeyValueSettingObserver;
import com.android.server.testing.FrameworkRobolectricTestRunner;
import com.android.server.testing.SystemLoaderClasses;
import com.android.server.testing.SystemLoaderPackages;
-
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(FrameworkRobolectricTestRunner.class)
@Config(manifest = Config.NONE, sdk = 26)
@SystemLoaderPackages({"com.android.server.backup"})
+@SystemLoaderClasses({KeyValueSettingObserver.class})
@Presubmit
public class BackupManagerConstantsTest {
private static final String PACKAGE_NAME = "some.package.name";
private static final String ANOTHER_PACKAGE_NAME = "another.package.name";
+ private ContentResolver mContentResolver;
+ private BackupManagerConstants mConstants;
+
@Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
+ public void setUp() {
+ final Context context = RuntimeEnvironment.application.getApplicationContext();
+
+ mContentResolver = context.getContentResolver();
+ mConstants = new BackupManagerConstants(new Handler(), mContentResolver);
+ mConstants.start();
+ }
+
+ @After
+ public void tearDown() {
+ mConstants.stop();
}
@Test
- public void testDefaultValues() throws Exception {
- final Context context = RuntimeEnvironment.application.getApplicationContext();
- final Handler handler = new Handler();
+ public void testGetConstants_afterConstructorWithStart_returnsDefaultValues() {
+ long keyValueBackupIntervalMilliseconds =
+ mConstants.getKeyValueBackupIntervalMilliseconds();
+ long keyValueBackupFuzzMilliseconds = mConstants.getKeyValueBackupFuzzMilliseconds();
+ boolean keyValueBackupRequireCharging = mConstants.getKeyValueBackupRequireCharging();
+ int keyValueBackupRequiredNetworkType = mConstants.getKeyValueBackupRequiredNetworkType();
+ long fullBackupIntervalMilliseconds = mConstants.getFullBackupIntervalMilliseconds();
+ boolean fullBackupRequireCharging = mConstants.getFullBackupRequireCharging();
+ int fullBackupRequiredNetworkType = mConstants.getFullBackupRequiredNetworkType();
+ String[] backupFinishedNotificationReceivers =
+ mConstants.getBackupFinishedNotificationReceivers();
- Settings.Secure.putString(
- context.getContentResolver(), Settings.Secure.BACKUP_MANAGER_CONSTANTS, null);
+ assertThat(keyValueBackupIntervalMilliseconds)
+ .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS);
+ assertThat(keyValueBackupFuzzMilliseconds)
+ .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS);
+ assertThat(keyValueBackupRequireCharging)
+ .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING);
+ assertThat(keyValueBackupRequiredNetworkType)
+ .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE);
+ assertThat(fullBackupIntervalMilliseconds)
+ .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS);
+ assertThat(fullBackupRequireCharging)
+ .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRE_CHARGING);
+ assertThat(fullBackupRequiredNetworkType)
+ .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE);
+ assertThat(backupFinishedNotificationReceivers).isEqualTo(new String[0]);
+ }
- final BackupManagerConstants constants =
- new BackupManagerConstants(handler, context.getContentResolver());
+ /**
+ * Tests that if there is a setting change when we are not currently observing the setting, that
+ * once we start observing again, we receive the most up-to-date value.
+ */
+ @Test
+ public void testGetConstant_withSettingChangeBeforeStart_updatesValues() {
+ mConstants.stop();
+ long testInterval =
+ BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS * 2;
+ final String setting =
+ BackupManagerConstants.KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS + "=" + testInterval;
+ putStringAndNotify(setting);
- assertThat(constants.getKeyValueBackupIntervalMilliseconds())
- .isEqualTo(4 * AlarmManager.INTERVAL_HOUR);
- assertThat(constants.getKeyValueBackupFuzzMilliseconds()).isEqualTo(10 * 60 * 1000);
- assertThat(constants.getKeyValueBackupRequireCharging()).isEqualTo(true);
- assertThat(constants.getKeyValueBackupRequiredNetworkType()).isEqualTo(1);
+ mConstants.start();
- assertThat(constants.getFullBackupIntervalMilliseconds())
- .isEqualTo(24 * AlarmManager.INTERVAL_HOUR);
- assertThat(constants.getFullBackupRequireCharging()).isEqualTo(true);
- assertThat(constants.getFullBackupRequiredNetworkType()).isEqualTo(2);
- assertThat(constants.getBackupFinishedNotificationReceivers()).isEqualTo(new String[0]);
+ long keyValueBackupIntervalMilliseconds =
+ mConstants.getKeyValueBackupIntervalMilliseconds();
+ assertThat(keyValueBackupIntervalMilliseconds).isEqualTo(testInterval);
}
@Test
- public void testParseNotificationReceivers() throws Exception {
- final Context context = RuntimeEnvironment.application.getApplicationContext();
- final Handler handler = new Handler();
+ public void testGetConstants_whenSettingIsNull_returnsDefaultValues() {
+ putStringAndNotify(null);
- final String recieversSetting =
- "backup_finished_notification_receivers="
+ long keyValueBackupIntervalMilliseconds =
+ mConstants.getKeyValueBackupIntervalMilliseconds();
+ long keyValueBackupFuzzMilliseconds = mConstants.getKeyValueBackupFuzzMilliseconds();
+ boolean keyValueBackupRequireCharging = mConstants.getKeyValueBackupRequireCharging();
+ int keyValueBackupRequiredNetworkType = mConstants.getKeyValueBackupRequiredNetworkType();
+ long fullBackupIntervalMilliseconds = mConstants.getFullBackupIntervalMilliseconds();
+ boolean fullBackupRequireCharging = mConstants.getFullBackupRequireCharging();
+ int fullBackupRequiredNetworkType = mConstants.getFullBackupRequiredNetworkType();
+ String[] backupFinishedNotificationReceivers =
+ mConstants.getBackupFinishedNotificationReceivers();
+
+ assertThat(keyValueBackupIntervalMilliseconds)
+ .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS);
+ assertThat(keyValueBackupFuzzMilliseconds)
+ .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS);
+ assertThat(keyValueBackupRequireCharging)
+ .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING);
+ assertThat(keyValueBackupRequiredNetworkType)
+ .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE);
+ assertThat(fullBackupIntervalMilliseconds)
+ .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS);
+ assertThat(fullBackupRequireCharging)
+ .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRE_CHARGING);
+ assertThat(fullBackupRequiredNetworkType)
+ .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE);
+ assertThat(backupFinishedNotificationReceivers).isEqualTo(new String[0]);
+ }
+
+ /**
+ * Test passing in a malformed setting string. The setting expects
+ * "key1=value,key2=value,key3=value..." but we pass in "key1=,value"
+ */
+ @Test
+ public void testGetConstant_whenSettingIsMalformed_doesNotUpdateParamsOrThrow() {
+ long testFuzz = BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS * 2;
+ final String invalidSettingFormat =
+ BackupManagerConstants.KEY_VALUE_BACKUP_FUZZ_MILLISECONDS + "=," + testFuzz;
+ putStringAndNotify(invalidSettingFormat);
+
+ long keyValueBackupFuzzMilliseconds = mConstants.getKeyValueBackupFuzzMilliseconds();
+
+ assertThat(keyValueBackupFuzzMilliseconds)
+ .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS);
+ }
+
+ /**
+ * Test passing in an invalid value type. {@link
+ * BackupManagerConstants#KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE} expects an integer, but we
+ * pass in a boolean.
+ */
+ @Test
+ public void testGetConstant_whenSettingHasInvalidType_doesNotUpdateParamsOrThrow() {
+ boolean testValue = true;
+ final String invalidSettingType =
+ BackupManagerConstants.KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE + "=" + testValue;
+ putStringAndNotify(invalidSettingType);
+
+ int keyValueBackupRequiredNetworkType = mConstants.getKeyValueBackupRequiredNetworkType();
+
+ assertThat(keyValueBackupRequiredNetworkType)
+ .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE);
+ }
+
+ @Test
+ public void testGetConstants_afterSettingChange_updatesValues() {
+ long testKVInterval =
+ BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS * 2;
+ long testFullInterval =
+ BackupManagerConstants.DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS * 2;
+ final String intervalSetting =
+ BackupManagerConstants.KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS
+ + "="
+ + testKVInterval
+ + ","
+ + BackupManagerConstants.FULL_BACKUP_INTERVAL_MILLISECONDS
+ + "="
+ + testFullInterval;
+ putStringAndNotify(intervalSetting);
+
+ long keyValueBackupIntervalMilliseconds =
+ mConstants.getKeyValueBackupIntervalMilliseconds();
+ long fullBackupIntervalMilliseconds = mConstants.getFullBackupIntervalMilliseconds();
+
+ assertThat(keyValueBackupIntervalMilliseconds).isEqualTo(testKVInterval);
+ assertThat(fullBackupIntervalMilliseconds).isEqualTo(testFullInterval);
+ }
+
+ @Test
+ public void testBackupNotificationReceivers_afterSetting_updatesAndParsesCorrectly() {
+ final String receiversSetting =
+ BackupManagerConstants.BACKUP_FINISHED_NOTIFICATION_RECEIVERS
+ + "="
+ PACKAGE_NAME
+ ':'
+ ANOTHER_PACKAGE_NAME;
- Settings.Secure.putString(
- context.getContentResolver(),
- Settings.Secure.BACKUP_MANAGER_CONSTANTS,
- recieversSetting);
+ putStringAndNotify(receiversSetting);
- final BackupManagerConstants constants =
- new BackupManagerConstants(handler, context.getContentResolver());
-
- assertThat(constants.getBackupFinishedNotificationReceivers())
+ String[] backupFinishedNotificationReceivers =
+ mConstants.getBackupFinishedNotificationReceivers();
+ assertThat(backupFinishedNotificationReceivers)
.isEqualTo(new String[] {PACKAGE_NAME, ANOTHER_PACKAGE_NAME});
}
+
+ /**
+ * Robolectric does not notify observers of changes to settings so we have to trigger it here.
+ * Currently, the mock of {@link Settings.Secure#putString(ContentResolver, String, String)}
+ * only stores the value. TODO: Implement properly in ShadowSettings.
+ */
+ private void putStringAndNotify(String value) {
+ Settings.Secure.putString(
+ mContentResolver, Settings.Secure.BACKUP_MANAGER_CONSTANTS, value);
+
+ // We pass null as the observer since notifyChange iterates over all available observers and
+ // we don't have access to the local observer.
+ mContentResolver.notifyChange(
+ Settings.Secure.getUriFor(Settings.Secure.BACKUP_MANAGER_CONSTANTS),
+ /*observer*/ null);
+ }
}