• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.launcher3.apppairs
18 
19 import android.content.Context
20 import android.graphics.Canvas
21 import android.graphics.Rect
22 import android.util.AttributeSet
23 import android.view.Gravity
24 import android.widget.FrameLayout
25 import androidx.annotation.OpenForTesting
26 import com.android.launcher3.DeviceProfile
27 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener
28 import com.android.launcher3.icons.BitmapInfo
29 import com.android.launcher3.model.data.AppPairInfo
30 import com.android.launcher3.views.ActivityContext
31 
32 /**
33  * A FrameLayout marking the area on an [AppPairIcon] where the visual icon will be drawn. One of
34  * two child UI elements on an [AppPairIcon], along with a BubbleTextView holding the text title.
35  */
36 @OpenForTesting
37 open class AppPairIconGraphic
38 @JvmOverloads
39 constructor(context: Context, attrs: AttributeSet? = null) :
40     FrameLayout(context, attrs), OnDeviceProfileChangeListener {
41     private val TAG = "AppPairIconGraphic"
42 
43     companion object {
44         /** Composes a drawable for this icon, consisting of a background and 2 app icons. */
45         @JvmStatic
composeDrawablenull46         fun composeDrawable(
47             appPairInfo: AppPairInfo,
48             p: AppPairIconDrawingParams,
49         ): AppPairIconDrawable {
50             // Generate new icons, using themed flag since the icon is drawn on homescreen
51             val appIcon1 = appPairInfo.getFirstApp().newIcon(p.context, BitmapInfo.FLAG_THEMED)
52             val appIcon2 = appPairInfo.getSecondApp().newIcon(p.context, BitmapInfo.FLAG_THEMED)
53             appIcon1.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt())
54             appIcon2.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt())
55 
56             // If icons are unlaunchable due to screen size, manually override disabled appearance.
57             // (otherwise, leave disabled state alone; icons will naturally inherit the app's state)
58             val (isApp1Launchable, isApp2Launchable) = appPairInfo.isLaunchable(p.context)
59             if (!isApp1Launchable) appIcon1.setIsDisabled(true)
60             if (!isApp2Launchable) appIcon2.setIsDisabled(true)
61 
62             // Create icon drawable.
63             val fullIconDrawable = AppPairIconDrawable(p, appIcon1, appIcon2)
64             fullIconDrawable.setBounds(0, 0, p.iconSize, p.iconSize)
65 
66             return fullIconDrawable
67         }
68     }
69 
70     private lateinit var parentIcon: AppPairIcon
71     private lateinit var drawParams: AppPairIconDrawingParams
72     lateinit var drawable: AppPairIconDrawable
73 
initnull74     fun init(icon: AppPairIcon, container: Int) {
75         parentIcon = icon
76         drawParams = AppPairIconDrawingParams(context, container)
77         drawable = composeDrawable(icon.info, drawParams)
78 
79         // Center the drawable area in the larger icon canvas
80         val lp: LayoutParams = layoutParams as LayoutParams
81         lp.gravity = Gravity.CENTER_HORIZONTAL
82         lp.height = drawParams.iconSize
83         lp.width = drawParams.iconSize
84         layoutParams = lp
85     }
86 
onAttachedToWindownull87     override fun onAttachedToWindow() {
88         super.onAttachedToWindow()
89         getActivityContext().addOnDeviceProfileChangeListener(this)
90     }
91 
onDetachedFromWindownull92     override fun onDetachedFromWindow() {
93         super.onDetachedFromWindow()
94         getActivityContext().removeOnDeviceProfileChangeListener(this)
95     }
96 
getActivityContextnull97     private fun getActivityContext(): ActivityContext {
98         return ActivityContext.lookupContext(context)
99     }
100 
101     /** When device profile changes, update orientation */
onDeviceProfileChangednull102     override fun onDeviceProfileChanged(dp: DeviceProfile) {
103         drawParams.updateOrientation(dp)
104         redraw()
105     }
106 
107     /**
108      * When the icon is temporary moved to a different colored surface, update the background color.
109      * Calling this method with [null] reverts the icon back to its default color.
110      */
onTemporaryContainerChangenull111     fun onTemporaryContainerChange(newContainer: Int?) {
112         drawParams.updateBgColor(newContainer ?: parentIcon.container)
113         redraw()
114     }
115 
116     /**
117      * Gets this icon graphic's visual bounds, with respect to the parent icon's coordinate system.
118      */
getIconBoundsnull119     fun getIconBounds(outBounds: Rect) {
120         outBounds.set(0, 0, drawParams.backgroundSize.toInt(), drawParams.backgroundSize.toInt())
121         outBounds.offset(
122             // x-coordinate in parent's coordinate system
123             ((parentIcon.width - drawParams.backgroundSize) / 2).toInt(),
124             // y-coordinate in parent's coordinate system
125             (parentIcon.paddingTop + drawParams.standardIconPadding + drawParams.outerPadding)
126                 .toInt(),
127         )
128     }
129 
130     /** Updates the icon drawable and redraws it */
redrawnull131     fun redraw() {
132         drawable = composeDrawable(parentIcon.info, drawParams)
133         invalidate()
134     }
135 
dispatchDrawnull136     override fun dispatchDraw(canvas: Canvas) {
137         super.dispatchDraw(canvas)
138         drawable.draw(canvas)
139     }
140 
141     /** Sets the scale of the icon background while hovered. */
setHoverScalenull142     fun setHoverScale(scale: Float) {
143         drawParams.hoverScale = scale
144         redraw()
145     }
146 
147     /** Gets the scale of the icon background while hovered. */
getHoverScalenull148     fun getHoverScale(): Float {
149         return drawParams.hoverScale
150     }
151 }
152