diff options
| author | 2024-05-08 16:30:50 -0700 | |
|---|---|---|
| committer | 2024-05-10 14:12:30 -0700 | |
| commit | 78359ff22fae3934e513ba8c498af7e8a48992fc (patch) | |
| tree | 27495dec0a6ebef71ba0062f41e80eba41cc479e /java/src | |
| parent | 6b2802803702740646eb8f07bada2a4d2eec23b8 (diff) | |
Read image size from URI metadata
Read preview sizes from both URI metdata, and the additional content
proivider response (the latter gets priority, when present); use them to
set aspect ratio for the item preview.
If the size is missing, fallback to default aspect
ratio, 1:1.
Bug: 339679442
Test: atest IntentResolver-tests-unit
Test: manual testing with ShareTest app
Change-Id: Ia6072620a79b5df0b4b4bc9ebd11fb3961cb18a6
Diffstat (limited to 'java/src')
9 files changed, 58 insertions, 5 deletions
| diff --git a/java/src/com/android/intentresolver/contentpreview/FileInfo.kt b/java/src/com/android/intentresolver/contentpreview/FileInfo.kt index fe35365b..16a948df 100644 --- a/java/src/com/android/intentresolver/contentpreview/FileInfo.kt +++ b/java/src/com/android/intentresolver/contentpreview/FileInfo.kt @@ -22,8 +22,11 @@ class FileInfo private constructor(val uri: Uri, val previewUri: Uri?, val mimeT      @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)      class Builder(val uri: Uri) {          var previewUri: Uri? = null +            @Synchronized get              private set +          var mimeType: String? = null +            @Synchronized get              private set          @Synchronized fun withPreviewUri(uri: Uri?): Builder = apply { previewUri = uri } diff --git a/java/src/com/android/intentresolver/contentpreview/UriMetadataReader.kt b/java/src/com/android/intentresolver/contentpreview/UriMetadataReader.kt index b5361889..4e403c22 100644 --- a/java/src/com/android/intentresolver/contentpreview/UriMetadataReader.kt +++ b/java/src/com/android/intentresolver/contentpreview/UriMetadataReader.kt @@ -20,6 +20,8 @@ import android.content.ContentInterface  import android.media.MediaMetadata  import android.net.Uri  import android.provider.DocumentsContract +import android.provider.MediaStore.MediaColumns +import android.util.Size  import dagger.Binds  import dagger.Module  import dagger.Provides @@ -29,6 +31,7 @@ import javax.inject.Inject  fun interface UriMetadataReader {      fun getMetadata(uri: Uri): FileInfo +    fun readPreviewSize(uri: Uri): Size? = null  }  class UriMetadataReaderImpl @@ -56,6 +59,8 @@ constructor(          return builder.build()      } +    override fun readPreviewSize(uri: Uri): Size? = contentResolver.readPreviewSize(uri) +      private fun ContentInterface.supportsImageType(uri: Uri): Boolean =          getStreamTypesSafe(uri).firstOrNull { typeClassifier.isImageType(it) } != null @@ -73,6 +78,15 @@ constructor(                  null              }          } + +    private fun ContentInterface.readPreviewSize(uri: Uri): Size? = +        querySafe(uri, arrayOf(MediaColumns.WIDTH, MediaColumns.HEIGHT))?.use { cursor -> +            if (cursor.moveToFirst()) { +                cursor.readSize() +            } else { +                null +            } +        }  }  @Module 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 c7d29a72..97b087e1 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 @@ -242,10 +242,14 @@ constructor(      ): PreviewModel =          unclaimedRecords.remove(row.uri)?.second              ?: uriMetadataReader.getMetadata(row.uri).let { metadata -> +                val size = +                    row.previewSize +                        ?: metadata.previewUri?.let { uriMetadataReader.readPreviewSize(it) }                  PreviewModel(                      uri = row.uri,                      previewUri = metadata.previewUri,                      mimeType = metadata.mimeType, +                    aspectRatio = size.aspectRatioOrDefault(1f),                  )              } 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 c87504e1..80cd03d9 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 @@ -65,6 +65,11 @@ constructor(                      uri = uri,                      previewUri = metadata.previewUri,                      mimeType = metadata.mimeType, +                    aspectRatio = +                        metadata.previewUri?.let { +                            uriMetadataReader.readPreviewSize(it).aspectRatioOrDefault(1f) +                        } +                            ?: 1f,                  )              }              .toSet() diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SizeExtensions.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SizeExtensions.kt new file mode 100644 index 00000000..4cf10414 --- /dev/null +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SizeExtensions.kt @@ -0,0 +1,26 @@ +/* + * 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.interactor + +import android.util.Size + +internal fun Size?.aspectRatioOrDefault(default: Float): Float = +    when { +        this == null -> default +        width >= 0 && height > 0 -> width.toFloat() / height.toFloat() +        else -> default +    } diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/model/PreviewModel.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/model/PreviewModel.kt index 6b805391..85c70004 100644 --- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/model/PreviewModel.kt +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/model/PreviewModel.kt @@ -26,4 +26,5 @@ data class PreviewModel(      val previewUri: Uri? = uri,      /** Mimetype for the data [uri] points to. */      val mimeType: String?, +    val aspectRatio: Float = 1f,  ) diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt index 0a431c2a..85ad6ab3 100644 --- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt @@ -115,11 +115,9 @@ private fun ShareouselCard(viewModel: ShareouselPreviewViewModel) {      val scope = rememberCoroutineScope()      ShareouselCard(          image = { +            // TODO: max ratio is actually equal to the viewport ratio +            val aspectRatio = viewModel.aspectRatio.coerceIn(MIN_ASPECT_RATIO, MAX_ASPECT_RATIO)              bitmap?.let { bitmap -> -                val aspectRatio = -                    (bitmap.width.toFloat() / bitmap.height.toFloat()) -                        // TODO: max ratio is actually equal to the viewport ratio -                        .coerceIn(MIN_ASPECT_RATIO, MAX_ASPECT_RATIO)                  Image(                      bitmap = bitmap.asImageBitmap(),                      contentDescription = null, @@ -129,7 +127,7 @@ private fun ShareouselCard(viewModel: ShareouselPreviewViewModel) {              }                  ?: run {                      // TODO: look at ScrollableImagePreviewView.setLoading() -                    Box(modifier = Modifier.fillMaxHeight().aspectRatio(2f / 5f)) +                    Box(modifier = Modifier.fillMaxHeight().aspectRatio(aspectRatio))                  }          },          contentType = contentType, diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselPreviewViewModel.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselPreviewViewModel.kt index a245b3e3..9827fcd4 100644 --- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselPreviewViewModel.kt +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselPreviewViewModel.kt @@ -29,6 +29,7 @@ data class ShareouselPreviewViewModel(      val isSelected: Flow<Boolean>,      /** Sets whether this preview has been selected by the user. */      val setSelected: suspend (Boolean) -> Unit, +    val aspectRatio: Float,  )  /** Type of the content being previewed. */ diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt index cf118934..8b2dd818 100644 --- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt @@ -117,6 +117,7 @@ object ShareouselViewModelModule {                      contentType = flowOf(ContentType.Image), // TODO: convert from metadata                      isSelected = previewInteractor.isSelected,                      setSelected = previewInteractor::setSelected, +                    aspectRatio = key.aspectRatio,                  )              },          ) |