Merge "Extracting buttons below expanded QS to a separate view and controller" into sc-v2-dev am: 0f7c56a233
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15425036 Change-Id: I0a04b906b19eaf77d149b95e27096103b924069e
This commit is contained in:
104
packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml
Normal file
104
packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<?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>
|
||||||
@@ -68,93 +68,8 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/qs_footer_actions"/>
|
||||||
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>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</com.android.systemui.qs.QSFooterView>
|
</com.android.systemui.qs.QSFooterView>
|
||||||
|
|||||||
@@ -34,11 +34,6 @@ public interface QSFooter {
|
|||||||
*/
|
*/
|
||||||
void setExpanded(boolean expanded);
|
void setExpanded(boolean expanded);
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the full height of the footer.
|
|
||||||
*/
|
|
||||||
int getHeight();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the percentage amount that the quick settings has been expanded.
|
* Sets the percentage amount that the quick settings has been expanded.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,60 +21,40 @@ import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.graphics.PorterDuff.Mode;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.graphics.drawable.RippleDrawable;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.android.settingslib.Utils;
|
|
||||||
import com.android.settingslib.development.DevelopmentSettingsEnabler;
|
import com.android.settingslib.development.DevelopmentSettingsEnabler;
|
||||||
import com.android.settingslib.drawable.UserIconDrawable;
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.qs.TouchAnimator.Builder;
|
|
||||||
import com.android.systemui.statusbar.phone.MultiUserSwitch;
|
|
||||||
import com.android.systemui.statusbar.phone.SettingsButton;
|
|
||||||
|
|
||||||
/** */
|
/**
|
||||||
|
* Footer of expanded Quick Settings, tiles page indicator, (optionally) build number and
|
||||||
|
* {@link QSFooterActionsView}
|
||||||
|
*/
|
||||||
public class QSFooterView extends FrameLayout {
|
public class QSFooterView extends FrameLayout {
|
||||||
private SettingsButton mSettingsButton;
|
|
||||||
protected View mSettingsContainer;
|
|
||||||
private PageIndicator mPageIndicator;
|
private PageIndicator mPageIndicator;
|
||||||
private TextView mBuildText;
|
private TextView mBuildText;
|
||||||
private boolean mShouldShowBuildText;
|
private View mActionsContainer;
|
||||||
|
|
||||||
private boolean mQsDisabled;
|
|
||||||
|
|
||||||
private boolean mExpanded;
|
|
||||||
|
|
||||||
private boolean mListening;
|
|
||||||
|
|
||||||
protected MultiUserSwitch mMultiUserSwitch;
|
|
||||||
private ImageView mMultiUserAvatar;
|
|
||||||
|
|
||||||
protected TouchAnimator mFooterAnimator;
|
protected TouchAnimator mFooterAnimator;
|
||||||
|
|
||||||
|
private boolean mQsDisabled;
|
||||||
|
private boolean mExpanded;
|
||||||
private float mExpansionAmount;
|
private float mExpansionAmount;
|
||||||
|
|
||||||
protected View mEdit;
|
private boolean mShouldShowBuildText;
|
||||||
private TouchAnimator mSettingsCogAnimator;
|
|
||||||
|
|
||||||
private View mActionsContainer;
|
|
||||||
private View mTunerIcon;
|
|
||||||
private int mTunerIconTranslation;
|
|
||||||
|
|
||||||
private OnClickListener mExpandClickListener;
|
private OnClickListener mExpandClickListener;
|
||||||
|
|
||||||
@@ -94,27 +74,11 @@ public class QSFooterView extends FrameLayout {
|
|||||||
@Override
|
@Override
|
||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
mEdit = requireViewById(android.R.id.edit);
|
|
||||||
|
|
||||||
mPageIndicator = findViewById(R.id.footer_page_indicator);
|
mPageIndicator = findViewById(R.id.footer_page_indicator);
|
||||||
|
|
||||||
mSettingsButton = findViewById(R.id.settings_button);
|
|
||||||
mSettingsContainer = findViewById(R.id.settings_button_container);
|
|
||||||
|
|
||||||
mMultiUserSwitch = findViewById(R.id.multi_user_switch);
|
|
||||||
mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
|
|
||||||
|
|
||||||
mActionsContainer = requireViewById(R.id.qs_footer_actions_container);
|
mActionsContainer = requireViewById(R.id.qs_footer_actions_container);
|
||||||
mBuildText = findViewById(R.id.build);
|
mBuildText = findViewById(R.id.build);
|
||||||
mTunerIcon = 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 (mSettingsButton.getBackground() instanceof RippleDrawable) {
|
|
||||||
((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
|
|
||||||
}
|
|
||||||
updateResources();
|
updateResources();
|
||||||
|
|
||||||
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
|
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
|
||||||
setBuildText();
|
setBuildText();
|
||||||
}
|
}
|
||||||
@@ -137,18 +101,7 @@ public class QSFooterView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateAnimator(int width, int numTiles) {
|
void updateExpansion() {
|
||||||
int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size)
|
|
||||||
- mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_padding);
|
|
||||||
int remaining = (width - numTiles * size) / (numTiles - 1);
|
|
||||||
int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space);
|
|
||||||
|
|
||||||
mSettingsCogAnimator = new Builder()
|
|
||||||
.addFloat(mSettingsButton, "translationX",
|
|
||||||
isLayoutRtl() ? (remaining - defSpace) : -(remaining - defSpace), 0)
|
|
||||||
.addFloat(mSettingsButton, "rotation", -120, 0)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
setExpansion(mExpansionAmount);
|
setExpansion(mExpansionAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,20 +111,11 @@ public class QSFooterView extends FrameLayout {
|
|||||||
updateResources();
|
updateResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRtlPropertiesChanged(int layoutDirection) {
|
|
||||||
super.onRtlPropertiesChanged(layoutDirection);
|
|
||||||
updateResources();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateResources() {
|
private void updateResources() {
|
||||||
updateFooterAnimator();
|
updateFooterAnimator();
|
||||||
MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
|
MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
|
||||||
lp.bottomMargin = getResources().getDimensionPixelSize(R.dimen.qs_footers_margin_bottom);
|
lp.bottomMargin = getResources().getDimensionPixelSize(R.dimen.qs_footers_margin_bottom);
|
||||||
setLayoutParams(lp);
|
setLayoutParams(lp);
|
||||||
mTunerIconTranslation = mContext.getResources()
|
|
||||||
.getDimensionPixelOffset(R.dimen.qs_footer_tuner_icon_translation);
|
|
||||||
mTunerIcon.setTranslationX(isLayoutRtl() ? -mTunerIconTranslation : mTunerIconTranslation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFooterAnimator() {
|
private void updateFooterAnimator() {
|
||||||
@@ -197,17 +141,15 @@ public class QSFooterView extends FrameLayout {
|
|||||||
mExpandClickListener = onClickListener;
|
mExpandClickListener = onClickListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setExpanded(boolean expanded, boolean isTunerEnabled, boolean multiUserEnabled) {
|
void setExpanded(boolean expanded) {
|
||||||
if (mExpanded == expanded) return;
|
if (mExpanded == expanded) return;
|
||||||
mExpanded = expanded;
|
mExpanded = expanded;
|
||||||
updateEverything(isTunerEnabled, multiUserEnabled);
|
updateEverything();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
public void setExpansion(float headerExpansionFraction) {
|
public void setExpansion(float headerExpansionFraction) {
|
||||||
mExpansionAmount = headerExpansionFraction;
|
mExpansionAmount = headerExpansionFraction;
|
||||||
if (mSettingsCogAnimator != null) mSettingsCogAnimator.setPosition(headerExpansionFraction);
|
|
||||||
|
|
||||||
if (mFooterAnimator != null) {
|
if (mFooterAnimator != null) {
|
||||||
mFooterAnimator.setPosition(headerExpansionFraction);
|
mFooterAnimator.setPosition(headerExpansionFraction);
|
||||||
}
|
}
|
||||||
@@ -228,14 +170,6 @@ public class QSFooterView extends FrameLayout {
|
|||||||
super.onDetachedFromWindow();
|
super.onDetachedFromWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
|
||||||
public void setListening(boolean listening) {
|
|
||||||
if (listening == mListening) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mListening = listening;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean performAccessibilityAction(int action, Bundle arguments) {
|
public boolean performAccessibilityAction(int action, Bundle arguments) {
|
||||||
if (action == AccessibilityNodeInfo.ACTION_EXPAND) {
|
if (action == AccessibilityNodeInfo.ACTION_EXPAND) {
|
||||||
@@ -253,50 +187,26 @@ public class QSFooterView extends FrameLayout {
|
|||||||
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
|
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable(int state2, boolean isTunerEnabled, boolean multiUserEnabled) {
|
void disable(int state2) {
|
||||||
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
|
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
|
||||||
if (disabled == mQsDisabled) return;
|
if (disabled == mQsDisabled) return;
|
||||||
mQsDisabled = disabled;
|
mQsDisabled = disabled;
|
||||||
updateEverything(isTunerEnabled, multiUserEnabled);
|
updateEverything();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateEverything(boolean isTunerEnabled, boolean multiUserEnabled) {
|
void updateEverything() {
|
||||||
post(() -> {
|
post(() -> {
|
||||||
updateVisibilities(isTunerEnabled, multiUserEnabled);
|
updateVisibilities();
|
||||||
updateClickabilities();
|
updateClickabilities();
|
||||||
setClickable(false);
|
setClickable(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateClickabilities() {
|
private void updateClickabilities() {
|
||||||
mMultiUserSwitch.setClickable(mMultiUserSwitch.getVisibility() == View.VISIBLE);
|
|
||||||
mEdit.setClickable(mEdit.getVisibility() == View.VISIBLE);
|
|
||||||
mSettingsButton.setClickable(mSettingsButton.getVisibility() == View.VISIBLE);
|
|
||||||
mBuildText.setLongClickable(mBuildText.getVisibility() == View.VISIBLE);
|
mBuildText.setLongClickable(mBuildText.getVisibility() == View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateVisibilities(boolean isTunerEnabled, boolean multiUserEnabled) {
|
private void updateVisibilities() {
|
||||||
mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
|
|
||||||
mTunerIcon.setVisibility(isTunerEnabled ? View.VISIBLE : View.INVISIBLE);
|
|
||||||
final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
|
|
||||||
mMultiUserSwitch.setVisibility(
|
|
||||||
showUserSwitcher(multiUserEnabled) ? View.VISIBLE : View.GONE);
|
|
||||||
mSettingsButton.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
|
|
||||||
|
|
||||||
mBuildText.setVisibility(mExpanded && mShouldShowBuildText ? View.VISIBLE : View.INVISIBLE);
|
mBuildText.setVisibility(mExpanded && mShouldShowBuildText ? View.VISIBLE : View.INVISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean showUserSwitcher(boolean multiUserEnabled) {
|
|
||||||
return mExpanded && multiUserEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onUserInfoChanged(Drawable picture, boolean isGuestUser) {
|
|
||||||
if (picture != null && isGuestUser && !(picture instanceof UserIconDrawable)) {
|
|
||||||
picture = picture.getConstantState().newDrawable(getResources()).mutate();
|
|
||||||
picture.setColorFilter(
|
|
||||||
Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorForeground),
|
|
||||||
Mode.SRC_IN);
|
|
||||||
}
|
|
||||||
mMultiUserAvatar.setImageDrawable(picture);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -16,39 +16,19 @@
|
|||||||
|
|
||||||
package com.android.systemui.qs;
|
package com.android.systemui.qs;
|
||||||
|
|
||||||
import static com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED;
|
|
||||||
|
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.UserManager;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
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.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.QSScope;
|
import com.android.systemui.qs.dagger.QSScope;
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
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.tuner.TunerService;
|
|
||||||
import com.android.systemui.util.ViewController;
|
import com.android.systemui.util.ViewController;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for {@link QSFooterView}.
|
* Controller for {@link QSFooterView}.
|
||||||
@@ -56,137 +36,45 @@ import javax.inject.Named;
|
|||||||
@QSScope
|
@QSScope
|
||||||
public class QSFooterViewController extends ViewController<QSFooterView> implements QSFooter {
|
public class QSFooterViewController extends ViewController<QSFooterView> implements QSFooter {
|
||||||
|
|
||||||
private final UserManager mUserManager;
|
|
||||||
private final UserInfoController mUserInfoController;
|
|
||||||
private final ActivityStarter mActivityStarter;
|
|
||||||
private final DeviceProvisionedController mDeviceProvisionedController;
|
|
||||||
private final UserTracker mUserTracker;
|
private final UserTracker mUserTracker;
|
||||||
private final QSPanelController mQsPanelController;
|
private final QSPanelController mQsPanelController;
|
||||||
private final QuickQSPanelController mQuickQSPanelController;
|
private final QuickQSPanelController mQuickQSPanelController;
|
||||||
private final TunerService mTunerService;
|
private final QSFooterActionsController mQsFooterActionsController;
|
||||||
private final MetricsLogger mMetricsLogger;
|
|
||||||
private final FalsingManager mFalsingManager;
|
|
||||||
private final MultiUserSwitchController mMultiUserSwitchController;
|
|
||||||
private final SettingsButton mSettingsButton;
|
|
||||||
private final View mSettingsButtonContainer;
|
|
||||||
private final TextView mBuildText;
|
private final TextView mBuildText;
|
||||||
private final View mEdit;
|
|
||||||
private final PageIndicator mPageIndicator;
|
private final PageIndicator mPageIndicator;
|
||||||
private final View mPowerMenuLite;
|
|
||||||
private final boolean mShowPMLiteButton;
|
|
||||||
private final GlobalActionsDialogLite mGlobalActionsDialog;
|
|
||||||
private final UiEventLogger mUiEventLogger;
|
|
||||||
|
|
||||||
private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
|
|
||||||
new UserInfoController.OnUserInfoChangedListener() {
|
|
||||||
@Override
|
|
||||||
public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
|
|
||||||
boolean isGuestUser = mUserManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser());
|
|
||||||
mView.onUserInfoChanged(picture, isGuestUser);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final View.OnClickListener mSettingsOnClickListener = new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
// Don't do anything until views are unhidden. Don't do anything if the tap looks
|
|
||||||
// suspicious.
|
|
||||||
if (!mExpanded || mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v == mSettingsButton) {
|
|
||||||
if (!mDeviceProvisionedController.isCurrentUserSetup()) {
|
|
||||||
// If user isn't setup just unlock the device and dump them back at SUW.
|
|
||||||
mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mMetricsLogger.action(
|
|
||||||
mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
|
|
||||||
: MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
|
|
||||||
if (mSettingsButton.isTunerClick()) {
|
|
||||||
mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
|
|
||||||
if (isTunerEnabled()) {
|
|
||||||
mTunerService.showResetRequest(
|
|
||||||
() -> {
|
|
||||||
// Relaunch settings so that the tuner disappears.
|
|
||||||
startSettingsActivity();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Toast.makeText(getContext(), R.string.tuner_toast,
|
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
mTunerService.setTunerEnabled(true);
|
|
||||||
}
|
|
||||||
startSettingsActivity();
|
|
||||||
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
startSettingsActivity();
|
|
||||||
}
|
|
||||||
} else if (v == mPowerMenuLite) {
|
|
||||||
mUiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS);
|
|
||||||
mGlobalActionsDialog.showOrHideDialog(false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private boolean mListening;
|
|
||||||
private boolean mExpanded;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
QSFooterViewController(QSFooterView view, UserManager userManager,
|
QSFooterViewController(QSFooterView view,
|
||||||
UserInfoController userInfoController, ActivityStarter activityStarter,
|
UserTracker userTracker,
|
||||||
DeviceProvisionedController deviceProvisionedController, UserTracker userTracker,
|
|
||||||
QSPanelController qsPanelController,
|
QSPanelController qsPanelController,
|
||||||
MultiUserSwitchController multiUserSwitchController,
|
|
||||||
QuickQSPanelController quickQSPanelController,
|
QuickQSPanelController quickQSPanelController,
|
||||||
TunerService tunerService, MetricsLogger metricsLogger, FalsingManager falsingManager,
|
QSFooterActionsController qsFooterActionsController) {
|
||||||
@Named(PM_LITE_ENABLED) boolean showPMLiteButton,
|
|
||||||
GlobalActionsDialogLite globalActionsDialog, UiEventLogger uiEventLogger) {
|
|
||||||
super(view);
|
super(view);
|
||||||
mUserManager = userManager;
|
|
||||||
mUserInfoController = userInfoController;
|
|
||||||
mActivityStarter = activityStarter;
|
|
||||||
mDeviceProvisionedController = deviceProvisionedController;
|
|
||||||
mUserTracker = userTracker;
|
mUserTracker = userTracker;
|
||||||
mQsPanelController = qsPanelController;
|
mQsPanelController = qsPanelController;
|
||||||
mQuickQSPanelController = quickQSPanelController;
|
mQuickQSPanelController = quickQSPanelController;
|
||||||
mTunerService = tunerService;
|
mQsFooterActionsController = qsFooterActionsController;
|
||||||
mMetricsLogger = metricsLogger;
|
|
||||||
mFalsingManager = falsingManager;
|
|
||||||
mMultiUserSwitchController = multiUserSwitchController;
|
|
||||||
|
|
||||||
mSettingsButton = mView.findViewById(R.id.settings_button);
|
|
||||||
mSettingsButtonContainer = mView.findViewById(R.id.settings_button_container);
|
|
||||||
mBuildText = mView.findViewById(R.id.build);
|
mBuildText = mView.findViewById(R.id.build);
|
||||||
mEdit = mView.findViewById(android.R.id.edit);
|
|
||||||
mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
|
mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
|
||||||
mPowerMenuLite = mView.findViewById(R.id.pm_lite);
|
|
||||||
mShowPMLiteButton = showPMLiteButton;
|
|
||||||
mGlobalActionsDialog = globalActionsDialog;
|
|
||||||
mUiEventLogger = uiEventLogger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onInit() {
|
protected void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
mMultiUserSwitchController.init();
|
mQsFooterActionsController.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onViewAttached() {
|
protected void onViewAttached() {
|
||||||
if (mShowPMLiteButton) {
|
|
||||||
mPowerMenuLite.setVisibility(View.VISIBLE);
|
|
||||||
mPowerMenuLite.setOnClickListener(mSettingsOnClickListener);
|
|
||||||
} else {
|
|
||||||
mPowerMenuLite.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
mView.addOnLayoutChangeListener(
|
mView.addOnLayoutChangeListener(
|
||||||
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
|
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
||||||
mView.updateAnimator(
|
mView.updateExpansion();
|
||||||
right - left, mQuickQSPanelController.getNumQuickTiles()));
|
mQsFooterActionsController.updateAnimator(right - left,
|
||||||
mSettingsButton.setOnClickListener(mSettingsOnClickListener);
|
mQuickQSPanelController.getNumQuickTiles());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
mBuildText.setOnLongClickListener(view -> {
|
mBuildText.setOnLongClickListener(view -> {
|
||||||
CharSequence buildText = mBuildText.getText();
|
CharSequence buildText = mBuildText.getText();
|
||||||
if (!TextUtils.isEmpty(buildText)) {
|
if (!TextUtils.isEmpty(buildText)) {
|
||||||
@@ -200,17 +88,8 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
mEdit.setOnClickListener(view -> {
|
|
||||||
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mActivityStarter.postQSRunnableDismissingKeyguard(() ->
|
|
||||||
mQsPanelController.showEdit(view));
|
|
||||||
});
|
|
||||||
|
|
||||||
mQsPanelController.setFooterPageIndicator(mPageIndicator);
|
mQsPanelController.setFooterPageIndicator(mPageIndicator);
|
||||||
mView.updateEverything(isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
|
mView.updateEverything();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -225,38 +104,25 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setExpanded(boolean expanded) {
|
public void setExpanded(boolean expanded) {
|
||||||
mExpanded = expanded;
|
mQsFooterActionsController.setExpanded(expanded);
|
||||||
mView.setExpanded(
|
mView.setExpanded(expanded);
|
||||||
expanded, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() {
|
|
||||||
return mView.getHeight();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setExpansion(float expansion) {
|
public void setExpansion(float expansion) {
|
||||||
mView.setExpansion(expansion);
|
mView.setExpansion(expansion);
|
||||||
|
mQsFooterActionsController.setExpansion(expansion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setListening(boolean listening) {
|
public void setListening(boolean listening) {
|
||||||
if (mListening == listening) {
|
mQsFooterActionsController.setListening(listening);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mListening = listening;
|
|
||||||
if (mListening) {
|
|
||||||
mUserInfoController.addCallback(mOnUserInfoChangedListener);
|
|
||||||
} else {
|
|
||||||
mUserInfoController.removeCallback(mOnUserInfoChangedListener);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setKeyguardShowing(boolean keyguardShowing) {
|
public void setKeyguardShowing(boolean keyguardShowing) {
|
||||||
mView.setKeyguardShowing();
|
mView.setKeyguardShowing();
|
||||||
|
mQsFooterActionsController.setKeyguardShowing();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@@ -267,19 +133,7 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disable(int state1, int state2, boolean animate) {
|
public void disable(int state1, int state2, boolean animate) {
|
||||||
mView.disable(state2, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
|
mView.disable(state2);
|
||||||
}
|
mQsFooterActionsController.disable(state2);
|
||||||
|
|
||||||
private void startSettingsActivity() {
|
|
||||||
ActivityLaunchAnimator.Controller animationController =
|
|
||||||
mSettingsButtonContainer != null ? ActivityLaunchAnimator.Controller.fromView(
|
|
||||||
mSettingsButtonContainer,
|
|
||||||
InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON) : null;
|
|
||||||
mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
|
|
||||||
true /* dismissShade */, animationController);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isTunerEnabled() {
|
|
||||||
return mTunerService.isTunerEnabled();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import com.android.systemui.dagger.qualifiers.RootView;
|
|||||||
import com.android.systemui.plugins.qs.QS;
|
import com.android.systemui.plugins.qs.QS;
|
||||||
import com.android.systemui.qs.QSContainerImpl;
|
import com.android.systemui.qs.QSContainerImpl;
|
||||||
import com.android.systemui.qs.QSFooter;
|
import com.android.systemui.qs.QSFooter;
|
||||||
|
import com.android.systemui.qs.QSFooterActionsView;
|
||||||
import com.android.systemui.qs.QSFooterView;
|
import com.android.systemui.qs.QSFooterView;
|
||||||
import com.android.systemui.qs.QSFooterViewController;
|
import com.android.systemui.qs.QSFooterViewController;
|
||||||
import com.android.systemui.qs.QSFragment;
|
import com.android.systemui.qs.QSFragment;
|
||||||
@@ -120,6 +121,12 @@ public interface QSFragmentModule {
|
|||||||
return view.findViewById(R.id.qs_footer);
|
return view.findViewById(R.id.qs_footer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** */
|
||||||
|
@Provides
|
||||||
|
static QSFooterActionsView providesQSFooterActionsView(@RootView View view) {
|
||||||
|
return view.findViewById(R.id.qs_footer_actions_container);
|
||||||
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@Provides
|
@Provides
|
||||||
@QSScope
|
@QSScope
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package com.android.systemui.qs
|
||||||
|
|
||||||
|
import com.android.systemui.R
|
||||||
|
import android.os.UserManager
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.internal.logging.MetricsLogger
|
||||||
|
import com.android.internal.logging.UiEventLogger
|
||||||
|
import com.android.internal.logging.testing.FakeMetricsLogger
|
||||||
|
import com.android.systemui.Dependency
|
||||||
|
import com.android.systemui.classifier.FalsingManagerFake
|
||||||
|
import com.android.systemui.globalactions.GlobalActionsDialogLite
|
||||||
|
import com.android.systemui.plugins.ActivityStarter
|
||||||
|
import com.android.systemui.statusbar.phone.MultiUserSwitchController
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceProvisionedController
|
||||||
|
import com.android.systemui.statusbar.policy.UserInfoController
|
||||||
|
import com.android.systemui.tuner.TunerService
|
||||||
|
import com.android.systemui.utils.leaks.FakeTunerService
|
||||||
|
import com.android.systemui.utils.leaks.LeakCheckedTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.ArgumentMatchers.any
|
||||||
|
import org.mockito.ArgumentMatchers.anyBoolean
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
import org.mockito.Mockito.`when` as whenever
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
class QSFooterActionsControllerTest : LeakCheckedTest() {
|
||||||
|
@Mock
|
||||||
|
private lateinit var userManager: UserManager
|
||||||
|
@Mock
|
||||||
|
private lateinit var activityStarter: ActivityStarter
|
||||||
|
@Mock
|
||||||
|
private lateinit var deviceProvisionedController: DeviceProvisionedController
|
||||||
|
@Mock
|
||||||
|
private lateinit var userInfoController: UserInfoController
|
||||||
|
@Mock
|
||||||
|
private lateinit var qsPanelController: QSPanelController
|
||||||
|
@Mock
|
||||||
|
private lateinit var multiUserSwitchController: MultiUserSwitchController
|
||||||
|
@Mock
|
||||||
|
private lateinit var globalActionsDialog: GlobalActionsDialogLite
|
||||||
|
@Mock
|
||||||
|
private lateinit var uiEventLogger: UiEventLogger
|
||||||
|
@Mock
|
||||||
|
private lateinit var controller: QSFooterActionsController
|
||||||
|
|
||||||
|
private val metricsLogger: MetricsLogger = FakeMetricsLogger()
|
||||||
|
private lateinit var view: QSFooterActionsView
|
||||||
|
private val falsingManager: FalsingManagerFake = FalsingManagerFake()
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
injectLeakCheckedDependencies(*LeakCheckedTest.ALL_SUPPORTED_CLASSES)
|
||||||
|
val fakeTunerService = Dependency.get(TunerService::class.java) as FakeTunerService
|
||||||
|
|
||||||
|
view = LayoutInflater.from(context)
|
||||||
|
.inflate(R.layout.qs_footer_actions, null) as QSFooterActionsView
|
||||||
|
|
||||||
|
controller = QSFooterActionsController(view, qsPanelController, activityStarter,
|
||||||
|
userManager, userInfoController, multiUserSwitchController,
|
||||||
|
deviceProvisionedController, falsingManager, metricsLogger, fakeTunerService,
|
||||||
|
globalActionsDialog, uiEventLogger, showPMLiteButton = true)
|
||||||
|
controller.init()
|
||||||
|
controller.onViewAttached()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLogPowerMenuClick() {
|
||||||
|
controller.expanded = true
|
||||||
|
falsingManager.setFalseTap(false)
|
||||||
|
|
||||||
|
view.findViewById<View>(R.id.pm_lite).performClick()
|
||||||
|
// Verify clicks are logged
|
||||||
|
verify(uiEventLogger, Mockito.times(1))
|
||||||
|
.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSettings_UserNotSetup() {
|
||||||
|
whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
|
||||||
|
view.findViewById<View>(R.id.settings_button).performClick()
|
||||||
|
// Verify Settings wasn't launched.
|
||||||
|
verify<ActivityStarter>(activityStarter, Mockito.never()).startActivity(any(), anyBoolean())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,16 +18,11 @@ package com.android.systemui.qs;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
||||||
import static org.mockito.Mockito.never;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.os.UserManager;
|
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
import android.testing.TestableLooper;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -35,21 +30,8 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
import com.android.internal.logging.MetricsLogger;
|
|
||||||
import com.android.internal.logging.UiEventLogger;
|
|
||||||
import com.android.internal.logging.testing.FakeMetricsLogger;
|
|
||||||
import com.android.systemui.Dependency;
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.classifier.FalsingManagerFake;
|
|
||||||
import com.android.systemui.globalactions.GlobalActionsDialogLite;
|
|
||||||
import com.android.systemui.plugins.ActivityStarter;
|
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
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.tuner.TunerService;
|
|
||||||
import com.android.systemui.utils.leaks.FakeTunerService;
|
|
||||||
import com.android.systemui.utils.leaks.LeakCheckedTest;
|
import com.android.systemui.utils.leaks.LeakCheckedTest;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -67,14 +49,6 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private QSFooterView mView;
|
private QSFooterView mView;
|
||||||
@Mock
|
@Mock
|
||||||
private UserManager mUserManager;
|
|
||||||
@Mock
|
|
||||||
private ActivityStarter mActivityStarter;
|
|
||||||
@Mock
|
|
||||||
private DeviceProvisionedController mDeviceProvisionedController;
|
|
||||||
@Mock
|
|
||||||
private UserInfoController mUserInfoController;
|
|
||||||
@Mock
|
|
||||||
private UserTracker mUserTracker;
|
private UserTracker mUserTracker;
|
||||||
@Mock
|
@Mock
|
||||||
private QSPanelController mQSPanelController;
|
private QSPanelController mQSPanelController;
|
||||||
@@ -82,36 +56,19 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
|
|||||||
private ClipboardManager mClipboardManager;
|
private ClipboardManager mClipboardManager;
|
||||||
@Mock
|
@Mock
|
||||||
private QuickQSPanelController mQuickQSPanelController;
|
private QuickQSPanelController mQuickQSPanelController;
|
||||||
private FakeTunerService mFakeTunerService;
|
|
||||||
private MetricsLogger mMetricsLogger = new FakeMetricsLogger();
|
|
||||||
private FalsingManagerFake mFalsingManager;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private SettingsButton mSettingsButton;
|
|
||||||
@Mock
|
@Mock
|
||||||
private TextView mBuildText;
|
private TextView mBuildText;
|
||||||
@Mock
|
@Mock
|
||||||
private View mEdit;
|
private QSFooterActionsController mQSFooterActionsController;
|
||||||
@Mock
|
|
||||||
private MultiUserSwitchController mMultiUserSwitchController;
|
|
||||||
@Mock
|
|
||||||
private View mPowerMenuLiteView;
|
|
||||||
@Mock
|
|
||||||
private GlobalActionsDialogLite mGlobalActionsDialog;
|
|
||||||
@Mock
|
|
||||||
private UiEventLogger mUiEventLogger;
|
|
||||||
|
|
||||||
private QSFooterViewController mController;
|
private QSFooterViewController mController;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
mFalsingManager = new FalsingManagerFake();
|
|
||||||
|
|
||||||
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
|
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
|
||||||
|
|
||||||
mFakeTunerService = (FakeTunerService) Dependency.get(TunerService.class);
|
|
||||||
|
|
||||||
mContext.addMockSystemService(ClipboardManager.class, mClipboardManager);
|
mContext.addMockSystemService(ClipboardManager.class, mClipboardManager);
|
||||||
|
|
||||||
when(mView.getContext()).thenReturn(mContext);
|
when(mView.getContext()).thenReturn(mContext);
|
||||||
@@ -119,16 +76,10 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
|
|||||||
when(mUserTracker.getUserContext()).thenReturn(mContext);
|
when(mUserTracker.getUserContext()).thenReturn(mContext);
|
||||||
|
|
||||||
when(mView.isAttachedToWindow()).thenReturn(true);
|
when(mView.isAttachedToWindow()).thenReturn(true);
|
||||||
when(mView.findViewById(R.id.settings_button)).thenReturn(mSettingsButton);
|
|
||||||
when(mView.findViewById(R.id.build)).thenReturn(mBuildText);
|
when(mView.findViewById(R.id.build)).thenReturn(mBuildText);
|
||||||
when(mView.findViewById(android.R.id.edit)).thenReturn(mEdit);
|
|
||||||
when(mView.findViewById(R.id.pm_lite)).thenReturn(mPowerMenuLiteView);
|
|
||||||
|
|
||||||
mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
|
mController = new QSFooterViewController(mView, mUserTracker, mQSPanelController,
|
||||||
mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
|
mQuickQSPanelController, mQSFooterActionsController);
|
||||||
mMultiUserSwitchController, mQuickQSPanelController, mFakeTunerService,
|
|
||||||
mMetricsLogger, mFalsingManager, false, mGlobalActionsDialog,
|
|
||||||
mUiEventLogger);
|
|
||||||
|
|
||||||
mController.init();
|
mController.init();
|
||||||
}
|
}
|
||||||
@@ -148,40 +99,4 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
|
|||||||
verify(mClipboardManager).setPrimaryClip(captor.capture());
|
verify(mClipboardManager).setPrimaryClip(captor.capture());
|
||||||
assertThat(captor.getValue().getItemAt(0).getText()).isEqualTo(text);
|
assertThat(captor.getValue().getItemAt(0).getText()).isEqualTo(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSettings_UserNotSetup() {
|
|
||||||
ArgumentCaptor<View.OnClickListener> onClickCaptor =
|
|
||||||
ArgumentCaptor.forClass(View.OnClickListener.class);
|
|
||||||
verify(mSettingsButton).setOnClickListener(onClickCaptor.capture());
|
|
||||||
|
|
||||||
when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false);
|
|
||||||
|
|
||||||
onClickCaptor.getValue().onClick(mSettingsButton);
|
|
||||||
// Verify Settings wasn't launched.
|
|
||||||
verify(mActivityStarter, never()).startActivity(any(), anyBoolean());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLogPowerMenuClick() {
|
|
||||||
// Enable power menu button
|
|
||||||
mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
|
|
||||||
mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
|
|
||||||
mMultiUserSwitchController, mQuickQSPanelController, mFakeTunerService,
|
|
||||||
mMetricsLogger, new FalsingManagerFake(), true, mGlobalActionsDialog,
|
|
||||||
mUiEventLogger);
|
|
||||||
mController.init();
|
|
||||||
mController.setExpanded(true);
|
|
||||||
mFalsingManager.setFalseTap(false);
|
|
||||||
|
|
||||||
ArgumentCaptor<View.OnClickListener> onClickCaptor =
|
|
||||||
ArgumentCaptor.forClass(View.OnClickListener.class);
|
|
||||||
verify(mPowerMenuLiteView).setOnClickListener(onClickCaptor.capture());
|
|
||||||
|
|
||||||
onClickCaptor.getValue().onClick(mPowerMenuLiteView);
|
|
||||||
|
|
||||||
// Verify clicks are logged
|
|
||||||
verify(mUiEventLogger, times(1))
|
|
||||||
.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user