• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.systemui.privacy
16 
17 import android.content.Context
18 import android.content.pm.ActivityInfo
19 import android.content.res.Configuration
20 import android.util.AttributeSet
21 import android.view.Gravity.CENTER_VERTICAL
22 import android.view.Gravity.END
23 import android.view.ViewGroup
24 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
25 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
26 import android.widget.FrameLayout
27 import android.widget.ImageView
28 import android.widget.LinearLayout
29 import com.android.settingslib.Utils
30 import com.android.systemui.res.R
31 import com.android.systemui.statusbar.events.BackgroundAnimatableView
32 
33 class OngoingPrivacyChip @JvmOverloads constructor(
34     context: Context,
35     attrs: AttributeSet? = null,
36     defStyleAttrs: Int = 0,
37     defStyleRes: Int = 0
38 ) : FrameLayout(context, attrs, defStyleAttrs, defStyleRes), BackgroundAnimatableView {
39 
40     private var configuration: Configuration
41     private var iconMargin = 0
42     private var iconSize = 0
43     private var iconColor = 0
44 
45     private val iconsContainer: LinearLayout
46     val launchableContentView
47         get() = iconsContainer
48 
49     var privacyList = emptyList<PrivacyItem>()
50         set(value) {
51             field = value
52             updateView(PrivacyChipBuilder(context, field))
53         }
54 
55     init {
56         inflate(context, R.layout.ongoing_privacy_chip, this)
57         id = R.id.privacy_chip
58         layoutParams = LayoutParams(WRAP_CONTENT, MATCH_PARENT, CENTER_VERTICAL or END)
59         clipChildren = true
60         clipToPadding = true
61         iconsContainer = requireViewById(R.id.icons_container)
62         configuration = Configuration(context.resources.configuration)
63         updateResources()
64     }
65 
66     /**
67      * When animating as a chip in the status bar, we want to animate the width for the container
68      * of the privacy items. We have to subtract our own top and left offset because the bounds
69      * come to us as absolute on-screen bounds, and `iconsContainer` is laid out relative to the
70      * frame layout's bounds.
71      */
72     override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
73         iconsContainer.setLeftTopRightBottom(l - left, t - top, r - left, b - top)
74     }
75 
76     // Should only be called if the builder icons or app changed
77     private fun updateView(builder: PrivacyChipBuilder) {
78         fun setIcons(chipBuilder: PrivacyChipBuilder, iconsContainer: ViewGroup) {
79             iconsContainer.removeAllViews()
80             chipBuilder.generateIcons().forEachIndexed { i, it ->
81                 it.mutate()
82                 it.setTint(iconColor)
83                 val image = ImageView(context).apply {
84                     setImageDrawable(it)
85                     scaleType = ImageView.ScaleType.CENTER_INSIDE
86                 }
87                 iconsContainer.addView(image, iconSize, iconSize)
88                 if (i != 0) {
89                     val lp = image.layoutParams as MarginLayoutParams
90                     lp.marginStart = iconMargin
91                     image.layoutParams = lp
92                 }
93             }
94         }
95 
96         if (!privacyList.isEmpty()) {
97             generateContentDescription(builder)
98             setIcons(builder, iconsContainer)
99         } else {
100             iconsContainer.removeAllViews()
101         }
102         requestLayout()
103     }
104 
105     private fun generateContentDescription(builder: PrivacyChipBuilder) {
106         val typesText = builder.joinTypes()
107         contentDescription = context.getString(
108                 R.string.ongoing_privacy_chip_content_multiple_apps, typesText)
109     }
110 
111     override fun onConfigurationChanged(newConfig: Configuration?) {
112         super.onConfigurationChanged(newConfig)
113         if (newConfig != null) {
114             val diff = newConfig.diff(configuration)
115             configuration.setTo(newConfig)
116             if (diff.and(ActivityInfo.CONFIG_DENSITY.or(ActivityInfo.CONFIG_FONT_SCALE)) != 0) {
117                 updateResources()
118             }
119         }
120     }
121 
122     private fun updateResources() {
123         iconMargin = context.resources
124                 .getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin)
125         iconSize = context.resources
126                 .getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size)
127         iconColor =
128                 Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary)
129 
130         val height = context.resources
131                 .getDimensionPixelSize(R.dimen.ongoing_appops_chip_height)
132         val padding = context.resources
133                 .getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding)
134         iconsContainer.layoutParams.height = height
135         iconsContainer.setPaddingRelative(padding, 0, padding, 0)
136         iconsContainer.background = context.getDrawable(R.drawable.statusbar_privacy_chip_bg)
137     }
138 }