1 /* <lambda>null2 * Copyright 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.photopicker.data 18 19 import android.content.Context 20 import android.util.Log 21 import com.android.photopicker.core.user.UserMonitor 22 import com.android.photopicker.core.user.UserProfile 23 import com.android.photopicker.features.search.model.GlobalSearchState 24 import com.android.photopicker.features.search.model.GlobalSearchStateInfo 25 import com.android.photopicker.util.mapOfDeferredWithTimeout 26 import kotlinx.coroutines.CoroutineDispatcher 27 import kotlinx.coroutines.CoroutineScope 28 import kotlinx.coroutines.Deferred 29 30 /** Implementation of [PrefetchDataService] that typically fetches data from MediaProvider. */ 31 class PrefetchDataServiceImpl( 32 val mediaProviderClient: MediaProviderClient, 33 val userMonitor: UserMonitor, 34 val context: Context, 35 val dispatcher: CoroutineDispatcher, 36 val scope: CoroutineScope, 37 ) : PrefetchDataService { 38 39 override suspend fun getGlobalSearchState(): GlobalSearchState { 40 // Create a map of user id to lambda that fetches search provider authorities for that 41 // user. 42 val inputMap: Map<Int, suspend (MediaProviderClient) -> Any?> = 43 userMonitor.userStatus.value.allProfiles 44 .map { profile: UserProfile -> 45 val lambda: suspend (MediaProviderClient) -> Any? = 46 { mediaProviderClient: MediaProviderClient -> 47 mediaProviderClient.fetchSearchProviderAuthorities( 48 context 49 .createPackageContextAsUser( 50 context.packageName, /* flags */ 51 0, 52 profile.handle, 53 ) 54 .contentResolver 55 ) 56 } 57 profile.identifier to lambda 58 } 59 .toMap() 60 61 // Get a map of user id to Deferred task that fetches search provider authorities for 62 // that user in parallel with a timeout. 63 val deferredMap: Map<Int, Deferred<Any?>> = 64 mapOfDeferredWithTimeout( 65 inputMap = inputMap, 66 input = mediaProviderClient, 67 timeoutMillis = 150L, 68 backgroundScope = scope, 69 dispatcher = dispatcher, 70 ) 71 72 // Await all the deferred tasks and create a map of user id to the search provider 73 // authorities. 74 @Suppress("UNCHECKED_CAST") 75 val globalSearchProviders: Map<Int, List<String>?> = 76 deferredMap 77 .map { 78 val searchProviders: Any? = it.value.await() 79 it.key to if (searchProviders is List<*>?) searchProviders else null 80 } 81 .toMap() as Map<Int, List<String>?> 82 83 val globalSearchStateInfo = 84 GlobalSearchStateInfo( 85 globalSearchProviders, 86 userMonitor.userStatus.value.activeUserProfile.identifier, 87 ) 88 Log.d( 89 PrefetchDataService.TAG, 90 "Global search providers available are $globalSearchProviders. " + 91 "Search state is $globalSearchStateInfo.state", 92 ) 93 return globalSearchStateInfo.state 94 } 95 } 96