Merge changes from topic "room-runtime-paging-kotlinify" into androidx-main

* changes:
  Converting `paging` related files in `room-runtime` from Java to Kotlin.
  Initial code check-in for renaming `paging` related files in `room-runtime` from *.java to *.kt.
diff --git a/room/room-runtime/api/restricted_current.ignore b/room/room-runtime/api/restricted_current.ignore
index e6a9bf9..a566a8f 100644
--- a/room/room-runtime/api/restricted_current.ignore
+++ b/room/room-runtime/api/restricted_current.ignore
@@ -1,3 +1,7 @@
 // Baseline format: 1.0
+ChangedType: androidx.room.paging.LimitOffsetDataSource#convertRows(android.database.Cursor):
+    Method androidx.room.paging.LimitOffsetDataSource.convertRows has changed return type from java.util.List<T!> to java.util.List<T>
+
+
 RemovedClass: androidx.room.util.CopyLock:
     Removed class androidx.room.util.CopyLock
diff --git a/room/room-runtime/api/restricted_current.txt b/room/room-runtime/api/restricted_current.txt
index 8f29006..24bc4fb 100644
--- a/room/room-runtime/api/restricted_current.txt
+++ b/room/room-runtime/api/restricted_current.txt
@@ -236,13 +236,14 @@
 package androidx.room.paging {
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class LimitOffsetDataSource<T> extends androidx.paging.PositionalDataSource<T> {
-    ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase, androidx.sqlite.db.SupportSQLiteQuery, boolean, java.lang.String!...);
-    ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase, androidx.sqlite.db.SupportSQLiteQuery, boolean, boolean, java.lang.String!...);
-    ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase, androidx.room.RoomSQLiteQuery, boolean, java.lang.String!...);
-    ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase, androidx.room.RoomSQLiteQuery, boolean, boolean, java.lang.String!...);
-    method protected abstract java.util.List<T!> convertRows(android.database.Cursor);
-    method public void loadInitial(androidx.paging.PositionalDataSource.LoadInitialParams, androidx.paging.PositionalDataSource.LoadInitialCallback<T!>);
-    method public void loadRange(androidx.paging.PositionalDataSource.LoadRangeParams, androidx.paging.PositionalDataSource.LoadRangeCallback<T!>);
+    ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase db, androidx.room.RoomSQLiteQuery sourceQuery, boolean inTransaction, boolean registerObserverImmediately, java.lang.String... tables);
+    ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase db, androidx.sqlite.db.SupportSQLiteQuery query, boolean inTransaction, java.lang.String... tables);
+    ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase db, androidx.sqlite.db.SupportSQLiteQuery query, boolean inTransaction, boolean registerObserverImmediately, java.lang.String... tables);
+    ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase db, androidx.room.RoomSQLiteQuery query, boolean inTransaction, java.lang.String... tables);
+    method protected abstract java.util.List<T> convertRows(android.database.Cursor cursor);
+    method public void loadInitial(androidx.paging.PositionalDataSource.LoadInitialParams params, androidx.paging.PositionalDataSource.LoadInitialCallback<T> callback);
+    method public void loadRange(androidx.paging.PositionalDataSource.LoadRangeParams params, androidx.paging.PositionalDataSource.LoadRangeCallback<T> callback);
+    property public boolean isInvalid;
   }
 
 }
diff --git a/room/room-runtime/build.gradle b/room/room-runtime/build.gradle
index 0cdeecd..3e43c71 100644
--- a/room/room-runtime/build.gradle
+++ b/room/room-runtime/build.gradle
@@ -36,7 +36,7 @@
     api(project(":sqlite:sqlite-framework"))
     api(project(":sqlite:sqlite"))
     implementation("androidx.arch.core:core-runtime:2.0.1")
-    compileOnly("androidx.paging:paging-common:2.0.0")
+    compileOnly("androidx.paging:paging-common:3.1.0")
     compileOnly("androidx.lifecycle:lifecycle-livedata-core:2.0.0")
     implementation("androidx.annotation:annotation-experimental:1.1.0-rc01")
     compileOnly libs.kotlinStdlib // Due to :annotation-experimental
diff --git a/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java b/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java
deleted file mode 100644
index 81ba417..0000000
--- a/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2017 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.paging;
-
-import android.database.Cursor;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.room.InvalidationTracker;
-import androidx.room.RoomDatabase;
-import androidx.room.RoomSQLiteQuery;
-import androidx.sqlite.db.SupportSQLiteQuery;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * A simple data source implementation that uses Limit & Offset to page the query.
- * <p>
- * This is NOT the most efficient way to do paging on SQLite. It is
- * <a href="http://www.sqlite.org/cvstrac/wiki?p=ScrollingCursor">recommended</a> to use an indexed
- * ORDER BY statement but that requires a more complex API. This solution is technically equal to
- * receiving a {@link Cursor} from a large query but avoids the need to manually manage it, and
- * never returns inconsistent data if it is invalidated.
- *
- * This class is used for both Paging2 and Pagin3 (via its compat API). When used with Paging3,
- * it does lazy registration for observers to be suitable for initialization on the main thread
- * whereas in Paging2, it will register observer eagerly to obey Paging2's strict Data Source
- * rules. (Paging2 does not let data source to possibly return invalidated data).
- *
- * @param <T> Data type returned by the data source.
- *
- * @hide
- */
-@SuppressWarnings("deprecation")
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public abstract class LimitOffsetDataSource<T> extends androidx.paging.PositionalDataSource<T> {
-    private final RoomSQLiteQuery mSourceQuery;
-    private final String mCountQuery;
-    private final String mLimitOffsetQuery;
-    private final RoomDatabase mDb;
-    @SuppressWarnings("FieldCanBeLocal")
-    private final InvalidationTracker.Observer mObserver;
-    private final boolean mInTransaction;
-    private final AtomicBoolean mRegisteredObserver = new AtomicBoolean(false);
-
-    protected LimitOffsetDataSource(@NonNull RoomDatabase db,
-            @NonNull SupportSQLiteQuery query,
-            boolean inTransaction,
-            @NonNull
-                    String... tables) {
-        this(db, RoomSQLiteQuery.copyFrom(query), inTransaction, tables);
-    }
-
-    protected LimitOffsetDataSource(
-            @NonNull RoomDatabase db,
-            @NonNull SupportSQLiteQuery query,
-            boolean inTransaction,
-            boolean registerObserverImmediately,
-            @NonNull String... tables) {
-        this(db, RoomSQLiteQuery.copyFrom(query), inTransaction, registerObserverImmediately,
-                tables);
-    }
-
-    protected LimitOffsetDataSource(
-            @NonNull RoomDatabase db,
-            @NonNull RoomSQLiteQuery query,
-            boolean inTransaction,
-            @NonNull String... tables) {
-        this(db, query, inTransaction, true /*register registerObserverImmediately*/, tables);
-    }
-
-    protected LimitOffsetDataSource(
-            @NonNull RoomDatabase db,
-            @NonNull RoomSQLiteQuery query,
-            boolean inTransaction,
-            boolean registerObserverImmediately,
-            @NonNull String... tables) {
-        mDb = db;
-        mSourceQuery = query;
-        mInTransaction = inTransaction;
-        mCountQuery = "SELECT COUNT(*) FROM ( " + mSourceQuery.getSql() + " )";
-        mLimitOffsetQuery = "SELECT * FROM ( " + mSourceQuery.getSql() + " ) LIMIT ? OFFSET ?";
-        mObserver = new InvalidationTracker.Observer(tables) {
-            @Override
-            public void onInvalidated(@NonNull Set<String> tables) {
-                invalidate();
-            }
-        };
-        if (registerObserverImmediately) {
-            registerObserverIfNecessary();
-        }
-    }
-
-    private void registerObserverIfNecessary() {
-        if (mRegisteredObserver.compareAndSet(false, true)) {
-            mDb.getInvalidationTracker().addWeakObserver(mObserver);
-        }
-    }
-
-    /**
-     * Count number of rows query can return
-     *
-     * @hide
-     */
-    @SuppressWarnings("WeakerAccess")
-    public int countItems() {
-        registerObserverIfNecessary();
-        final RoomSQLiteQuery sqLiteQuery = RoomSQLiteQuery.acquire(mCountQuery,
-                mSourceQuery.getArgCount());
-        sqLiteQuery.copyArgumentsFrom(mSourceQuery);
-        Cursor cursor = mDb.query(sqLiteQuery);
-        try {
-            if (cursor.moveToFirst()) {
-                return cursor.getInt(0);
-            }
-            return 0;
-        } finally {
-            cursor.close();
-            sqLiteQuery.release();
-        }
-    }
-
-    @Override
-    public boolean isInvalid() {
-        registerObserverIfNecessary();
-        mDb.getInvalidationTracker().refreshVersionsSync();
-        return super.isInvalid();
-    }
-
-    @NonNull
-    @SuppressWarnings("WeakerAccess")
-    protected abstract List<T> convertRows(@NonNull Cursor cursor);
-
-    @SuppressWarnings("deprecation")
-    @Override
-    public void loadInitial(@NonNull LoadInitialParams params,
-            @NonNull LoadInitialCallback<T> callback) {
-        registerObserverIfNecessary();
-        List<T> list = Collections.emptyList();
-        int totalCount;
-        int firstLoadPosition = 0;
-        RoomSQLiteQuery sqLiteQuery = null;
-        Cursor cursor = null;
-        mDb.beginTransaction();
-        try {
-            totalCount = countItems();
-            if (totalCount != 0) {
-                // bound the size requested, based on known count
-                firstLoadPosition = computeInitialLoadPosition(params, totalCount);
-                int firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount);
-
-                sqLiteQuery = getSQLiteQuery(firstLoadPosition, firstLoadSize);
-                cursor = mDb.query(sqLiteQuery);
-                List<T> rows = convertRows(cursor);
-                mDb.setTransactionSuccessful();
-                list = rows;
-            }
-        } finally {
-            if (cursor != null) {
-                cursor.close();
-            }
-            mDb.endTransaction();
-            if (sqLiteQuery != null) {
-                sqLiteQuery.release();
-            }
-        }
-
-        callback.onResult(list, firstLoadPosition, totalCount);
-    }
-
-    @Override
-    public void loadRange(@NonNull LoadRangeParams params,
-            @NonNull LoadRangeCallback<T> callback) {
-        callback.onResult(loadRange(params.startPosition, params.loadSize));
-    }
-
-    /**
-     * Return the rows from startPos to startPos + loadCount
-     *
-     * @hide
-     */
-    @SuppressWarnings("deprecation")
-    @NonNull
-    public List<T> loadRange(int startPosition, int loadCount) {
-        final RoomSQLiteQuery sqLiteQuery = getSQLiteQuery(startPosition, loadCount);
-        if (mInTransaction) {
-            mDb.beginTransaction();
-            Cursor cursor = null;
-            //noinspection TryFinallyCanBeTryWithResources
-            try {
-                cursor = mDb.query(sqLiteQuery);
-                List<T> rows = convertRows(cursor);
-                mDb.setTransactionSuccessful();
-                return rows;
-            } finally {
-                if (cursor != null) {
-                    cursor.close();
-                }
-                mDb.endTransaction();
-                sqLiteQuery.release();
-            }
-        } else {
-            Cursor cursor = mDb.query(sqLiteQuery);
-            //noinspection TryFinallyCanBeTryWithResources
-            try {
-                return convertRows(cursor);
-            } finally {
-                cursor.close();
-                sqLiteQuery.release();
-            }
-        }
-    }
-
-    private RoomSQLiteQuery getSQLiteQuery(int startPosition, int loadCount) {
-        final RoomSQLiteQuery sqLiteQuery = RoomSQLiteQuery.acquire(mLimitOffsetQuery,
-                mSourceQuery.getArgCount() + 2);
-        sqLiteQuery.copyArgumentsFrom(mSourceQuery);
-        sqLiteQuery.bindLong(sqLiteQuery.getArgCount() - 1, loadCount);
-        sqLiteQuery.bindLong(sqLiteQuery.getArgCount(), startPosition);
-        return sqLiteQuery;
-    }
-}
diff --git a/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.kt b/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.kt
new file mode 100644
index 0000000..f1203ae
--- /dev/null
+++ b/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.kt
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+@file:Suppress("DEPRECATION")
+
+package androidx.room.paging
+
+import android.database.Cursor
+import androidx.annotation.RestrictTo
+import androidx.paging.PositionalDataSource
+import androidx.room.InvalidationTracker
+import androidx.room.RoomDatabase
+import androidx.room.RoomSQLiteQuery
+import androidx.sqlite.db.SupportSQLiteQuery
+import java.util.concurrent.atomic.AtomicBoolean
+
+/**
+ * A simple data source implementation that uses Limit & Offset to page the query.
+ *
+ * This is NOT the most efficient way to do paging on SQLite. It is
+ * [recommended](http://www.sqlite.org/cvstrac/wiki?p=ScrollingCursor) to use an indexed
+ * ORDER BY statement but that requires a more complex API. This solution is technically equal to
+ * receiving a [Cursor] from a large query but avoids the need to manually manage it, and
+ * never returns inconsistent data if it is invalidated.
+ *
+ * This class is used for both Paging2 and Paging3 (via its compat API). When used with Paging3,
+ * it does lazy registration for observers to be suitable for initialization on the main thread
+ * whereas in Paging2, it will register observer eagerly to obey Paging2's strict Data Source
+ * rules. (Paging2 does not let data source to possibly return invalidated data).
+ *
+ * @property <T> Data type returned by the data source.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+abstract class LimitOffsetDataSource<T : Any> protected constructor(
+    private val db: RoomDatabase,
+    private val sourceQuery: RoomSQLiteQuery,
+    private val inTransaction: Boolean,
+    registerObserverImmediately: Boolean,
+    vararg tables: String
+) : PositionalDataSource<T>() {
+    private val countQuery = "SELECT COUNT(*) FROM ( " + sourceQuery.sql + " )"
+    private val limitOffsetQuery = "SELECT * FROM ( " + sourceQuery.sql + " ) LIMIT ? OFFSET ?"
+    private val observer: InvalidationTracker.Observer
+    private val registeredObserver = AtomicBoolean(false)
+
+    protected constructor(
+        db: RoomDatabase,
+        query: SupportSQLiteQuery,
+        inTransaction: Boolean,
+        vararg tables: String
+    ) : this(db, RoomSQLiteQuery.copyFrom(query), inTransaction, *tables)
+
+    protected constructor(
+        db: RoomDatabase,
+        query: SupportSQLiteQuery,
+        inTransaction: Boolean,
+        registerObserverImmediately: Boolean,
+        vararg tables: String
+    ) : this(
+        db, RoomSQLiteQuery.copyFrom(query), inTransaction, registerObserverImmediately, *tables
+    )
+
+    protected constructor(
+        db: RoomDatabase,
+        query: RoomSQLiteQuery,
+        inTransaction: Boolean,
+        vararg tables: String
+    ) : this(db, query, inTransaction, true, *tables)
+
+    init {
+        observer = object : InvalidationTracker.Observer(tables) {
+            override fun onInvalidated(tables: Set<String>) {
+                invalidate()
+            }
+        }
+        if (registerObserverImmediately) {
+            registerObserverIfNecessary()
+        }
+    }
+
+    private fun registerObserverIfNecessary() {
+        if (registeredObserver.compareAndSet(false, true)) {
+            db.invalidationTracker.addWeakObserver(observer)
+        }
+    }
+
+    /**
+     * Count number of rows query can return
+     *
+     * @hide
+     */
+    fun countItems(): Int {
+        registerObserverIfNecessary()
+        val sqLiteQuery = RoomSQLiteQuery.acquire(
+            countQuery,
+            sourceQuery.argCount
+        )
+        sqLiteQuery.copyArgumentsFrom(sourceQuery)
+        val cursor = db.query(sqLiteQuery)
+        return try {
+            if (cursor.moveToFirst()) {
+                cursor.getInt(0)
+            } else 0
+        } finally {
+            cursor.close()
+            sqLiteQuery.release()
+        }
+    }
+
+    override val isInvalid: Boolean
+        get() {
+        registerObserverIfNecessary()
+        db.invalidationTracker.refreshVersionsSync()
+        return super.isInvalid
+    }
+
+    protected abstract fun convertRows(cursor: Cursor): List<T>
+
+    @Suppress("deprecation")
+    override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<T>) {
+        registerObserverIfNecessary()
+        val onResultCaller: () -> Unit
+        db.beginTransaction()
+        try {
+            val totalCount = countItems()
+            if (totalCount != 0) {
+                // bound the size requested, based on known count
+                val firstLoadPosition = computeInitialLoadPosition(params, totalCount)
+                val firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount)
+                db.query(getSQLiteQuery(firstLoadPosition, firstLoadSize)).use { cursor ->
+                    val rows = convertRows(cursor)
+                    db.setTransactionSuccessful()
+                    onResultCaller = { callback.onResult(rows, firstLoadPosition, totalCount) }
+                }
+            } else {
+                onResultCaller = { callback.onResult(emptyList(), 0, totalCount) }
+            }
+        } finally {
+            db.endTransaction()
+        }
+        onResultCaller.invoke()
+    }
+
+    override fun loadRange(
+        params: LoadRangeParams,
+        callback: LoadRangeCallback<T>
+    ) {
+        callback.onResult(loadRange(params.startPosition, params.loadSize))
+    }
+
+    /**
+     * Return the rows from startPos to startPos + loadCount
+     *
+     * @hide
+     */
+    @Suppress("deprecation")
+    fun loadRange(startPosition: Int, loadCount: Int): List<T> {
+        val sqLiteQuery = getSQLiteQuery(startPosition, loadCount)
+        try {
+            if (inTransaction) {
+                db.beginTransaction()
+                try {
+                    db.query(sqLiteQuery).use { cursor ->
+                        val rows = convertRows(cursor)
+                        db.setTransactionSuccessful()
+                        return rows
+                    }
+                } finally {
+                    db.endTransaction()
+                }
+            } else {
+                db.query(sqLiteQuery).use { cursor ->
+                    return convertRows(cursor)
+                }
+            }
+        } finally {
+            sqLiteQuery.release()
+        }
+    }
+
+    private fun getSQLiteQuery(startPosition: Int, loadCount: Int): RoomSQLiteQuery {
+        val sqLiteQuery = RoomSQLiteQuery.acquire(
+            limitOffsetQuery,
+            sourceQuery.argCount + 2
+        )
+        sqLiteQuery.copyArgumentsFrom(sourceQuery)
+        sqLiteQuery.bindLong(sqLiteQuery.argCount - 1, loadCount.toLong())
+        sqLiteQuery.bindLong(sqLiteQuery.argCount, startPosition.toLong())
+        return sqLiteQuery
+    }
+}
\ No newline at end of file