[go: nahoru, domu]

Make the PreferencesDataStore factory easier to use and make both Factories objects instead of classes.

Test: All current DataStore tests as well as a new test for the newly added function in PreferenceDataStoreTest
Bug: 163595491
RelNote: Make DataStore factories easier to use
Change-Id: I2f28a5eca2f9fb3a3faa222664430ae2c0098fb6
diff --git a/datastore/datastore-core/api/api_lint.ignore b/datastore/datastore-core/api/api_lint.ignore
index 8b7d447..f65d316 100644
--- a/datastore/datastore-core/api/api_lint.ignore
+++ b/datastore/datastore-core/api/api_lint.ignore
@@ -1,6 +1,4 @@
 // Baseline format: 1.0
-MissingJvmstatic: androidx.datastore.migrations.SharedPreferencesMigration#SharedPreferencesMigration(android.content.Context, String, androidx.datastore.migrations.MigrationFromSharedPreferences<T>, java.util.Set<java.lang.String>, boolean):
-    A Kotlin method with default parameter values should be annotated with @JvmOverloads for better Java interoperability; see https://android.github.io/kotlin-guides/interop.html#function-overloads-for-defaults
 MissingJvmstatic: androidx.datastore.migrations.SharedPreferencesView#getString(String, String):
     A Kotlin method with default parameter values should be annotated with @JvmOverloads for better Java interoperability; see https://android.github.io/kotlin-guides/interop.html#function-overloads-for-defaults
 MissingJvmstatic: androidx.datastore.migrations.SharedPreferencesView#getStringSet(String, java.util.Set<java.lang.String>):
diff --git a/datastore/datastore-core/api/current.txt b/datastore/datastore-core/api/current.txt
index 80f8b50..34756f70 100644
--- a/datastore/datastore-core/api/current.txt
+++ b/datastore/datastore-core/api/current.txt
@@ -22,11 +22,15 @@
   }
 
   public final class DataStoreFactory {
-    ctor public DataStoreFactory();
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf());
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null);
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer);
+    field public static final androidx.datastore.DataStoreFactory INSTANCE;
+  }
+
+  public final class DataStoreFactoryKt {
+    method public static <T> androidx.datastore.DataStore<T> createDataStore(android.content.Context, String fileName, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
   }
 
   public interface Serializer<T> {
diff --git a/datastore/datastore-core/api/public_plus_experimental_current.txt b/datastore/datastore-core/api/public_plus_experimental_current.txt
index 80f8b50..34756f70 100644
--- a/datastore/datastore-core/api/public_plus_experimental_current.txt
+++ b/datastore/datastore-core/api/public_plus_experimental_current.txt
@@ -22,11 +22,15 @@
   }
 
   public final class DataStoreFactory {
-    ctor public DataStoreFactory();
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf());
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null);
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer);
+    field public static final androidx.datastore.DataStoreFactory INSTANCE;
+  }
+
+  public final class DataStoreFactoryKt {
+    method public static <T> androidx.datastore.DataStore<T> createDataStore(android.content.Context, String fileName, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
   }
 
   public interface Serializer<T> {
diff --git a/datastore/datastore-core/api/restricted_current.txt b/datastore/datastore-core/api/restricted_current.txt
index 80f8b50..34756f70 100644
--- a/datastore/datastore-core/api/restricted_current.txt
+++ b/datastore/datastore-core/api/restricted_current.txt
@@ -22,11 +22,15 @@
   }
 
   public final class DataStoreFactory {
-    ctor public DataStoreFactory();
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf());
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null);
     method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer);
+    field public static final androidx.datastore.DataStoreFactory INSTANCE;
+  }
+
+  public final class DataStoreFactoryKt {
+    method public static <T> androidx.datastore.DataStore<T> createDataStore(android.content.Context, String fileName, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
   }
 
   public interface Serializer<T> {
diff --git a/datastore/datastore-core/src/test/java/androidx/datastore/DataStoreFactoryTest.kt b/datastore/datastore-core/src/androidTest/java/androidx/datastore/DataStoreFactoryTest.kt
similarity index 62%
rename from datastore/datastore-core/src/test/java/androidx/datastore/DataStoreFactoryTest.kt
rename to datastore/datastore-core/src/androidTest/java/androidx/datastore/DataStoreFactoryTest.kt
index f58247c..6ea9d01 100644
--- a/datastore/datastore-core/src/test/java/androidx/datastore/DataStoreFactoryTest.kt
+++ b/datastore/datastore-core/src/androidTest/java/androidx/datastore/DataStoreFactoryTest.kt
@@ -16,7 +16,9 @@
 
 package androidx.datastore
 
+import android.content.Context
 import androidx.datastore.handlers.ReplaceFileCorruptionHandler
+import androidx.test.core.app.ApplicationProvider
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.test.TestCoroutineScope
@@ -37,17 +39,18 @@
 
     private lateinit var testFile: File
     private lateinit var dataStoreScope: TestCoroutineScope
+    private lateinit var context: Context
 
     @Before
     fun setUp() {
         testFile = tmp.newFile()
         dataStoreScope = TestCoroutineScope()
+        context = ApplicationProvider.getApplicationContext()
     }
 
     @Test
     fun testNewInstance() = runBlockingTest {
-        val factory = DataStoreFactory()
-        val store = factory.create(
+        val store = DataStoreFactory.create(
             produceFile = { testFile },
             serializer = TestingSerializer(),
             scope = dataStoreScope
@@ -65,9 +68,7 @@
     fun testCorruptionHandlerInstalled() = runBlockingTest {
         val valueToReplace = 123.toByte()
 
-        val factory = DataStoreFactory()
-
-        val store = factory.create(
+        val store = DataStoreFactory.create(
             produceFile = { testFile },
             serializer = TestingSerializer(failReadWithCorruptionException = true),
             corruptionHandler = ReplaceFileCorruptionHandler<Byte> {
@@ -81,24 +82,22 @@
 
     @Test
     fun testMigrationsInstalled() = runBlockingTest {
-        val factory = DataStoreFactory()
-
         val migratedByte = 1
 
         val migratePlus2 = object : DataMigration<Byte> {
-                override suspend fun shouldMigrate(currentData: Byte) = true
-                override suspend fun migrate(currentData: Byte) = currentData.inc().inc()
-                override suspend fun cleanUp() {}
-            }
+            override suspend fun shouldMigrate(currentData: Byte) = true
+            override suspend fun migrate(currentData: Byte) = currentData.inc().inc()
+            override suspend fun cleanUp() {}
+        }
         val migrateMinus1 = object : DataMigration<Byte> {
-                override suspend fun shouldMigrate(currentData: Byte) = true
+            override suspend fun shouldMigrate(currentData: Byte) = true
 
-                override suspend fun migrate(currentData: Byte) = currentData.dec()
+            override suspend fun migrate(currentData: Byte) = currentData.dec()
 
-                override suspend fun cleanUp() {}
-            }
+            override suspend fun cleanUp() {}
+        }
 
-        val store = factory.create(
+        val store = DataStoreFactory.create(
             produceFile = { testFile },
             migrations = listOf(migratePlus2, migrateMinus1),
             scope = dataStoreScope,
@@ -107,4 +106,33 @@
 
         assertThat(store.data.first()).isEqualTo(migratedByte)
     }
+
+    @Test
+    fun testCreateWithContextAndName() = runBlockingTest {
+        val byte = 1
+
+        var store = context.createDataStore(
+            serializer = TestingSerializer(),
+            fileName = "my_settings.byte",
+            scope = dataStoreScope
+        )
+        store.updateData { 1 }
+
+        // Create it again and confirm it's still there
+        store = context.createDataStore(
+            serializer = TestingSerializer(),
+            fileName = "my_settings.byte",
+            scope = dataStoreScope
+        )
+        assertThat(store.data.first()).isEqualTo(byte)
+
+        // Check that the file name is context.filesDir + fileName
+        store = DataStoreFactory.create(
+            produceFile = {
+                File(context.filesDir, "datastore/my_settings.byte")
+            }, serializer = TestingSerializer(),
+            scope = dataStoreScope
+        )
+        assertThat(store.data.first()).isEqualTo(byte)
+    }
 }
\ No newline at end of file
diff --git a/datastore/datastore-core/src/androidTest/java/migrations/SharedPreferencesMigrationTest.kt b/datastore/datastore-core/src/androidTest/java/androidx/datastore/migrations/SharedPreferencesMigrationTest.kt
similarity index 98%
rename from datastore/datastore-core/src/androidTest/java/migrations/SharedPreferencesMigrationTest.kt
rename to datastore/datastore-core/src/androidTest/java/androidx/datastore/migrations/SharedPreferencesMigrationTest.kt
index bb90413..73501f4 100644
--- a/datastore/datastore-core/src/androidTest/java/migrations/SharedPreferencesMigrationTest.kt
+++ b/datastore/datastore-core/src/androidTest/java/androidx/datastore/migrations/SharedPreferencesMigrationTest.kt
@@ -138,7 +138,7 @@
     private fun getDataStoreWithMigrations(
         migrations: List<DataMigration<Byte>>
     ): DataStore<Byte> {
-        return DataStoreFactory().create(
+        return DataStoreFactory.create(
             produceFile = { datastoreFile },
             serializer = TestingSerializer(),
             migrations = migrations,
diff --git a/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt b/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt
index 969495e..496e239 100644
--- a/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt
+++ b/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt
@@ -16,6 +16,7 @@
 
 package androidx.datastore
 
+import android.content.Context
 import androidx.datastore.handlers.NoOpCorruptionHandler
 import androidx.datastore.handlers.ReplaceFileCorruptionHandler
 import kotlinx.coroutines.CoroutineScope
@@ -26,7 +27,7 @@
 /**
  * Public factory for creating DataStore instances.
  */
-class DataStoreFactory {
+object DataStoreFactory {
     /**
      * Create an instance of SingleProcessDataStore. The user is responsible for ensuring that
      * there is never more than one DataStore acting on a file at a time.
@@ -63,4 +64,34 @@
             initTasksList = listOf(DataMigrationInitializer.getInitializer(migrations)),
             scope = scope
         )
-}
\ No newline at end of file
+}
+
+/**
+ * Create an instance of SingleProcessDataStore. The user is responsible for ensuring that
+ * there is never more than one instance of SingleProcessDataStore acting on a file at a time.
+ *
+ * @param fileName the filename relative to Context.filesDir that DataStore acts on. The File is
+ * obtained by calling File(context.filesDir, fileName). No two instances of DataStore should
+ * act on the same file at the same time.
+ * @param corruptionHandler The corruptionHandler is invoked if DataStore encounters a
+ * [CorruptionException] when attempting to read data. CorruptionExceptions are thrown by
+ * serializers when data can not be de-serialized.
+ * @param migrations are run before any access to data can occur. Each producer and migration
+ * may be run more than once whether or not it already succeeded (potentially because another
+ * migration failed or a write to disk failed.)
+ * @param scope The scope in which IO operations and transform functions will execute.
+ */
+fun <T> Context.createDataStore(
+    fileName: String,
+    serializer: Serializer<T>,
+    corruptionHandler: ReplaceFileCorruptionHandler<T>? = null,
+    migrations: List<DataMigration<T>> = listOf(),
+    scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
+): DataStore<T> =
+    DataStoreFactory.create(
+        produceFile = { File(this.filesDir, "datastore/$fileName") },
+        serializer = serializer,
+        corruptionHandler = corruptionHandler,
+        migrations = migrations,
+        scope = scope
+    )
diff --git a/datastore/datastore-preferences/api/api_lint.ignore b/datastore/datastore-preferences/api/api_lint.ignore
index 50dbca8..5586703 100644
--- a/datastore/datastore-preferences/api/api_lint.ignore
+++ b/datastore/datastore-preferences/api/api_lint.ignore
@@ -3,5 +3,5 @@
     Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.datastore.preferences.Preferences.Builder.remove(String)
 
 
-MissingJvmstatic: androidx.datastore.preferences.SharedPreferencesToPreferencesKt#SharedPreferencesMigration(android.content.Context, String, java.util.Set<java.lang.String>, boolean):
+MissingJvmstatic: androidx.datastore.preferences.PreferenceDataStoreFactory#create(kotlin.jvm.functions.Function0<? extends java.io.File>, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>>, kotlinx.coroutines.CoroutineScope):
     A Kotlin method with default parameter values should be annotated with @JvmOverloads for better Java interoperability; see https://android.github.io/kotlin-guides/interop.html#function-overloads-for-defaults
diff --git a/datastore/datastore-preferences/api/current.txt b/datastore/datastore-preferences/api/current.txt
index 217726b..2242287 100644
--- a/datastore/datastore-preferences/api/current.txt
+++ b/datastore/datastore-preferences/api/current.txt
@@ -2,11 +2,12 @@
 package androidx.datastore.preferences {
 
   public final class PreferenceDataStoreFactory {
-    ctor public PreferenceDataStoreFactory();
     method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
-    method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf());
-    method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null);
-    method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile);
+    field public static final androidx.datastore.preferences.PreferenceDataStoreFactory INSTANCE;
+  }
+
+  public final class PreferenceDataStoreFactoryKt {
+    method public static androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> createDataStore(android.content.Context, String name, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
   }
 
   public final class Preferences {
diff --git a/datastore/datastore-preferences/api/public_plus_experimental_current.txt b/datastore/datastore-preferences/api/public_plus_experimental_current.txt
index 217726b..2242287 100644
--- a/datastore/datastore-preferences/api/public_plus_experimental_current.txt
+++ b/datastore/datastore-preferences/api/public_plus_experimental_current.txt
@@ -2,11 +2,12 @@
 package androidx.datastore.preferences {
 
   public final class PreferenceDataStoreFactory {
-    ctor public PreferenceDataStoreFactory();
     method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
-    method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf());
-    method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null);
-    method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile);
+    field public static final androidx.datastore.preferences.PreferenceDataStoreFactory INSTANCE;
+  }
+
+  public final class PreferenceDataStoreFactoryKt {
+    method public static androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> createDataStore(android.content.Context, String name, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
   }
 
   public final class Preferences {
diff --git a/datastore/datastore-preferences/api/restricted_current.txt b/datastore/datastore-preferences/api/restricted_current.txt
index 217726b..2242287 100644
--- a/datastore/datastore-preferences/api/restricted_current.txt
+++ b/datastore/datastore-preferences/api/restricted_current.txt
@@ -2,11 +2,12 @@
 package androidx.datastore.preferences {
 
   public final class PreferenceDataStoreFactory {
-    ctor public PreferenceDataStoreFactory();
     method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
-    method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf());
-    method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null);
-    method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile);
+    field public static final androidx.datastore.preferences.PreferenceDataStoreFactory INSTANCE;
+  }
+
+  public final class PreferenceDataStoreFactoryKt {
+    method public static androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> createDataStore(android.content.Context, String name, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
   }
 
   public final class Preferences {
diff --git a/datastore/datastore-preferences/src/test/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt b/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
similarity index 76%
rename from datastore/datastore-preferences/src/test/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
rename to datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
index 7ae14dc..1b26243 100644
--- a/datastore/datastore-preferences/src/test/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
+++ b/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
@@ -16,8 +16,10 @@
 
 package androidx.datastore.preferences
 
+import android.content.Context
 import androidx.datastore.DataMigration
 import androidx.datastore.handlers.ReplaceFileCorruptionHandler
+import androidx.test.core.app.ApplicationProvider
 import kotlinx.coroutines.FlowPreview
 import kotlinx.coroutines.ObsoleteCoroutinesApi
 import kotlinx.coroutines.flow.first
@@ -39,17 +41,18 @@
 
     private lateinit var testFile: File
     private lateinit var dataStoreScope: TestCoroutineScope
+    private lateinit var context: Context
 
     @Before
     fun setUp() {
         testFile = tmp.newFile("test_file." + PreferencesSerializer.fileExtension)
         dataStoreScope = TestCoroutineScope()
+        context = ApplicationProvider.getApplicationContext()
     }
 
     @Test
     fun testNewInstance() = runBlockingTest {
-        val factory = PreferenceDataStoreFactory()
-        val store = factory.create(
+        val store = PreferenceDataStoreFactory.create(
             produceFile = { testFile },
             scope = dataStoreScope
         )
@@ -68,11 +71,9 @@
     fun testCorruptionHandlerInstalled() = runBlockingTest {
         testFile.writeBytes(byteArrayOf(0x00, 0x00, 0x00, 0x03)) // Protos can not start with 0x00.
 
-        val factory = PreferenceDataStoreFactory()
-
         val valueToReplace = Preferences.Builder().setBoolean("key", true).build()
 
-        val store = factory.create(
+        val store = PreferenceDataStoreFactory.create(
             produceFile = { testFile },
             corruptionHandler = ReplaceFileCorruptionHandler<Preferences> {
                 valueToReplace
@@ -84,7 +85,6 @@
 
     @Test
     fun testMigrationsInstalled() = runBlockingTest {
-        val factory = PreferenceDataStoreFactory()
 
         val expectedPreferences = Preferences.Builder()
             .setString("string_key", "value")
@@ -109,7 +109,7 @@
             override suspend fun cleanUp() {}
         }
 
-        val store = factory.create(
+        val store = PreferenceDataStoreFactory.create(
             produceFile = { testFile },
             migrations = listOf(migrateTo5, migratePlus1),
             scope = dataStoreScope
@@ -117,4 +117,25 @@
 
         assertEquals(expectedPreferences, store.data.first())
     }
+
+    @Test
+    fun testCreateWithContextAndName() = runBlockingTest {
+        val prefs = Preferences.Builder().setInt("int_key", 12345).build()
+
+        var store = context.createDataStore(
+            name = "my_settings",
+            scope = dataStoreScope
+        )
+        store.updateData { prefs }
+
+        // Create it again and confirm it's still there
+        store = context.createDataStore("my_settings", scope = dataStoreScope)
+        assertEquals(prefs, store.data.first())
+
+        // Check that the file name is context.filesDir + name + ".preferences_pb"
+        store = PreferenceDataStoreFactory.create(produceFile = {
+            File(context.filesDir, "datastore/my_settings.preferences_pb")
+        }, scope = dataStoreScope)
+        assertEquals(prefs, store.data.first())
+    }
 }
\ No newline at end of file
diff --git a/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt b/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt
index c92da6e..cc02e8a 100644
--- a/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt
+++ b/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt
@@ -393,7 +393,7 @@
     private fun getDataStoreWithMigrations(
         migrations: List<DataMigration<Preferences>>
     ): DataStore<Preferences> {
-        return PreferenceDataStoreFactory().create(
+        return PreferenceDataStoreFactory.create(
             produceFile = { datastoreFile },
             migrations = migrations,
             scope = TestCoroutineScope()
diff --git a/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt b/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt
index 7de4135..f03680d 100644
--- a/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt
+++ b/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt
@@ -16,6 +16,7 @@
 
 package androidx.datastore.preferences
 
+import android.content.Context
 import androidx.datastore.CorruptionException
 import androidx.datastore.DataMigration
 import androidx.datastore.DataStore
@@ -29,33 +30,30 @@
 /**
  * Public factory for creating PreferenceDataStore instances.
  */
-class PreferenceDataStoreFactory {
-    private val dataStoreFactory = DataStoreFactory()
-
+object PreferenceDataStoreFactory {
     /**
      * Create an instance of SingleProcessDataStore. The user is responsible for ensuring that
      * there is never more than one instance of SingleProcessDataStore acting on a file at a time.
      *
-     * @param produceFile Function which returns the file that the new DataStore will act on. The function
-     * must return the same path every time. No two instances of PreferenceDataStore
+     * @param produceFile Function which returns the file that the new DataStore will act on.
+     * The function must return the same path every time. No two instances of PreferenceDataStore
      * should act on the same file at the same time. The file must have the extension
      * preferences_pb.
-     * @param corruptionHandler The corruptionHandler is invoked if DataStore encounters a [CorruptionException] when
-     * attempting to read data. CorruptionExceptions are thrown by serializers when data can
-     * not be de-serialized.
-     * @param migrations are run before any access to data can occur. Each
-     * producer and migration may be run more than once whether or not it already succeeded
-     * (potentially because another migration failed or a write to disk failed.)
+     * @param corruptionHandler The corruptionHandler is invoked if DataStore encounters a
+     * [CorruptionException] when attempting to read data. CorruptionExceptions are thrown by
+     * serializers when data cannot be de-serialized.
+     * @param migrations are run before any access to data can occur. Each producer and migration
+     * may be run more than once whether or not it already succeeded (potentially because another
+     * migration failed or a write to disk failed.)
      * @param scope The scope in which IO operations and transform functions will execute.
      */
-    @JvmOverloads // Generate methods for default params for java users.
     fun create(
         produceFile: () -> File,
         corruptionHandler: ReplaceFileCorruptionHandler<Preferences>? = null,
         migrations: List<DataMigration<Preferences>> = listOf(),
         scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
     ): DataStore<Preferences> =
-        dataStoreFactory.create(
+        DataStoreFactory.create(
             produceFile = {
                 val file = produceFile()
                 check(file.extension == PreferencesSerializer.fileExtension) {
@@ -69,4 +67,33 @@
             migrations = migrations,
             scope = scope
         )
-}
\ No newline at end of file
+}
+
+/**
+ * Create an instance of SingleProcessDataStore. The user is responsible for ensuring that
+ * there is never more than one instance of SingleProcessDataStore acting on a file at a time.
+ *
+ * @param name The name of the preferences. The preferences will be stored in a file obtained
+ * by calling: File(context.filesDir, "datastore/" + name + ".preferences_pb")
+ * @param corruptionHandler The corruptionHandler is invoked if DataStore encounters a
+ * [CorruptionException] when attempting to read data. CorruptionExceptions are thrown by
+ * serializers when data can not be de-serialized.
+ * @param migrations are run before any access to data can occur. Each producer and migration
+ * may be run more than once whether or not it already succeeded (potentially because another
+ * migration failed or a write to disk failed.)
+ * @param scope The scope in which IO operations and transform functions will execute.
+ */
+fun Context.createDataStore(
+    name: String,
+    corruptionHandler: ReplaceFileCorruptionHandler<Preferences>? = null,
+    migrations: List<DataMigration<Preferences>> = listOf(),
+    scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
+): DataStore<Preferences> =
+    PreferenceDataStoreFactory.create(
+        produceFile = {
+            File(this.filesDir, "datastore/$name.preferences_pb")
+        },
+        corruptionHandler = corruptionHandler,
+        migrations = migrations,
+        scope = scope
+    )
diff --git a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/PreferencesDataStoreActivity.kt b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/PreferencesDataStoreActivity.kt
index d36e21b..65b3a74 100644
--- a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/PreferencesDataStoreActivity.kt
+++ b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/PreferencesDataStoreActivity.kt
@@ -24,27 +24,25 @@
 import androidx.annotation.Sampled
 import androidx.appcompat.app.AppCompatActivity
 import androidx.datastore.DataStore
-import androidx.datastore.preferences.PreferenceDataStoreFactory
 import androidx.datastore.preferences.Preferences
+import androidx.datastore.preferences.createDataStore
 import androidx.lifecycle.lifecycleScope
 import kotlinx.coroutines.flow.catch
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.launch
-import java.io.File
 import java.io.IOException
 
 @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
 class PreferencesDataStoreActivity : AppCompatActivity() {
     private val TAG = "PreferencesActivity"
 
-    private val PREFERENCE_STORE_FILE_NAME = "datastore_test_app.preferences_pb"
+    private val PREFERENCE_STORE_FILE_NAME = "datastore_test_app"
     private val COUNTER_KEY = "counter"
 
     private val preferenceStore: DataStore<Preferences> by lazy {
-        PreferenceDataStoreFactory().create(
-            { File(applicationContext.filesDir, PREFERENCE_STORE_FILE_NAME) })
+        applicationContext.createDataStore(PREFERENCE_STORE_FILE_NAME)
     }
 
     @Sampled
diff --git a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/ProtoDataStoreActivity.kt b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/ProtoDataStoreActivity.kt
index 57d6411..8b46d26 100644
--- a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/ProtoDataStoreActivity.kt
+++ b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/ProtoDataStoreActivity.kt
@@ -46,7 +46,7 @@
     private val PROTO_STORE_FILE_NAME = "datastore_test_app.pb"
 
     private val settingsStore: DataStore<Settings> by lazy {
-        DataStoreFactory().create(
+        DataStoreFactory.create(
             { File(applicationContext.filesDir, PROTO_STORE_FILE_NAME) },
             SettingsSerializer
         )
diff --git a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/SettingsFragment.kt b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/SettingsFragment.kt
index cd4966f..b2e8d2b 100644
--- a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/SettingsFragment.kt
+++ b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/SettingsFragment.kt
@@ -69,7 +69,7 @@
     private val PROTO_STORE_FILE_NAME = "datastore_test_app.pb"
 
     private val settingsStore: DataStore<Settings> by lazy {
-        DataStoreFactory().create(
+        DataStoreFactory.create(
             { File(requireActivity().applicationContext.filesDir, PROTO_STORE_FILE_NAME) },
             SettingsSerializer
         )