diff --git a/packages/SystemUI/res-keyguard/layout/fgs_footer.xml b/packages/SystemUI/res-keyguard/layout/fgs_footer.xml
new file mode 100644
index 0000000000000..5343411e4c958
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/fgs_footer.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/layout/new_footer_actions.xml b/packages/SystemUI/res-keyguard/layout/new_footer_actions.xml
index 95bdd8948c7cb..4884df7f838e7 100644
--- a/packages/SystemUI/res-keyguard/layout/new_footer_actions.xml
+++ b/packages/SystemUI/res-keyguard/layout/new_footer_actions.xml
@@ -20,34 +20,41 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="match_parent"
- android:layout_height="@dimen/qs_footer_height"
+ android:layout_height="@dimen/new_footer_height"
+ android:elevation="@dimen/qs_panel_elevation"
+ android:paddingTop="8dp"
+ android:paddingBottom="4dp"
+ android:background="@drawable/qs_footer_actions_background"
android:gravity="center_vertical"
android:layout_gravity="bottom"
>
-
+ />
+
@@ -56,19 +63,17 @@
android:id="@+id/settings_button_container"
android:layout_width="@dimen/qs_footer_action_button_size"
android:layout_height="@dimen/qs_footer_action_button_size"
- android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
android:background="@drawable/qs_footer_action_circle"
android:clipChildren="false"
android:clipToPadding="false">
diff --git a/packages/SystemUI/res/drawable/new_fgs_dot.xml b/packages/SystemUI/res/drawable/new_fgs_dot.xml
new file mode 100644
index 0000000000000..759ddaf1e73f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/new_fgs_dot.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_circle.xml b/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
index f54c30f2e7949..d057f5f32dc4a 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
@@ -15,10 +15,7 @@
~ limitations under the License.
-->
+ android:inset="@dimen/new_qs_footer_action_inset">
-
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml b/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
index 1a323bccfa654..944061cc8e701 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
@@ -15,10 +15,7 @@
~ limitations under the License.
-->
+ android:inset="@dimen/new_qs_footer_action_inset">
-
diff --git a/packages/SystemUI/res/drawable/qs_footer_actions_background.xml b/packages/SystemUI/res/drawable/qs_footer_actions_background.xml
new file mode 100644
index 0000000000000..c9517cd905dc9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_footer_actions_background.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/drawable/qs_security_footer_background.xml b/packages/SystemUI/res/drawable/qs_security_footer_background.xml
index 860d23b114391..381af503d47c0 100644
--- a/packages/SystemUI/res/drawable/qs_security_footer_background.xml
+++ b/packages/SystemUI/res/drawable/qs_security_footer_background.xml
@@ -15,8 +15,8 @@
~ limitations under the License.
-->
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 22abd0c2f0346..85b33cc4cc257 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -25,7 +25,7 @@
android:id="@+id/expanded_qs_scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:elevation="4dp"
+ android:elevation="@dimen/qs_panel_elevation"
android:importantForAccessibility="no"
android:scrollbars="none"
android:clipChildren="false"
@@ -55,7 +55,7 @@
android:id="@+id/container_stub"
android:inflatedId="@+id/qs_footer_actions"
android:layout="@layout/new_footer_actions"
- android:layout_height="@dimen/qs_footer_height"
+ android:layout_height="@dimen/new_footer_height"
android:layout_width="match_parent"
android:layout_gravity="bottom"
/>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 268088cb2607f..fe79f271d0b64 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -329,6 +329,9 @@
etc. -->
48dp
+
+ 60dp
+
48dp
@@ -336,6 +339,9 @@
2dp
+
+ 4dp
+ -4dp
2dp
@@ -491,7 +497,8 @@
14sp
16dp
6dp
- @dimen/qs_footer_height
+ 4dp
+ @dimen/new_footer_height
48dp
0dp
56dp
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 53aebda8a4b4e..d39e295689864 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2375,6 +2375,9 @@
- %s active app
- %s active apps
+
+ New information
Active apps
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
index 58ebe89f199a1..bbe0a99309c63 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -40,6 +40,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED
import com.android.systemui.R
import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -50,6 +51,7 @@ import java.util.concurrent.Executor
import javax.inject.Inject
import kotlin.math.max
+@SysUISingleton
class FgsManagerController @Inject constructor(
private val context: Context,
@Main private val mainExecutor: Executor,
@@ -65,6 +67,9 @@ class FgsManagerController @Inject constructor(
private val LOG_TAG = FgsManagerController::class.java.simpleName
}
+ var changesSinceDialog = false
+ private set
+
private var isAvailable = false
private val lock = Any()
@@ -137,6 +142,7 @@ class FgsManagerController @Inject constructor(
val numPackagesAfter = getNumRunningPackagesLocked()
if (numPackagesAfter != numPackagesBefore) {
+ changesSinceDialog = true
onNumberOfPackagesChangedListeners.forEach {
backgroundExecutor.execute { it.onNumberOfPackagesChanged(numPackagesAfter) }
}
@@ -210,6 +216,7 @@ class FgsManagerController @Inject constructor(
this.dialog = dialog
dialog.setOnDismissListener {
+ changesSinceDialog = false
synchronized(lock) {
this.dialog = null
updateAppItemsLocked()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index 4aedbc983d9c2..77feb90f575a8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -22,6 +22,8 @@ import android.os.UserManager
import android.provider.Settings
import android.provider.Settings.Global.USER_SWITCHER_ENABLED
import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
import android.widget.Toast
import androidx.annotation.VisibleForTesting
import com.android.internal.jank.InteractionJankMonitor
@@ -29,7 +31,6 @@ 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.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.flags.FeatureFlags
@@ -46,6 +47,7 @@ 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.DualHeightHorizontalLinearLayout
import com.android.systemui.util.ViewController
import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
@@ -57,7 +59,7 @@ import javax.inject.Named
* determined by [buttonsVisibleState]
*/
@QSScope
-class FooterActionsController @Inject constructor(
+internal class FooterActionsController @Inject constructor(
view: FooterActionsView,
multiUserSwitchControllerFactory: MultiUserSwitchController.Factory,
private val activityStarter: ActivityStarter,
@@ -65,6 +67,8 @@ class FooterActionsController @Inject constructor(
private val userTracker: UserTracker,
private val userInfoController: UserInfoController,
private val deviceProvisionedController: DeviceProvisionedController,
+ private val securityFooterController: QSSecurityFooter,
+ private val fgsManagerFooterController: QSFgsManagerFooter,
private val falsingManager: FalsingManager,
private val metricsLogger: MetricsLogger,
private val tunerService: TunerService,
@@ -90,15 +94,15 @@ class FooterActionsController @Inject constructor(
updateVisibility()
}
- init {
- view.elevation = resources.displayMetrics.density * 4f
- view.setBackgroundColor(Utils.getColorAttrDefaultColor(context, R.attr.underSurfaceColor))
- }
-
private val settingsButton: SettingsButton = view.findViewById(R.id.settings_button)
private val settingsButtonContainer: View? = view.findViewById(R.id.settings_button_container)
+ private val securityFootersContainer: ViewGroup? =
+ view.findViewById(R.id.security_footers_container)
private val powerMenuLite: View = view.findViewById(R.id.pm_lite)
private val multiUserSwitchController = multiUserSwitchControllerFactory.create(view)
+ private val securityFootersSeparator = View(context).apply {
+ visibility = View.GONE
+ }
private val onUserInfoChangedListener = OnUserInfoChangedListener { _, picture, _ ->
val isGuestUser: Boolean = userManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser())
@@ -151,6 +155,7 @@ class FooterActionsController @Inject constructor(
override fun onInit() {
multiUserSwitchController.init()
+ fgsManagerFooterController.init()
}
private fun updateVisibility() {
@@ -178,9 +183,46 @@ class FooterActionsController @Inject constructor(
powerMenuLite.visibility = View.GONE
}
settingsButton.setOnClickListener(onClickListener)
+ if (featureFlags.isEnabled(Flags.NEW_FOOTER)) {
+ val securityFooter = securityFooterController.view as DualHeightHorizontalLinearLayout
+ securityFootersContainer?.addView(securityFooter)
+ val separatorWidth = resources.getDimensionPixelSize(R.dimen.new_qs_footer_action_inset)
+ securityFootersContainer?.addView(securityFootersSeparator, separatorWidth, 1)
+ reformatForNewFooter(securityFooter)
+ val fgsFooter = fgsManagerFooterController.view
+ securityFootersContainer?.addView(fgsFooter)
+
+ val visibilityListener =
+ VisibilityChangedDispatcher.OnVisibilityChangedListener { visibility ->
+ if (visibility == View.GONE) {
+ securityFootersSeparator.visibility = View.GONE
+ } else if (securityFooter.visibility == View.VISIBLE &&
+ fgsFooter.visibility == View.VISIBLE) {
+ securityFootersSeparator.visibility = View.VISIBLE
+ } else {
+ securityFootersSeparator.visibility = View.GONE
+ }
+ fgsManagerFooterController
+ .setCollapsed(securityFooter.visibility == View.VISIBLE)
+ }
+ securityFooterController.setOnVisibilityChangedListener(visibilityListener)
+ fgsManagerFooterController.setOnVisibilityChangedListener(visibilityListener)
+ }
updateView()
}
+ private fun reformatForNewFooter(view: DualHeightHorizontalLinearLayout) {
+ // This is only necessary while things are flagged as the view could be attached in two
+ // different locations.
+ (view.layoutParams as LinearLayout.LayoutParams).apply {
+ bottomMargin = 0
+ width = 0
+ weight = 1f
+ marginEnd = resources.getDimensionPixelSize(R.dimen.new_qs_footer_action_inset)
+ }
+ view.alwaysSingleLine = true
+ }
+
private fun updateView() {
mView.updateEverything(isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
}
@@ -201,6 +243,10 @@ class FooterActionsController @Inject constructor(
} else {
userInfoController.removeCallback(onUserInfoChangedListener)
}
+ if (featureFlags.isEnabled(Flags.NEW_FOOTER)) {
+ fgsManagerFooterController.setListening(listening)
+ securityFooterController.setListening(listening)
+ }
}
fun disable(state2: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 7800027ea967f..707313f08af60 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -211,9 +211,13 @@ public class QSContainerImpl extends FrameLayout implements Dumpable {
// Some views are always full width or have dependent padding
continue;
}
- LayoutParams lp = (LayoutParams) view.getLayoutParams();
- lp.rightMargin = mSideMargins;
- lp.leftMargin = mSideMargins;
+ if (!(view instanceof FooterActionsView)) {
+ // Only padding for FooterActionsView, no margin. That way, the background goes
+ // all the way to the edge.
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ lp.rightMargin = mSideMargins;
+ lp.leftMargin = mSideMargins;
+ }
if (view == mQSPanelContainer) {
// QS panel lays out some of its content full width
qsPanelController.setContentMargins(mContentPadding, mContentPadding);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
index 55d4a53ced7b2..0fe909552cb15 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
@@ -20,12 +20,17 @@ import static com.android.systemui.qs.dagger.QSFragmentModule.QS_FGS_MANAGER_FOO
import android.content.Context;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.qs.dagger.QSScope;
import java.util.concurrent.Executor;
@@ -35,9 +40,11 @@ import javax.inject.Named;
/**
* Footer entry point for the foreground service manager
*/
+@QSScope
public class QSFgsManagerFooter implements View.OnClickListener,
FgsManagerController.OnDialogDismissedListener,
- FgsManagerController.OnNumberOfPackagesChangedListener {
+ FgsManagerController.OnNumberOfPackagesChangedListener,
+ VisibilityChangedDispatcher {
private final View mRootView;
private final TextView mFooterText;
@@ -50,20 +57,43 @@ public class QSFgsManagerFooter implements View.OnClickListener,
private boolean mIsInitialized = false;
private int mNumPackages;
+ private final View mTextContainer;
+ private final View mNumberContainer;
+ private final TextView mNumberView;
+ private final ImageView mDotView;
+
+ @Nullable
+ private VisibilityChangedDispatcher.OnVisibilityChangedListener mVisibilityChangedListener;
+
@Inject
QSFgsManagerFooter(@Named(QS_FGS_MANAGER_FOOTER_VIEW) View rootView,
@Main Executor mainExecutor, @Background Executor executor,
FgsManagerController fgsManagerController) {
mRootView = rootView;
mFooterText = mRootView.findViewById(R.id.footer_text);
- ImageView icon = mRootView.findViewById(R.id.primary_footer_icon);
- icon.setImageResource(R.drawable.ic_info_outline);
+ mTextContainer = mRootView.findViewById(R.id.fgs_text_container);
+ mNumberContainer = mRootView.findViewById(R.id.fgs_number_container);
+ mNumberView = mRootView.findViewById(R.id.fgs_number);
+ mDotView = mRootView.findViewById(R.id.fgs_new);
mContext = rootView.getContext();
mMainExecutor = mainExecutor;
mExecutor = executor;
mFgsManagerController = fgsManagerController;
}
+ /**
+ * Whether to show the footer in collapsed mode (just a number) or not (text).
+ * @param collapsed
+ */
+ public void setCollapsed(boolean collapsed) {
+ mTextContainer.setVisibility(collapsed ? View.GONE : View.VISIBLE);
+ mNumberContainer.setVisibility(collapsed ? View.VISIBLE : View.GONE);
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mRootView.getLayoutParams();
+ lp.width = collapsed ? ViewGroup.LayoutParams.WRAP_CONTENT : 0;
+ lp.weight = collapsed ? 0f : 1f;
+ mRootView.setLayoutParams(lp);
+ }
+
public void init() {
if (mIsInitialized) {
return;
@@ -88,6 +118,12 @@ public class QSFgsManagerFooter implements View.OnClickListener,
}
}
+ @Override
+ public void setOnVisibilityChangedListener(
+ @Nullable OnVisibilityChangedListener onVisibilityChangedListener) {
+ mVisibilityChangedListener = onVisibilityChangedListener;
+ }
+
@Override
public void onClick(View view) {
mFgsManagerController.showDialog(mRootView);
@@ -103,11 +139,19 @@ public class QSFgsManagerFooter implements View.OnClickListener,
public void handleRefreshState() {
mMainExecutor.execute(() -> {
- mFooterText.setText(mContext.getResources().getQuantityString(
- R.plurals.fgs_manager_footer_label, mNumPackages, mNumPackages));
+ CharSequence text = mContext.getResources().getQuantityString(
+ R.plurals.fgs_manager_footer_label, mNumPackages, mNumPackages);
+ mFooterText.setText(text);
+ mNumberView.setText(Integer.toString(mNumPackages));
+ mNumberView.setContentDescription(text);
if (mFgsManagerController.shouldUpdateFooterVisibility()) {
mRootView.setVisibility(mNumPackages > 0
&& mFgsManagerController.isAvailable() ? View.VISIBLE : View.GONE);
+ mDotView.setVisibility(
+ mFgsManagerController.getChangesSinceDialog() ? View.VISIBLE : View.GONE);
+ if (mVisibilityChangedListener != null) {
+ mVisibilityChangedListener.onVisibilityChanged(mRootView.getVisibility());
+ }
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 6b515c85dc9f2..7c04cd4dcb059 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -110,6 +110,7 @@ public class QSPanel extends LinearLayout implements Tunable {
private float mSquishinessFraction = 1f;
private final ArrayMap mChildrenLayoutTop = new ArrayMap<>();
private final Rect mClippingRect = new Rect();
+ private boolean mUseNewFooter = false;
public QSPanel(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -151,6 +152,10 @@ public class QSPanel extends LinearLayout implements Tunable {
}
}
+ void setUseNewFooter(boolean useNewFooter) {
+ mUseNewFooter = useNewFooter;
+ }
+
protected void setHorizontalContentContainerClipping() {
mHorizontalContentContainer.setClipChildren(true);
mHorizontalContentContainer.setClipToPadding(false);
@@ -368,11 +373,12 @@ public class QSPanel extends LinearLayout implements Tunable {
protected void updatePadding() {
final Resources res = mContext.getResources();
- int padding = res.getDimensionPixelSize(R.dimen.qs_panel_padding_top);
+ int paddingTop = res.getDimensionPixelSize(R.dimen.qs_panel_padding_top);
+ // Bottom padding only when there's a new footer with its height.
setPaddingRelative(getPaddingStart(),
- padding,
+ paddingTop,
getPaddingEnd(),
- res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
+ mUseNewFooter ? res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom) : 0);
}
void addOnConfigurationChangedListener(OnConfigurationChangedListener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 8f268b5cffe4c..418c4ae023ca0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -31,6 +31,8 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.FalsingManager;
@@ -67,6 +69,7 @@ public class QSPanelController extends QSPanelControllerBase {
private final BrightnessController mBrightnessController;
private final BrightnessSliderController mBrightnessSliderController;
private final BrightnessMirrorHandler mBrightnessMirrorHandler;
+ private final FeatureFlags mFeatureFlags;
private boolean mGridContentVisible = true;
@@ -104,7 +107,7 @@ public class QSPanelController extends QSPanelControllerBase {
DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
BrightnessSliderController.Factory brightnessSliderFactory,
- FalsingManager falsingManager, CommandQueue commandQueue) {
+ FalsingManager falsingManager, CommandQueue commandQueue, FeatureFlags featureFlags) {
super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
metricsLogger, uiEventLogger, qsLogger, dumpManager);
mQSFgsManagerFooter = qsFgsManagerFooter;
@@ -114,13 +117,14 @@ public class QSPanelController extends QSPanelControllerBase {
mQsTileRevealControllerFactory = qsTileRevealControllerFactory;
mFalsingManager = falsingManager;
mCommandQueue = commandQueue;
- mQsSecurityFooter.setHostEnvironment(qstileHost);
mBrightnessSliderController = brightnessSliderFactory.create(getContext(), mView);
mView.setBrightnessView(mBrightnessSliderController.getRootView());
mBrightnessController = brightnessControllerFactory.create(mBrightnessSliderController);
mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
+ mFeatureFlags = featureFlags;
+ view.setUseNewFooter(featureFlags.isEnabled(Flags.NEW_FOOTER));
}
@Override
@@ -150,8 +154,10 @@ public class QSPanelController extends QSPanelControllerBase {
refreshAllTiles();
}
mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
- mView.setFgsManagerFooter(mQSFgsManagerFooter.getView());
- mView.setSecurityFooter(mQsSecurityFooter.getView(), mShouldUseSplitNotificationShade);
+ if (!mFeatureFlags.isEnabled(Flags.NEW_FOOTER)) {
+ mView.setSecurityFooter(mQsSecurityFooter.getView(), mShouldUseSplitNotificationShade);
+ mView.setFgsManagerFooter(mQSFgsManagerFooter.getView());
+ }
switchTileLayout(true);
mBrightnessMirrorHandler.onQsPanelAttached();
@@ -192,8 +198,10 @@ public class QSPanelController extends QSPanelControllerBase {
refreshAllTiles();
}
- mQSFgsManagerFooter.setListening(listening);
- mQsSecurityFooter.setListening(listening);
+ if (!mFeatureFlags.isEnabled(Flags.NEW_FOOTER)) {
+ mQSFgsManagerFooter.setListening(listening);
+ mQsSecurityFooter.setListening(listening);
+ }
// Set the listening as soon as the QS fragment starts listening regardless of the
//expansion, so it will update the current brightness before the slider is visible.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 9e17c121a79f2..fb55cd2d22453 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -80,6 +80,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -88,11 +89,14 @@ import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.SecurityController;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import javax.inject.Inject;
import javax.inject.Named;
@QSScope
-class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListener {
+class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListener,
+ VisibilityChangedDispatcher {
protected static final String TAG = "QSSecurityFooter";
protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final boolean DEBUG_FORCE_VISIBLE = false;
@@ -107,11 +111,16 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
private final ActivityStarter mActivityStarter;
private final Handler mMainHandler;
private final UserTracker mUserTracker;
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
+
+ private final AtomicBoolean mShouldUseSettingsButton = new AtomicBoolean(false);
private AlertDialog mDialog;
- private QSTileHost mHost;
protected H mHandler;
+ // Does it move between footer and header? Remove this once all the flagging is removed
+ private boolean mIsMovable = true;
+
private boolean mIsVisible;
@Nullable
private CharSequence mFooterTextContent = null;
@@ -119,10 +128,14 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
@Nullable
private Drawable mPrimaryFooterIconDrawable;
+ @Nullable
+ private VisibilityChangedDispatcher.OnVisibilityChangedListener mVisibilityChangedListener;
+
@Inject
QSSecurityFooter(@Named(QS_SECURITY_FOOTER_VIEW) View rootView,
UserTracker userTracker, @Main Handler mainHandler, ActivityStarter activityStarter,
- SecurityController securityController, @Background Looper bgLooper) {
+ SecurityController securityController, DialogLaunchAnimator dialogLaunchAnimator,
+ @Background Looper bgLooper) {
mRootView = rootView;
mRootView.setOnClickListener(this);
mFooterText = mRootView.findViewById(R.id.footer_text);
@@ -135,10 +148,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
mSecurityController = securityController;
mHandler = new H(bgLooper);
mUserTracker = userTracker;
- }
-
- public void setHostEnvironment(QSTileHost host) {
- mHost = host;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
}
public void setListening(boolean listening) {
@@ -150,23 +160,31 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
}
}
+ @Override
+ public void setOnVisibilityChangedListener(
+ @Nullable OnVisibilityChangedListener onVisibilityChangedListener) {
+ mVisibilityChangedListener = onVisibilityChangedListener;
+ }
+
public void onConfigurationChanged() {
FontSizeUtils.updateFontSize(mFooterText, R.dimen.qs_tile_text_size);
- Resources r = mContext.getResources();
+ if (mIsMovable) {
+ Resources r = mContext.getResources();
- mFooterText.setMaxLines(r.getInteger(R.integer.qs_security_footer_maxLines));
- int padding = r.getDimensionPixelSize(R.dimen.qs_footer_padding);
- mRootView.setPaddingRelative(padding, padding, padding, padding);
+ mFooterText.setMaxLines(r.getInteger(R.integer.qs_security_footer_maxLines));
+ int padding = r.getDimensionPixelSize(R.dimen.qs_footer_padding);
+ mRootView.setPaddingRelative(padding, padding, padding, padding);
- int bottomMargin = r.getDimensionPixelSize(R.dimen.qs_footers_margin_bottom);
- ViewGroup.MarginLayoutParams lp =
- (ViewGroup.MarginLayoutParams) mRootView.getLayoutParams();
- lp.bottomMargin = bottomMargin;
- lp.width = r.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT
- ? MATCH_PARENT : WRAP_CONTENT;
- mRootView.setLayoutParams(lp);
+ int bottomMargin = r.getDimensionPixelSize(R.dimen.qs_footers_margin_bottom);
+ ViewGroup.MarginLayoutParams lp =
+ (ViewGroup.MarginLayoutParams) mRootView.getLayoutParams();
+ lp.bottomMargin = bottomMargin;
+ lp.width = r.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT
+ ? MATCH_PARENT : WRAP_CONTENT;
+ mRootView.setLayoutParams(lp);
+ }
mRootView.setBackground(mContext.getDrawable(R.drawable.qs_security_footer_background));
}
@@ -455,23 +473,27 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_NEGATIVE) {
final Intent intent = new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS);
- mDialog.dismiss();
+ dialog.dismiss();
// This dismisses the shade on opening the activity
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
}
}
private void createDialog() {
- mDialog = new SystemUIDialog(mContext, 0); // Use mContext theme
- mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
- mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
- mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getNegativeButton(), this);
+ mShouldUseSettingsButton.set(false);
+ final View view = createDialogView();
+ mMainHandler.post(() -> {
+ mDialog = new SystemUIDialog(mContext, 0); // Use mContext theme
+ mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+ mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
+ mDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
+ mShouldUseSettingsButton.get() ? getSettingsButton() : getNegativeButton(),
+ this);
- mDialog.setView(createDialogView());
+ mDialog.setView(view);
- mDialog.show();
- mDialog.getWindow().setLayout(MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
+ mDialogLaunchAnimator.showFromView(mDialog, mRootView);
+ });
}
@VisibleForTesting
@@ -510,7 +532,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
TextView deviceManagementWarning =
(TextView) dialogView.findViewById(R.id.device_management_warning);
deviceManagementWarning.setText(managementMessage);
- mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
+ mShouldUseSettingsButton.set(true);
}
// ca certificate section
@@ -782,6 +804,9 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
mFooterText.setText(mFooterTextContent);
}
mRootView.setVisibility(mIsVisible || DEBUG_FORCE_VISIBLE ? View.VISIBLE : View.GONE);
+ if (mVisibilityChangedListener != null) {
+ mVisibilityChangedListener.onVisibilityChanged(mRootView.getVisibility());
+ }
}
};
@@ -814,7 +839,6 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
} catch (Throwable t) {
final String error = "Error in " + name;
Log.w(TAG, error, t);
- mHost.warn(error, t);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/VisibilityChangedDispatcher.kt b/packages/SystemUI/src/com/android/systemui/qs/VisibilityChangedDispatcher.kt
new file mode 100644
index 0000000000000..73362cec701e9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/VisibilityChangedDispatcher.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 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
+
+/**
+ * Dispatches events that set the visibility from the controller.
+ */
+interface VisibilityChangedDispatcher {
+
+ fun setOnVisibilityChangedListener(onVisibilityChangedListener: OnVisibilityChangedListener?)
+
+ fun interface OnVisibilityChangedListener {
+ fun onVisibilityChanged(visibility: Int)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index fdf9ae0d4b635..2780b163e5ca0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -202,6 +202,6 @@ public interface QSFragmentModule {
@QSThemedContext LayoutInflater layoutInflater,
QSPanel qsPanel
) {
- return layoutInflater.inflate(R.layout.quick_settings_security_footer, qsPanel, false);
+ return layoutInflater.inflate(R.layout.fgs_footer, qsPanel, false);
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
index b457ebf60c716..7c9e597e74a13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
@@ -102,17 +102,21 @@ class NotificationsQSContainerController @Inject constructor(
private fun updateBottomSpacing() {
val (containerPadding, notificationsMargin) = calculateBottomSpacing()
var qsScrollPaddingBottom = 0
- if (!(splitShadeEnabled || isQSCustomizing || isQSDetailShowing || isGestureNavigation ||
- taskbarVisible)) {
+ val newFooter = featureFlags.isEnabled(Flags.NEW_FOOTER)
+ if (!newFooter && !(splitShadeEnabled || isQSCustomizing || isQSDetailShowing ||
+ isGestureNavigation || taskbarVisible)) {
// no taskbar, portrait, navigation buttons enabled:
// padding is needed so QS can scroll up over bottom insets - to reach the point when
// the whole QS is above bottom insets
qsScrollPaddingBottom = bottomStableInsets
+ } else if (newFooter && !(isQSCustomizing || isQSDetailShowing)) {
+ // With the new footer, we also want this padding in the bottom in these cases
+ qsScrollPaddingBottom = bottomStableInsets
}
mView.setPadding(0, 0, 0, containerPadding)
mView.setNotificationsMarginBottom(notificationsMargin)
- if (featureFlags.isEnabled(Flags.NEW_FOOTER)) {
- mView.setQSContainerPaddingBottom(notificationsMargin)
+ if (newFooter) {
+ mView.setQSContainerPaddingBottom(qsScrollPaddingBottom)
} else {
mView.setQSScrollPaddingBottom(qsScrollPaddingBottom)
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/DualHeightHorizontalLinearLayout.kt b/packages/SystemUI/src/com/android/systemui/util/DualHeightHorizontalLinearLayout.kt
index 0e04871106ef8..cfceefa2006c4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DualHeightHorizontalLinearLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/DualHeightHorizontalLinearLayout.kt
@@ -65,6 +65,17 @@ class DualHeightHorizontalLinearLayout @JvmOverloads constructor(
private var initialPadding = mPaddingTop // All vertical padding is the same
+ private var originalMaxLines = 1
+ var alwaysSingleLine: Boolean = false
+ set(value) {
+ field = value
+ if (field) {
+ textView?.setSingleLine()
+ } else {
+ textView?.maxLines = originalMaxLines
+ }
+ }
+
init {
if (orientation != HORIZONTAL) {
throw IllegalStateException("This view should always have horizontal orientation")
@@ -120,7 +131,7 @@ class DualHeightHorizontalLinearLayout @JvmOverloads constructor(
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
textView?.let { tv ->
- if (tv.lineCount < 2) {
+ if (tv.lineCount < 2 || alwaysSingleLine) {
setMeasuredDimension(measuredWidth, singleLineHeightPx)
mPaddingBottom = 0
mPaddingTop = 0
@@ -133,7 +144,9 @@ class DualHeightHorizontalLinearLayout @JvmOverloads constructor(
override fun onFinishInflate() {
super.onFinishInflate()
- textView = findViewById(textViewId)
+ textView = findViewById(textViewId)?.also {
+ originalMaxLines = it.maxLines
+ }
}
override fun onConfigurationChanged(newConfig: Configuration?) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
index f5fa0d030901e..91a9f9e5ef36d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
@@ -64,6 +64,10 @@ class FooterActionsControllerTest : LeakCheckedTest() {
private lateinit var uiEventLogger: UiEventLogger
@Mock
private lateinit var featureFlags: FeatureFlags
+ @Mock
+ private lateinit var securityFooterController: QSSecurityFooter
+ @Mock
+ private lateinit var fgsManagerController: QSFgsManagerFooter
private lateinit var controller: FooterActionsController
@@ -90,7 +94,8 @@ class FooterActionsControllerTest : LeakCheckedTest() {
controller = FooterActionsController(view, multiUserSwitchControllerFactory,
activityStarter, userManager, userTracker, userInfoController,
- deviceProvisionedController, falsingManager, metricsLogger, fakeTunerService,
+ deviceProvisionedController, securityFooterController, fgsManagerController,
+ falsingManager, metricsLogger, fakeTunerService,
globalActionsDialog, uiEventLogger, showPMLiteButton = true, fakeSettings,
Handler(testableLooper.looper), featureFlags)
controller.init()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
index b5ce7066f5529..b2ca62f18f27c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
@@ -36,6 +36,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.customize.QSCustomizerController;
@@ -106,6 +107,8 @@ public class QSPanelControllerTest extends SysuiTestCase {
Resources mResources;
@Mock
Configuration mConfiguration;
+ @Mock
+ FeatureFlags mFeatureFlags;
private QSPanelController mController;
@@ -133,7 +136,7 @@ public class QSPanelControllerTest extends SysuiTestCase {
mTunerService, mQSTileHost, mQSCustomizerController, true, mMediaHost,
mQSTileRevealControllerFactory, mDumpManager, mMetricsLogger, mUiEventLogger,
mQSLogger, mBrightnessControllerFactory, mToggleSliderViewControllerFactory,
- mFalsingManager, mCommandQueue
+ mFalsingManager, mCommandQueue, mFeatureFlags
);
mController.init();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index 3500c183de394..4ae193327b7bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -162,6 +162,20 @@ class QSPanelTest : SysuiTestCase() {
assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(-1)
}
+ @Test
+ fun testBottomPadding() {
+ mQsPanel.setUseNewFooter(false)
+
+ mQsPanel.updatePadding()
+ assertThat(mQsPanel.paddingBottom).isEqualTo(0)
+
+ mQsPanel.setUseNewFooter(true)
+
+ mQsPanel.updatePadding()
+ assertThat(mQsPanel.paddingBottom)
+ .isEqualTo(mContext.resources.getDimensionPixelSize(R.dimen.new_footer_height))
+ }
+
private fun getNewOrientationConfig(@Configuration.Orientation newOrientation: Int) =
context.resources.configuration.apply { orientation = newOrientation }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 770cf2ca03313..2b7fa42903c4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -22,12 +22,14 @@ import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.pm.UserInfo;
@@ -50,6 +52,7 @@ import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.SecurityController;
@@ -57,10 +60,13 @@ import com.android.systemui.statusbar.policy.SecurityController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.concurrent.atomic.AtomicInteger;
+
/*
* Compile and run the whole SystemUI test suite:
runtest --path frameworks/base/packages/SystemUI/tests
@@ -94,20 +100,24 @@ public class QSSecurityFooterTest extends SysuiTestCase {
private UserTracker mUserTracker;
@Mock
private ActivityStarter mActivityStarter;
+ @Mock
+ private DialogLaunchAnimator mDialogLaunchAnimator;
+
+ private TestableLooper mTestableLooper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- Looper looper = TestableLooper.get(this).getLooper();
+ mTestableLooper = TestableLooper.get(this);
+ Looper looper = mTestableLooper.getLooper();
when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class));
mRootView = (ViewGroup) new LayoutInflaterBuilder(mContext)
.replace("ImageView", TestableImageView.class)
.build().inflate(R.layout.quick_settings_security_footer, null, false);
mFooter = new QSSecurityFooter(mRootView, mUserTracker, new Handler(looper),
- mActivityStarter, mSecurityController, looper);
+ mActivityStarter, mSecurityController, mDialogLaunchAnimator, looper);
mFooterText = mRootView.findViewById(R.id.footer_text);
mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon);
- mFooter.setHostEnvironment(null);
when(mSecurityController.getDeviceOwnerComponentOnAnyUser())
.thenReturn(DEVICE_OWNER_COMPONENT);
@@ -650,8 +660,6 @@ public class QSSecurityFooterTest extends SysuiTestCase {
@Test
public void testNoClickWhenGone() {
- QSTileHost mockHost = mock(QSTileHost.class);
- mFooter.setHostEnvironment(mockHost);
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
@@ -660,7 +668,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
mFooter.onClick(mFooter.getView());
// Proxy for dialog being created
- verify(mockHost, never()).collapsePanels();
+ verify(mDialogLaunchAnimator, never()).showFromView(any(), any());
}
@Test
@@ -699,6 +707,16 @@ public class QSSecurityFooterTest extends SysuiTestCase {
assertEquals(PARENTAL_CONTROLS_LABEL, textView.getText());
}
+ @Test
+ public void testDialogUsesDialogLauncher() {
+ when(mSecurityController.isDeviceManaged()).thenReturn(true);
+ mFooter.onClick(mRootView);
+
+ mTestableLooper.processAllMessages();
+
+ verify(mDialogLaunchAnimator).showFromView(any(), eq(mRootView));
+ }
+
@Test
public void testCreateDialogViewForFinancedDevice() {
when(mSecurityController.isDeviceManaged()).thenReturn(true);
@@ -707,12 +725,6 @@ public class QSSecurityFooterTest extends SysuiTestCase {
when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_FINANCED);
- // Initialize AlertDialog which sets the text for the negative button, which is used when
- // creating the dialog for a financed device.
- mFooter.showDeviceMonitoringDialog();
- // The above statement would display the Quick Settings dialog which requires user input,
- // so simulate the press to continue with the unit test (otherwise, it is stuck).
- mFooter.onClick(null, DialogInterface.BUTTON_NEGATIVE);
View view = mFooter.createDialogView();
TextView managementSubtitle = view.findViewById(R.id.device_management_subtitle);
@@ -727,6 +739,49 @@ public class QSSecurityFooterTest extends SysuiTestCase {
mFooter.getSettingsButton());
}
+ @Test
+ public void testFinancedDeviceUsesSettingsButtonText() {
+ when(mSecurityController.isDeviceManaged()).thenReturn(true);
+ when(mSecurityController.getDeviceOwnerOrganizationName())
+ .thenReturn(MANAGING_ORGANIZATION);
+ when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
+ .thenReturn(DEVICE_OWNER_TYPE_FINANCED);
+
+ mFooter.showDeviceMonitoringDialog();
+ ArgumentCaptor dialogCaptor = ArgumentCaptor.forClass(AlertDialog.class);
+
+ mTestableLooper.processAllMessages();
+ verify(mDialogLaunchAnimator).showFromView(dialogCaptor.capture(), any());
+
+ AlertDialog dialog = dialogCaptor.getValue();
+ dialog.create();
+
+ assertEquals(mFooter.getSettingsButton(),
+ dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getText());
+
+ dialog.dismiss();
+ }
+
+ @Test
+ public void testVisibilityListener() {
+ final AtomicInteger lastVisibility = new AtomicInteger(-1);
+ VisibilityChangedDispatcher.OnVisibilityChangedListener listener =
+ (VisibilityChangedDispatcher.OnVisibilityChangedListener) lastVisibility::set;
+
+ mFooter.setOnVisibilityChangedListener(listener);
+
+ when(mSecurityController.isDeviceManaged()).thenReturn(true);
+ mFooter.refreshState();
+ mTestableLooper.processAllMessages();
+ assertEquals(View.VISIBLE, lastVisibility.get());
+
+ when(mSecurityController.isDeviceManaged()).thenReturn(false);
+ mFooter.refreshState();
+ mTestableLooper.processAllMessages();
+ assertEquals(View.GONE, lastVisibility.get());
+ }
+
+
private CharSequence addLink(CharSequence description) {
final SpannableStringBuilder message = new SpannableStringBuilder();
message.append(description);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
index bbb2346797b98..00af446ded3d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
@@ -114,13 +114,15 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
navigationMode = GESTURES_NAVIGATION,
insets = windowInsets().withStableBottom())
then(expectedContainerPadding = 0, // taskbar should disappear when shade is expanded
- expectedNotificationsMargin = NOTIFICATIONS_MARGIN)
+ expectedNotificationsMargin = NOTIFICATIONS_MARGIN,
+ expectedQsPadding = STABLE_INSET_BOTTOM)
given(taskbarVisible = true,
navigationMode = BUTTONS_NAVIGATION,
insets = windowInsets().withStableBottom())
then(expectedContainerPadding = STABLE_INSET_BOTTOM,
- expectedNotificationsMargin = NOTIFICATIONS_MARGIN)
+ expectedNotificationsMargin = NOTIFICATIONS_MARGIN,
+ expectedQsPadding = STABLE_INSET_BOTTOM)
}
@Test
@@ -150,13 +152,15 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
given(taskbarVisible = false,
navigationMode = GESTURES_NAVIGATION,
insets = windowInsets().withStableBottom())
- then(expectedContainerPadding = 0)
+ then(expectedContainerPadding = 0,
+ expectedQsPadding = STABLE_INSET_BOTTOM)
given(taskbarVisible = false,
navigationMode = BUTTONS_NAVIGATION,
insets = windowInsets().withStableBottom())
then(expectedContainerPadding = 0, // qs goes full height as it's not obscuring nav buttons
- expectedNotificationsMargin = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN)
+ expectedNotificationsMargin = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN,
+ expectedQsPadding = STABLE_INSET_BOTTOM)
}
@Test
@@ -190,7 +194,8 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
navigationMode = BUTTONS_NAVIGATION,
insets = windowInsets().withCutout().withStableBottom())
then(expectedContainerPadding = 0,
- expectedNotificationsMargin = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN)
+ expectedNotificationsMargin = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN,
+ expectedQsPadding = STABLE_INSET_BOTTOM)
}
@Test
@@ -217,12 +222,14 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
given(taskbarVisible = true,
navigationMode = GESTURES_NAVIGATION,
insets = windowInsets().withStableBottom())
- then(expectedContainerPadding = 0)
+ then(expectedContainerPadding = 0,
+ expectedQsPadding = STABLE_INSET_BOTTOM)
given(taskbarVisible = true,
navigationMode = BUTTONS_NAVIGATION,
insets = windowInsets().withStableBottom())
- then(expectedContainerPadding = STABLE_INSET_BOTTOM)
+ then(expectedContainerPadding = STABLE_INSET_BOTTOM,
+ expectedQsPadding = STABLE_INSET_BOTTOM)
}
@Test
@@ -259,7 +266,7 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
given(taskbarVisible = false,
navigationMode = GESTURES_NAVIGATION,
insets = windowInsets().withCutout().withStableBottom())
- then(expectedContainerPadding = CUTOUT_HEIGHT)
+ then(expectedContainerPadding = CUTOUT_HEIGHT, expectedQsPadding = STABLE_INSET_BOTTOM)
given(taskbarVisible = false,
navigationMode = BUTTONS_NAVIGATION,
@@ -350,6 +357,7 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testDetailShowingInSplitShade() {
notificationsQSContainerController.splitShadeEnabled = true
+ notificationsQSContainerController.setDetailShowing(true)
useNewFooter(false)
given(taskbarVisible = false,
@@ -357,7 +365,6 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
insets = windowInsets().withStableBottom())
then(expectedContainerPadding = 0)
- notificationsQSContainerController.setDetailShowing(true)
// should not influence spacing
given(taskbarVisible = false,
navigationMode = BUTTONS_NAVIGATION,
@@ -368,6 +375,7 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testDetailShowingInSplitShade_newFooter() {
notificationsQSContainerController.splitShadeEnabled = true
+ notificationsQSContainerController.setDetailShowing(true)
useNewFooter(true)
given(taskbarVisible = false,
@@ -375,7 +383,6 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
insets = windowInsets().withStableBottom())
then(expectedContainerPadding = 0)
- notificationsQSContainerController.setDetailShowing(true)
// should not influence spacing
given(taskbarVisible = false,
navigationMode = BUTTONS_NAVIGATION,
@@ -417,7 +424,7 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
val newFooter = featureFlags.isEnabled(Flags.NEW_FOOTER)
if (newFooter) {
verify(notificationsQSContainer)
- .setQSContainerPaddingBottom(expectedNotificationsMargin)
+ .setQSContainerPaddingBottom(expectedQsPadding)
} else {
verify(notificationsQSContainer).setQSScrollPaddingBottom(expectedQsPadding)
}