summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-05-10 19:10:10 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-05-10 19:10:10 +0000
commitf95a9b5c71a57d6daf9b75c58f543e7bc5debe12 (patch)
tree86a82af54afcfc17c39d78ab82779870ba7da655 /java
parenta80f46c7fe49ef00ebee256a89e291b420d9efa0 (diff)
parent90bddf71b63f5082c4ec9e697b0baaacb5f81ecd (diff)
Merge "Add support for preview size columns in the additional content query." into main
Diffstat (limited to 'java')
-rw-r--r--java/src/com/android/intentresolver/contentpreview/UriMetadataHelpers.kt22
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/cursor/PayloadToggleCursorResolver.kt27
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractor.kt44
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractor.kt3
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/CursorRow.kt23
5 files changed, 90 insertions, 29 deletions
diff --git a/java/src/com/android/intentresolver/contentpreview/UriMetadataHelpers.kt b/java/src/com/android/intentresolver/contentpreview/UriMetadataHelpers.kt
index 41638b1f..c532b9a5 100644
--- a/java/src/com/android/intentresolver/contentpreview/UriMetadataHelpers.kt
+++ b/java/src/com/android/intentresolver/contentpreview/UriMetadataHelpers.kt
@@ -23,9 +23,12 @@ import android.net.Uri
import android.provider.DocumentsContract
import android.provider.DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL
import android.provider.Downloads
+import android.provider.MediaStore.MediaColumns.HEIGHT
+import android.provider.MediaStore.MediaColumns.WIDTH
import android.provider.OpenableColumns
import android.text.TextUtils
import android.util.Log
+import android.util.Size
import com.android.intentresolver.measurements.runTracing
internal fun ContentInterface.getTypeSafe(uri: Uri): String? =
@@ -83,6 +86,25 @@ internal fun Cursor.readPreviewUri(): Uri? =
}
.getOrNull()
+fun Cursor.readSize(): Size? {
+ val widthIdx = columnNames.indexOf(WIDTH)
+ val heightIdx = columnNames.indexOf(HEIGHT)
+ return if (widthIdx < 0 || heightIdx < 0 || isNull(widthIdx) || isNull(heightIdx)) {
+ null
+ } else {
+ runCatching {
+ val width = getInt(widthIdx)
+ val height = getInt(heightIdx)
+ if (width >= 0 && height > 0) {
+ Size(width, height)
+ } else {
+ null
+ }
+ }
+ .getOrNull()
+ }
+}
+
internal fun Cursor.readTitle(): String =
runCatching {
var nameColIndex = -1
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/cursor/PayloadToggleCursorResolver.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/cursor/PayloadToggleCursorResolver.kt
index 3cf2af13..d9612696 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/cursor/PayloadToggleCursorResolver.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/cursor/PayloadToggleCursorResolver.kt
@@ -16,11 +16,14 @@
package com.android.intentresolver.contentpreview.payloadtoggle.domain.cursor
-import android.content.ContentResolver
+import android.content.ContentInterface
import android.content.Intent
+import android.database.Cursor
import android.net.Uri
import android.service.chooser.AdditionalContentContract.Columns.URI
import androidx.core.os.bundleOf
+import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.CursorRow
+import com.android.intentresolver.contentpreview.readSize
import com.android.intentresolver.inject.AdditionalContent
import com.android.intentresolver.inject.ChooserIntent
import com.android.intentresolver.util.cursor.CursorView
@@ -37,23 +40,31 @@ import javax.inject.Qualifier
class PayloadToggleCursorResolver
@Inject
constructor(
- private val contentResolver: ContentResolver,
+ private val contentResolver: ContentInterface,
@AdditionalContent private val cursorUri: Uri,
@ChooserIntent private val chooserIntent: Intent,
-) : CursorResolver<Uri?> {
- override suspend fun getCursor(): CursorView<Uri?>? = withCancellationSignal { signal ->
+) : CursorResolver<CursorRow?> {
+ override suspend fun getCursor(): CursorView<CursorRow?>? = withCancellationSignal { signal ->
runCatching {
contentResolver.query(
cursorUri,
- arrayOf(URI),
+ // TODO: uncomment to start using that data
+ arrayOf(URI /*, WIDTH, HEIGHT*/),
bundleOf(Intent.EXTRA_INTENT to chooserIntent),
signal,
)
}
.getOrNull()
- ?.viewBy {
- getString(0)?.let(Uri::parse)?.takeIf { it.authority != cursorUri.authority }
+ ?.viewBy { readUri()?.let { uri -> CursorRow(uri, readSize()) } }
+ }
+
+ private fun Cursor.readUri(): Uri? {
+ val uriIdx = columnNames.indexOf(URI)
+ if (uriIdx < 0) return null
+ return runCatching {
+ getString(uriIdx)?.let(Uri::parse)?.takeIf { it.authority != cursorUri.authority }
}
+ .getOrNull()
}
@Module
@@ -61,7 +72,7 @@ constructor(
interface Binding {
@Binds
@PayloadToggle
- fun bind(cursorResolver: PayloadToggleCursorResolver): CursorResolver<Uri?>
+ fun bind(cursorResolver: PayloadToggleCursorResolver): CursorResolver<CursorRow?>
}
}
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractor.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractor.kt
index f642f420..9d62ffa2 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractor.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractor.kt
@@ -21,6 +21,7 @@ package com.android.intentresolver.contentpreview.payloadtoggle.domain.interacto
import android.net.Uri
import android.service.chooser.AdditionalContentContract.CursorExtraKeys.POSITION
import com.android.intentresolver.contentpreview.UriMetadataReader
+import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.CursorRow
import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.LoadDirection
import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.LoadedWindow
import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.expandWindowLeft
@@ -64,7 +65,7 @@ constructor(
}
/** Start reading data from [uriCursor], and listen for requests to load more. */
- suspend fun launch(uriCursor: CursorView<Uri?>, initialPreviews: Iterable<PreviewModel>) {
+ suspend fun launch(uriCursor: CursorView<CursorRow?>, initialPreviews: Iterable<PreviewModel>) {
// Unclaimed values from the initial selection set. Entries will be removed as the cursor is
// read, and any still present are inserted at the start / end of the cursor when it is
// reached by the user.
@@ -73,7 +74,7 @@ constructor(
.asSequence()
.mapIndexed { i, m -> Pair(m.uri, Pair(i, m)) }
.toMap(ConcurrentHashMap())
- val pagedCursor: PagedCursor<Uri?> = uriCursor.paged(pageSize)
+ val pagedCursor: PagedCursor<CursorRow?> = uriCursor.paged(pageSize)
val startPosition = uriCursor.extras?.getInt(POSITION, 0) ?: 0
val state = readInitialState(pagedCursor, startPosition, unclaimedRecords)
processLoadRequests(state, pagedCursor, unclaimedRecords)
@@ -82,7 +83,7 @@ constructor(
/** Loop forever, processing any loading requests from the UI and updating local cache. */
private suspend fun processLoadRequests(
initialState: CursorWindow,
- pagedCursor: PagedCursor<Uri?>,
+ pagedCursor: PagedCursor<CursorRow?>,
unclaimedRecords: MutableUnclaimedMap,
) {
var state = initialState
@@ -108,7 +109,7 @@ constructor(
*/
private suspend fun Flow<LoadDirection?>.handleOneLoadRequest(
state: CursorWindow,
- pagedCursor: PagedCursor<Uri?>,
+ pagedCursor: PagedCursor<CursorRow?>,
unclaimedRecords: MutableUnclaimedMap,
): CursorWindow =
mapLatest { loadDirection ->
@@ -127,7 +128,7 @@ constructor(
* [startPosition].
*/
private suspend fun readInitialState(
- cursor: PagedCursor<Uri?>,
+ cursor: PagedCursor<CursorRow?>,
startPosition: Int,
unclaimedRecords: MutableUnclaimedMap,
): CursorWindow {
@@ -138,13 +139,13 @@ constructor(
if (!hasMoreLeft) {
// First read the initial page; this might claim some unclaimed Uris
val page =
- cursor.getPageUris(startPageIdx)?.toPage(mutableMapOf(), unclaimedRecords)
+ cursor.getPageRows(startPageIdx)?.toPage(mutableMapOf(), unclaimedRecords)
// Now that unclaimed Uris are up-to-date, add them first.
putAllUnclaimedLeft(unclaimedRecords)
// Then add the loaded page
page?.let(::putAll)
} else {
- cursor.getPageUris(startPageIdx)?.toPage(this, unclaimedRecords)
+ cursor.getPageRows(startPageIdx)?.toPage(this, unclaimedRecords)
}
// Finally, add the remainder of the unclaimed Uris.
if (!hasMoreRight) {
@@ -162,7 +163,7 @@ constructor(
}
private suspend fun CursorWindow.loadMoreRight(
- cursor: PagedCursor<Uri?>,
+ cursor: PagedCursor<CursorRow?>,
unclaimedRecords: MutableUnclaimedMap,
): CursorWindow {
val pageNum = lastLoadedPageNum + 1
@@ -181,7 +182,7 @@ constructor(
}
private suspend fun CursorWindow.loadMoreLeft(
- cursor: PagedCursor<Uri?>,
+ cursor: PagedCursor<CursorRow?>,
unclaimedRecords: MutableUnclaimedMap,
): CursorWindow {
val pageNum = firstLoadedPageNum - 1
@@ -207,7 +208,7 @@ constructor(
private suspend fun readPage(
state: CursorWindow,
- pagedCursor: PagedCursor<Uri?>,
+ pagedCursor: PagedCursor<CursorRow?>,
pageNum: Int,
unclaimedRecords: MutableUnclaimedMap,
): PreviewMap =
@@ -216,30 +217,33 @@ constructor(
private suspend fun <M : MutablePreviewMap> M.readAndPutPage(
state: CursorWindow,
- pagedCursor: PagedCursor<Uri?>,
+ pagedCursor: PagedCursor<CursorRow?>,
pageNum: Int,
unclaimedRecords: MutableUnclaimedMap,
): M =
pagedCursor
- .getPageUris(pageNum) // TODO: what do we do if the load fails?
- ?.filter { it !in state.merged }
+ .getPageRows(pageNum) // TODO: what do we do if the load fails?
+ ?.filter { it.uri !in state.merged }
?.toPage(this, unclaimedRecords)
?: this
- private suspend fun <M : MutablePreviewMap> Sequence<Uri>.toPage(
+ private suspend fun <M : MutablePreviewMap> Sequence<CursorRow>.toPage(
destination: M,
unclaimedRecords: MutableUnclaimedMap,
): M =
// Restrict parallelism so as to not overload the metadata reader; anecdotally, too
// many parallel queries causes failures.
- mapParallel(parallelism = 4) { uri -> createPreviewModel(uri, unclaimedRecords) }
+ mapParallel(parallelism = 4) { row -> createPreviewModel(row, unclaimedRecords) }
.associateByTo(destination) { it.uri }
- private fun createPreviewModel(uri: Uri, unclaimedRecords: MutableUnclaimedMap): PreviewModel =
- unclaimedRecords.remove(uri)?.second
+ private fun createPreviewModel(
+ row: CursorRow,
+ unclaimedRecords: MutableUnclaimedMap,
+ ): PreviewModel =
+ unclaimedRecords.remove(row.uri)?.second
?: PreviewModel(
- uri = uri,
- mimeType = uriMetadataReader.getMetadata(uri).mimeType,
+ uri = row.uri,
+ mimeType = uriMetadataReader.getMetadata(row.uri).mimeType,
)
private fun <M : MutablePreviewMap> M.putAllUnclaimedRight(unclaimed: UnclaimedMap): M =
@@ -275,7 +279,7 @@ private fun <M : MutablePreviewMap> M.putAllUnclaimedWhere(
.map { it.key to it.value.second }
.toMap(this)
-private fun PagedCursor<Uri?>.getPageUris(pageNum: Int): Sequence<Uri>? =
+private fun PagedCursor<CursorRow?>.getPageRows(pageNum: Int): Sequence<CursorRow>? =
get(pageNum)?.filterNotNull()
@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class PageSize
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractor.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractor.kt
index 9bc7ae63..927a3a84 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractor.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractor.kt
@@ -21,6 +21,7 @@ import com.android.intentresolver.contentpreview.UriMetadataReader
import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.PreviewSelectionsRepository
import com.android.intentresolver.contentpreview.payloadtoggle.domain.cursor.CursorResolver
import com.android.intentresolver.contentpreview.payloadtoggle.domain.cursor.PayloadToggle
+import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.CursorRow
import com.android.intentresolver.contentpreview.payloadtoggle.shared.model.PreviewModel
import com.android.intentresolver.inject.ContentUris
import com.android.intentresolver.inject.FocusedItemIndex
@@ -39,7 +40,7 @@ constructor(
@FocusedItemIndex private val focusedItemIdx: Int,
@ContentUris private val selectedItems: List<@JvmSuppressWildcards Uri>,
private val uriMetadataReader: UriMetadataReader,
- @PayloadToggle private val cursorResolver: CursorResolver<@JvmSuppressWildcards Uri?>,
+ @PayloadToggle private val cursorResolver: CursorResolver<@JvmSuppressWildcards CursorRow?>,
) {
suspend fun activate() = coroutineScope {
val cursor = async { cursorResolver.getCursor() }
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/CursorRow.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/CursorRow.kt
new file mode 100644
index 00000000..f1d856ac
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/CursorRow.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2024 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 com.android.intentresolver.contentpreview.payloadtoggle.domain.model
+
+import android.net.Uri
+import android.util.Size
+
+/** Represents additional content cursor row */
+data class CursorRow(val uri: Uri, val previewSize: Size?)