Merge "Add package-private DelegatingOpenHelper and have SqliteCopyOpenHelper and QueryInterceptorOpenHelper implement it so that they can be configured in the RoomDataBase.init block." into androidx-main
diff --git a/room/runtime/src/androidTest/java/androidx/room/AutoClosingRoomOpenHelperTest.kt b/room/runtime/src/androidTest/java/androidx/room/AutoClosingRoomOpenHelperTest.kt
index e19a845..c601d2e 100644
--- a/room/runtime/src/androidTest/java/androidx/room/AutoClosingRoomOpenHelperTest.kt
+++ b/room/runtime/src/androidTest/java/androidx/room/AutoClosingRoomOpenHelperTest.kt
@@ -237,4 +237,25 @@
             assertThat(it.isNull(4)).isTrue()
         }
     }
+
+    @Test
+    public fun testGetDelegate() {
+        val delegateOpenHelper = FrameworkSQLiteOpenHelperFactory()
+            .create(
+                SupportSQLiteOpenHelper.Configuration
+                    .builder(ApplicationProvider.getApplicationContext())
+                    .callback(Callback())
+                    .name("name")
+                    .build()
+            )
+
+        val autoCloseExecutor = Executors.newSingleThreadExecutor()
+
+        val autoClosing = AutoClosingRoomOpenHelper(
+            delegateOpenHelper,
+            AutoCloser(0, TimeUnit.MILLISECONDS, autoCloseExecutor)
+        )
+
+        assertThat(autoClosing.getDelegate()).isSameInstanceAs(delegateOpenHelper)
+    }
 }
\ No newline at end of file
diff --git a/room/runtime/src/main/java/androidx/room/AutoClosingRoomOpenHelper.java b/room/runtime/src/main/java/androidx/room/AutoClosingRoomOpenHelper.java
index 87d364f..9aabf95 100644
--- a/room/runtime/src/main/java/androidx/room/AutoClosingRoomOpenHelper.java
+++ b/room/runtime/src/main/java/androidx/room/AutoClosingRoomOpenHelper.java
@@ -48,7 +48,7 @@
 /**
  * A SupportSQLiteOpenHelper that has autoclose enabled for database connections.
  */
-final class AutoClosingRoomOpenHelper implements SupportSQLiteOpenHelper {
+final class AutoClosingRoomOpenHelper implements SupportSQLiteOpenHelper, DelegatingOpenHelper {
     @NonNull
     private final SupportSQLiteOpenHelper mDelegateOpenHelper;
 
@@ -116,6 +116,12 @@
         return this.mAutoClosingDb;
     }
 
+    @Override
+    @NonNull
+    public SupportSQLiteOpenHelper getDelegate() {
+        return mDelegateOpenHelper;
+    }
+
     /**
      * SupportSQLiteDatabase that also keeps refcounts and autocloses the database
      */
diff --git a/room/runtime/src/main/java/androidx/room/DelegatingOpenHelper.java b/room/runtime/src/main/java/androidx/room/DelegatingOpenHelper.java
new file mode 100644
index 0000000..7c84fc5
--- /dev/null
+++ b/room/runtime/src/main/java/androidx/room/DelegatingOpenHelper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 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 androidx.room;
+
+import androidx.annotation.NonNull;
+import androidx.sqlite.db.SupportSQLiteOpenHelper;
+
+/**
+ * Package private interface for OpenHelpers which delegate to other open helpers.
+ *
+ * TODO(b/175612939): delete this interface once implementations are merged.
+ */
+interface DelegatingOpenHelper {
+
+    /**
+     * Returns the delegate open helper (which may itself be a DelegatingOpenHelper) so
+     * configurations on specific instances can be applied.
+     *
+     * @return the delegate
+     */
+    @NonNull
+    SupportSQLiteOpenHelper getDelegate();
+}
diff --git a/room/runtime/src/main/java/androidx/room/QueryInterceptorOpenHelper.java b/room/runtime/src/main/java/androidx/room/QueryInterceptorOpenHelper.java
index c2ca486..9916294 100644
--- a/room/runtime/src/main/java/androidx/room/QueryInterceptorOpenHelper.java
+++ b/room/runtime/src/main/java/androidx/room/QueryInterceptorOpenHelper.java
@@ -26,7 +26,7 @@
 
 import java.util.concurrent.Executor;
 
-final class QueryInterceptorOpenHelper implements SupportSQLiteOpenHelper {
+final class QueryInterceptorOpenHelper implements SupportSQLiteOpenHelper, DelegatingOpenHelper {
 
     private final SupportSQLiteOpenHelper mDelegate;
     private final RoomDatabase.QueryCallback mQueryCallback;
@@ -68,4 +68,11 @@
     public void close() {
         mDelegate.close();
     }
+
+    @Override
+    @NonNull
+    public SupportSQLiteOpenHelper getDelegate() {
+        return mDelegate;
+    }
+
 }
diff --git a/room/runtime/src/main/java/androidx/room/RoomDatabase.java b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
index 4561876..0fa15d8 100644
--- a/room/runtime/src/main/java/androidx/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
@@ -179,10 +179,14 @@
     @CallSuper
     public void init(@NonNull DatabaseConfiguration configuration) {
         mOpenHelper = createOpenHelper(configuration);
-        if (mOpenHelper instanceof SQLiteCopyOpenHelper) {
-            SQLiteCopyOpenHelper copyOpenHelper = (SQLiteCopyOpenHelper) mOpenHelper;
+
+        // Configure SqliteCopyOpenHelper if it is available:
+        SQLiteCopyOpenHelper copyOpenHelper = unwrapOpenHelper(SQLiteCopyOpenHelper.class,
+                mOpenHelper);
+        if (copyOpenHelper != null) {
             copyOpenHelper.setDatabaseConfiguration(configuration);
         }
+
         boolean wal = false;
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
             wal = configuration.journalMode == JournalMode.WRITE_AHEAD_LOGGING;
@@ -239,6 +243,26 @@
     }
 
     /**
+     * Unwraps (delegating) open helpers until it finds clazz, otherwise returns null.
+     *
+     * @param clazz the open helper type to search for
+     * @param openHelper the open helper to search through
+     * @param <T> the type of clazz
+     * @return the instance of clazz, otherwise null
+     */
+    @Nullable
+    @SuppressWarnings("unchecked")
+    private <T> T unwrapOpenHelper(Class<T> clazz, SupportSQLiteOpenHelper openHelper) {
+        if (clazz.isInstance(openHelper)) {
+            return (T) openHelper;
+        }
+        if (openHelper instanceof DelegatingOpenHelper) {
+            return unwrapOpenHelper(clazz, ((DelegatingOpenHelper) openHelper).getDelegate());
+        }
+        return null;
+    }
+
+    /**
      * Returns the SQLite open helper used by this database.
      *
      * @return The SQLite open helper used by this database.
diff --git a/room/runtime/src/main/java/androidx/room/SQLiteCopyOpenHelper.java b/room/runtime/src/main/java/androidx/room/SQLiteCopyOpenHelper.java
index dc45973..b7d244e 100644
--- a/room/runtime/src/main/java/androidx/room/SQLiteCopyOpenHelper.java
+++ b/room/runtime/src/main/java/androidx/room/SQLiteCopyOpenHelper.java
@@ -44,7 +44,7 @@
  * An open helper that will copy & open a pre-populated database if it doesn't exists in internal
  * storage.
  */
-class SQLiteCopyOpenHelper implements SupportSQLiteOpenHelper {
+class SQLiteCopyOpenHelper implements SupportSQLiteOpenHelper, DelegatingOpenHelper {
 
     @NonNull
     private final Context mContext;
@@ -112,6 +112,12 @@
         mVerified = false;
     }
 
+    @Override
+    @NonNull
+    public SupportSQLiteOpenHelper getDelegate() {
+        return mDelegate;
+    }
+
     // Can't be constructor param because the factory is needed by the database builder which in
     // turn is the one that actually builds the configuration.
     void setDatabaseConfiguration(@Nullable DatabaseConfiguration databaseConfiguration) {
@@ -253,7 +259,7 @@
         FrameworkSQLiteOpenHelperFactory factory = new FrameworkSQLiteOpenHelperFactory();
         Configuration configuration = Configuration.builder(mContext)
                 .name(databaseName)
-                .callback(new Callback(version){
+                .callback(new Callback(version) {
                     @Override
                     public void onCreate(@NonNull SupportSQLiteDatabase db) {
                     }
diff --git a/room/runtime/src/test/java/androidx/room/SQLiteCopyOpenHelperTest.kt b/room/runtime/src/test/java/androidx/room/SQLiteCopyOpenHelperTest.kt
index 7f4cb20..78e64d0 100644
--- a/room/runtime/src/test/java/androidx/room/SQLiteCopyOpenHelperTest.kt
+++ b/room/runtime/src/test/java/androidx/room/SQLiteCopyOpenHelperTest.kt
@@ -20,6 +20,7 @@
 import android.content.res.AssetManager
 import androidx.sqlite.db.SupportSQLiteOpenHelper
 import org.junit.Assert.assertEquals
+import org.junit.Assert.assertSame
 import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
@@ -184,6 +185,13 @@
         assertEquals(1, exceptions.size)
     }
 
+    @Test
+    fun testGetDelegate() {
+        val openHelper = createOpenHelper(tempDirectory.newFile("toCopy.db"))
+
+        assertSame(delegate, openHelper.getDelegate())
+    }
+
     internal fun setupMocks(tmpDir: File, copyFromFile: File, onAssetOpen: () -> Unit = {}) {
         `when`(delegate.databaseName).thenReturn(DB_NAME)
         `when`(context.getDatabasePath(DB_NAME)).thenReturn(File(tmpDir, DB_NAME))