summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res/layout/qs_carrier.xml7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java87
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt120
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java184
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java51
11 files changed, 485 insertions, 120 deletions
diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/qs_carrier.xml
index d4594d17f02b..a854660f64f8 100644
--- a/packages/SystemUI/res/layout/qs_carrier.xml
+++ b/packages/SystemUI/res/layout/qs_carrier.xml
@@ -39,6 +39,13 @@
android:singleLine="true"
android:maxEms="7"/>
+ <View
+ android:id="@+id/spacer"
+ android:layout_width="@dimen/qs_carrier_margin_width"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ />
+
<include
layout="@layout/mobile_signal_group"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 03a2c843a15e..cd9db614e477 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -32,6 +32,8 @@ import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.Space;
+import androidx.annotation.NonNull;
+
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.R;
@@ -41,6 +43,8 @@ import com.android.systemui.statusbar.phone.StatusBarWindowView;
import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
+import java.util.List;
+
/**
* 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}.
@@ -86,18 +90,13 @@ public class QuickStatusBarHeader extends FrameLayout {
private float mKeyguardExpansionFraction;
private int mTextColorPrimary = Color.TRANSPARENT;
private int mTopViewMeasureHeight;
- private boolean mProviderModel;
- private final String mMobileSlotName;
- private final String mNoCallingSlotName;
- private final String mCallStrengthSlotName;
+ @NonNull
+ private List<String> mRssiIgnoredSlots;
+ private boolean mIsSingleCarrier;
public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
- mMobileSlotName = context.getString(com.android.internal.R.string.status_bar_mobile);
- mNoCallingSlotName = context.getString(com.android.internal.R.string.status_bar_no_calling);
- mCallStrengthSlotName =
- context.getString(com.android.internal.R.string.status_bar_call_strength);
}
/**
@@ -148,9 +147,9 @@ public class QuickStatusBarHeader extends FrameLayout {
void onAttach(TintedIconManager iconManager,
QSExpansionPathInterpolator qsExpansionPathInterpolator,
- boolean providerModel) {
- mProviderModel = providerModel;
+ List<String> rssiIgnoredSlots) {
mTintedIconManager = iconManager;
+ mRssiIgnoredSlots = rssiIgnoredSlots;
int fillColor = Utils.getColorAttrDefaultColor(getContext(),
android.R.attr.textColorPrimary);
@@ -161,6 +160,11 @@ public class QuickStatusBarHeader extends FrameLayout {
updateAnimators();
}
+ void setIsSingleCarrier(boolean isSingleCarrier) {
+ mIsSingleCarrier = isSingleCarrier;
+ updateAlphaAnimator();
+ }
+
public QuickQSPanel getHeaderQsPanel() {
return mHeaderQsPanel;
}
@@ -267,39 +271,26 @@ public class QuickStatusBarHeader extends FrameLayout {
.setListener(new TouchAnimator.ListenerAdapter() {
@Override
public void onAnimationAtEnd() {
- // TODO(b/185580157): Remove the mProviderModel if the mobile slot can be
- // hidden in Provider model.
- if (mProviderModel) {
- mIconContainer.addIgnoredSlot(mNoCallingSlotName);
- mIconContainer.addIgnoredSlot(mCallStrengthSlotName);
- } else {
- mIconContainer.addIgnoredSlot(mMobileSlotName);
+ super.onAnimationAtEnd();
+ if (!mIsSingleCarrier) {
+ mIconContainer.addIgnoredSlots(mRssiIgnoredSlots);
}
}
@Override
public void onAnimationStarted() {
- if (mProviderModel) {
- mIconContainer.addIgnoredSlot(mNoCallingSlotName);
- mIconContainer.addIgnoredSlot(mCallStrengthSlotName);
- } else {
- mIconContainer.addIgnoredSlot(mMobileSlotName);
- }
-
setSeparatorVisibility(false);
+ if (!mIsSingleCarrier) {
+ mIconContainer.addIgnoredSlots(mRssiIgnoredSlots);
+ }
}
@Override
public void onAnimationAtStart() {
super.onAnimationAtStart();
- if (mProviderModel) {
- mIconContainer.removeIgnoredSlot(mNoCallingSlotName);
- mIconContainer.removeIgnoredSlot(mCallStrengthSlotName);
- } else {
- mIconContainer.removeIgnoredSlot(mMobileSlotName);
- }
-
setSeparatorVisibility(mShowClockIconsSeparator);
+ // In QQS we never ignore RSSI.
+ mIconContainer.removeIgnoredSlots(mRssiIgnoredSlots);
}
});
mAlphaAnimator = builder.build();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index fcf1302b8fb4..b8b7f42455bb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -43,7 +43,6 @@ import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.util.ViewController;
-import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
@@ -76,6 +75,9 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
private boolean mMicCameraIndicatorsEnabled;
private boolean mLocationIndicatorsEnabled;
private boolean mPrivacyChipLogged;
+ private final String mCameraSlot;
+ private final String mMicSlot;
+ private final String mLocationSlot;
private SysuiColorExtractor mColorExtractor;
private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener;
@@ -104,8 +106,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
}
private void update() {
- StatusIconContainer iconContainer = mView.requireViewById(R.id.statusIcons);
- iconContainer.setIgnoredSlots(getIgnoredIconSlots());
+ updatePrivacyIconSlots();
setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
}
};
@@ -154,7 +155,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mClockView = mView.findViewById(R.id.clock);
mIconContainer = mView.findViewById(R.id.statusIcons);
- mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, mFeatureFlags);
+ mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, featureFlags);
mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
mColorExtractor = colorExtractor;
mOnColorsChangedListener = (extractor, which) -> {
@@ -162,6 +163,10 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mClockView.onColorsChanged(lightTheme);
};
mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
+
+ mCameraSlot = getResources().getString(com.android.internal.R.string.status_bar_camera);
+ mMicSlot = getResources().getString(com.android.internal.R.string.status_bar_microphone);
+ mLocationSlot = getResources().getString(com.android.internal.R.string.status_bar_location);
}
@Override
@@ -172,14 +177,30 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mLocationIndicatorsEnabled = mPrivacyItemController.getLocationAvailable();
// Ignore privacy icons because they show in the space above QQS
- mIconContainer.setIgnoredSlots(getIgnoredIconSlots());
+ updatePrivacyIconSlots();
mIconContainer.setShouldRestrictIcons(false);
mStatusBarIconController.addIconGroup(mIconManager);
setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
- mView.onAttach(mIconManager, mQSExpansionPathInterpolator,
- mFeatureFlags.isCombinedStatusBarSignalIconsEnabled());
+ mView.setIsSingleCarrier(mQSCarrierGroupController.isSingleCarrier());
+ mQSCarrierGroupController
+ .setOnSingleCarrierChangedListener(mView::setIsSingleCarrier);
+
+ List<String> rssiIgnoredSlots;
+
+ if (mFeatureFlags.isCombinedStatusBarSignalIconsEnabled()) {
+ rssiIgnoredSlots = List.of(
+ getResources().getString(com.android.internal.R.string.status_bar_no_calling),
+ getResources().getString(com.android.internal.R.string.status_bar_call_strength)
+ );
+ } else {
+ rssiIgnoredSlots = List.of(
+ getResources().getString(com.android.internal.R.string.status_bar_mobile)
+ );
+ }
+
+ mView.onAttach(mIconManager, mQSExpansionPathInterpolator, rssiIgnoredSlots);
mDemoModeController.addCallback(mDemoModeReceiver);
}
@@ -189,6 +210,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mColorExtractor.removeOnColorsChangedListener(mOnColorsChangedListener);
mPrivacyChip.setOnClickListener(null);
mStatusBarIconController.removeIconGroup(mIconManager);
+ mQSCarrierGroupController.setOnSingleCarrierChangedListener(null);
mDemoModeController.removeCallback(mDemoModeReceiver);
setListening(false);
}
@@ -236,21 +258,25 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mView.setChipVisibility(chipVisible);
}
- private List<String> getIgnoredIconSlots() {
- ArrayList<String> ignored = new ArrayList<>();
+ private void updatePrivacyIconSlots() {
if (getChipEnabled()) {
if (mMicCameraIndicatorsEnabled) {
- ignored.add(mView.getResources().getString(
- com.android.internal.R.string.status_bar_camera));
- ignored.add(mView.getResources().getString(
- com.android.internal.R.string.status_bar_microphone));
+ mIconContainer.addIgnoredSlot(mCameraSlot);
+ mIconContainer.addIgnoredSlot(mMicSlot);
+ } else {
+ mIconContainer.removeIgnoredSlot(mCameraSlot);
+ mIconContainer.removeIgnoredSlot(mMicSlot);
}
if (mLocationIndicatorsEnabled) {
- ignored.add(mView.getResources().getString(
- com.android.internal.R.string.status_bar_location));
+ mIconContainer.addIgnoredSlot(mLocationSlot);
+ } else {
+ mIconContainer.removeIgnoredSlot(mLocationSlot);
}
+ } else {
+ mIconContainer.removeIgnoredSlot(mCameraSlot);
+ mIconContainer.removeIgnoredSlot(mMicSlot);
+ mIconContainer.removeIgnoredSlot(mLocationSlot);
}
- return ignored;
}
private boolean getChipEnabled() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
index d6fa21646402..32ac73375f1d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
@@ -25,6 +25,8 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.VisibleForTesting;
+
import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.R;
@@ -37,8 +39,10 @@ public class QSCarrier extends LinearLayout {
private TextView mCarrierText;
private ImageView mMobileSignal;
private ImageView mMobileRoaming;
+ private View mSpacer;
private CellSignalState mLastSignalState;
private boolean mProviderModelInitialized = false;
+ private boolean mIsSingleCarrier;
public QSCarrier(Context context) {
super(context);
@@ -63,18 +67,25 @@ public class QSCarrier extends LinearLayout {
mMobileRoaming = findViewById(R.id.mobile_roaming);
mMobileSignal = findViewById(R.id.mobile_signal);
mCarrierText = findViewById(R.id.qs_carrier_text);
+ mSpacer = findViewById(R.id.spacer);
}
/**
* Update the state of this view
* @param state the current state of the signal for this view
+ * @param isSingleCarrier whether there is a single carrier being shown in the container
* @return true if the state was actually changed
*/
- public boolean updateState(CellSignalState state) {
- if (Objects.equals(state, mLastSignalState)) return false;
+ public boolean updateState(CellSignalState state, boolean isSingleCarrier) {
+ if (Objects.equals(state, mLastSignalState) && isSingleCarrier == mIsSingleCarrier) {
+ return false;
+ }
mLastSignalState = state;
- mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
- if (state.visible) {
+ mIsSingleCarrier = isSingleCarrier;
+ final boolean visible = state.visible && !isSingleCarrier;
+ mMobileGroup.setVisibility(visible ? View.VISIBLE : View.GONE);
+ mSpacer.setVisibility(isSingleCarrier ? View.VISIBLE : View.GONE);
+ if (visible) {
mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
ColorStateList colorStateList = Utils.getColorAttr(mContext,
android.R.attr.textColorPrimary);
@@ -125,6 +136,11 @@ public class QSCarrier extends LinearLayout {
com.android.settingslib.R.string.not_default_data_content_description));
}
+ @VisibleForTesting
+ View getRSSIView() {
+ return mMobileGroup;
+ }
+
public void setCarrierText(CharSequence text) {
mCarrierText.setText(text);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index f23c0580c409..67c4d33d53d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -37,6 +37,7 @@ import com.android.keyguard.CarrierTextManager;
import com.android.settingslib.AccessibilityContentDescriptions;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -62,7 +63,8 @@ public class QSCarrierGroupController {
private final NetworkController mNetworkController;
private final CarrierTextManager mCarrierTextManager;
private final TextView mNoSimTextView;
- private final H mMainHandler;
+ // Non final for testing
+ private H mMainHandler;
private final Callback mCallback;
private boolean mListening;
private final CellSignalState[] mInfos =
@@ -74,6 +76,11 @@ public class QSCarrierGroupController {
private final boolean mProviderModel;
private final CarrierConfigTracker mCarrierConfigTracker;
+ private boolean mIsSingleCarrier;
+ private OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
+
+ private final SlotIndexResolver mSlotIndexResolver;
+
private final NetworkController.SignalCallback mSignalCallback =
new NetworkController.SignalCallback() {
@Override
@@ -207,7 +214,8 @@ public class QSCarrierGroupController {
@Background Handler bgHandler, @Main Looper mainLooper,
NetworkController networkController,
CarrierTextManager.Builder carrierTextManagerBuilder, Context context,
- CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags) {
+ CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags,
+ SlotIndexResolver slotIndexResolver) {
if (featureFlags.isCombinedStatusBarSignalIconsEnabled()) {
mProviderModel = true;
@@ -222,6 +230,7 @@ public class QSCarrierGroupController {
.setShowMissingSim(false)
.build();
mCarrierConfigTracker = carrierConfigTracker;
+ mSlotIndexResolver = slotIndexResolver;
View.OnClickListener onClickListener = v -> {
if (!v.isVisibleToUser()) {
return;
@@ -256,6 +265,7 @@ public class QSCarrierGroupController {
.toString();
mCarrierGroups[i].setOnClickListener(onClickListener);
}
+ mIsSingleCarrier = computeIsSingleCarrier();
view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@@ -272,10 +282,24 @@ public class QSCarrierGroupController {
@VisibleForTesting
protected int getSlotIndex(int subscriptionId) {
- return SubscriptionManager.getSlotIndex(subscriptionId);
+ return mSlotIndexResolver.getSlotIndex(subscriptionId);
+ }
+
+ /**
+ * Sets a {@link OnSingleCarrierChangedListener}.
+ *
+ * This will get notified when the number of carriers changes between 1 and "not one".
+ * @param listener
+ */
+ public void setOnSingleCarrierChangedListener(OnSingleCarrierChangedListener listener) {
+ mOnSingleCarrierChangedListener = listener;
+ }
+
+ public boolean isSingleCarrier() {
+ return mIsSingleCarrier;
}
- private boolean isSingleCarrier() {
+ private boolean computeIsSingleCarrier() {
int carrierCount = 0;
for (int i = 0; i < SIM_SLOTS; i++) {
@@ -315,7 +339,9 @@ public class QSCarrierGroupController {
return;
}
- if (isSingleCarrier()) {
+ boolean singleCarrier = computeIsSingleCarrier();
+
+ if (singleCarrier) {
for (int i = 0; i < SIM_SLOTS; i++) {
if (mInfos[i].visible
&& mInfos[i].mobileSignalIconId == R.drawable.ic_qs_sim_card) {
@@ -326,7 +352,7 @@ public class QSCarrierGroupController {
}
for (int i = 0; i < SIM_SLOTS; i++) {
- mCarrierGroups[i].updateState(mInfos[i]);
+ mCarrierGroups[i].updateState(mInfos[i], singleCarrier);
}
mCarrierDividers[0].setVisibility(
@@ -337,6 +363,12 @@ public class QSCarrierGroupController {
mCarrierDividers[1].setVisibility(
(mInfos[1].visible && mInfos[2].visible)
|| (mInfos[0].visible && mInfos[2].visible) ? View.VISIBLE : View.GONE);
+ if (mIsSingleCarrier != singleCarrier) {
+ mIsSingleCarrier = singleCarrier;
+ if (mOnSingleCarrierChangedListener != null) {
+ mOnSingleCarrierChangedListener.onSingleCarrierChanged(singleCarrier);
+ }
+ }
}
@MainThread
@@ -433,12 +465,14 @@ public class QSCarrierGroupController {
private final Context mContext;
private final CarrierConfigTracker mCarrierConfigTracker;
private final FeatureFlags mFeatureFlags;
+ private final SlotIndexResolver mSlotIndexResolver;
@Inject
public Builder(ActivityStarter activityStarter, @Background Handler handler,
@Main Looper looper, NetworkController networkController,
CarrierTextManager.Builder carrierTextControllerBuilder, Context context,
- CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags) {
+ CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags,
+ SlotIndexResolver slotIndexResolver) {
mActivityStarter = activityStarter;
mHandler = handler;
mLooper = looper;
@@ -447,6 +481,7 @@ public class QSCarrierGroupController {
mContext = context;
mCarrierConfigTracker = carrierConfigTracker;
mFeatureFlags = featureFlags;
+ mSlotIndexResolver = slotIndexResolver;
}
public Builder setQSCarrierGroup(QSCarrierGroup view) {
@@ -457,7 +492,43 @@ public class QSCarrierGroupController {
public QSCarrierGroupController build() {
return new QSCarrierGroupController(mView, mActivityStarter, mHandler, mLooper,
mNetworkController, mCarrierTextControllerBuilder, mContext,
- mCarrierConfigTracker, mFeatureFlags);
+ mCarrierConfigTracker, mFeatureFlags, mSlotIndexResolver);
+ }
+ }
+
+ /**
+ * Notify when the state changes from 1 carrier to "not one" and viceversa
+ */
+ @FunctionalInterface
+ public interface OnSingleCarrierChangedListener {
+ void onSingleCarrierChanged(boolean isSingleCarrier);
+ }
+
+ /**
+ * Interface for resolving slot index from subscription ID.
+ */
+ @FunctionalInterface
+ public interface SlotIndexResolver {
+ /**
+ * Get slot index for given sub id.
+ */
+ int getSlotIndex(int subscriptionId);
+ }
+
+ /**
+ * Default implementation for {@link SlotIndexResolver}.
+ *
+ * It retrieves the slot index using {@link SubscriptionManager#getSlotIndex}.
+ */
+ @SysUISingleton
+ public static class SubscriptionManagerSlotIndexResolver implements SlotIndexResolver {
+
+ @Inject
+ public SubscriptionManagerSlotIndexResolver() {}
+
+ @Override
+ public int getSlotIndex(int subscriptionId) {
+ return SubscriptionManager.getSlotIndex(subscriptionId);
}
}
}
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 34aac492dc30..4d633492ed76 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -33,6 +33,7 @@ import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QuickQSPanel;
import com.android.systemui.qs.QuickStatusBarHeader;
+import com.android.systemui.qs.carrier.QSCarrierGroupController;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.statusbar.phone.MultiUserSwitch;
@@ -146,4 +147,8 @@ public interface QSFragmentModule {
return useQsMediaPlayer(context);
}
+ /** */
+ @Binds
+ QSCarrierGroupController.SlotIndexResolver provideSlotIndexResolver(
+ QSCarrierGroupController.SubscriptionManagerSlotIndexResolver impl);
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index de3be78e5463..6d1bbeed5372 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -89,5 +89,4 @@ public interface QSModule {
/** */
@Binds
QSHost provideQsHost(QSTileHost controllerImpl);
-
}
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 64a497ddd317..329293409dc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -245,8 +245,19 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
* @param slotName name of the icon slot to remove from the ignored list
*/
public void removeIgnoredSlot(String slotName) {
- if (mIgnoredSlots.contains(slotName)) {
- mIgnoredSlots.remove(slotName);
+ mIgnoredSlots.remove(slotName);
+
+ requestLayout();
+ }
+
+ /**
+ * Remove a list of slots from the list of ignored icon slots.
+ * It will then be shown when set to visible by the {@link StatusBarIconController}.
+ * @param slots name of the icon slots to remove from the ignored list
+ */
+ public void removeIgnoredSlots(List<String> slots) {
+ for (String slot : slots) {
+ mIgnoredSlots.remove(slot);
}
requestLayout();
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 f140eb85e76d..35360bd19393 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -48,6 +48,7 @@ import org.mockito.Answers
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -98,6 +99,10 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
private lateinit var controller: QuickStatusBarHeaderController
+ private lateinit var cameraSlotName: String
+ private lateinit var microphoneSlotName: String
+ private lateinit var locationSlotName: String
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -108,6 +113,13 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
`when`(view.isAttachedToWindow).thenReturn(true)
`when`(view.context).thenReturn(context)
+ cameraSlotName = mContext.resources.getString(
+ com.android.internal.R.string.status_bar_camera)
+ microphoneSlotName = mContext.resources.getString(
+ com.android.internal.R.string.status_bar_microphone)
+ locationSlotName = mContext.resources.getString(
+ com.android.internal.R.string.status_bar_location)
+
controller = QuickStatusBarHeaderController(
view,
privacyItemController,
@@ -141,10 +153,9 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
controller.init()
- val captor = argumentCaptor<List<String>>()
- verify(iconContainer).setIgnoredSlots(capture(captor))
-
- assertThat(captor.value).isEmpty()
+ verify(iconContainer).removeIgnoredSlot(cameraSlotName)
+ verify(iconContainer).removeIgnoredSlot(microphoneSlotName)
+ verify(iconContainer).removeIgnoredSlot(locationSlotName)
}
@Test
@@ -153,15 +164,9 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
controller.init()
- val captor = argumentCaptor<List<String>>()
- verify(iconContainer).setIgnoredSlots(capture(captor))
-
- val cameraString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_camera)
- val micString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_microphone)
-
- assertThat(captor.value).containsExactly(cameraString, micString)
+ verify(iconContainer).addIgnoredSlot(cameraSlotName)
+ verify(iconContainer).addIgnoredSlot(microphoneSlotName)
+ verify(iconContainer).removeIgnoredSlot(locationSlotName)
}
@Test
@@ -170,13 +175,9 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
controller.init()
- val captor = argumentCaptor<List<String>>()
- verify(iconContainer).setIgnoredSlots(capture(captor))
-
- val locationString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_location)
-
- assertThat(captor.value).containsExactly(locationString)
+ verify(iconContainer).removeIgnoredSlot(cameraSlotName)
+ verify(iconContainer).removeIgnoredSlot(microphoneSlotName)
+ verify(iconContainer).addIgnoredSlot(locationSlotName)
}
@Test
@@ -185,17 +186,9 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
controller.init()
- val captor = argumentCaptor<List<String>>()
- verify(iconContainer).setIgnoredSlots(capture(captor))
-
- val cameraString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_camera)
- val micString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_microphone)
- val locationString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_location)
-
- assertThat(captor.value).containsExactly(cameraString, micString, locationString)
+ verify(iconContainer).addIgnoredSlot(cameraSlotName)
+ verify(iconContainer).addIgnoredSlot(microphoneSlotName)
+ verify(iconContainer).addIgnoredSlot(locationSlotName)
}
@Test
@@ -210,6 +203,71 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
verify(privacyDialogController).showDialog(any(Context::class.java))
}
+ @Test
+ fun testSingleCarrierListenerAttachedOnInit() {
+ controller.init()
+
+ verify(qsCarrierGroupController).setOnSingleCarrierChangedListener(any())
+ }
+
+ @Test
+ fun testSingleCarrierSetOnViewOnInit_false() {
+ `when`(qsCarrierGroupController.isSingleCarrier).thenReturn(false)
+ controller.init()
+
+ verify(view).setIsSingleCarrier(false)
+ }
+
+ @Test
+ fun testSingleCarrierSetOnViewOnInit_true() {
+ `when`(qsCarrierGroupController.isSingleCarrier).thenReturn(true)
+ controller.init()
+
+ verify(view).setIsSingleCarrier(true)
+ }
+
+ @Test
+ fun testRSSISlot_notCombined() {
+ `when`(featureFlags.isCombinedStatusBarSignalIconsEnabled).thenReturn(false)
+ controller.init()
+
+ val captor = argumentCaptor<List<String>>()
+ verify(view).onAttach(any(), any(), capture(captor))
+
+ assertThat(captor.value).containsExactly(
+ mContext.getString(com.android.internal.R.string.status_bar_mobile)
+ )
+ }
+
+ @Test
+ fun testRSSISlot_combined() {
+ `when`(featureFlags.isCombinedStatusBarSignalIconsEnabled).thenReturn(true)
+ controller.init()
+
+ val captor = argumentCaptor<List<String>>()
+ verify(view).onAttach(any(), any(), capture(captor))
+
+ assertThat(captor.value).containsExactly(
+ mContext.getString(com.android.internal.R.string.status_bar_no_calling),
+ mContext.getString(com.android.internal.R.string.status_bar_call_strength)
+ )
+ }
+
+ @Test
+ fun testSingleCarrierCallback() {
+ controller.init()
+ reset(view)
+
+ val captor = argumentCaptor<QSCarrierGroupController.OnSingleCarrierChangedListener>()
+ verify(qsCarrierGroupController).setOnSingleCarrierChangedListener(capture(captor))
+
+ captor.value.onSingleCarrierChanged(true)
+ verify(view).setIsSingleCarrier(true)
+
+ captor.value.onSingleCarrierChanged(false)
+ verify(view).setIsSingleCarrier(false)
+ }
+
private fun stubViews() {
`when`(view.findViewById<View>(anyInt())).thenReturn(mockView)
`when`(view.findViewById<QSCarrierGroup>(R.id.carrier_group)).thenReturn(qsCarrierGroup)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
index 9ae606901a91..72c7ddd3e5a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
@@ -17,15 +17,18 @@
package com.android.systemui.qs.carrier;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.Handler;
-import android.telephony.SubscriptionManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
@@ -46,9 +49,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -70,8 +71,18 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest {
private CarrierTextManager mCarrierTextManager;
@Mock
private CarrierConfigTracker mCarrierConfigTracker;
+ @Mock
+ private QSCarrier mQSCarrier1;
+ @Mock
+ private QSCarrier mQSCarrier2;
+ @Mock
+ private QSCarrier mQSCarrier3;
private TestableLooper mTestableLooper;
@Mock private FeatureFlags mFeatureFlags;
+ @Mock
+ private QSCarrierGroupController.OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
+
+ private FakeSlotIndexResolver mSlotIndexResolver;
@Before
public void setup() throws Exception {
@@ -96,29 +107,31 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest {
.setListening(any(CarrierTextManager.CarrierTextCallback.class));
when(mQSCarrierGroup.getNoSimTextView()).thenReturn(new TextView(mContext));
- when(mQSCarrierGroup.getCarrier1View()).thenReturn(mock(QSCarrier.class));
- when(mQSCarrierGroup.getCarrier2View()).thenReturn(mock(QSCarrier.class));
- when(mQSCarrierGroup.getCarrier3View()).thenReturn(mock(QSCarrier.class));
+ when(mQSCarrierGroup.getCarrier1View()).thenReturn(mQSCarrier1);
+ when(mQSCarrierGroup.getCarrier2View()).thenReturn(mQSCarrier2);
+ when(mQSCarrierGroup.getCarrier3View()).thenReturn(mQSCarrier3);
when(mQSCarrierGroup.getCarrierDivider1()).thenReturn(new View(mContext));
when(mQSCarrierGroup.getCarrierDivider2()).thenReturn(new View(mContext));
+ mSlotIndexResolver = new FakeSlotIndexResolver();
+
mQSCarrierGroupController = new QSCarrierGroupController.Builder(
mActivityStarter, handler, TestableLooper.get(this).getLooper(),
mNetworkController, mCarrierTextControllerBuilder, mContext, mCarrierConfigTracker,
- mFeatureFlags)
+ mFeatureFlags, mSlotIndexResolver)
.setQSCarrierGroup(mQSCarrierGroup)
.build();
mQSCarrierGroupController.setListening(true);
}
+ @Test
+ public void testInitiallyMultiCarrier() {
+ assertFalse(mQSCarrierGroupController.isSingleCarrier());
+ }
+
@Test // throws no Exception
public void testUpdateCarrierText_sameLengths() {
- QSCarrierGroupController spiedCarrierGroupController =
- Mockito.spy(mQSCarrierGroupController);
- when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenAnswer(
- (Answer<Integer>) invocationOnMock -> invocationOnMock.getArgument(0));
-
// listOfCarriers length 1, subscriptionIds length 1, anySims false
CarrierTextManager.CarrierTextCallbackInfo
c1 = new CarrierTextManager.CarrierTextCallbackInfo(
@@ -160,11 +173,6 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest {
@Test // throws no Exception
public void testUpdateCarrierText_differentLength() {
- QSCarrierGroupController spiedCarrierGroupController =
- Mockito.spy(mQSCarrierGroupController);
- when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenAnswer(
- (Answer<Integer>) invocationOnMock -> invocationOnMock.getArgument(0));
-
// listOfCarriers length 2, subscriptionIds length 1, anySims false
CarrierTextManager.CarrierTextCallbackInfo
c1 = new CarrierTextManager.CarrierTextCallbackInfo(
@@ -205,10 +213,7 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest {
@Test // throws no Exception
public void testUpdateCarrierText_invalidSim() {
- QSCarrierGroupController spiedCarrierGroupController =
- Mockito.spy(mQSCarrierGroupController);
- when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenReturn(
- SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+ mSlotIndexResolver.overrideInvalid = true;
CarrierTextManager.CarrierTextCallbackInfo
c4 = new CarrierTextManager.CarrierTextCallbackInfo(
@@ -222,6 +227,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest {
@Test // throws no Exception
public void testSetMobileDataIndicators_invalidSim() {
+ mSlotIndexResolver.overrideInvalid = true;
+
MobileDataIndicators indicators = new MobileDataIndicators(
mock(NetworkController.IconState.class),
mock(NetworkController.IconState.class),
@@ -242,4 +249,137 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest {
mTestableLooper.processAllMessages();
assertEquals(View.GONE, mQSCarrierGroup.getNoSimTextView().getVisibility());
}
+
+ @Test
+ public void testListenerNotCalledOnRegistreation() {
+ mQSCarrierGroupController
+ .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener);
+
+ verify(mOnSingleCarrierChangedListener, never()).onSingleCarrierChanged(anyBoolean());
+ }
+
+ @Test
+ public void testSingleCarrier() {
+ // Only one element in the info
+ CarrierTextManager.CarrierTextCallbackInfo
+ info = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ true,
+ new int[]{0},
+ false /* airplaneMode */);
+
+ mCallback.updateCarrierInfo(info);
+ mTestableLooper.processAllMessages();
+
+ verify(mQSCarrier1).updateState(any(), eq(true));
+ verify(mQSCarrier2).updateState(any(), eq(true));
+ verify(mQSCarrier3).updateState(any(), eq(true));
+ }
+
+ @Test
+ public void testMultiCarrier() {
+ // More than one element in the info
+ CarrierTextManager.CarrierTextCallbackInfo
+ info = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0, 1},
+ false /* airplaneMode */);
+
+ mCallback.updateCarrierInfo(info);
+ mTestableLooper.processAllMessages();
+
+ verify(mQSCarrier1).updateState(any(), eq(false));
+ verify(mQSCarrier2).updateState(any(), eq(false));
+ verify(mQSCarrier3).updateState(any(), eq(false));
+ }
+
+ @Test
+ public void testSingleMultiCarrierSwitch() {
+ CarrierTextManager.CarrierTextCallbackInfo
+ singleCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ true,
+ new int[]{0},
+ false /* airplaneMode */);
+
+ CarrierTextManager.CarrierTextCallbackInfo
+ multiCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0, 1},
+ false /* airplaneMode */);
+
+ mCallback.updateCarrierInfo(singleCarrierInfo);
+ mTestableLooper.processAllMessages();
+
+ mQSCarrierGroupController
+ .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener);
+ reset(mOnSingleCarrierChangedListener);
+
+ mCallback.updateCarrierInfo(multiCarrierInfo);
+ mTestableLooper.processAllMessages();
+ verify(mOnSingleCarrierChangedListener).onSingleCarrierChanged(false);
+
+ mCallback.updateCarrierInfo(singleCarrierInfo);
+ mTestableLooper.processAllMessages();
+ verify(mOnSingleCarrierChangedListener).onSingleCarrierChanged(true);
+ }
+
+ @Test
+ public void testNoCallbackIfSingleCarrierDoesntChange() {
+ CarrierTextManager.CarrierTextCallbackInfo
+ singleCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ true,
+ new int[]{0},
+ false /* airplaneMode */);
+
+ mCallback.updateCarrierInfo(singleCarrierInfo);
+ mTestableLooper.processAllMessages();
+
+ mQSCarrierGroupController
+ .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener);
+
+ mCallback.updateCarrierInfo(singleCarrierInfo);
+ mTestableLooper.processAllMessages();
+
+ verify(mOnSingleCarrierChangedListener, never()).onSingleCarrierChanged(anyBoolean());
+ }
+
+ @Test
+ public void testNoCallbackIfMultiCarrierDoesntChange() {
+ CarrierTextManager.CarrierTextCallbackInfo
+ multiCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0, 1},
+ false /* airplaneMode */);
+
+ mCallback.updateCarrierInfo(multiCarrierInfo);
+ mTestableLooper.processAllMessages();
+
+ mQSCarrierGroupController
+ .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener);
+
+ mCallback.updateCarrierInfo(multiCarrierInfo);
+ mTestableLooper.processAllMessages();
+
+ verify(mOnSingleCarrierChangedListener, never()).onSingleCarrierChanged(anyBoolean());
+ }
+
+ private class FakeSlotIndexResolver implements QSCarrierGroupController.SlotIndexResolver {
+ public boolean overrideInvalid;
+
+ @Override
+ public int getSlotIndex(int subscriptionId) {
+ return overrideInvalid ? -1 : subscriptionId;
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
index 9bee47db3e87..93c75ad83afc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.carrier;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -23,6 +24,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.FeatureFlagUtils;
import android.view.LayoutInflater;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -64,25 +66,64 @@ public class QSCarrierTest extends SysuiTestCase {
public void testUpdateState_first() {
CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
- assertTrue(mQSCarrier.updateState(c));
+ assertTrue(mQSCarrier.updateState(c, false));
}
@Test
public void testUpdateState_same() {
CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
- assertTrue(mQSCarrier.updateState(c));
- assertFalse(mQSCarrier.updateState(c));
+ assertTrue(mQSCarrier.updateState(c, false));
+ assertFalse(mQSCarrier.updateState(c, false));
}
@Test
public void testUpdateState_changed() {
CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
- assertTrue(mQSCarrier.updateState(c));
+ assertTrue(mQSCarrier.updateState(c, false));
CellSignalState other = c.changeVisibility(false);
- assertTrue(mQSCarrier.updateState(other));
+ assertTrue(mQSCarrier.updateState(other, false));
+ }
+
+ @Test
+ public void testUpdateState_singleCarrier_first() {
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
+
+ assertTrue(mQSCarrier.updateState(c, true));
+ }
+
+ @Test
+ public void testUpdateState_singleCarrier_noShowIcon() {
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
+
+ mQSCarrier.updateState(c, true);
+
+ assertEquals(View.GONE, mQSCarrier.getRSSIView().getVisibility());
+ }
+
+ @Test
+ public void testUpdateState_multiCarrier_showIcon() {
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
+
+ mQSCarrier.updateState(c, false);
+
+ assertEquals(View.VISIBLE, mQSCarrier.getRSSIView().getVisibility());
+ }
+
+ @Test
+ public void testUpdateState_changeSingleMultiSingle() {
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
+
+ mQSCarrier.updateState(c, true);
+ assertEquals(View.GONE, mQSCarrier.getRSSIView().getVisibility());
+
+ mQSCarrier.updateState(c, false);
+ assertEquals(View.VISIBLE, mQSCarrier.getRSSIView().getVisibility());
+
+ mQSCarrier.updateState(c, true);
+ assertEquals(View.GONE, mQSCarrier.getRSSIView().getVisibility());
}
}