• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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