1 /* <lambda>null2 * Copyright (C) 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.wallpaper.picker.category.client 18 19 import android.content.ComponentName 20 import android.content.Context 21 import android.content.Intent 22 import android.content.pm.PackageManager 23 import androidx.annotation.XmlRes 24 import com.android.wallpaper.R 25 import com.android.wallpaper.model.Category 26 import com.android.wallpaper.model.DefaultWallpaperInfo 27 import com.android.wallpaper.model.ImageCategory 28 import com.android.wallpaper.model.LegacyPartnerWallpaperInfo 29 import com.android.wallpaper.model.LiveWallpaperInfo 30 import com.android.wallpaper.model.ThirdPartyAppCategory 31 import com.android.wallpaper.model.ThirdPartyLiveWallpaperCategory 32 import com.android.wallpaper.model.WallpaperCategory 33 import com.android.wallpaper.model.WallpaperInfo 34 import com.android.wallpaper.module.DefaultCategoryProvider 35 import com.android.wallpaper.module.PartnerProvider 36 import com.android.wallpaper.util.WallpaperParser 37 import dagger.hilt.android.qualifiers.ApplicationContext 38 import java.util.Locale 39 import javax.inject.Inject 40 import javax.inject.Singleton 41 42 /** 43 * This class is responsible for fetching wallpaper categories, listed as follows: 44 * 1. MyPhotos category that allows users to select custom photos 45 * 2. OnDevice category that are pre-loaded wallpapers on device (legacy way of pre-loading 46 * wallpapers, modern way is described below) 47 * 3. System categories on device (modern way of pre-loading wallpapers on device) 48 * 4. Third party app categories 49 */ 50 @Singleton 51 class DefaultWallpaperCategoryClientImpl 52 @Inject 53 constructor( 54 @ApplicationContext val context: Context, 55 private val partnerProvider: PartnerProvider, 56 private val wallpaperXMLParser: WallpaperParser, 57 private val liveWallpapersClient: LiveWallpapersClient 58 ) : DefaultWallpaperCategoryClient { 59 60 private var systemCategories: List<Category>? = null 61 62 /** This method is used for fetching and creating the MyPhotos category tile. */ 63 override suspend fun getMyPhotosCategory(): Category { 64 val imageCategory = ImageCategory( 65 context.getString(R.string.my_photos_category_title), 66 context.getString(R.string.image_wallpaper_collection_id), 67 PRIORITY_MY_PHOTOS_WHEN_CREATIVE_WALLPAPERS_ENABLED, 68 R.drawable.wallpaperpicker_emptystate, /* overlayIconResId */ 69 ) 70 return imageCategory 71 } 72 73 /** 74 * This method is used for fetching the on-device categories. This returns a category which 75 * incorporates both GEL and bundled wallpapers. 76 */ 77 override suspend fun getOnDeviceCategory(): Category? { 78 val onDeviceWallpapers = mutableListOf<WallpaperInfo?>() 79 80 if (!partnerProvider.shouldHideDefaultWallpaper()) { 81 val defaultWallpaperInfo = DefaultWallpaperInfo() 82 onDeviceWallpapers.add(defaultWallpaperInfo) 83 } 84 85 val partnerWallpaperInfos = wallpaperXMLParser.parsePartnerWallpaperInfoResources() 86 onDeviceWallpapers.addAll(partnerWallpaperInfos) 87 88 val legacyPartnerWallpaperInfos = LegacyPartnerWallpaperInfo.getAll(context) 89 onDeviceWallpapers.addAll(legacyPartnerWallpaperInfos) 90 91 val privateWallpapers = getPrivateDeviceWallpapers() 92 privateWallpapers?.let { onDeviceWallpapers.addAll(it) } 93 94 return onDeviceWallpapers 95 .takeIf { it.isNotEmpty() } 96 ?.let { 97 val wallpaperCategory = 98 WallpaperCategory( 99 context.getString(R.string.on_device_wallpapers_category_title), 100 context.getString(R.string.on_device_wallpaper_collection_id), 101 it, 102 PRIORITY_ON_DEVICE 103 ) 104 wallpaperCategory 105 } 106 } 107 108 override suspend fun getThirdPartyCategory 109 (excludedPackageNames: List<String>): List<Category> { 110 val pickWallpaperIntent = Intent(Intent.ACTION_SET_WALLPAPER) 111 val apps = context.packageManager.queryIntentActivities(pickWallpaperIntent, 0) 112 113 // Get list of image picker intents. 114 val pickImageIntent = Intent(Intent.ACTION_GET_CONTENT) 115 pickImageIntent.setType("image/*") 116 val imagePickerActivities = context.packageManager.queryIntentActivities(pickImageIntent, 0) 117 118 val thirdPartyApps = apps.mapNotNull { info -> 119 val itemComponentName = ComponentName(info.activityInfo.packageName, info.activityInfo.name) 120 val itemPackageName = itemComponentName.packageName 121 122 if (excludedPackageNames.contains(itemPackageName) || 123 itemPackageName == context.packageName || 124 imagePickerActivities.any { it.activityInfo.packageName == itemPackageName }) { 125 null 126 } else { 127 ThirdPartyAppCategory( 128 context, 129 info, context.getString(R.string.third_party_app_wallpaper_collection_id) + "_" + itemPackageName, 130 PRIORITY_THIRD_PARTY 131 ) 132 } 133 } 134 135 return thirdPartyApps 136 } 137 138 override suspend fun getThirdPartyLiveWallpaperCategory 139 (excludedPackageNames: Set<String>): List<Category> { 140 if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_LIVE_WALLPAPER)) { 141 val liveWallpapers = liveWallpapersClient.getAll(excludedPackageNames) 142 if (liveWallpapers.isNotEmpty()) { 143 val thirdPartyLiveWallpaperCategory = ThirdPartyLiveWallpaperCategory( 144 context.getString(R.string.live_wallpapers_category_title), 145 context.getString(R.string.live_wallpaper_collection_id), liveWallpapers, 146 PRIORITY_LIVE, 147 getExcludedLiveWallpaperPackageNames() + excludedPackageNames) 148 return listOf(thirdPartyLiveWallpaperCategory) 149 } 150 } 151 return listOf() 152 } 153 154 override fun getExcludedLiveWallpaperPackageNames(): Set<String> { 155 val excluded = mutableSetOf<String>() 156 systemCategories?.forEach { category -> 157 if (category is WallpaperCategory) { 158 category.wallpapers.forEach { wallpaperInfo -> 159 if (wallpaperInfo is LiveWallpaperInfo) { 160 excluded.add(wallpaperInfo.wallpaperComponent.packageName) 161 } 162 } 163 } 164 } 165 return excluded 166 } 167 168 override fun getExcludedThirdPartyPackageNames(): List<String> { 169 return listOf( 170 LAUNCHER_PACKAGE, // Legacy launcher 171 LIVE_WALLPAPER_PICKER) // Live wallpaper picker 172 } 173 174 /** This method is used for fetching the system categories. */ 175 override suspend fun getSystemCategories(): List<Category> { 176 systemCategories?.let { return it } 177 val partnerRes = partnerProvider.resources 178 val packageName = partnerProvider.packageName 179 if (partnerRes == null || packageName == null) { 180 return listOf() 181 } 182 183 @XmlRes val wallpapersResId = 184 partnerRes.getIdentifier(PartnerProvider.WALLPAPER_RES_ID, "xml", packageName) 185 // Certain partner configurations don't have wallpapers provided, so need to check; 186 // return early if they are missing. 187 if (wallpapersResId == 0) { 188 return listOf() 189 } 190 191 systemCategories = 192 wallpaperXMLParser.parseSystemCategories(partnerRes.getXml(wallpapersResId)) 193 return systemCategories as List<Category> 194 } 195 196 private fun getLocale(): Locale { 197 return context.resources.configuration.locales.get(0) 198 } 199 200 private fun getPrivateDeviceWallpapers(): Collection<WallpaperInfo?>? { 201 return null 202 } 203 204 companion object { 205 private const val TAG = "DefaultWallpaperCategoryClientImpl" 206 private const val LAUNCHER_PACKAGE = "com.android.launcher" 207 private const val LIVE_WALLPAPER_PICKER = "com.android.wallpaper.livepicker" 208 209 /** 210 * Relative category priorities. Lower numbers correspond to higher priorities (i.e., should 211 * appear higher in the categories list). 212 */ 213 private const val PRIORITY_MY_PHOTOS_WHEN_CREATIVE_WALLPAPERS_ENABLED = 51 214 private const val PRIORITY_ON_DEVICE = 200 215 private const val PRIORITY_LIVE = 300 216 private const val PRIORITY_THIRD_PARTY = 400 217 } 218 } 219