1 /* <lambda>null2 * Copyright (C) 2023 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 package com.android.wallpaper.picker.preview.ui.fragment 17 18 import android.app.Activity.RESULT_OK 19 import android.app.Flags.liveWallpaperContentHandling 20 import android.app.wallpaper.WallpaperDescription 21 import android.content.Context 22 import android.content.Intent 23 import android.os.Bundle 24 import android.view.LayoutInflater 25 import android.view.SurfaceView 26 import android.view.View 27 import android.view.ViewGroup 28 import android.widget.Button 29 import android.widget.Toolbar 30 import androidx.activity.result.contract.ActivityResultContract 31 import androidx.activity.result.contract.ActivityResultContracts 32 import androidx.core.view.isVisible 33 import androidx.fragment.app.activityViewModels 34 import androidx.navigation.fragment.findNavController 35 import com.android.wallpaper.R 36 import com.android.wallpaper.model.WallpaperInfoContract 37 import com.android.wallpaper.picker.AppbarFragment 38 import com.android.wallpaper.picker.data.LiveWallpaperData 39 import com.android.wallpaper.picker.data.WallpaperModel.LiveWallpaperModel 40 import com.android.wallpaper.picker.di.modules.MainDispatcher 41 import com.android.wallpaper.picker.preview.data.repository.WallpaperPreviewRepository 42 import com.android.wallpaper.picker.preview.ui.binder.FullWallpaperPreviewBinder 43 import com.android.wallpaper.picker.preview.ui.fragment.SmallPreviewFragment.Companion.ARG_EDIT_INTENT 44 import com.android.wallpaper.picker.preview.ui.viewmodel.PreviewActionsViewModel 45 import com.android.wallpaper.picker.preview.ui.viewmodel.WallpaperPreviewViewModel 46 import com.android.wallpaper.util.DisplayUtils 47 import com.android.wallpaper.util.wallpaperconnection.WallpaperConnectionUtils 48 import dagger.hilt.android.AndroidEntryPoint 49 import dagger.hilt.android.qualifiers.ApplicationContext 50 import javax.inject.Inject 51 import kotlinx.coroutines.CompletableDeferred 52 import kotlinx.coroutines.CoroutineScope 53 import kotlinx.coroutines.runBlocking 54 55 /** Shows full preview with an edit activity overlay. */ 56 @AndroidEntryPoint(AppbarFragment::class) 57 class CreativeEditPreviewFragment : Hilt_CreativeEditPreviewFragment() { 58 59 @Inject @ApplicationContext lateinit var appContext: Context 60 @Inject @MainDispatcher lateinit var mainScope: CoroutineScope 61 @Inject lateinit var displayUtils: DisplayUtils 62 @Inject lateinit var previewRepository: WallpaperPreviewRepository 63 @Inject lateinit var wallpaperConnectionUtils: WallpaperConnectionUtils 64 65 private lateinit var currentView: View 66 67 private val wallpaperPreviewViewModel by activityViewModels<WallpaperPreviewViewModel>() 68 69 override fun onCreateView( 70 inflater: LayoutInflater, 71 container: ViewGroup?, 72 savedInstanceState: Bundle?, 73 ): View? { 74 currentView = inflater.inflate(R.layout.fragment_full_preview, container, false) 75 setUpToolbar(currentView, true, true) 76 77 wallpaperPreviewViewModel.setDefaultFullPreviewConfigViewModel( 78 deviceDisplayType = displayUtils.getCurrentDisplayType(requireActivity()) 79 ) 80 81 currentView.requireViewById<Toolbar>(R.id.toolbar).isVisible = false 82 currentView.requireViewById<SurfaceView>(R.id.workspace_surface).isVisible = false 83 currentView.requireViewById<Button>(R.id.crop_wallpaper_button).isVisible = false 84 85 val intent = 86 arguments?.getParcelable(ARG_EDIT_INTENT, Intent::class.java) 87 ?: throw IllegalArgumentException( 88 "To render the first screen in the create new creative wallpaper flow, the intent for rendering the edit activity overlay can not be null." 89 ) 90 val isCreateNew = 91 intent.getBooleanExtra(PreviewActionsViewModel.EXTRA_KEY_IS_CREATE_NEW, false) 92 val creativeWallpaperEditActivityResult = 93 if (isCreateNew) { 94 requireActivity().activityResultRegistry.register( 95 CREATIVE_RESULT_REGISTRY, 96 ActivityResultContracts.StartActivityForResult(), 97 ) { 98 // Reset full preview view model to disable full to small preview transition 99 wallpaperPreviewViewModel.resetFullPreviewConfigViewModel() 100 wallpaperPreviewViewModel.isCurrentlyEditingCreativeWallpaper = false 101 // Callback when the overlaying edit activity is finished. Result code of 102 // RESULT_OK means the user clicked on the check button; RESULT_CANCELED 103 // otherwise. 104 if (it.resultCode == RESULT_OK) { 105 if (liveWallpaperContentHandling()) { 106 updatePreview(it.resultCode, it.data) 107 } 108 // When clicking on the check button, navigate to the small preview 109 // fragment. 110 findNavController() 111 .navigate( 112 R.id.action_creativeEditPreviewFragment_to_smallPreviewFragment 113 ) 114 } else { 115 activity?.finish() 116 } 117 } 118 } else { 119 requireActivity().activityResultRegistry.register( 120 CREATIVE_RESULT_REGISTRY, 121 object : ActivityResultContract<Intent, Int>() { 122 override fun createIntent(context: Context, input: Intent): Intent { 123 return input 124 } 125 126 override fun parseResult(resultCode: Int, intent: Intent?): Int { 127 wallpaperPreviewViewModel.isCurrentlyEditingCreativeWallpaper = false 128 if (liveWallpaperContentHandling()) { 129 updatePreview(resultCode, intent) 130 } 131 return resultCode 132 } 133 }, 134 ) { 135 // Reset full preview view model to disable full to small preview transition 136 wallpaperPreviewViewModel.resetFullPreviewConfigViewModel() 137 findNavController().popBackStack() 138 } 139 } 140 141 if (!wallpaperPreviewViewModel.isCurrentlyEditingCreativeWallpaper) { 142 wallpaperPreviewViewModel.isCurrentlyEditingCreativeWallpaper = true 143 creativeWallpaperEditActivityResult.launch(intent) 144 } 145 146 return currentView 147 } 148 149 // Updates the current preview using the WallpaperDescription returned with the Intent if any 150 private fun updatePreview(resultCode: Int, intent: Intent?) { 151 if (!liveWallpaperContentHandling()) return 152 if (resultCode == RESULT_OK) { 153 val component = 154 (previewRepository.wallpaperModel.value as LiveWallpaperModel) 155 .liveWallpaperData 156 .systemWallpaperInfo 157 .component 158 intent 159 ?.extras 160 ?.getParcelable( 161 WallpaperInfoContract.WALLPAPER_DESCRIPTION_CONTENT_HANDLING, 162 WallpaperDescription::class.java, 163 ) 164 ?.let { 165 if (it.component != null) { 166 it 167 } else { 168 // Live wallpaper services can't provide their component name, so 169 // set it here 170 it.toBuilder().setComponent(component).build() 171 } 172 } 173 ?.let { description -> 174 (previewRepository.wallpaperModel.value as LiveWallpaperModel).let { 175 val sourceLiveData = it.liveWallpaperData 176 val updatedLiveData = 177 LiveWallpaperData( 178 sourceLiveData.groupName, 179 sourceLiveData.systemWallpaperInfo, 180 sourceLiveData.isTitleVisible, 181 sourceLiveData.isApplied, 182 sourceLiveData.isEffectWallpaper, 183 sourceLiveData.effectNames, 184 sourceLiveData.contextDescription, 185 description, 186 ) 187 val updatedWallpaper = 188 LiveWallpaperModel( 189 it.commonWallpaperData, 190 updatedLiveData, 191 it.creativeWallpaperData, 192 it.internalLiveWallpaperData, 193 ) 194 runBlocking { previewRepository.setWallpaperModel(updatedWallpaper) } 195 } 196 } 197 } 198 } 199 200 override fun onViewStateRestored(savedInstanceState: Bundle?) { 201 super.onViewStateRestored(savedInstanceState) 202 203 FullWallpaperPreviewBinder.bind( 204 applicationContext = appContext, 205 view = currentView, 206 viewModel = wallpaperPreviewViewModel, 207 transition = null, 208 displayUtils = displayUtils, 209 mainScope = mainScope, 210 lifecycleOwner = viewLifecycleOwner, 211 savedInstanceState = savedInstanceState, 212 wallpaperConnectionUtils = wallpaperConnectionUtils, 213 isFirstBindingDeferred = CompletableDeferred(savedInstanceState == null), 214 ) 215 } 216 217 companion object { 218 private const val CREATIVE_RESULT_REGISTRY = "creative_result_registry" 219 } 220 } 221