Loading packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml 0 → 100644 +104 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ** Copyright 2021, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. --> <com.android.systemui.qs.QSFooterActionsView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/qs_footer_actions_container" android:layout_width="match_parent" android:layout_height="48dp" android:gravity="center_vertical"> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@android:id/edit" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:clickable="true" android:clipToPadding="false" android:contentDescription="@string/accessibility_quick_settings_edit" android:focusable="true" android:padding="@dimen/qs_footer_icon_padding" android:src="@*android:drawable/ic_mode_edit" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:focusable="true"> <ImageView android:id="@+id/multi_user_avatar" android:layout_width="@dimen/multi_user_avatar_expanded_size" android:layout_height="@dimen/multi_user_avatar_expanded_size" android:layout_gravity="center" android:scaleType="centerInside" /> </com.android.systemui.statusbar.phone.MultiUserSwitch> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/pm_lite" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:clickable="true" android:clipToPadding="false" android:focusable="true" android:padding="@dimen/qs_footer_icon_padding" android:src="@*android:drawable/ic_lock_power_off" android:contentDescription="@string/accessibility_quick_settings_power_menu" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.AlphaOptimizedFrameLayout android:id="@+id/settings_button_container" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:background="@drawable/qs_footer_action_chip_background" android:layout_weight="1" android:clipChildren="false" android:clipToPadding="false"> <com.android.systemui.statusbar.phone.SettingsButton android:id="@+id/settings_button" android:layout_width="match_parent" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_gravity="center" android:contentDescription="@string/accessibility_quick_settings_settings" android:background="@drawable/qs_footer_action_chip_background_borderless" android:padding="@dimen/qs_footer_icon_padding" android:scaleType="centerInside" android:src="@drawable/ic_settings" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/tuner_icon" android:layout_width="8dp" android:layout_height="8dp" android:layout_gravity="center_horizontal|bottom" android:layout_marginBottom="@dimen/qs_footer_icon_padding" android:src="@drawable/tuner" android:tint="?android:attr/textColorTertiary" android:visibility="invisible" /> </com.android.systemui.statusbar.AlphaOptimizedFrameLayout> </com.android.systemui.qs.QSFooterActionsView> No newline at end of file packages/SystemUI/res/layout/qs_footer_impl.xml +1 −86 Original line number Diff line number Diff line Loading @@ -68,93 +68,8 @@ </LinearLayout> <LinearLayout android:id="@+id/qs_footer_actions_container" android:layout_width="match_parent" android:layout_height="48dp" android:gravity="center_vertical"> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@android:id/edit" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:clickable="true" android:clipToPadding="false" android:contentDescription="@string/accessibility_quick_settings_edit" android:focusable="true" android:padding="@dimen/qs_footer_icon_padding" android:src="@*android:drawable/ic_mode_edit" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:focusable="true"> <include layout="@layout/qs_footer_actions"/> <ImageView android:id="@+id/multi_user_avatar" android:layout_width="@dimen/multi_user_avatar_expanded_size" android:layout_height="@dimen/multi_user_avatar_expanded_size" android:layout_gravity="center" android:scaleType="centerInside" /> </com.android.systemui.statusbar.phone.MultiUserSwitch> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/pm_lite" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:clickable="true" android:clipToPadding="false" android:focusable="true" android:padding="@dimen/qs_footer_icon_padding" android:src="@*android:drawable/ic_lock_power_off" android:contentDescription="@string/accessibility_quick_settings_power_menu" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.AlphaOptimizedFrameLayout android:id="@+id/settings_button_container" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:background="@drawable/qs_footer_action_chip_background" android:layout_weight="1" android:clipChildren="false" android:clipToPadding="false"> <com.android.systemui.statusbar.phone.SettingsButton android:id="@+id/settings_button" android:layout_width="match_parent" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_gravity="center" android:contentDescription="@string/accessibility_quick_settings_settings" android:background="@drawable/qs_footer_action_chip_background_borderless" android:padding="@dimen/qs_footer_icon_padding" android:scaleType="centerInside" android:src="@drawable/ic_settings" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/tuner_icon" android:layout_width="8dp" android:layout_height="8dp" android:layout_gravity="center_horizontal|bottom" android:layout_marginBottom="@dimen/qs_footer_icon_padding" android:src="@drawable/tuner" android:tint="?android:attr/textColorTertiary" android:visibility="invisible" /> </com.android.systemui.statusbar.AlphaOptimizedFrameLayout> </LinearLayout> </LinearLayout> </com.android.systemui.qs.QSFooterView> packages/SystemUI/src/com/android/systemui/qs/QSFooter.java +0 −5 Original line number Diff line number Diff line Loading @@ -34,11 +34,6 @@ public interface QSFooter { */ void setExpanded(boolean expanded); /** * Returns the full height of the footer. */ int getHeight(); /** * Sets the percentage amount that the quick settings has been expanded. * Loading packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt 0 → 100644 +167 −0 Original line number Diff line number Diff line package com.android.systemui.qs import android.content.Intent import android.os.UserManager import android.provider.Settings import android.view.View import android.widget.Toast import androidx.annotation.VisibleForTesting import com.android.internal.jank.InteractionJankMonitor import com.android.internal.logging.MetricsLogger import com.android.internal.logging.UiEventLogger import com.android.internal.logging.nano.MetricsProto import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.globalactions.GlobalActionsDialogLite import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED import com.android.systemui.statusbar.phone.MultiUserSwitchController import com.android.systemui.statusbar.phone.SettingsButton import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.UserInfoController import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener import com.android.systemui.tuner.TunerService import com.android.systemui.util.ViewController import javax.inject.Inject import javax.inject.Named class QSFooterActionsController @Inject constructor( view: QSFooterActionsView, private val qsPanelController: QSPanelController, private val activityStarter: ActivityStarter, private val userManager: UserManager, private val userInfoController: UserInfoController, private val multiUserSwitchController: MultiUserSwitchController, private val deviceProvisionedController: DeviceProvisionedController, private val falsingManager: FalsingManager, private val metricsLogger: MetricsLogger, private val tunerService: TunerService, private val globalActionsDialog: GlobalActionsDialogLite, private val uiEventLogger: UiEventLogger, @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean ) : ViewController<QSFooterActionsView>(view) { private var listening: Boolean = false var expanded = false set(value) { field = value mView.setExpanded(value, isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled) } private val settingsButton: SettingsButton = view.findViewById(R.id.settings_button) private val settingsButtonContainer: View? = view.findViewById(R.id.settings_button_container) private val editButton: View = view.findViewById(android.R.id.edit) private val powerMenuLite: View = view.findViewById(R.id.pm_lite) private val onUserInfoChangedListener = OnUserInfoChangedListener { _, picture, _ -> val isGuestUser: Boolean = userManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser()) mView.onUserInfoChanged(picture, isGuestUser) } private val onClickListener = View.OnClickListener { v -> // Don't do anything until views are unhidden. Don't do anything if the tap looks // suspicious. if (!expanded || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return@OnClickListener } if (v === settingsButton) { if (!deviceProvisionedController.isCurrentUserSetup) { // If user isn't setup just unlock the device and dump them back at SUW. activityStarter.postQSRunnableDismissingKeyguard {} return@OnClickListener } metricsLogger.action( if (expanded) MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH else MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH) if (settingsButton.isTunerClick) { activityStarter.postQSRunnableDismissingKeyguard { if (isTunerEnabled()) { tunerService.showResetRequest { // Relaunch settings so that the tuner disappears. startSettingsActivity() } } else { Toast.makeText(context, R.string.tuner_toast, Toast.LENGTH_LONG).show() tunerService.isTunerEnabled = true } startSettingsActivity() } } else { startSettingsActivity() } } else if (v === powerMenuLite) { uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS) globalActionsDialog.showOrHideDialog(false, true) } } override fun onInit() { multiUserSwitchController.init() } private fun startSettingsActivity() { val animationController = settingsButtonContainer?.let { ActivityLaunchAnimator.Controller.fromView( it, InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON) } activityStarter.startActivity(Intent(Settings.ACTION_SETTINGS), true /* dismissShade */, animationController) } @VisibleForTesting public override fun onViewAttached() { if (showPMLiteButton) { powerMenuLite.visibility = View.VISIBLE powerMenuLite.setOnClickListener(onClickListener) } else { powerMenuLite.visibility = View.GONE } settingsButton.setOnClickListener(onClickListener) editButton.setOnClickListener(View.OnClickListener { view: View? -> if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return@OnClickListener } activityStarter.postQSRunnableDismissingKeyguard { qsPanelController.showEdit(view) } }) mView.updateEverything(isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled) } override fun onViewDetached() { setListening(false) } fun setListening(listening: Boolean) { if (this.listening == listening) { return } this.listening = listening if (this.listening) { userInfoController.addCallback(onUserInfoChangedListener) } else { userInfoController.removeCallback(onUserInfoChangedListener) } } fun disable(state2: Int) { mView.disable(state2, isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled) } fun setExpansion(headerExpansionFraction: Float) { mView.setExpansion(headerExpansionFraction) } fun updateAnimator(width: Int, numTiles: Int) { mView.updateAnimator(width, numTiles) } fun setKeyguardShowing() { mView.setKeyguardShowing() } private fun isTunerEnabled() = tunerService.isTunerEnabled } No newline at end of file packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt 0 → 100644 +159 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs import android.app.StatusBarManager import android.content.Context import android.content.res.Configuration import android.graphics.PorterDuff import android.graphics.drawable.Drawable import android.graphics.drawable.RippleDrawable import android.os.UserManager import android.util.AttributeSet import android.view.View import android.widget.ImageView import android.widget.LinearLayout import com.android.settingslib.Utils import com.android.settingslib.drawable.UserIconDrawable import com.android.systemui.R import com.android.systemui.statusbar.phone.MultiUserSwitch import com.android.systemui.statusbar.phone.SettingsButton /** * Quick Settings bottom buttons placed in footer (aka utility bar) - always visible in expanded QS, * in split shade mode visible also in collapsed state. May contain up to 5 buttons: settings, * edit tiles, power off and conditionally: user switch and tuner */ class QSFooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) { private lateinit var settingsContainer: View private lateinit var settingsButton: SettingsButton private lateinit var multiUserSwitch: MultiUserSwitch private lateinit var multiUserAvatar: ImageView private lateinit var tunerIcon: View private lateinit var editTilesButton: View private var settingsCogAnimator: TouchAnimator? = null private var qsDisabled = false private var isExpanded = false private var expansionAmount = 0f override fun onFinishInflate() { super.onFinishInflate() editTilesButton = requireViewById(android.R.id.edit) settingsButton = findViewById(R.id.settings_button) settingsContainer = findViewById(R.id.settings_button_container) multiUserSwitch = findViewById(R.id.multi_user_switch) multiUserAvatar = multiUserSwitch.findViewById(R.id.multi_user_avatar) tunerIcon = requireViewById(R.id.tuner_icon) // RenderThread is doing more harm than good when touching the header (to expand quick // settings), so disable it for this view if (settingsButton.background is RippleDrawable) { (settingsButton.background as RippleDrawable).setForceSoftware(true) } updateResources() importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES } fun updateAnimator(width: Int, numTiles: Int) { val size = (mContext.resources.getDimensionPixelSize(R.dimen.qs_quick_tile_size) - mContext.resources.getDimensionPixelSize(R.dimen.qs_tile_padding)) val remaining = (width - numTiles * size) / (numTiles - 1) val defSpace = mContext.resources.getDimensionPixelOffset(R.dimen.default_gear_space) val translation = if (isLayoutRtl) (remaining - defSpace) else -(remaining - defSpace) settingsCogAnimator = TouchAnimator.Builder() .addFloat(settingsButton, "translationX", translation.toFloat(), 0f) .addFloat(settingsButton, "rotation", -120f, 0f) .build() setExpansion(expansionAmount) } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) updateResources() } override fun onRtlPropertiesChanged(layoutDirection: Int) { super.onRtlPropertiesChanged(layoutDirection) updateResources() } private fun updateResources() { val tunerIconTranslation = mContext.resources .getDimensionPixelOffset(R.dimen.qs_footer_tuner_icon_translation).toFloat() tunerIcon.translationX = if (isLayoutRtl) (-tunerIconTranslation) else tunerIconTranslation } fun setKeyguardShowing() { setExpansion(expansionAmount) } fun setExpanded(expanded: Boolean, isTunerEnabled: Boolean, multiUserEnabled: Boolean) { if (isExpanded == expanded) return isExpanded = expanded updateEverything(isTunerEnabled, multiUserEnabled) } fun setExpansion(headerExpansionFraction: Float) { expansionAmount = headerExpansionFraction if (settingsCogAnimator != null) settingsCogAnimator!!.setPosition(headerExpansionFraction) } fun disable(state2: Int, isTunerEnabled: Boolean, multiUserEnabled: Boolean) { val disabled = state2 and StatusBarManager.DISABLE2_QUICK_SETTINGS != 0 if (disabled == qsDisabled) return qsDisabled = disabled updateEverything(isTunerEnabled, multiUserEnabled) } fun updateEverything(isTunerEnabled: Boolean, multiUserEnabled: Boolean) { post { updateVisibilities(isTunerEnabled, multiUserEnabled) updateClickabilities() isClickable = false } } private fun updateClickabilities() { multiUserSwitch.isClickable = multiUserSwitch.visibility == VISIBLE editTilesButton.isClickable = editTilesButton.visibility == VISIBLE settingsButton.isClickable = settingsButton.visibility == VISIBLE } private fun updateVisibilities(isTunerEnabled: Boolean, multiUserEnabled: Boolean) { settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE tunerIcon.visibility = if (isTunerEnabled) VISIBLE else INVISIBLE multiUserSwitch.visibility = if (showUserSwitcher(multiUserEnabled)) VISIBLE else GONE val isDemo = UserManager.isDeviceInDemoMode(context) settingsButton.visibility = if (isDemo || !isExpanded) INVISIBLE else VISIBLE } private fun showUserSwitcher(multiUserEnabled: Boolean): Boolean { return isExpanded && multiUserEnabled } fun onUserInfoChanged(picture: Drawable?, isGuestUser: Boolean) { var pictureToSet = picture if (picture != null && isGuestUser && picture !is UserIconDrawable) { pictureToSet = picture.constantState.newDrawable(resources).mutate() pictureToSet.setColorFilter( Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorForeground), PorterDuff.Mode.SRC_IN) } multiUserAvatar.setImageDrawable(pictureToSet) } } No newline at end of file Loading
packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml 0 → 100644 +104 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ** Copyright 2021, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. --> <com.android.systemui.qs.QSFooterActionsView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/qs_footer_actions_container" android:layout_width="match_parent" android:layout_height="48dp" android:gravity="center_vertical"> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@android:id/edit" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:clickable="true" android:clipToPadding="false" android:contentDescription="@string/accessibility_quick_settings_edit" android:focusable="true" android:padding="@dimen/qs_footer_icon_padding" android:src="@*android:drawable/ic_mode_edit" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:focusable="true"> <ImageView android:id="@+id/multi_user_avatar" android:layout_width="@dimen/multi_user_avatar_expanded_size" android:layout_height="@dimen/multi_user_avatar_expanded_size" android:layout_gravity="center" android:scaleType="centerInside" /> </com.android.systemui.statusbar.phone.MultiUserSwitch> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/pm_lite" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:clickable="true" android:clipToPadding="false" android:focusable="true" android:padding="@dimen/qs_footer_icon_padding" android:src="@*android:drawable/ic_lock_power_off" android:contentDescription="@string/accessibility_quick_settings_power_menu" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.AlphaOptimizedFrameLayout android:id="@+id/settings_button_container" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:background="@drawable/qs_footer_action_chip_background" android:layout_weight="1" android:clipChildren="false" android:clipToPadding="false"> <com.android.systemui.statusbar.phone.SettingsButton android:id="@+id/settings_button" android:layout_width="match_parent" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_gravity="center" android:contentDescription="@string/accessibility_quick_settings_settings" android:background="@drawable/qs_footer_action_chip_background_borderless" android:padding="@dimen/qs_footer_icon_padding" android:scaleType="centerInside" android:src="@drawable/ic_settings" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/tuner_icon" android:layout_width="8dp" android:layout_height="8dp" android:layout_gravity="center_horizontal|bottom" android:layout_marginBottom="@dimen/qs_footer_icon_padding" android:src="@drawable/tuner" android:tint="?android:attr/textColorTertiary" android:visibility="invisible" /> </com.android.systemui.statusbar.AlphaOptimizedFrameLayout> </com.android.systemui.qs.QSFooterActionsView> No newline at end of file
packages/SystemUI/res/layout/qs_footer_impl.xml +1 −86 Original line number Diff line number Diff line Loading @@ -68,93 +68,8 @@ </LinearLayout> <LinearLayout android:id="@+id/qs_footer_actions_container" android:layout_width="match_parent" android:layout_height="48dp" android:gravity="center_vertical"> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@android:id/edit" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:clickable="true" android:clipToPadding="false" android:contentDescription="@string/accessibility_quick_settings_edit" android:focusable="true" android:padding="@dimen/qs_footer_icon_padding" android:src="@*android:drawable/ic_mode_edit" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:focusable="true"> <include layout="@layout/qs_footer_actions"/> <ImageView android:id="@+id/multi_user_avatar" android:layout_width="@dimen/multi_user_avatar_expanded_size" android:layout_height="@dimen/multi_user_avatar_expanded_size" android:layout_gravity="center" android:scaleType="centerInside" /> </com.android.systemui.statusbar.phone.MultiUserSwitch> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/pm_lite" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" android:layout_weight="1" android:background="@drawable/qs_footer_action_chip_background" android:clickable="true" android:clipToPadding="false" android:focusable="true" android:padding="@dimen/qs_footer_icon_padding" android:src="@*android:drawable/ic_lock_power_off" android:contentDescription="@string/accessibility_quick_settings_power_menu" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.AlphaOptimizedFrameLayout android:id="@+id/settings_button_container" android:layout_width="0dp" android:layout_height="@dimen/qs_footer_action_button_size" android:background="@drawable/qs_footer_action_chip_background" android:layout_weight="1" android:clipChildren="false" android:clipToPadding="false"> <com.android.systemui.statusbar.phone.SettingsButton android:id="@+id/settings_button" android:layout_width="match_parent" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_gravity="center" android:contentDescription="@string/accessibility_quick_settings_settings" android:background="@drawable/qs_footer_action_chip_background_borderless" android:padding="@dimen/qs_footer_icon_padding" android:scaleType="centerInside" android:src="@drawable/ic_settings" android:tint="?android:attr/textColorPrimary" /> <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/tuner_icon" android:layout_width="8dp" android:layout_height="8dp" android:layout_gravity="center_horizontal|bottom" android:layout_marginBottom="@dimen/qs_footer_icon_padding" android:src="@drawable/tuner" android:tint="?android:attr/textColorTertiary" android:visibility="invisible" /> </com.android.systemui.statusbar.AlphaOptimizedFrameLayout> </LinearLayout> </LinearLayout> </com.android.systemui.qs.QSFooterView>
packages/SystemUI/src/com/android/systemui/qs/QSFooter.java +0 −5 Original line number Diff line number Diff line Loading @@ -34,11 +34,6 @@ public interface QSFooter { */ void setExpanded(boolean expanded); /** * Returns the full height of the footer. */ int getHeight(); /** * Sets the percentage amount that the quick settings has been expanded. * Loading
packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt 0 → 100644 +167 −0 Original line number Diff line number Diff line package com.android.systemui.qs import android.content.Intent import android.os.UserManager import android.provider.Settings import android.view.View import android.widget.Toast import androidx.annotation.VisibleForTesting import com.android.internal.jank.InteractionJankMonitor import com.android.internal.logging.MetricsLogger import com.android.internal.logging.UiEventLogger import com.android.internal.logging.nano.MetricsProto import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.globalactions.GlobalActionsDialogLite import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED import com.android.systemui.statusbar.phone.MultiUserSwitchController import com.android.systemui.statusbar.phone.SettingsButton import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.UserInfoController import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener import com.android.systemui.tuner.TunerService import com.android.systemui.util.ViewController import javax.inject.Inject import javax.inject.Named class QSFooterActionsController @Inject constructor( view: QSFooterActionsView, private val qsPanelController: QSPanelController, private val activityStarter: ActivityStarter, private val userManager: UserManager, private val userInfoController: UserInfoController, private val multiUserSwitchController: MultiUserSwitchController, private val deviceProvisionedController: DeviceProvisionedController, private val falsingManager: FalsingManager, private val metricsLogger: MetricsLogger, private val tunerService: TunerService, private val globalActionsDialog: GlobalActionsDialogLite, private val uiEventLogger: UiEventLogger, @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean ) : ViewController<QSFooterActionsView>(view) { private var listening: Boolean = false var expanded = false set(value) { field = value mView.setExpanded(value, isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled) } private val settingsButton: SettingsButton = view.findViewById(R.id.settings_button) private val settingsButtonContainer: View? = view.findViewById(R.id.settings_button_container) private val editButton: View = view.findViewById(android.R.id.edit) private val powerMenuLite: View = view.findViewById(R.id.pm_lite) private val onUserInfoChangedListener = OnUserInfoChangedListener { _, picture, _ -> val isGuestUser: Boolean = userManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser()) mView.onUserInfoChanged(picture, isGuestUser) } private val onClickListener = View.OnClickListener { v -> // Don't do anything until views are unhidden. Don't do anything if the tap looks // suspicious. if (!expanded || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return@OnClickListener } if (v === settingsButton) { if (!deviceProvisionedController.isCurrentUserSetup) { // If user isn't setup just unlock the device and dump them back at SUW. activityStarter.postQSRunnableDismissingKeyguard {} return@OnClickListener } metricsLogger.action( if (expanded) MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH else MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH) if (settingsButton.isTunerClick) { activityStarter.postQSRunnableDismissingKeyguard { if (isTunerEnabled()) { tunerService.showResetRequest { // Relaunch settings so that the tuner disappears. startSettingsActivity() } } else { Toast.makeText(context, R.string.tuner_toast, Toast.LENGTH_LONG).show() tunerService.isTunerEnabled = true } startSettingsActivity() } } else { startSettingsActivity() } } else if (v === powerMenuLite) { uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS) globalActionsDialog.showOrHideDialog(false, true) } } override fun onInit() { multiUserSwitchController.init() } private fun startSettingsActivity() { val animationController = settingsButtonContainer?.let { ActivityLaunchAnimator.Controller.fromView( it, InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON) } activityStarter.startActivity(Intent(Settings.ACTION_SETTINGS), true /* dismissShade */, animationController) } @VisibleForTesting public override fun onViewAttached() { if (showPMLiteButton) { powerMenuLite.visibility = View.VISIBLE powerMenuLite.setOnClickListener(onClickListener) } else { powerMenuLite.visibility = View.GONE } settingsButton.setOnClickListener(onClickListener) editButton.setOnClickListener(View.OnClickListener { view: View? -> if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return@OnClickListener } activityStarter.postQSRunnableDismissingKeyguard { qsPanelController.showEdit(view) } }) mView.updateEverything(isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled) } override fun onViewDetached() { setListening(false) } fun setListening(listening: Boolean) { if (this.listening == listening) { return } this.listening = listening if (this.listening) { userInfoController.addCallback(onUserInfoChangedListener) } else { userInfoController.removeCallback(onUserInfoChangedListener) } } fun disable(state2: Int) { mView.disable(state2, isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled) } fun setExpansion(headerExpansionFraction: Float) { mView.setExpansion(headerExpansionFraction) } fun updateAnimator(width: Int, numTiles: Int) { mView.updateAnimator(width, numTiles) } fun setKeyguardShowing() { mView.setKeyguardShowing() } private fun isTunerEnabled() = tunerService.isTunerEnabled } No newline at end of file
packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt 0 → 100644 +159 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs import android.app.StatusBarManager import android.content.Context import android.content.res.Configuration import android.graphics.PorterDuff import android.graphics.drawable.Drawable import android.graphics.drawable.RippleDrawable import android.os.UserManager import android.util.AttributeSet import android.view.View import android.widget.ImageView import android.widget.LinearLayout import com.android.settingslib.Utils import com.android.settingslib.drawable.UserIconDrawable import com.android.systemui.R import com.android.systemui.statusbar.phone.MultiUserSwitch import com.android.systemui.statusbar.phone.SettingsButton /** * Quick Settings bottom buttons placed in footer (aka utility bar) - always visible in expanded QS, * in split shade mode visible also in collapsed state. May contain up to 5 buttons: settings, * edit tiles, power off and conditionally: user switch and tuner */ class QSFooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) { private lateinit var settingsContainer: View private lateinit var settingsButton: SettingsButton private lateinit var multiUserSwitch: MultiUserSwitch private lateinit var multiUserAvatar: ImageView private lateinit var tunerIcon: View private lateinit var editTilesButton: View private var settingsCogAnimator: TouchAnimator? = null private var qsDisabled = false private var isExpanded = false private var expansionAmount = 0f override fun onFinishInflate() { super.onFinishInflate() editTilesButton = requireViewById(android.R.id.edit) settingsButton = findViewById(R.id.settings_button) settingsContainer = findViewById(R.id.settings_button_container) multiUserSwitch = findViewById(R.id.multi_user_switch) multiUserAvatar = multiUserSwitch.findViewById(R.id.multi_user_avatar) tunerIcon = requireViewById(R.id.tuner_icon) // RenderThread is doing more harm than good when touching the header (to expand quick // settings), so disable it for this view if (settingsButton.background is RippleDrawable) { (settingsButton.background as RippleDrawable).setForceSoftware(true) } updateResources() importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES } fun updateAnimator(width: Int, numTiles: Int) { val size = (mContext.resources.getDimensionPixelSize(R.dimen.qs_quick_tile_size) - mContext.resources.getDimensionPixelSize(R.dimen.qs_tile_padding)) val remaining = (width - numTiles * size) / (numTiles - 1) val defSpace = mContext.resources.getDimensionPixelOffset(R.dimen.default_gear_space) val translation = if (isLayoutRtl) (remaining - defSpace) else -(remaining - defSpace) settingsCogAnimator = TouchAnimator.Builder() .addFloat(settingsButton, "translationX", translation.toFloat(), 0f) .addFloat(settingsButton, "rotation", -120f, 0f) .build() setExpansion(expansionAmount) } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) updateResources() } override fun onRtlPropertiesChanged(layoutDirection: Int) { super.onRtlPropertiesChanged(layoutDirection) updateResources() } private fun updateResources() { val tunerIconTranslation = mContext.resources .getDimensionPixelOffset(R.dimen.qs_footer_tuner_icon_translation).toFloat() tunerIcon.translationX = if (isLayoutRtl) (-tunerIconTranslation) else tunerIconTranslation } fun setKeyguardShowing() { setExpansion(expansionAmount) } fun setExpanded(expanded: Boolean, isTunerEnabled: Boolean, multiUserEnabled: Boolean) { if (isExpanded == expanded) return isExpanded = expanded updateEverything(isTunerEnabled, multiUserEnabled) } fun setExpansion(headerExpansionFraction: Float) { expansionAmount = headerExpansionFraction if (settingsCogAnimator != null) settingsCogAnimator!!.setPosition(headerExpansionFraction) } fun disable(state2: Int, isTunerEnabled: Boolean, multiUserEnabled: Boolean) { val disabled = state2 and StatusBarManager.DISABLE2_QUICK_SETTINGS != 0 if (disabled == qsDisabled) return qsDisabled = disabled updateEverything(isTunerEnabled, multiUserEnabled) } fun updateEverything(isTunerEnabled: Boolean, multiUserEnabled: Boolean) { post { updateVisibilities(isTunerEnabled, multiUserEnabled) updateClickabilities() isClickable = false } } private fun updateClickabilities() { multiUserSwitch.isClickable = multiUserSwitch.visibility == VISIBLE editTilesButton.isClickable = editTilesButton.visibility == VISIBLE settingsButton.isClickable = settingsButton.visibility == VISIBLE } private fun updateVisibilities(isTunerEnabled: Boolean, multiUserEnabled: Boolean) { settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE tunerIcon.visibility = if (isTunerEnabled) VISIBLE else INVISIBLE multiUserSwitch.visibility = if (showUserSwitcher(multiUserEnabled)) VISIBLE else GONE val isDemo = UserManager.isDeviceInDemoMode(context) settingsButton.visibility = if (isDemo || !isExpanded) INVISIBLE else VISIBLE } private fun showUserSwitcher(multiUserEnabled: Boolean): Boolean { return isExpanded && multiUserEnabled } fun onUserInfoChanged(picture: Drawable?, isGuestUser: Boolean) { var pictureToSet = picture if (picture != null && isGuestUser && picture !is UserIconDrawable) { pictureToSet = picture.constantState.newDrawable(resources).mutate() pictureToSet.setColorFilter( Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorForeground), PorterDuff.Mode.SRC_IN) } multiUserAvatar.setImageDrawable(pictureToSet) } } No newline at end of file