1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor 18 19 import android.net.Uri 20 import com.android.intentresolver.contentpreview.UriMetadataReader 21 import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.PreviewSelectionsRepository 22 import com.android.intentresolver.contentpreview.payloadtoggle.domain.cursor.CursorResolver 23 import com.android.intentresolver.contentpreview.payloadtoggle.domain.cursor.PayloadToggle 24 import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.CursorRow 25 import com.android.intentresolver.contentpreview.payloadtoggle.shared.model.PreviewModel 26 import com.android.intentresolver.inject.ContentUris 27 import com.android.intentresolver.inject.FocusedItemIndex 28 import com.android.intentresolver.util.mapParallelIndexed 29 import javax.inject.Inject 30 import kotlinx.coroutines.async 31 import kotlinx.coroutines.coroutineScope 32 33 /** Populates the data displayed in Shareousel. */ 34 class FetchPreviewsInteractor 35 @Inject 36 constructor( 37 private val setCursorPreviews: SetCursorPreviewsInteractor, 38 private val selectionRepository: PreviewSelectionsRepository, 39 private val cursorInteractor: CursorPreviewsInteractor, 40 @FocusedItemIndex private val focusedItemIdx: Int, 41 @ContentUris private val selectedItems: List<@JvmSuppressWildcards Uri>, 42 private val uriMetadataReader: UriMetadataReader, 43 @PayloadToggle private val cursorResolver: CursorResolver<@JvmSuppressWildcards CursorRow?>, 44 ) { 45 suspend fun activate() = coroutineScope { 46 val cursor = async { cursorResolver.getCursor() } 47 val initialPreviewMap = getInitialPreviews() 48 selectionRepository.selections.value = initialPreviewMap.associateBy { it.uri } 49 setCursorPreviews.setPreviews( 50 previews = initialPreviewMap, 51 startIndex = focusedItemIdx, 52 hasMoreLeft = false, 53 hasMoreRight = false, 54 leftTriggerIndex = initialPreviewMap.indices.first(), 55 rightTriggerIndex = initialPreviewMap.indices.last(), 56 ) 57 cursorInteractor.launch(cursor.await() ?: return@coroutineScope, initialPreviewMap) 58 } 59 60 private suspend fun getInitialPreviews(): List<PreviewModel> = 61 selectedItems 62 // Restrict parallelism so as to not overload the metadata reader; anecdotally, too 63 // many parallel queries causes failures. 64 .mapParallelIndexed(parallelism = 4) { index, uri -> 65 val metadata = uriMetadataReader.getMetadata(uri) 66 PreviewModel( 67 uri = uri, 68 previewUri = metadata.previewUri, 69 mimeType = metadata.mimeType, 70 aspectRatio = 71 metadata.previewUri?.let { 72 uriMetadataReader.readPreviewSize(it).aspectRatioOrDefault(1f) 73 } ?: 1f, 74 order = when { 75 index < focusedItemIdx -> Int.MIN_VALUE + index 76 index == focusedItemIdx -> 0 77 else -> Int.MAX_VALUE - selectedItems.size + index + 1 78 } 79 ) 80 } 81 } 82