1 /* <lambda>null2 * Copyright (C) 2025 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.module 18 19 import android.app.WallpaperInfo 20 import android.app.wallpaper.WallpaperDescription 21 import android.content.Context 22 import android.net.Uri 23 import android.os.Parcel 24 import android.os.RemoteException 25 import android.util.Log 26 import android.util.Pair 27 import androidx.annotation.VisibleForTesting 28 import androidx.core.database.getBlobOrNull 29 import com.android.wallpaper.model.CreativeCategory 30 import com.android.wallpaper.model.WallpaperInfoContract 31 import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination 32 import javax.inject.Inject 33 34 class DefaultCreativeHelper @Inject constructor() : CreativeHelper { 35 override fun getCreativePreviewUri( 36 context: Context, 37 info: WallpaperInfo, 38 destination: WallpaperDestination, 39 ): Uri? { 40 return getCurrentCreativeData(context, info, destination).first 41 } 42 43 override fun getCreativeDescription( 44 context: Context, 45 info: WallpaperInfo, 46 destination: WallpaperDestination, 47 ): WallpaperDescription? { 48 return getCurrentCreativeData(context, info, destination).second 49 } 50 51 companion object { 52 private const val TAG = "DefaultCreativeHelper" 53 54 // Queries a live wallpaper for its preview Uri and description, and returns them if they 55 // exist. 56 @VisibleForTesting 57 private fun getCurrentCreativeData( 58 context: Context, 59 info: WallpaperInfo, 60 destination: WallpaperDestination, 61 ): Pair<Uri?, WallpaperDescription?> { 62 val metaData = info.serviceInfo.metaData 63 val defaultValue: Pair<Uri?, WallpaperDescription?> = Pair(null, null) 64 val uri = 65 metaData.getString(CreativeCategory.KEY_WALLPAPER_SAVE_CREATIVE_WALLPAPER_CURRENT) 66 ?: return defaultValue 67 68 val currentAssetsUri = Uri.parse(uri) 69 if (currentAssetsUri.authority == null) return defaultValue 70 context.contentResolver 71 .acquireContentProviderClient(currentAssetsUri.authority!!) 72 ?.use { client -> 73 try { 74 client.query(currentAssetsUri, null, null, null, null)?.use { cursor -> 75 if (!cursor.moveToFirst()) return defaultValue 76 do { 77 val dest = 78 cursor.getString( 79 cursor.getColumnIndex( 80 WallpaperInfoContract.CURRENT_DESTINATION 81 ) 82 ) 83 val previewUri = 84 Uri.parse( 85 cursor.getString( 86 cursor.getColumnIndex( 87 WallpaperInfoContract.CURRENT_CONFIG_PREVIEW_URI 88 ) 89 ) 90 ) 91 val descriptionIndex = 92 cursor.getColumnIndex( 93 WallpaperInfoContract.CURRENT_DESCRIPITION 94 ) 95 val description = 96 if (descriptionIndex >= 0) { 97 cursor.getBlobOrNull(descriptionIndex)?.let { 98 descriptionFromBytes(it).let { desc -> 99 if (desc.component == null) { 100 desc 101 .toBuilder() 102 .setComponent(info.component) 103 .build() 104 } else desc 105 } 106 } 107 } else null 108 if ( 109 (dest == "home" && destination == WallpaperDestination.HOME) || 110 (dest == "lock" && destination == WallpaperDestination.LOCK) 111 ) { 112 return Pair(previewUri, description) 113 } 114 } while (cursor.moveToNext()) 115 } 116 } catch (e: RemoteException) { 117 Log.w(TAG, "Error retrieving current creative asset id: ", e) 118 } 119 } 120 121 return defaultValue 122 } 123 124 private fun descriptionFromBytes(bytes: ByteArray): WallpaperDescription { 125 val parcel = Parcel.obtain() 126 parcel.unmarshall(bytes, 0, bytes.size) 127 parcel.setDataPosition(0) 128 val desc = WallpaperDescription.CREATOR.createFromParcel(parcel) 129 parcel.recycle() 130 return desc 131 } 132 } 133 } 134