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.net.Uri 21 import androidx.paging.PagingSource 22 import com.android.photopicker.data.model.CloudMediaProviderDetails 23 import com.android.photopicker.data.model.CollectionInfo 24 import com.android.photopicker.data.model.Group.Album 25 import com.android.photopicker.data.model.Media 26 import com.android.photopicker.data.model.MediaPageKey 27 import com.android.photopicker.data.model.Provider 28 import com.android.photopicker.data.paging.FakeInMemoryAlbumPagingSource 29 import com.android.photopicker.data.paging.FakeInMemoryMediaPagingSource 30 import kotlinx.coroutines.channels.Channel 31 import kotlinx.coroutines.channels.Channel.Factory.CONFLATED 32 import kotlinx.coroutines.flow.MutableStateFlow 33 import kotlinx.coroutines.flow.StateFlow 34 import kotlinx.coroutines.flow.update 35 36 /** 37 * A test implementation of [DataService] that provides fake, in memory paging sources that isolate 38 * device state from the test by providing fake data that is not backed by real media. 39 * 40 * Tests can override the size of data or the actual list of data itself by injecting the data 41 * service class into the test and changing the corresponding values. 42 */ 43 class TestDataServiceImpl() : DataService { 44 45 // Overrides for MediaPagingSource 46 var mediaSetSize: Int = FakeInMemoryMediaPagingSource.DEFAULT_SIZE 47 var mediaList: List<Media>? = null 48 49 // Overrides for AlbumPagingSource 50 var albumSetSize: Int = FakeInMemoryAlbumPagingSource.DEFAULT_SIZE 51 var albumsList: List<Album>? = null 52 53 // Overrides for AlbumMediaPagingSource 54 var albumMediaSetSize: Int = FakeInMemoryMediaPagingSource.DEFAULT_SIZE 55 var albumMediaList: List<Media>? = null 56 57 val _availableProviders = MutableStateFlow<List<Provider>>(emptyList()) 58 override val availableProviders: StateFlow<List<Provider>> = _availableProviders 59 60 var allowedProviders: List<Provider> = emptyList() 61 62 val collectionInfo: HashMap<Provider, CollectionInfo> = HashMap() 63 64 private var _preGrantsCount = MutableStateFlow(/* default value */ 0) 65 setAvailableProvidersnull66 fun setAvailableProviders(newProviders: List<Provider>) { 67 _availableProviders.update { newProviders } 68 } 69 70 override val activeContentResolver: StateFlow<ContentResolver> 71 get() = TODO("Not yet implemented") 72 73 override val preGrantedMediaCount: StateFlow<Int> = _preGrantsCount 74 override val preSelectionMediaData: StateFlow<List<Media>?> = 75 MutableStateFlow(ArrayList<Media>()) 76 setInitPreGrantsCountnull77 fun setInitPreGrantsCount(count: Int) { 78 _preGrantsCount.update { count } 79 } 80 albumMediaPagingSourcenull81 override fun albumMediaPagingSource(album: Album): PagingSource<MediaPageKey, Media> { 82 return albumMediaList?.let { FakeInMemoryMediaPagingSource(it) } 83 ?: FakeInMemoryMediaPagingSource(albumMediaSetSize) 84 } 85 albumPagingSourcenull86 override fun albumPagingSource(): PagingSource<MediaPageKey, Album> { 87 return albumsList?.let { FakeInMemoryAlbumPagingSource(it) } 88 ?: FakeInMemoryAlbumPagingSource(albumSetSize) 89 } 90 cloudMediaProviderDetailsnull91 override fun cloudMediaProviderDetails( 92 authority: String 93 ): StateFlow<CloudMediaProviderDetails?> = 94 throw NotImplementedError("This method is not implemented yet.") 95 96 override fun mediaPagingSource(): PagingSource<MediaPageKey, Media> { 97 return mediaList?.let { FakeInMemoryMediaPagingSource(it) } 98 ?: FakeInMemoryMediaPagingSource(mediaSetSize) 99 } 100 previewMediaPagingSourcenull101 override fun previewMediaPagingSource( 102 currentSelection: Set<Media>, 103 currentDeselection: Set<Media>, 104 ): PagingSource<MediaPageKey, Media> { 105 // re-using the media source, modify as per future test usage. 106 return mediaList?.let { FakeInMemoryMediaPagingSource(it) } 107 ?: FakeInMemoryMediaPagingSource(mediaSetSize) 108 } 109 refreshMedianull110 override suspend fun refreshMedia() = 111 throw NotImplementedError("This method is not implemented yet.") 112 113 override suspend fun refreshAlbumMedia(album: Album) = 114 throw NotImplementedError("This method is not implemented yet.") 115 116 override val disruptiveDataUpdateChannel = Channel<Unit>(CONFLATED) 117 118 suspend fun sendDisruptiveDataUpdateNotification() { 119 disruptiveDataUpdateChannel.send(Unit) 120 } 121 getCollectionInfonull122 override suspend fun getCollectionInfo(provider: Provider): CollectionInfo = 123 collectionInfo.getOrElse(provider, { CollectionInfo(provider.authority) }) 124 ensureProvidersnull125 override suspend fun ensureProviders() {} 126 getAllAllowedProvidersnull127 override fun getAllAllowedProviders(): List<Provider> = allowedProviders 128 129 override fun refreshPreGrantedItemsCount() { 130 // no_op 131 } 132 fetchMediaDataForUrisnull133 override fun fetchMediaDataForUris(uris: List<Uri>) { 134 // no-op 135 } 136 } 137