• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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.ContentResolver
20 import android.util.Log
21 import com.android.photopicker.data.model.CollectionInfo
22 import com.android.photopicker.data.model.Provider
23 import kotlin.collections.HashMap
24 import kotlin.collections.Map
25 import kotlinx.coroutines.flow.StateFlow
26 import kotlinx.coroutines.sync.Mutex
27 import kotlinx.coroutines.sync.withLock
28 
29 /**
30  * A Utility class that tracks and updates the currently known Collection Info for the given
31  * Providers.
32  */
33 class CollectionInfoState(
34     private val mediaProviderClient: MediaProviderClient,
35     private val activeContentResolver: StateFlow<ContentResolver>,
36     private val availableProviders: StateFlow<List<Provider>>
37 ) {
38     companion object {
39         private const val TAG = "CollectionInfoState"
40     }
41 
42     private val providerCollectionInfo: HashMap<Provider, CollectionInfo> = HashMap()
43     private val mutex = Mutex()
44 
45     /** Clear the collection info cache. */
clearnull46     suspend fun clear() {
47         mutex.withLock { providerCollectionInfo.clear() }
48     }
49 
50     /**
51      * Clears the current collection info cache and updates it with the collection info list
52      * provided in the parameters.
53      *
54      * @param collectionInfo List of the latest collection infos fetched from the data source.
55      */
updateCollectionInfonull56     suspend fun updateCollectionInfo(collectionInfo: List<CollectionInfo>) {
57         val availableProviderAuthorities: Map<String, Provider> =
58             availableProviders.value.map { it.authority to it }.toMap()
59         mutex.withLock {
60             providerCollectionInfo.clear()
61             collectionInfo.forEach {
62                 if (availableProviderAuthorities.containsKey(it.authority)) {
63                     providerCollectionInfo.put(
64                         availableProviderAuthorities.getValue(it.authority),
65                         it
66                     )
67                 }
68             }
69         }
70     }
71 
72     /**
73      * Tries to fetch the collection info of the given provider from cache. If it is not available,
74      * returns null.
75      */
getCachedCollectionInfonull76     suspend fun getCachedCollectionInfo(provider: Provider): CollectionInfo? {
77         mutex.withLock {
78             return providerCollectionInfo.get(provider)
79         }
80     }
81 
82     /**
83      * Tries to fetch the collection info of the given provider from cache. If it is not available,
84      * updates the collection info cache from the data source and again tries to fetch the
85      * collection info from the updated cache and returns it.
86      *
87      * If it is still not available, returns a default collection info object with only the
88      * authority set.
89      */
getCollectionInfonull90     suspend fun getCollectionInfo(provider: Provider): CollectionInfo {
91         var cachedCollectionInfo = getCachedCollectionInfo(provider)
92 
93         if (cachedCollectionInfo == null) {
94             try {
95                 val collectionInfos =
96                     mediaProviderClient.fetchCollectionInfo(activeContentResolver.value)
97                 updateCollectionInfo(collectionInfos)
98 
99                 cachedCollectionInfo = getCachedCollectionInfo(provider)
100             } catch (e: RuntimeException) {
101                 Log.e(TAG, "Could not refresh collection info cache", e)
102             }
103         }
104 
105         return cachedCollectionInfo ?: CollectionInfo(provider.authority)
106     }
107 }
108