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 }