1 /* 2 * Copyright (C) 2020 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.wm.shell.bubbles 18 19 import android.content.Context 20 import android.graphics.drawable.TransitionDrawable 21 import android.view.Gravity 22 import android.view.View 23 import android.view.ViewGroup 24 import android.widget.FrameLayout 25 import androidx.dynamicanimation.animation.DynamicAnimation 26 import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY 27 import androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW 28 import com.android.wm.shell.R 29 import com.android.wm.shell.animation.PhysicsAnimator 30 import com.android.wm.shell.common.DismissCircleView 31 32 /* 33 * View that handles interactions between DismissCircleView and BubbleStackView. 34 */ 35 class DismissView(context: Context) : FrameLayout(context) { 36 <lambda>null37 var circle = DismissCircleView(context).apply { 38 val targetSize: Int = context.resources.getDimensionPixelSize(R.dimen.dismiss_circle_size) 39 val newParams = LayoutParams(targetSize, targetSize) 40 newParams.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL 41 setLayoutParams(newParams) 42 setTranslationY( 43 resources.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height).toFloat()) 44 } 45 46 var isShowing = false 47 private val animator = PhysicsAnimator.getInstance(circle) 48 private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY) 49 private val DISMISS_SCRIM_FADE_MS = 200 50 init { 51 setLayoutParams(LayoutParams( 52 ViewGroup.LayoutParams.MATCH_PARENT, 53 resources.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height), 54 Gravity.BOTTOM)) 55 setPadding(0, 0, 0, resources.getDimensionPixelSize(R.dimen.floating_dismiss_bottom_margin)) 56 setClipToPadding(false) 57 setClipChildren(false) 58 setVisibility(View.INVISIBLE) 59 setBackgroundResource( 60 R.drawable.floating_dismiss_gradient_transition) 61 addView(circle) 62 } 63 64 /** 65 * Animates this view in. 66 */ shownull67 fun show() { 68 if (isShowing) return 69 isShowing = true 70 setVisibility(View.VISIBLE) 71 (getBackground() as TransitionDrawable).startTransition(DISMISS_SCRIM_FADE_MS) 72 animator.cancel() 73 animator 74 .spring(DynamicAnimation.TRANSLATION_Y, 0f, spring) 75 .start() 76 } 77 78 /** 79 * Animates this view out, as well as the circle that encircles the bubbles, if they 80 * were dragged into the target and encircled. 81 */ hidenull82 fun hide() { 83 if (!isShowing) return 84 isShowing = false 85 (getBackground() as TransitionDrawable).reverseTransition(DISMISS_SCRIM_FADE_MS) 86 animator 87 .spring(DynamicAnimation.TRANSLATION_Y, height.toFloat(), 88 spring) 89 .withEndActions({ setVisibility(View.INVISIBLE) }) 90 .start() 91 } 92 updateResourcesnull93 fun updateResources() { 94 val targetSize: Int = context.resources.getDimensionPixelSize(R.dimen.dismiss_circle_size) 95 circle.layoutParams.width = targetSize 96 circle.layoutParams.height = targetSize 97 circle.requestLayout() 98 } 99 }