From 9d8c4f2de6221cee2f2792e5fa22e7537df76598 Mon Sep 17 00:00:00 2001 From: Fabian Kozynski Date: Fri, 16 Jul 2021 16:15:47 -0400 Subject: [PATCH] Hide RSSI next to single carrier name If there's exactly one SIM, do not show the RSSI next to the name in QSBH. Instead, show it with the other icons. If there's more than one SIM, show each RSSI next to the carrier name, and not with the other icons (not even in QQS). Test: atest com.android.systemui.qs Test: manual single sim Bug: 187654917 Change-Id: I8b80bb14b8f60872d44d5a92ddfa7c5903420874 Merged-In: I8b80bb14b8f60872d44d5a92ddfa7c5903420874 --- packages/SystemUI/res/layout/qs_carrier.xml | 7 + .../systemui/qs/QuickStatusBarHeader.java | 53 +++-- .../qs/QuickStatusBarHeaderController.java | 58 ++++-- .../systemui/qs/carrier/QSCarrier.java | 24 ++- .../qs/carrier/QSCarrierGroupController.java | 87 ++++++++- .../systemui/qs/dagger/QSFragmentModule.java | 5 + .../android/systemui/qs/dagger/QSModule.java | 1 - .../statusbar/phone/StatusIconContainer.java | 15 +- .../qs/QuickStatusBarHeaderControllerTest.kt | 120 +++++++++--- .../carrier/QSCarrierGroupControllerTest.java | 184 +++++++++++++++--- .../systemui/qs/carrier/QSCarrierTest.java | 51 ++++- 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 d4594d17f02bd..a854660f64f8d 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"/> + + 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 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 fcf1302b8fb41..b8b7f42455bba 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 { @@ -162,6 +163,10 @@ class QuickStatusBarHeaderController extends ViewController 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 getIgnoredIconSlots() { - ArrayList 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 d6fa216464021..32ac73375f1d9 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 f23c0580c4091..67c4d33d53d3f 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); } - private boolean isSingleCarrier() { + /** + * 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 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 34aac492dc30d..4d633492ed761 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 de3be78e5463c..6d1bbeed5372c 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 64a497ddd3173..329293409dc20 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 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 f140eb85e76d9..35360bd193932 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>() - 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>() - 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>() - 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>() - 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>() + 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>() + 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() + 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(anyInt())).thenReturn(mockView) `when`(view.findViewById(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 9ae606901a91a..72c7ddd3e5a51 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) 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) 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 9bee47db3e871..93c75ad83afc7 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()); } }