• 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         getExpandedView()?.initialize(controller, controller.stackView, true /* isOverflow */)
58     }
59 
cleanUpExpandedStatenull60     fun cleanUpExpandedState() {
61         expandedView?.cleanUpExpandedState()
62         expandedView = null
63     }
64 
updatenull65     fun update() {
66         updateResources()
67         getExpandedView()?.applyThemeAttrs()
68         // Apply inset and new style to fresh icon drawable.
69         getIconView()?.setImageResource(R.drawable.bubble_ic_overflow_button)
70         updateBtnTheme()
71     }
72 
updateResourcesnull73     fun updateResources() {
74         overflowIconInset = context.resources.getDimensionPixelSize(
75                 R.dimen.bubble_overflow_icon_inset)
76         overflowBtn?.layoutParams = FrameLayout.LayoutParams(positioner.bubbleSize,
77                 positioner.bubbleSize)
78         expandedView?.updateDimensions()
79     }
80 
updateBtnThemenull81     private fun updateBtnTheme() {
82         val res = context.resources
83 
84         // Set overflow button accent color, dot color
85         val typedValue = TypedValue()
86         context.theme.resolveAttribute(com.android.internal.R.attr.colorAccentPrimary,
87                 typedValue, true)
88         val colorAccent = res.getColor(typedValue.resourceId, null)
89         dotColor = colorAccent
90 
91         val shapeColor = res.getColor(android.R.color.system_accent1_1000)
92         overflowBtn?.drawable?.setTint(shapeColor)
93 
94         val iconFactory = BubbleIconFactory(context)
95 
96         // Update bitmap
97         val fg = InsetDrawable(overflowBtn?.drawable, overflowIconInset)
98         bitmap = iconFactory.createBadgedIconBitmap(AdaptiveIconDrawable(
99                 ColorDrawable(colorAccent), fg),
100             null /* user */, true /* shrinkNonAdaptiveIcons */).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!!.drawable,
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 
getExpandedViewnull127     override fun getExpandedView(): BubbleExpandedView? {
128         if (expandedView == null) {
129             expandedView = inflater.inflate(R.layout.bubble_expanded_view,
130                     null /* root */, false /* attachToRoot */) as BubbleExpandedView
131             expandedView?.applyThemeAttrs()
132             updateResources()
133         }
134         return expandedView
135     }
136 
getDotColornull137     override fun getDotColor(): Int {
138         return dotColor
139     }
140 
getAppBadgenull141     override fun getAppBadge(): Bitmap? {
142         return null
143     }
144 
getBubbleIconnull145     override fun getBubbleIcon(): Bitmap {
146         return bitmap
147     }
148 
showDotnull149     override fun showDot(): Boolean {
150         return showDot
151     }
152 
getDotPathnull153     override fun getDotPath(): Path? {
154         return dotPath
155     }
156 
setExpandedContentAlphanull157     override fun setExpandedContentAlpha(alpha: Float) {
158         expandedView?.alpha = alpha
159     }
160 
setTaskViewVisibilitynull161     override fun setTaskViewVisibility(visible: Boolean) {
162         // Overflow does not have a TaskView.
163     }
164 
getIconViewnull165     override fun getIconView(): BadgedImageView? {
166         if (overflowBtn == null) {
167             overflowBtn = inflater.inflate(R.layout.bubble_overflow_button,
168                     null /* root */, false /* attachToRoot */) as BadgedImageView
169             overflowBtn?.initialize(positioner)
170             overflowBtn?.contentDescription = context.resources.getString(
171                     R.string.bubble_overflow_button_content_description)
172             val bubbleSize = positioner.bubbleSize
173             overflowBtn?.layoutParams = FrameLayout.LayoutParams(bubbleSize, bubbleSize)
174             updateBtnTheme()
175         }
176         return overflowBtn
177     }
178 
getKeynull179     override fun getKey(): String {
180         return KEY
181     }
182 
getTaskIdnull183     override fun getTaskId(): Int {
184         return if (expandedView != null) expandedView!!.taskId else INVALID_TASK_ID
185     }
186 
187     companion object {
188         const val KEY = "Overflow"
189     }
190 }