blob: b7c4b7542d3784c2141dbce462a2fdd17c5d89b4 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.wallpaper.picker.preview.ui.binder
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.graphics.Point
import android.graphics.RenderEffect
import android.graphics.Shader
import android.view.View
import android.view.animation.Interpolator
import android.view.animation.PathInterpolator
import android.widget.ImageView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.wallpaper.model.wallpaper.ScreenOrientation
import com.android.wallpaper.picker.preview.ui.util.FullResImageViewUtil
import com.android.wallpaper.picker.preview.ui.viewmodel.FullResWallpaperViewModel
import com.android.wallpaper.picker.preview.ui.viewmodel.SmallPreviewConfigViewModel
import com.android.wallpaper.picker.preview.ui.viewmodel.StaticWallpaperPreviewViewModel
import com.android.wallpaper.util.WallpaperSurfaceCallback.LOW_RES_BITMAP_BLUR_RADIUS
import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import kotlinx.coroutines.launch
object StaticWallpaperPreviewBinder {
private val ALPHA_OUT: Interpolator = PathInterpolator(0f, 0f, 0.8f, 1f)
private const val CROSS_FADE_DURATION: Long = 200
fun bind(
fullResImageView: SubsamplingScaleImageView,
lowResImageView: ImageView,
viewModel: StaticWallpaperPreviewViewModel,
smallPreviewConfig: SmallPreviewConfigViewModel,
viewLifecycleOwner: LifecycleOwner,
) {
lowResImageView.initLowResImageView()
fullResImageView.initFullResImageView()
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch { viewModel.lowResBitmap.collect { lowResImageView.setImageBitmap(it) } }
launch {
viewModel.subsamplingScaleImageViewModel.collect {
fullResImageView.setFullResImage(it, smallPreviewConfig.screenOrientation)
crossFadeInFullResImageView(lowResImageView, fullResImageView)
}
}
}
}
}
private fun ImageView.initLowResImageView() {
setRenderEffect(
RenderEffect.createBlurEffect(
LOW_RES_BITMAP_BLUR_RADIUS,
LOW_RES_BITMAP_BLUR_RADIUS,
Shader.TileMode.CLAMP
)
)
}
private fun SubsamplingScaleImageView.initFullResImageView() {
setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM)
setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE)
}
private fun SubsamplingScaleImageView.setFullResImage(
viewModel: FullResWallpaperViewModel,
orientation: ScreenOrientation
) {
// Calculate the scale and the center point for the full res image
FullResImageViewUtil.getScaleAndCenter(
Point(measuredWidth, measuredHeight),
viewModel.rawWallpaperSize,
viewModel.cropHints?.get(orientation),
)
.let { scaleAndCenter ->
minScale = scaleAndCenter.minScale
maxScale = scaleAndCenter.maxScale
setScaleAndCenter(scaleAndCenter.defaultScale, scaleAndCenter.center)
}
// Set the full res image
setImage(ImageSource.bitmap(viewModel.rawWallpaperBitmap))
}
private fun crossFadeInFullResImageView(lowResImageView: ImageView, fullResImageView: View) {
fullResImageView.alpha = 0f
fullResImageView
.animate()
.alpha(1f)
.setInterpolator(ALPHA_OUT)
.setDuration(CROSS_FADE_DURATION)
.setListener(
object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
lowResImageView.setImageBitmap(null)
}
}
)
}
}