1 /* 2 * 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.google.android.setupdesign.view 18 19 import android.animation.Animator 20 import android.animation.Animator.AnimatorListener 21 import android.content.Context 22 import android.util.AttributeSet 23 import android.view.View 24 import androidx.annotation.StringRes 25 import androidx.core.view.AccessibilityDelegateCompat 26 import androidx.core.view.ViewCompat 27 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat 28 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat 29 import com.airbnb.lottie.LottieAnimationView 30 import com.google.android.setupcompat.util.Logger 31 32 /** A [LottieAnimationView] that take response to pause and resume animation when user clicks. */ 33 class SudLottieAnimationView 34 @JvmOverloads 35 constructor(context: Context, attrs: AttributeSet? = null) : 36 LottieAnimationView(context, attrs), 37 View.OnClickListener, 38 AnimatorListener, 39 Animator.AnimatorPauseListener { 40 var clickListener: OnClickListener? = null 41 42 private val actionInfoAnimatorPlaying = 43 buildAccessibilityAction(R.string.sud_lottie_animation_view_accessibility_action_pause) 44 45 private val actionInfoAnimatorPaused = 46 buildAccessibilityAction(R.string.sud_lottie_animation_view_accessibility_action_resume) 47 48 init { 49 super.setOnClickListener(this) 50 setContentDescription( 51 resources.getString(R.string.sud_lottie_animation_view_accessibility_description) 52 ) 53 addAnimatorListener(this) 54 addAnimatorPauseListener(this) 55 } 56 buildAccessibilityActionnull57 private fun buildAccessibilityAction(@StringRes stringId: Int) = 58 AccessibilityActionCompat( 59 AccessibilityNodeInfoCompat.ACTION_CLICK, 60 resources.getString(stringId), 61 ) 62 63 override fun setOnClickListener(listener: OnClickListener?) { 64 clickListener = listener 65 } 66 setAccessibilityDelegatenull67 private fun setAccessibilityDelegate( 68 accessibilityAction: AccessibilityNodeInfoCompat.AccessibilityActionCompat 69 ) { 70 ViewCompat.setAccessibilityDelegate( 71 this, 72 object : AccessibilityDelegateCompat() { 73 override fun onInitializeAccessibilityNodeInfo( 74 host: View, 75 info: AccessibilityNodeInfoCompat, 76 ) { 77 super.onInitializeAccessibilityNodeInfo(host, info) 78 info.addAction(accessibilityAction) 79 } 80 }, 81 ) 82 } 83 onClicknull84 override fun onClick(v: View) { 85 clickListener?.onClick(v) 86 if (isAnimating) { 87 pauseAnimation() 88 } else { 89 resumeAnimation() 90 } 91 } 92 onAnimationPausenull93 override fun onAnimationPause(animation: Animator) { 94 LOG.atInfo("onAnimationPause") 95 setAccessibilityDelegate(actionInfoAnimatorPaused) 96 } 97 onAnimationResumenull98 override fun onAnimationResume(animation: Animator) { 99 LOG.atInfo("onAnimationResume") 100 setAccessibilityDelegate(actionInfoAnimatorPlaying) 101 } 102 onAnimationStartnull103 override fun onAnimationStart(animation: Animator) { 104 LOG.atInfo("onAnimationStart") 105 setAccessibilityDelegate(actionInfoAnimatorPlaying) 106 } 107 onAnimationEndnull108 override fun onAnimationEnd(animation: Animator) { 109 // Do nothing 110 } 111 onAnimationCancelnull112 override fun onAnimationCancel(animation: Animator) { 113 // Do nothing 114 } 115 onAnimationRepeatnull116 override fun onAnimationRepeat(animation: Animator) { 117 // Do nothing 118 } 119 120 private companion object { 121 val LOG = Logger(SudLottieAnimationView::class.java) 122 } 123 } 124