diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index 42c2c6912d819..ca549aeba1f5a 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -30,9 +30,7 @@
@dimen/status_bar_height_landscape
- @dimen/status_bar_height_landscape
-
- 152dp
+ 48dp
40dip
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index afbbe467078c2..cf5b4e1558f9a 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -47,10 +47,6 @@
@dimen/status_bar_height_portrait
48dp
-
- 176dp
-
- 224dp
48dp
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8621147137dd1..beed9a3fe1c5f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1716,8 +1716,6 @@
-
-
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 44f52efd175e0..bbf69a939dcea 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -18,32 +18,52 @@
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/quick_qs_status_icons"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/qs_header_top_padding"
- android:paddingBottom="@dimen/qs_header_bottom_padding"
- android:layout_below="@id/quick_status_bar_system_icons"
+ android:layout_height="@*android:dimen/quick_qs_offset_height"
android:clipChildren="false"
android:clipToPadding="false"
- android:minHeight="20dp"
+ android:minHeight="48dp"
android:clickable="false"
android:focusable="true"
android:theme="@style/QSHeaderTheme">
-
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock" />
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 059bda3a23762..5bf691928300e 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -32,26 +32,32 @@
android:paddingStart="0dp"
android:elevation="4dp" >
-
-
+
+
-
-
-
-
-
+
+
+
+
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
similarity index 72%
rename from packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
rename to packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
index f663ab4eb4aae..22cf2cb8cc1a1 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
@@ -17,33 +17,35 @@
+ android:paddingTop="@dimen/status_bar_padding_top"
+ android:minHeight="48dp">
-
+
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index b8823e148e684..ee0b0c28b0c5a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -65,12 +65,14 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
private final QuickQSPanel mQuickQsPanel;
private final QSPanelController mQsPanelController;
private final QuickQSPanelController mQuickQSPanelController;
+ private final QuickStatusBarHeader mQuickStatusBarHeader;
private final QSSecurityFooter mSecurityFooter;
private final QS mQs;
private PagedTileLayout mPagedLayout;
private boolean mOnFirstPage = true;
+ private QSExpansionPathInterpolator mQSExpansionPathInterpolator;
private TouchAnimator mFirstPageAnimator;
private TouchAnimator mFirstPageDelayedAnimator;
private TouchAnimator mTranslationXAnimator;
@@ -98,19 +100,22 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
private final FeatureFlags mFeatureFlags;
@Inject
- public QSAnimator(QS qs, QuickQSPanel quickPanel, QSPanelController qsPanelController,
+ public QSAnimator(QS qs, QuickQSPanel quickPanel, QuickStatusBarHeader quickStatusBarHeader,
+ QSPanelController qsPanelController,
QuickQSPanelController quickQSPanelController, QSTileHost qsTileHost,
QSSecurityFooter securityFooter, @Main Executor executor, TunerService tunerService,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags, QSExpansionPathInterpolator qsExpansionPathInterpolator) {
mQs = qs;
mQuickQsPanel = quickPanel;
mQsPanelController = qsPanelController;
mQuickQSPanelController = quickQSPanelController;
+ mQuickStatusBarHeader = quickStatusBarHeader;
mSecurityFooter = securityFooter;
mHost = qsTileHost;
mExecutor = executor;
mTunerService = tunerService;
mFeatureFlags = featureFlags;
+ mQSExpansionPathInterpolator = qsExpansionPathInterpolator;
mHost.addCallback(this);
mQsPanelController.addOnAttachStateChangeListener(this);
qs.getView().addOnLayoutChangeListener(this);
@@ -252,7 +257,9 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
if (count < tileLayout.getNumVisibleTiles()) {
getRelativePosition(loc1, quickTileView, view);
getRelativePosition(loc2, tileView, view);
- int yOffset = qsSideLabelsEnabled ? loc2[1] - loc1[1] : 0;
+ int yOffset = qsSideLabelsEnabled
+ ? loc2[1] - loc1[1]
+ : mQuickStatusBarHeader.getOffsetTranslation();
// Move the quick tile right from its location to the new one.
View v = qsSideLabelsEnabled ? quickTileView.getIcon() : quickTileView;
translationXBuilder.addFloat(v, "translationX", 0, xDiff);
@@ -266,8 +273,14 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
translationYBuilder.addFloat(v, "translationY", -yDiff + yOffset, 0);
if (qsSideLabelsEnabled) {
- translationYBuilder.addFloat(quickTileView, "translationY", 0, yOffset);
- translationYBuilder.addFloat(tileView, "translationY", -yOffset, 0);
+ // Offset the translation animation on the views
+ // (that goes from 0 to getOffsetTranslation)
+ int offsetWithQSBHTranslation =
+ yOffset - mQuickStatusBarHeader.getOffsetTranslation();
+ translationYBuilder.addFloat(quickTileView, "translationY", 0,
+ offsetWithQSBHTranslation);
+ translationYBuilder.addFloat(tileView, "translationY",
+ -offsetWithQSBHTranslation, 0);
if (mQQSTileHeightAnimator == null) {
mQQSTileHeightAnimator = new HeightExpansionAnimator(this,
@@ -375,22 +388,23 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
}
float px = 0;
- float py = 1;
if (tiles.size() <= 3) {
px = 1;
} else if (tiles.size() <= 6) {
px = .4f;
}
- PathInterpolatorBuilder interpolatorBuilder = new PathInterpolatorBuilder(0, 0, px, py);
- translationXBuilder.setInterpolator(interpolatorBuilder.getXInterpolator());
- translationYBuilder.setInterpolator(interpolatorBuilder.getYInterpolator());
+ mQSExpansionPathInterpolator.setControlX2(px);
+ translationXBuilder.setInterpolator(mQSExpansionPathInterpolator.getXInterpolator());
+ translationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
mTranslationXAnimator = translationXBuilder.build();
mTranslationYAnimator = translationYBuilder.build();
if (mQQSTileHeightAnimator != null) {
- mQQSTileHeightAnimator.setInterpolator(interpolatorBuilder.getYInterpolator());
+ mQQSTileHeightAnimator.setInterpolator(
+ mQSExpansionPathInterpolator.getYInterpolator());
}
if (mOtherTilesExpandAnimator != null) {
- mOtherTilesExpandAnimator.setInterpolator(interpolatorBuilder.getYInterpolator());
+ mOtherTilesExpandAnimator.setInterpolator(
+ mQSExpansionPathInterpolator.getYInterpolator());
}
}
mNonfirstPageAnimator = new TouchAnimator.Builder()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSExpansionPathInterpolator.kt b/packages/SystemUI/src/com/android/systemui/qs/QSExpansionPathInterpolator.kt
new file mode 100644
index 0000000000000..d351b89b97842
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSExpansionPathInterpolator.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.view.animation.Interpolator
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class QSExpansionPathInterpolator @Inject constructor() {
+
+ private var pathInterpolatorBuilder = PathInterpolatorBuilder(0f, 0f, 0f, 1f)
+ private var lastX = 0f
+ val xInterpolator: Interpolator
+ get() = pathInterpolatorBuilder.xInterpolator
+
+ val yInterpolator: Interpolator
+ get() = pathInterpolatorBuilder.yInterpolator
+
+ fun setControlX2(value: Float) {
+ if (value != lastX) {
+ lastX = value
+ pathInterpolatorBuilder = PathInterpolatorBuilder(0f, 0f, lastX, 1f)
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt
deleted file mode 100644
index c65462193758f..0000000000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2019 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.content.Context
-import android.util.AttributeSet
-import android.view.View
-import android.widget.FrameLayout
-import com.android.systemui.R
-
-/**
- * Container for the Next Alarm and Ringer status texts in [QuickStatusBarHeader].
- *
- * If both elements are visible, it splits the available space according to the following rules:
- * * If both views add up to less than the total space, they take all the space they need.
- * * If both views are larger than half the space, each view takes half the space.
- * * Otherwise, the smaller view takes the space it needs and the larger one takes all remaining
- * space.
- */
-class QSHeaderInfoLayout @JvmOverloads constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyle: Int = 0,
- defStyleRes: Int = 0
-) : FrameLayout(context, attrs, defStyle, defStyleRes) {
-
- private lateinit var alarmContainer: View
- private lateinit var ringerContainer: View
- private lateinit var statusSeparator: View
- private val location = Location(0, 0)
-
- override fun onFinishInflate() {
- super.onFinishInflate()
- alarmContainer = findViewById(R.id.alarm_container)
- ringerContainer = findViewById(R.id.ringer_container)
- statusSeparator = findViewById(R.id.status_separator)
- }
-
- override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
- // At most one view is there
- if (statusSeparator.visibility == View.GONE) super.onLayout(changed, l, t, r, b)
- else {
- val layoutRTL = isLayoutRtl
- val width = r - l
- val height = b - t
- var offset = 0
-
- offset += alarmContainer.layoutView(width, height, offset, layoutRTL)
- offset += statusSeparator.layoutView(width, height, offset, layoutRTL)
- ringerContainer.layoutView(width, height, offset, layoutRTL)
- }
- }
-
- private fun View.layoutView(pWidth: Int, pHeight: Int, offset: Int, RTL: Boolean): Int {
- location.setLocationFromOffset(pWidth, offset, this.measuredWidth, RTL)
- layout(location.left, 0, location.right, pHeight)
- return this.measuredWidth
- }
-
- override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
- super.onMeasure(
- MeasureSpec.makeMeasureSpec(
- MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST),
- heightMeasureSpec)
- val width = MeasureSpec.getSize(widthMeasureSpec)
- // Once we measure the views, using as much space as they need, we need to remeasure them
- // assigning them their final width. This is because TextViews decide whether to MARQUEE
- // after onMeasure.
- if (statusSeparator.visibility != View.GONE) {
- val alarmWidth = alarmContainer.measuredWidth
- val separatorWidth = statusSeparator.measuredWidth
- val ringerWidth = ringerContainer.measuredWidth
- val availableSpace = MeasureSpec.getSize(width) - separatorWidth
- if (alarmWidth < availableSpace / 2) {
- measureChild(
- ringerContainer,
- MeasureSpec.makeMeasureSpec(
- Math.min(ringerWidth, availableSpace - alarmWidth),
- MeasureSpec.AT_MOST),
- heightMeasureSpec)
- } else if (ringerWidth < availableSpace / 2) {
- measureChild(alarmContainer,
- MeasureSpec.makeMeasureSpec(
- Math.min(alarmWidth, availableSpace - ringerWidth),
- MeasureSpec.AT_MOST),
- heightMeasureSpec)
- } else {
- measureChild(
- alarmContainer,
- MeasureSpec.makeMeasureSpec(availableSpace / 2, MeasureSpec.AT_MOST),
- heightMeasureSpec)
- measureChild(
- ringerContainer,
- MeasureSpec.makeMeasureSpec(availableSpace / 2, MeasureSpec.AT_MOST),
- heightMeasureSpec)
- }
- }
- setMeasuredDimension(width, measuredHeight)
- }
-
- private data class Location(var left: Int, var right: Int) {
- /**
- * Sets the [left] and [right] with the correct values for laying out the child, respecting
- * RTL. Only set the variable through here to prevent concurrency issues.
- * This is done to prevent allocation of [Pair] in [onLayout].
- */
- fun setLocationFromOffset(parentWidth: Int, offset: Int, width: Int, RTL: Boolean) {
- if (RTL) {
- left = parentWidth - offset - width
- right = parentWidth - offset
- } else {
- left = offset
- right = offset + width
- }
- }
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index c794a2121cc2b..95f7e20106cf7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -391,20 +391,13 @@ public class QSPanel extends LinearLayout implements Tunable {
index++;
if (mSecurityFooter != null) {
- LinearLayout.LayoutParams layoutParams =
- (LayoutParams) mSecurityFooter.getLayoutParams();
if (mUsingHorizontalLayout && mHeaderContainer != null) {
// Adding the security view to the header, that enables us to avoid scrolling
- layoutParams.width = 0;
- layoutParams.weight = 1.6f;
- switchToParent(mSecurityFooter, mHeaderContainer, 1 /* always in second place */);
+ switchToParent(mSecurityFooter, mHeaderContainer, 0);
} else {
- layoutParams.width = LayoutParams.WRAP_CONTENT;
- layoutParams.weight = 0;
switchToParent(mSecurityFooter, parent, index);
index++;
}
- mSecurityFooter.setLayoutParams(layoutParams);
}
if (mFooter != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index a0bf5846ef535..82ae2dd959c5e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -17,15 +17,14 @@ package com.android.systemui.qs;
import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import android.annotation.ColorInt;
-import android.app.AlarmManager.AlarmClockInfo;
+import static com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN;
+import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
+
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
-import android.media.AudioManager;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.util.Pair;
@@ -34,66 +33,46 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
import android.widget.Space;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.LifecycleRegistry;
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.privacy.OngoingPrivacyChip;
import com.android.systemui.qs.QSDetail.Callback;
+import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
+import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
-import java.util.Locale;
-import java.util.Objects;
-
/**
- * View that contains the top-most bits of the screen (primarily the status bar with date, time, and
- * battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner
- * contents.
+ * View that contains the top-most bits of the QS panel (primarily the status bar with date, time,
+ * battery, carrier info and privacy icons) and also contains the {@link QuickQSPanel}.
*/
-public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwner {
-
- public static final int MAX_TOOLTIP_SHOWN_COUNT = 2;
+public class QuickStatusBarHeader extends FrameLayout {
private boolean mExpanded;
private boolean mQsDisabled;
+ private TouchAnimator mAlphaAnimator;
+ private TouchAnimator mTranslationAnimator;
+
protected QuickQSPanel mHeaderQsPanel;
- private TouchAnimator mStatusIconsAlphaAnimator;
- private TouchAnimator mHeaderTextContainerAlphaAnimator;
+ private View mDatePrivacyView;
+ private View mClockIconsView;
+ private View mContainer;
- private View mSystemIconsView;
- private View mQuickQsStatusIcons;
- private View mHeaderTextContainerView;
-
- private ImageView mNextAlarmIcon;
- /** {@link TextView} containing the actual text indicating when the next alarm will go off. */
- private TextView mNextAlarmTextView;
- private View mNextAlarmContainer;
- private View mStatusSeparator;
- private ImageView mRingerModeIcon;
- private TextView mRingerModeTextView;
- private View mRingerContainer;
+ private View mQSCarriers;
private Clock mClockView;
- private OngoingPrivacyChip mPrivacyChip;
private Space mSpace;
private BatteryMeterView mBatteryRemainingIcon;
- private TintedIconManager mTintedIconManager;
+ private StatusIconContainer mIconContainer;
- // Used for RingerModeTracker
- private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
+
+ private TintedIconManager mTintedIconManager;
+ private QSExpansionPathInterpolator mQSExpansionPathInterpolator;
private int mStatusBarPaddingTop = 0;
private int mRoundedCornerPadding = 0;
@@ -102,12 +81,26 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
private int mWaterfallTopInset;
private int mCutOutPaddingLeft;
private int mCutOutPaddingRight;
- private float mExpandedHeaderAlpha = 1.0f;
+ private float mClockIconsAlpha = 1.0f;
+ private float mDatePrivacyAlpha = 1.0f;
private float mKeyguardExpansionFraction;
private int mTextColorPrimary = Color.TRANSPARENT;
+ private int mTopViewMeasureHeight;
+
+ private final String mMobileSlotName;
public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
+ mMobileSlotName = context.getString(com.android.internal.R.string.status_bar_mobile);
+ }
+
+ /**
+ * How much the view containing the clock and QQS will translate down when QS is fully expanded.
+ *
+ * This matches the measured height of the view containing the date and privacy icons.
+ */
+ public int getOffsetTranslation() {
+ return mTopViewMeasureHeight;
}
@Override
@@ -115,19 +108,12 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
super.onFinishInflate();
mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
- mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
- mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
+ mDatePrivacyView = findViewById(R.id.quick_status_bar_date_privacy);
+ mClockIconsView = findViewById(R.id.quick_qs_status_icons);
+ mQSCarriers = findViewById(R.id.carrier_group);
+ mContainer = findViewById(R.id.container);
+ mIconContainer = findViewById(R.id.statusIcons);
- // Views corresponding to the header info section (e.g. ringer and next alarm).
- mHeaderTextContainerView = findViewById(R.id.header_text_container);
- mStatusSeparator = findViewById(R.id.status_separator);
- mNextAlarmIcon = findViewById(R.id.next_alarm_icon);
- mNextAlarmTextView = findViewById(R.id.next_alarm_text);
- mNextAlarmContainer = findViewById(R.id.alarm_container);
- mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
- mRingerModeTextView = findViewById(R.id.ringer_mode_text);
- mRingerContainer = findViewById(R.id.ringer_container);
- mPrivacyChip = findViewById(R.id.privacy_chip);
mClockView = findViewById(R.id.clock);
mSpace = findViewById(R.id.space);
// Tint for the battery icons are handled in setupHost()
@@ -140,79 +126,34 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
// QS will always show the estimate, and BatteryMeterView handles the case where
// it's unavailable or charging
mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
- mRingerModeTextView.setSelected(true);
- mNextAlarmTextView.setSelected(true);
}
- void onAttach(TintedIconManager iconManager) {
+ void onAttach(TintedIconManager iconManager,
+ QSExpansionPathInterpolator qsExpansionPathInterpolator) {
mTintedIconManager = iconManager;
int fillColor = Utils.getColorAttrDefaultColor(getContext(),
android.R.attr.textColorPrimary);
// Set the correct tint for the status icons so they contrast
iconManager.setTint(fillColor);
- mNextAlarmIcon.setImageTintList(ColorStateList.valueOf(fillColor));
- mRingerModeIcon.setImageTintList(ColorStateList.valueOf(fillColor));
+
+ mQSExpansionPathInterpolator = qsExpansionPathInterpolator;
+ updateAnimators();
}
public QuickQSPanel getHeaderQsPanel() {
return mHeaderQsPanel;
}
- void updateStatusText(int ringerMode, AlarmClockInfo nextAlarm, boolean zenOverridingRinger,
- boolean use24HourFormat) {
- boolean changed = updateRingerStatus(ringerMode, zenOverridingRinger)
- || updateAlarmStatus(nextAlarm, use24HourFormat);
-
- if (changed) {
- boolean alarmVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
- boolean ringerVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
- mStatusSeparator.setVisibility(alarmVisible && ringerVisible ? View.VISIBLE
- : View.GONE);
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (mDatePrivacyView.getMeasuredHeight() != mTopViewMeasureHeight) {
+ mTopViewMeasureHeight = mDatePrivacyView.getMeasuredHeight();
+ updateAnimators();
}
}
- private boolean updateRingerStatus(int ringerMode, boolean zenOverridingRinger) {
- boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
- CharSequence originalRingerText = mRingerModeTextView.getText();
-
- boolean ringerVisible = false;
- if (!zenOverridingRinger) {
- if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
- mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
- mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
- ringerVisible = true;
- } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
- mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
- mRingerModeTextView.setText(R.string.qs_status_phone_muted);
- ringerVisible = true;
- }
- }
- mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
- mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
- mRingerContainer.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
-
- return isOriginalVisible != ringerVisible ||
- !Objects.equals(originalRingerText, mRingerModeTextView.getText());
- }
-
- private boolean updateAlarmStatus(AlarmClockInfo nextAlarm, boolean use24HourFormat) {
- boolean isOriginalVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
- CharSequence originalAlarmText = mNextAlarmTextView.getText();
-
- boolean alarmVisible = false;
- if (nextAlarm != null) {
- alarmVisible = true;
- mNextAlarmTextView.setText(formatNextAlarm(nextAlarm, use24HourFormat));
- }
- mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
- mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
- mNextAlarmContainer.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
-
- return isOriginalVisible != alarmVisible ||
- !Objects.equals(originalAlarmText, mNextAlarmTextView.getText());
- }
-
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -225,40 +166,27 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
updateResources();
}
- /**
- * The height of QQS should always be the status bar height + 128dp. This is normally easy, but
- * when there is a notch involved the status bar can remain a fixed pixel size.
- */
- private void updateMinimumHeight() {
- int sbHeight = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height);
- int qqsHeight = mContext.getResources().getDimensionPixelSize(
- R.dimen.qs_quick_header_panel_height);
-
- setMinimumHeight(sbHeight + qqsHeight);
- }
-
void updateResources() {
Resources resources = mContext.getResources();
- updateMinimumHeight();
mRoundedCornerPadding = resources.getDimensionPixelSize(
R.dimen.rounded_corner_content_padding);
mStatusBarPaddingTop = resources.getDimensionPixelSize(R.dimen.status_bar_padding_top);
- // Update height for a few views, especially due to landscape mode restricting space.
- mHeaderTextContainerView.getLayoutParams().height =
- resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
- mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams());
-
- mSystemIconsView.getLayoutParams().height = resources.getDimensionPixelSize(
+ int qsOffsetHeight = resources.getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
- mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
+
+ mDatePrivacyView.getLayoutParams().height =
+ Math.max(qsOffsetHeight, mDatePrivacyView.getMinimumHeight());
+ mDatePrivacyView.setLayoutParams(mDatePrivacyView.getLayoutParams());
+
+ mClockIconsView.getLayoutParams().height =
+ Math.max(qsOffsetHeight, mClockIconsView.getMinimumHeight());
+ mClockIconsView.setLayoutParams(mClockIconsView.getLayoutParams());
ViewGroup.LayoutParams lp = getLayoutParams();
if (mQsDisabled) {
- lp.height = resources.getDimensionPixelSize(
- com.android.internal.R.dimen.quick_qs_offset_height);
+ lp.height = mClockIconsView.getLayoutParams().height;
} else {
lp.height = WRAP_CONTENT;
}
@@ -276,21 +204,45 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
mBatteryRemainingIcon.updateColors(mTextColorPrimary, textColorSecondary,
mTextColorPrimary);
}
-
- updateStatusIconAlphaAnimator();
- updateHeaderTextContainerAlphaAnimator();
+ updateHeadersPadding();
+ updateAnimators();
}
- private void updateStatusIconAlphaAnimator() {
- mStatusIconsAlphaAnimator = new TouchAnimator.Builder()
- .addFloat(mQuickQsStatusIcons, "alpha", 1, 0, 0)
+ private void updateAnimators() {
+ updateAlphaAnimator();
+ int offset = mTopViewMeasureHeight;
+
+ mTranslationAnimator = new TouchAnimator.Builder()
+ .addFloat(mContainer, "translationY", 0, offset)
+ .setInterpolator(mQSExpansionPathInterpolator != null
+ ? mQSExpansionPathInterpolator.getYInterpolator()
+ : null)
.build();
}
- private void updateHeaderTextContainerAlphaAnimator() {
- mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder()
- .addFloat(mHeaderTextContainerView, "alpha", 0, 0, mExpandedHeaderAlpha)
- .build();
+ private void updateAlphaAnimator() {
+ StatusBarMobileView icon =
+ ((StatusBarMobileView) mIconContainer.getViewForSlot(mMobileSlotName));
+ TouchAnimator.Builder builder = new TouchAnimator.Builder()
+ .addFloat(mQSCarriers, "alpha", 0, 1)
+ .addFloat(mDatePrivacyView, "alpha", 0, mDatePrivacyAlpha);
+ if (icon != null) {
+ builder.addFloat(icon, "alpha", 1, 0);
+ builder.setListener(new TouchAnimator.ListenerAdapter() {
+ @Override
+ public void onAnimationAtEnd() {
+ icon.forceHidden(true);
+ icon.setVisibleState(STATE_HIDDEN);
+ }
+
+ @Override
+ public void onAnimationStarted() {
+ icon.forceHidden(false);
+ icon.setVisibleState(STATE_ICON);
+ }
+ });
+ }
+ mAlphaAnimator = builder.build();
}
/** */
@@ -312,25 +264,19 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
public void setExpansion(boolean forceExpanded, float expansionFraction,
float panelTranslationY) {
final float keyguardExpansionFraction = forceExpanded ? 1f : expansionFraction;
- if (mStatusIconsAlphaAnimator != null) {
- mStatusIconsAlphaAnimator.setPosition(keyguardExpansionFraction);
- }
+ if (mAlphaAnimator != null) {
+ mAlphaAnimator.setPosition(keyguardExpansionFraction);
+ }
+ if (mTranslationAnimator != null) {
+ mTranslationAnimator.setPosition(keyguardExpansionFraction);
+ }
+ // If forceExpanded (we are opening QS from lockscreen), the animators have been set to
+ // position = 1f.
if (forceExpanded) {
- // If the keyguard is showing, we want to offset the text so that it comes in at the
- // same time as the panel as it slides down.
- mHeaderTextContainerView.setTranslationY(panelTranslationY);
+ setTranslationY(panelTranslationY);
} else {
- mHeaderTextContainerView.setTranslationY(0f);
- }
-
- if (mHeaderTextContainerAlphaAnimator != null) {
- mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction);
- if (keyguardExpansionFraction > 0) {
- mHeaderTextContainerView.setVisibility(VISIBLE);
- } else {
- mHeaderTextContainerView.setVisibility(INVISIBLE);
- }
+ setTranslationY(0);
}
mKeyguardExpansionFraction = keyguardExpansionFraction;
@@ -341,28 +287,21 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
if (disabled == mQsDisabled) return;
mQsDisabled = disabled;
mHeaderQsPanel.setDisabledByPolicy(disabled);
- mHeaderTextContainerView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
- mQuickQsStatusIcons.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
+ mClockIconsView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
updateResources();
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- // Handle padding of the clock
+ // Handle padding of the views
DisplayCutout cutout = insets.getDisplayCutout();
Pair cornerCutoutPadding = StatusBarWindowView.cornerCutoutMargins(
cutout, getDisplay());
Pair padding =
StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
cutout, cornerCutoutPadding, -1);
- if (padding == null) {
- mSystemIconsView.setPaddingRelative(
- getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start), 0,
- getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end), 0);
- } else {
- mSystemIconsView.setPadding(padding.first, 0, padding.second, 0);
-
- }
+ mDatePrivacyView.setPadding(padding.first, 0, padding.second, 0);
+ mClockIconsView.setPadding(padding.first, 0, padding.second, 0);
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSpace.getLayoutParams();
boolean cornerCutout = cornerCutoutPadding != null
&& (cornerCutoutPadding.first == 0 || cornerCutoutPadding.second == 0);
@@ -380,13 +319,13 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
mCutOutPaddingLeft = padding.first;
mCutOutPaddingRight = padding.second;
mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
- updateClockPadding();
+ updateHeadersPadding();
return super.onApplyWindowInsets(insets);
}
- private void updateClockPadding() {
- int clockPaddingLeft = 0;
- int clockPaddingRight = 0;
+ private void updateHeadersPadding() {
+ int paddingLeft = 0;
+ int paddingRight = 0;
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
int leftMargin = lp.leftMargin;
@@ -399,18 +338,22 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
// if there's a cutout, let's use at least the rounded corner inset
int cutoutPadding = Math.max(mCutOutPaddingLeft, mRoundedCornerPadding);
int contentMarginLeft = isLayoutRtl() ? mContentMarginEnd : mContentMarginStart;
- clockPaddingLeft = Math.max(cutoutPadding - contentMarginLeft - leftMargin, 0);
+ paddingLeft = Math.max(cutoutPadding - contentMarginLeft - leftMargin, 0);
}
if (mCutOutPaddingRight > 0) {
// if there's a cutout, let's use at least the rounded corner inset
int cutoutPadding = Math.max(mCutOutPaddingRight, mRoundedCornerPadding);
int contentMarginRight = isLayoutRtl() ? mContentMarginStart : mContentMarginEnd;
- clockPaddingRight = Math.max(cutoutPadding - contentMarginRight - rightMargin, 0);
+ paddingRight = Math.max(cutoutPadding - contentMarginRight - rightMargin, 0);
}
- mSystemIconsView.setPadding(clockPaddingLeft,
+ mDatePrivacyView.setPadding(paddingLeft,
mWaterfallTopInset + mStatusBarPaddingTop,
- clockPaddingRight,
+ paddingRight,
+ 0);
+ mClockIconsView.setPadding(paddingLeft,
+ mWaterfallTopInset + mStatusBarPaddingTop,
+ paddingRight,
0);
}
@@ -422,26 +365,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
mHeaderQsPanel.setCallback(qsPanelCallback);
}
- private String formatNextAlarm(AlarmClockInfo info, boolean use24HourFormat) {
- if (info == null) {
- return "";
- }
- String skeleton = use24HourFormat ? "EHm" : "Ehma";
- String pattern = android.text.format.DateFormat
- .getBestDateTimePattern(Locale.getDefault(), skeleton);
- return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
- }
-
- public static float getColorIntensity(@ColorInt int color) {
- return color == Color.WHITE ? 0 : 1;
- }
-
- @NonNull
- @Override
- public Lifecycle getLifecycle() {
- return mLifecycle;
- }
-
/** */
public void setContentMargins(int marginStart, int marginEnd,
QuickQSPanelController quickQSPanelController) {
@@ -459,24 +382,39 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
view.setLayoutParams(lp);
}
}
- updateClockPadding();
+ updateHeadersPadding();
}
+ /**
+ * When QS is scrolling, mClockIconsAlpha should scroll away and fade out.
+ *
+ * For a given scroll level, this method does the following:
+ *
+ * - Determine the alpha that {@code mClockIconsView} should have when the panel is fully
+ * expanded.
+ * - Set the scroll of {@code mClockIconsView} to the same of {@code QSPanel}.
+ * - Set the alpha of {@code mClockIconsView} to that determined by the expansion of
+ * the panel, interpolated between 1 (no expansion) and {@code mClockIconsAlpha} (fully
+ * expanded), matching the animator.
+ *
+ *
+ * @param scrollY the scroll of the QSPanel container
+ */
public void setExpandedScrollAmount(int scrollY) {
// The scrolling of the expanded qs has changed. Since the header text isn't part of it,
// but would overlap content, we're fading it out.
float newAlpha = 1.0f;
- if (mHeaderTextContainerView.getHeight() > 0) {
- newAlpha = MathUtils.map(0, mHeaderTextContainerView.getHeight() / 2.0f, 1.0f, 0.0f,
+ if (mClockIconsView.getHeight() > 0) {
+ newAlpha = MathUtils.map(0, mClockIconsView.getHeight() / 2.0f, 1.0f, 0.0f,
scrollY);
newAlpha = Interpolators.ALPHA_OUT.getInterpolation(newAlpha);
}
- mHeaderTextContainerView.setScrollY(scrollY);
- if (newAlpha != mExpandedHeaderAlpha) {
- mExpandedHeaderAlpha = newAlpha;
- mHeaderTextContainerView.setAlpha(MathUtils.lerp(0.0f, mExpandedHeaderAlpha,
+ mClockIconsView.setScrollY(scrollY);
+ if (newAlpha != mClockIconsAlpha) {
+ mClockIconsAlpha = newAlpha;
+ mClockIconsView.setAlpha(MathUtils.lerp(1.0f, mClockIconsAlpha,
mKeyguardExpansionFraction));
- updateHeaderTextContainerAlphaAnimator();
+ updateAlphaAnimator();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index b1689f665ebb4..3aafea98ff2ab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -16,21 +16,13 @@
package com.android.systemui.qs;
-import android.app.AlarmManager.AlarmClockInfo;
import android.content.Intent;
-import android.media.AudioManager;
import android.os.Bundle;
import android.provider.AlarmClock;
-import android.provider.Settings;
-import android.service.notification.ZenModeConfig;
-import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import androidx.annotation.NonNull;
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.LifecycleRegistry;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.logging.UiEventLogger;
@@ -47,15 +39,9 @@ import com.android.systemui.privacy.PrivacyItemController;
import com.android.systemui.privacy.logging.PrivacyLogger;
import com.android.systemui.qs.carrier.QSCarrierGroupController;
import com.android.systemui.qs.dagger.QSScope;
-import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.statusbar.policy.ZenModeController.Callback;
-import com.android.systemui.util.RingerModeTracker;
import com.android.systemui.util.ViewController;
import java.util.ArrayList;
@@ -70,75 +56,29 @@ import javax.inject.Inject;
class QuickStatusBarHeaderController extends ViewController {
private static final String TAG = "QuickStatusBarHeader";
- private final ZenModeController mZenModeController;
- private final NextAlarmController mNextAlarmController;
private final PrivacyItemController mPrivacyItemController;
- private final RingerModeTracker mRingerModeTracker;
private final ActivityStarter mActivityStarter;
private final UiEventLogger mUiEventLogger;
private final QSCarrierGroupController mQSCarrierGroupController;
private final QuickQSPanelController mHeaderQsPanelController;
- private final LifecycleRegistry mLifecycle;
private final OngoingPrivacyChip mPrivacyChip;
private final Clock mClockView;
- private final View mNextAlarmContainer;
- private final View mRingerContainer;
- private final QSTileHost mQSTileHost;
private final StatusBarIconController mStatusBarIconController;
private final DemoModeController mDemoModeController;
- private final UserTracker mUserTracker;
private final StatusIconContainer mIconContainer;
private final StatusBarIconController.TintedIconManager mIconManager;
private final DemoMode mDemoModeReceiver;
private final PrivacyLogger mPrivacyLogger;
private final PrivacyDialogController mPrivacyDialogController;
+ private final QSExpansionPathInterpolator mQSExpansionPathInterpolator;
private boolean mListening;
- private AlarmClockInfo mNextAlarm;
private boolean mMicCameraIndicatorsEnabled;
private boolean mLocationIndicatorsEnabled;
private boolean mPrivacyChipLogged;
private SysuiColorExtractor mColorExtractor;
private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener;
- private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
-
- private final ZenModeController.Callback mZenModeControllerCallback = new Callback() {
- @Override
- public void onZenChanged(int zen) {
- mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
- use24HourFormat());
- }
-
- @Override
- public void onConfigChanged(ZenModeConfig config) {
- mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
- use24HourFormat());
- }
- };
-
- private boolean use24HourFormat() {
- return android.text.format.DateFormat.is24HourFormat(
- mView.getContext(), mUserTracker.getUserId());
-
- }
-
- private final NextAlarmChangeCallback mNextAlarmChangeCallback = new NextAlarmChangeCallback() {
- @Override
- public void onNextAlarmChanged(AlarmClockInfo nextAlarm) {
- mNextAlarm = nextAlarm;
- mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
- use24HourFormat());
- }
- };
-
- private final LifecycleOwner mLifecycleOwner = new LifecycleOwner() {
- @NonNull
- @Override
- public Lifecycle getLifecycle() {
- return mLifecycle;
- }
- };
private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() {
@Override
@@ -176,63 +116,43 @@ class QuickStatusBarHeaderController extends ViewController {
- mRingerMode = ringer;
- mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
- use24HourFormat());
- });
-
mClockView.setOnClickListener(mOnClickListener);
- mNextAlarmContainer.setOnClickListener(mOnClickListener);
- mRingerContainer.setOnClickListener(mOnClickListener);
mPrivacyChip.setOnClickListener(mOnClickListener);
mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
@@ -268,18 +180,15 @@ class QuickStatusBarHeaderController extends ViewController implements QSTile, Lifecy
getInstanceId());
mQSLogger.logTileLongClick(mTileSpec, mStatusBarStateController.getState(), mState.state);
mHandler.sendEmptyMessage(H.LONG_CLICK);
-
- Prefs.putInt(
- mContext,
- Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
- QuickStatusBarHeader.MAX_TOOLTIP_SHOWN_COUNT);
}
public LogMaker populate(LogMaker logMaker) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 138c811e9084f..ab17ee0b7261b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -59,6 +59,7 @@ public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
private View mMobileRoamingSpace;
private int mVisibleState = -1;
private DualToneHandler mDualToneHandler;
+ private boolean mForceHidden;
public static StatusBarMobileView fromContext(Context context, String slot) {
LayoutInflater inflater = LayoutInflater.from(context);
@@ -150,7 +151,7 @@ public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
private void initViewState() {
setContentDescription(mState.contentDescription);
- if (!mState.visible) {
+ if (!mState.visible || mForceHidden) {
mMobileGroup.setVisibility(View.GONE);
} else {
mMobileGroup.setVisibility(View.VISIBLE);
@@ -176,8 +177,9 @@ public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
boolean needsLayout = false;
setContentDescription(state.contentDescription);
- if (mState.visible != state.visible) {
- mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
+ int newVisibility = state.visible && !mForceHidden ? View.VISIBLE : View.GONE;
+ if (newVisibility != mMobileGroup.getVisibility()) {
+ mMobileGroup.setVisibility(newVisibility);
needsLayout = true;
}
if (mState.strengthId != state.strengthId) {
@@ -252,7 +254,7 @@ public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
@Override
public boolean isIconVisible() {
- return mState.visible;
+ return mState.visible && !mForceHidden;
}
@Override
@@ -279,6 +281,23 @@ public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
}
}
+ /**
+ * Forces the state to be hidden (views will be GONE) and if necessary updates the layout.
+ *
+ * Makes sure that the {@link StatusBarIconController} cannot make it visible while this flag
+ * is enabled.
+ * @param forceHidden {@code true} if the icon should be GONE in its view regardless of its
+ * state.
+ * {@code false} if the icon should show as determined by its controller.
+ */
+ public void forceHidden(boolean forceHidden) {
+ if (mForceHidden != forceHidden) {
+ mForceHidden = forceHidden;
+ updateState(mState);
+ requestLayout();
+ }
+ }
+
@Override
public int getVisibleState() {
return mVisibleState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index c6f79831e022d..779ba1c6ac6db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -33,6 +33,8 @@ import android.view.View;
import android.view.WindowInsets;
import android.widget.FrameLayout;
+import androidx.annotation.NonNull;
+
import com.android.systemui.util.leak.RotationUtils;
/**
@@ -91,6 +93,7 @@ public class StatusBarWindowView extends FrameLayout {
* @param roundedCornerContentPadding
* @return
*/
+ @NonNull
public static Pair paddingNeededForCutoutAndRoundedCorner(
DisplayCutout cutout, Pair cornerCutoutPadding,
int roundedCornerContentPadding) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index f65f97a3a4501..64a497ddd3173 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -261,6 +261,25 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
addIgnoredSlots(slots);
}
+ /**
+ * Returns the view corresponding to a particular slot.
+ *
+ * Use it solely to manipulate how it is presented.
+ * @param slot name of the slot to find. Names are defined in
+ * {@link com.android.internal.R.config_statusBarIcons}
+ * @return a view for the slot if this container has it, else {@code null}
+ */
+ public View getViewForSlot(String slot) {
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ if (child instanceof StatusIconDisplayable
+ && ((StatusIconDisplayable) child).getSlot().equals(slot)) {
+ return child;
+ }
+ }
+ return null;
+ }
+
/**
* Layout is happening from end -> start
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index 3595095ba6154..3c1b36e41d891 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -21,9 +21,9 @@ import android.testing.AndroidTestingRunner
import android.view.View
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
-import com.android.systemui.colorextraction.SysuiColorExtractor
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.colorextraction.SysuiColorExtractor
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.privacy.OngoingPrivacyChip
@@ -32,16 +32,12 @@ import com.android.systemui.privacy.PrivacyItemController
import com.android.systemui.privacy.logging.PrivacyLogger
import com.android.systemui.qs.carrier.QSCarrierGroup
import com.android.systemui.qs.carrier.QSCarrierGroupController
-import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.policy.Clock
-import com.android.systemui.statusbar.policy.NextAlarmController
-import com.android.systemui.util.RingerModeTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
-import com.android.systemui.utils.leaks.FakeZenModeController
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -61,26 +57,16 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
@Mock
private lateinit var view: QuickStatusBarHeader
@Mock
- private lateinit var zenModeController: FakeZenModeController
- @Mock
- private lateinit var nextAlarmController: NextAlarmController
- @Mock
private lateinit var privacyItemController: PrivacyItemController
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private lateinit var ringerModeTracker: RingerModeTracker
@Mock
private lateinit var activityStarter: ActivityStarter
@Mock
private lateinit var uiEventLogger: UiEventLogger
@Mock
- private lateinit var qsTileHost: QSTileHost
- @Mock
private lateinit var statusBarIconController: StatusBarIconController
@Mock
private lateinit var demoModeController: DemoModeController
@Mock
- private lateinit var userTracker: UserTracker
- @Mock
private lateinit var quickQSPanelController: QuickQSPanelController
@Mock(answer = Answers.RETURNS_SELF)
private lateinit var qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder
@@ -105,6 +91,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private lateinit var context: Context
+ private val qsExpansionPathInterpolator = QSExpansionPathInterpolator()
+
private lateinit var controller: QuickStatusBarHeaderController
@Before
@@ -119,21 +107,17 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
controller = QuickStatusBarHeaderController(
view,
- zenModeController,
- nextAlarmController,
privacyItemController,
- ringerModeTracker,
activityStarter,
uiEventLogger,
- qsTileHost,
statusBarIconController,
demoModeController,
- userTracker,
quickQSPanelController,
qsCarrierGroupControllerBuilder,
privacyLogger,
colorExtractor,
- privacyDialogController
+ privacyDialogController,
+ qsExpansionPathInterpolator
)
}