1 /* 2 * Copyright (C) 2021 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 package com.android.systemui.qs 17 18 import android.app.StatusBarManager 19 import android.content.Context 20 import android.content.res.Configuration 21 import android.graphics.PorterDuff 22 import android.graphics.drawable.Drawable 23 import android.graphics.drawable.RippleDrawable 24 import android.os.UserManager 25 import android.util.AttributeSet 26 import android.view.View 27 import android.widget.ImageView 28 import android.widget.LinearLayout 29 import com.android.settingslib.Utils 30 import com.android.settingslib.drawable.UserIconDrawable 31 import com.android.systemui.R 32 import com.android.systemui.statusbar.phone.MultiUserSwitch 33 import com.android.systemui.statusbar.phone.SettingsButton 34 35 /** 36 * Quick Settings bottom buttons placed in footer (aka utility bar) - always visible in expanded QS, 37 * in split shade mode visible also in collapsed state. May contain up to 5 buttons: settings, 38 * edit tiles, power off and conditionally: user switch and tuner 39 */ 40 class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) { 41 private lateinit var settingsContainer: View 42 private lateinit var settingsButton: SettingsButton 43 private lateinit var multiUserSwitch: MultiUserSwitch 44 private lateinit var multiUserAvatar: ImageView 45 private lateinit var tunerIcon: View 46 private lateinit var editTilesButton: View 47 48 private var settingsCogAnimator: TouchAnimator? = null 49 50 private var qsDisabled = false 51 private var expansionAmount = 0f 52 53 override fun onFinishInflate() { 54 super.onFinishInflate() 55 editTilesButton = requireViewById(android.R.id.edit) 56 settingsButton = findViewById(R.id.settings_button) 57 settingsContainer = findViewById(R.id.settings_button_container) 58 multiUserSwitch = findViewById(R.id.multi_user_switch) 59 multiUserAvatar = multiUserSwitch.findViewById(R.id.multi_user_avatar) 60 tunerIcon = requireViewById(R.id.tuner_icon) 61 62 // RenderThread is doing more harm than good when touching the header (to expand quick 63 // settings), so disable it for this view 64 if (settingsButton.background is RippleDrawable) { 65 (settingsButton.background as RippleDrawable).setForceSoftware(true) 66 } 67 updateResources() 68 importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES 69 } 70 71 fun updateAnimator(width: Int, numTiles: Int) { 72 val size = (mContext.resources.getDimensionPixelSize(R.dimen.qs_quick_tile_size) - 73 mContext.resources.getDimensionPixelSize(R.dimen.qs_tile_padding)) 74 val remaining = (width - numTiles * size) / (numTiles - 1) 75 val defSpace = mContext.resources.getDimensionPixelOffset(R.dimen.default_gear_space) 76 val translation = if (isLayoutRtl) (remaining - defSpace) else -(remaining - defSpace) 77 settingsCogAnimator = TouchAnimator.Builder() 78 .addFloat(settingsButton, "translationX", translation.toFloat(), 0f) 79 .addFloat(settingsButton, "rotation", -120f, 0f) 80 .build() 81 setExpansion(expansionAmount) 82 } 83 84 override fun onConfigurationChanged(newConfig: Configuration) { 85 super.onConfigurationChanged(newConfig) 86 updateResources() 87 } 88 89 override fun onRtlPropertiesChanged(layoutDirection: Int) { 90 super.onRtlPropertiesChanged(layoutDirection) 91 updateResources() 92 } 93 94 private fun updateResources() { 95 val tunerIconTranslation = mContext.resources 96 .getDimensionPixelOffset(R.dimen.qs_footer_tuner_icon_translation).toFloat() 97 tunerIcon.translationX = if (isLayoutRtl) (-tunerIconTranslation) else tunerIconTranslation 98 } 99 100 fun setKeyguardShowing() { 101 setExpansion(expansionAmount) 102 } 103 104 fun setExpansion(headerExpansionFraction: Float) { 105 expansionAmount = headerExpansionFraction 106 if (settingsCogAnimator != null) settingsCogAnimator!!.setPosition(headerExpansionFraction) 107 } 108 109 fun disable( 110 state2: Int, 111 isTunerEnabled: Boolean, 112 multiUserEnabled: Boolean 113 ) { 114 val disabled = state2 and StatusBarManager.DISABLE2_QUICK_SETTINGS != 0 115 if (disabled == qsDisabled) return 116 qsDisabled = disabled 117 updateEverything(isTunerEnabled, multiUserEnabled) 118 } 119 120 fun updateEverything( 121 isTunerEnabled: Boolean, 122 multiUserEnabled: Boolean 123 ) { 124 post { 125 updateVisibilities(isTunerEnabled, multiUserEnabled) 126 updateClickabilities() 127 isClickable = false 128 } 129 } 130 131 private fun updateClickabilities() { 132 multiUserSwitch.isClickable = multiUserSwitch.visibility == VISIBLE 133 editTilesButton.isClickable = editTilesButton.visibility == VISIBLE 134 settingsButton.isClickable = settingsButton.visibility == VISIBLE 135 } 136 137 private fun updateVisibilities( 138 isTunerEnabled: Boolean, 139 multiUserEnabled: Boolean 140 ) { 141 settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE 142 tunerIcon.visibility = if (isTunerEnabled) VISIBLE else INVISIBLE 143 multiUserSwitch.visibility = if (multiUserEnabled) VISIBLE else GONE 144 val isDemo = UserManager.isDeviceInDemoMode(context) 145 settingsButton.visibility = if (isDemo) INVISIBLE else VISIBLE 146 } 147 148 fun onUserInfoChanged(picture: Drawable?, isGuestUser: Boolean) { 149 var pictureToSet = picture 150 if (picture != null && isGuestUser && picture !is UserIconDrawable) { 151 pictureToSet = picture.constantState.newDrawable(resources).mutate() 152 pictureToSet.setColorFilter( 153 Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorForeground), 154 PorterDuff.Mode.SRC_IN) 155 } 156 multiUserAvatar.setImageDrawable(pictureToSet) 157 } 158 }