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