• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.ActivityTaskManager.INVALID_TASK_ID
20 import android.content.Context
21 import android.graphics.Bitmap
22 import android.graphics.Matrix
23 import android.graphics.Path
24 import android.graphics.drawable.AdaptiveIconDrawable
25 import android.graphics.drawable.ColorDrawable
26 import android.graphics.drawable.InsetDrawable
27 import android.util.PathParser
28 import android.util.TypedValue
29 import android.view.LayoutInflater
30 import android.widget.FrameLayout
31 import com.android.wm.shell.R
32 
33 class BubbleOverflow(
34     private val context: Context,
35     private val positioner: BubblePositioner
36 ) : BubbleViewProvider {
37 
38     private lateinit var bitmap: Bitmap
39     private lateinit var dotPath: Path
40 
41     private var dotColor = 0
42     private var showDot = false
43     private var overflowIconInset = 0
44 
45     private val inflater: LayoutInflater = LayoutInflater.from(context)
46     private var expandedView: BubbleExpandedView?
47     private var overflowBtn: BadgedImageView?
48 
49     init {
50         updateResources()
51         expandedView = null
52         overflowBtn = null
53     }
54 
55     /** Call before use and again if cleanUpExpandedState was called.  */
initializenull56     fun initialize(controller: BubbleController) {
57         createExpandedView()
58         getExpandedView()?.initialize(controller, controller.stackView, true /* isOverflow */)
59     }
60 
cleanUpExpandedStatenull61     fun cleanUpExpandedState() {
62         expandedView?.cleanUpExpandedState()
63         expandedView = null
64     }
65 
updatenull66     fun update() {
67         updateResources()
68         getExpandedView()?.applyThemeAttrs()
69         // Apply inset and new style to fresh icon drawable.
70         getIconView()?.setIconImageResource(R.drawable.bubble_ic_overflow_button)
71         updateBtnTheme()
72     }
73 
updateResourcesnull74     fun updateResources() {
75         overflowIconInset = context.resources.getDimensionPixelSize(
76                 R.dimen.bubble_overflow_icon_inset)
77         overflowBtn?.layoutParams = FrameLayout.LayoutParams(positioner.bubbleSize,
78                 positioner.bubbleSize)
79         expandedView?.updateDimensions()
80     }
81 
updateBtnThemenull82     private fun updateBtnTheme() {
83         val res = context.resources
84 
85         // Set overflow button accent color, dot color
86         val typedValue = TypedValue()
87         context.theme.resolveAttribute(com.android.internal.R.attr.colorAccentPrimary,
88                 typedValue, true)
89         val colorAccent = res.getColor(typedValue.resourceId, null)
90         dotColor = colorAccent
91 
92         val shapeColor = res.getColor(android.R.color.system_accent1_1000)
93         overflowBtn?.iconDrawable?.setTint(shapeColor)
94 
95         val iconFactory = BubbleIconFactory(context)
96 
97         // Update bitmap
98         val fg = InsetDrawable(overflowBtn?.iconDrawable, overflowIconInset)
99         bitmap = iconFactory.createBadgedIconBitmap(
100                 AdaptiveIconDrawable(ColorDrawable(colorAccent), fg)).icon
101 
102         // Update dot path
103         dotPath = PathParser.createPathFromPathData(
104             res.getString(com.android.internal.R.string.config_icon_mask))
105         val scale = iconFactory.normalizer.getScale(iconView!!.iconDrawable,
106             null /* outBounds */, null /* path */, null /* outMaskShape */)
107         val radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f
108         val matrix = Matrix()
109         matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
110             radius /* pivot y */)
111         dotPath.transform(matrix)
112 
113         // Attach BubbleOverflow to BadgedImageView
114         overflowBtn?.setRenderedBubble(this)
115         overflowBtn?.removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE)
116     }
117 
setVisiblenull118     fun setVisible(visible: Int) {
119         overflowBtn?.visibility = visible
120     }
121 
setShowDotnull122     fun setShowDot(show: Boolean) {
123         showDot = show
124         overflowBtn?.updateDotVisibility(true /* animate */)
125     }
126 
createExpandedViewnull127     fun createExpandedView(): BubbleExpandedView? {
128         expandedView = inflater.inflate(R.layout.bubble_expanded_view,
129                 null /* root */, false /* attachToRoot */) as BubbleExpandedView
130         expandedView?.applyThemeAttrs()
131         updateResources()
132         return expandedView
133     }
134 
getExpandedViewnull135     override fun getExpandedView(): BubbleExpandedView? {
136         return expandedView
137     }
138 
getDotColornull139     override fun getDotColor(): Int {
140         return dotColor
141     }
142 
getAppBadgenull143     override fun getAppBadge(): Bitmap? {
144         return null
145     }
146 
getRawAppBadgenull147     override fun getRawAppBadge(): Bitmap? {
148         return null
149     }
150 
getBubbleIconnull151     override fun getBubbleIcon(): Bitmap {
152         return bitmap
153     }
154 
showDotnull155     override fun showDot(): Boolean {
156         return showDot
157     }
158 
getDotPathnull159     override fun getDotPath(): Path? {
160         return dotPath
161     }
162 
setTaskViewVisibilitynull163     override fun setTaskViewVisibility(visible: Boolean) {
164         // Overflow does not have a TaskView.
165     }
166 
getIconViewnull167     override fun getIconView(): BadgedImageView? {
168         if (overflowBtn == null) {
169             overflowBtn = inflater.inflate(R.layout.bubble_overflow_button,
170                     null /* root */, false /* attachToRoot */) as BadgedImageView
171             overflowBtn?.initialize(positioner)
172             overflowBtn?.contentDescription = context.resources.getString(
173                     R.string.bubble_overflow_button_content_description)
174             val bubbleSize = positioner.bubbleSize
175             overflowBtn?.layoutParams = FrameLayout.LayoutParams(bubbleSize, bubbleSize)
176             updateBtnTheme()
177         }
178         return overflowBtn
179     }
180 
getKeynull181     override fun getKey(): String {
182         return KEY
183     }
184 
getTaskIdnull185     override fun getTaskId(): Int {
186         return if (expandedView != null) expandedView!!.taskId else INVALID_TASK_ID
187     }
188 
189     companion object {
190         const val KEY = "Overflow"
191     }
192 }