diff options
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()); } } |