1 /*
2  * 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 
17 package com.android.quickstep.views
18 
19 import android.content.Context
20 import android.graphics.Canvas
21 import android.graphics.Rect
22 import android.graphics.RectF
23 import android.graphics.drawable.Drawable
24 import android.util.AttributeSet
25 import android.view.View
26 import android.view.ViewGroup
27 import android.widget.FrameLayout
28 import com.android.launcher3.R
29 import com.android.launcher3.Utilities
30 import com.android.launcher3.statemanager.StatefulActivity
31 import com.android.launcher3.views.BaseDragLayer
32 
33 /**
34  * A temporary View that is created for the app pair launch animation and destroyed at the end.
35  * Matches the size & position of the app pair icon graphic, and expands to full screen.
36  */
37 class FloatingAppPairView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
38     FrameLayout(context, attrs) {
39     companion object {
getFloatingAppPairViewnull40         fun getFloatingAppPairView(
41             launcher: StatefulActivity<*>,
42             originalView: View,
43             appIcon1: Drawable?,
44             appIcon2: Drawable?,
45             dividerPos: Int
46         ): FloatingAppPairView {
47             val dragLayer: ViewGroup = launcher.getDragLayer()
48             val floatingView =
49                 launcher
50                     .getLayoutInflater()
51                     .inflate(R.layout.floating_app_pair_view, dragLayer, false)
52                     as FloatingAppPairView
53             floatingView.init(launcher, originalView, appIcon1, appIcon2, dividerPos)
54             dragLayer.addView(floatingView, dragLayer.childCount - 1)
55             return floatingView
56         }
57     }
58 
59     val startingPosition = RectF()
60     private lateinit var background: FloatingAppPairBackground
61     var progress = 0f
62 
63     /** Initializes the view, copying the bounds and location of the original icon view. */
initnull64     fun init(
65         launcher: StatefulActivity<*>,
66         originalView: View,
67         appIcon1: Drawable?,
68         appIcon2: Drawable?,
69         dividerPos: Int
70     ) {
71         val viewBounds = Rect(0, 0, originalView.width, originalView.height)
72         Utilities.getBoundsForViewInDragLayer(
73             launcher.getDragLayer(),
74             originalView,
75             viewBounds,
76             false /* ignoreTransform */,
77             null /* recycle */,
78             startingPosition
79         )
80         val lp =
81             BaseDragLayer.LayoutParams(
82                 Math.round(startingPosition.width()),
83                 Math.round(startingPosition.height())
84             )
85         lp.ignoreInsets = true
86 
87         // Position the floating view exactly on top of the original
88         lp.topMargin = Math.round(startingPosition.top)
89         lp.leftMargin = Math.round(startingPosition.left)
90 
91         layout(lp.leftMargin, lp.topMargin, lp.leftMargin + lp.width, lp.topMargin + lp.height)
92         layoutParams = lp
93 
94         // Prepare to draw app pair icon background
95         background = if (appIcon1 == null || appIcon2 == null) {
96             val iconToAnimate = appIcon1 ?: appIcon2
97             checkNotNull(iconToAnimate)
98             FloatingFullscreenAppPairBackground(context, this, iconToAnimate,
99                     dividerPos)
100         } else {
101             FloatingAppPairBackground(context, this, appIcon1, appIcon2, dividerPos)
102         }
103         background.setBounds(0, 0, lp.width, lp.height)
104     }
105 
dispatchDrawnull106     override fun dispatchDraw(canvas: Canvas) {
107         super.dispatchDraw(canvas)
108         background.draw(canvas)
109     }
110 }
111