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.features.privacyexplainer 18 19 import android.provider.MediaStore 20 import androidx.compose.runtime.Composable 21 import androidx.compose.ui.Modifier 22 import androidx.compose.ui.graphics.vector.ImageVector 23 import androidx.compose.ui.res.stringResource 24 import androidx.compose.ui.res.vectorResource 25 import com.android.photopicker.R 26 import com.android.photopicker.core.banners.Banner 27 import com.android.photopicker.core.banners.BannerDefinitions 28 import com.android.photopicker.core.banners.BannerState 29 import com.android.photopicker.core.configuration.LocalPhotopickerConfiguration 30 import com.android.photopicker.core.configuration.PhotopickerConfiguration 31 import com.android.photopicker.core.events.RegisteredEventClass 32 import com.android.photopicker.core.features.FeatureManager 33 import com.android.photopicker.core.features.FeatureRegistration 34 import com.android.photopicker.core.features.FeatureToken 35 import com.android.photopicker.core.features.Location 36 import com.android.photopicker.core.features.LocationParams 37 import com.android.photopicker.core.features.PhotopickerUiFeature 38 import com.android.photopicker.core.features.PrefetchResultKey 39 import com.android.photopicker.core.features.Priority 40 import com.android.photopicker.core.user.UserMonitor 41 import com.android.photopicker.data.DataService 42 import kotlinx.coroutines.Deferred 43 44 /** Feature class for the Photopicker's Privacy explainer. */ 45 class PrivacyExplainerFeature : PhotopickerUiFeature { 46 47 companion object Registration : FeatureRegistration { 48 override val TAG: String = "PhotopickerPrivacyExplainerFeature" 49 isEnablednull50 override fun isEnabled( 51 config: PhotopickerConfiguration, 52 deferredPrefetchResultsMap: Map<PrefetchResultKey, Deferred<Any?>>, 53 ) = true 54 55 override fun build(featureManager: FeatureManager) = PrivacyExplainerFeature() 56 } 57 58 override fun registerLocations(): List<Pair<Location, Int>> = emptyList() 59 60 override val token = FeatureToken.PRIVACY_EXPLAINER.token 61 62 override val ownedBanners: Set<BannerDefinitions> = setOf(BannerDefinitions.PRIVACY_EXPLAINER) 63 64 override suspend fun getBannerPriority( 65 banner: BannerDefinitions, 66 bannerState: BannerState?, 67 config: PhotopickerConfiguration, 68 dataService: DataService, 69 userMonitor: UserMonitor, 70 ): Int { 71 return when (banner) { 72 BannerDefinitions.PRIVACY_EXPLAINER -> { 73 if (bannerState?.dismissed == true) { 74 Priority.DISABLED.priority 75 } else { 76 Priority.HIGH.priority 77 } 78 } 79 else -> 80 throw IllegalArgumentException("$TAG cannot build the requested banner: $banner") 81 } 82 } 83 buildBannernull84 override suspend fun buildBanner( 85 banner: BannerDefinitions, 86 dataService: DataService, 87 userMonitor: UserMonitor, 88 ): Banner { 89 return when (banner) { 90 BannerDefinitions.PRIVACY_EXPLAINER -> 91 object : Banner { 92 override val declaration = BannerDefinitions.PRIVACY_EXPLAINER 93 94 @Composable override fun buildTitle(): String = "" 95 96 @Composable 97 override fun buildMessage(): String { 98 val config = LocalPhotopickerConfiguration.current 99 val genericAppName = 100 stringResource(R.string.photopicker_privacy_explainer_generic_app_name) 101 102 return when (config.action) { 103 MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP -> 104 stringResource( 105 R.string.photopicker_privacy_explainer_permission_mode, 106 config.callingPackageLabel ?: genericAppName, 107 ) 108 else -> 109 stringResource( 110 R.string.photopicker_privacy_explainer, 111 config.callingPackageLabel ?: genericAppName, 112 ) 113 } 114 } 115 116 @Composable 117 override fun getIcon(): ImageVector? { 118 return ImageVector.vectorResource(R.drawable.android_security_privacy) 119 } 120 } 121 else -> 122 throw IllegalArgumentException("$TAG cannot build the requested banner: $banner") 123 } 124 } 125 126 override val eventsConsumed = setOf<RegisteredEventClass>() 127 override val eventsProduced = setOf<RegisteredEventClass>() 128 129 @Composable composenull130 override fun compose(location: Location, modifier: Modifier, params: LocationParams) {} 131 } 132