Loading packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +59 −28 Original line number Diff line number Diff line Loading @@ -52,9 +52,11 @@ public class CarrierTextController { private boolean mTelephonyCapable; private boolean mShowMissingSim; private boolean mShowAirplaneMode; private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @VisibleForTesting protected KeyguardUpdateMonitor mKeyguardUpdateMonitor; private WifiManager mWifiManager; private boolean[] mSimErrorState = new boolean[TelephonyManager.getDefault().getPhoneCount()]; private boolean[] mSimErrorState; private final int mSimSlotsNumber; private CarrierTextCallback mCarrierTextCallback; private Context mContext; private CharSequence mSeparator; Loading @@ -72,7 +74,8 @@ public class CarrierTextController { } }; private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { @VisibleForTesting protected final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { @Override public void onRefreshCarrierInfo() { if (DEBUG) { Loading @@ -93,7 +96,7 @@ public class CarrierTextController { } public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) { if (slotId < 0) { if (slotId < 0 || slotId >= mSimSlotsNumber) { Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId + " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable)); return; Loading Loading @@ -144,21 +147,30 @@ public class CarrierTextController { mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mSeparator = separator; mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); mSimSlotsNumber = ((TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE)).getPhoneCount(); mSimErrorState = new boolean[mSimSlotsNumber]; } /** * Checks if there are faulty cards. Adds the text depending on the slot of the card * * @param text: current carrier text based on the sim state * @param carrierNames names order by subscription order * @param subOrderBySlot array containing the sub index for each slot ID * @param noSims: whether a valid sim card is inserted * @return text */ private CharSequence updateCarrierTextWithSimIoError(CharSequence text, boolean noSims) { private CharSequence updateCarrierTextWithSimIoError(CharSequence text, CharSequence[] carrierNames, int[] subOrderBySlot, boolean noSims) { final CharSequence carrier = ""; CharSequence carrierTextForSimIOError = getCarrierTextForSimState( IccCardConstants.State.CARD_IO_ERROR, carrier); // mSimErrorState has the state of each sim indexed by slotID. for (int index = 0; index < mSimErrorState.length; index++) { if (mSimErrorState[index]) { if (!mSimErrorState[index]) { continue; } // In the case when no sim cards are detected but a faulty card is inserted // overwrite the text and only show "Invalid card" if (noSims) { Loading @@ -166,14 +178,17 @@ public class CarrierTextController { getContext().getText( com.android.internal.R.string.emergency_calls_only), mSeparator); } else if (index == 0) { // prepend "Invalid card" when faulty card is inserted in slot 0 text = concatenate(carrierTextForSimIOError, text, mSeparator); } else if (subOrderBySlot[index] != -1) { int subIndex = subOrderBySlot[index]; // prepend "Invalid card" when faulty card is inserted in slot 0 or 1 carrierNames[subIndex] = concatenate(carrierTextForSimIOError, carrierNames[subIndex], mSeparator); } else { // concatenate "Invalid card" when faulty card is inserted in slot 1 // concatenate "Invalid card" when faulty card is inserted in other slot text = concatenate(text, carrierTextForSimIOError, mSeparator); } } } return text; } Loading Loading @@ -209,16 +224,25 @@ public class CarrierTextController { protected void updateCarrierText() { boolean allSimsMissing = true; boolean anySimReadyAndInService = false; boolean missingSimsWithSubs = false; CharSequence displayText = null; List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false); final int numSubs = subs.size(); final int[] subsIds = new int[numSubs]; // This array will contain in position i, the index of subscription in slot ID i. // -1 if no subscription in that slot final int[] subOrderBySlot = new int[mSimSlotsNumber]; for (int i = 0; i < mSimSlotsNumber; i++) { subOrderBySlot[i] = -1; } final CharSequence[] carrierNames = new CharSequence[numSubs]; if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs); for (int i = 0; i < numSubs; i++) { int subId = subs.get(i).getSubscriptionId(); carrierNames[i] = ""; subsIds[i] = subId; subOrderBySlot[subs.get(i).getSimSlotIndex()] = i; IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId); CharSequence carrierName = subs.get(i).getCarrierName(); CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName); Loading @@ -227,7 +251,7 @@ public class CarrierTextController { } if (carrierTextForSimState != null) { allSimsMissing = false; displayText = concatenate(displayText, carrierTextForSimState, mSeparator); carrierNames[i] = carrierTextForSimState; } if (simState == IccCardConstants.State.READY) { ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId); Loading Loading @@ -256,7 +280,6 @@ public class CarrierTextController { // described above. displayText = makeCarrierStringOnEmergencyCapable( getMissingSimMessage(), subs.get(0).getCarrierName()); missingSimsWithSubs = true; } else { // We don't have a SubscriptionInfo to get the emergency calls only from. // Grab it from the old sticky broadcast if possible instead. We can use it Loading Loading @@ -286,24 +309,32 @@ public class CarrierTextController { } } displayText = updateCarrierTextWithSimIoError(displayText, allSimsMissing); displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot, allSimsMissing); // APM (airplane mode) != no carrier state. There are carrier services // (e.g. WFC = Wi-Fi calling) which may operate in APM. if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) { displayText = getAirplaneModeMessage(); } Handler handler = Dependency.get(Dependency.MAIN_HANDLER); if (TextUtils.isEmpty(displayText)) { displayText = TextUtils.join(mSeparator, carrierNames); } final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo( displayText, displayText.toString().split(mSeparator.toString()), anySimReadyAndInService && !missingSimsWithSubs, carrierNames, !allSimsMissing, subsIds); postToCallback(info); } @VisibleForTesting protected void postToCallback(CarrierTextCallbackInfo info) { Handler handler = Dependency.get(Dependency.MAIN_HANDLER); final CarrierTextCallback callback = mCarrierTextCallback; if (callback != null) { handler.post(() -> callback.updateCarrierInfo(info)); } } private Context getContext() { Loading packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java +3 −10 Original line number Diff line number Diff line Loading @@ -521,16 +521,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter, } } } else { // If there are sims ready but there are not the same number of carrier names as // subscription ids, just show the full text in the first slot mInfos[0].visible = true; mCarrierTexts[0].setText(info.carrierText); mCarrierGroups[0].setVisibility(View.VISIBLE); for (int i = 1; i < SIM_SLOTS; i++) { mInfos[i].visible = false; mCarrierTexts[i].setText(""); mCarrierGroups[i].setVisibility(View.GONE); } Log.e(TAG, "Carrier information arrays not of same length"); } } else { mInfos[0].visible = false; Loading Loading @@ -612,8 +603,10 @@ public class QSFooterImpl extends FrameLayout implements QSFooter, // Only show marquee when visible if (visibility == VISIBLE) { setEllipsize(TextUtils.TruncateAt.MARQUEE); setSelected(true); } else { setEllipsize(TextUtils.TruncateAt.END); setSelected(false); } } } Loading packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java 0 → 100644 +245 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.keyguard; import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE; import static android.telephony.SubscriptionManager.DATA_ROAMING_ENABLE; import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; 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.content.Context; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Handler; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.IccCardConstants; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.keyguard.WakefulnessLifecycle; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class CarrierTextControllerTest extends SysuiTestCase { private static final CharSequence SEPARATOR = " \u2014 "; private static final String TEST_CARRIER = "TEST_CARRIER"; private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(0, "", 0, TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", DATA_ROAMING_DISABLE, null, null, null, null, false, null, ""); private static final SubscriptionInfo TEST_SUBSCRIPTION_ROAMING = new SubscriptionInfo(0, "", 0, TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", DATA_ROAMING_ENABLE, null, null, null, null, false, null, ""); @Mock private WifiManager mWifiManager; @Mock private CarrierTextController.CarrierTextCallback mCarrierTextCallback; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock private ConnectivityManager mConnectivityManager; @Mock private TelephonyManager mTelephonyManager; private CarrierTextController.CarrierTextCallbackInfo mCarrierTextCallbackInfo; private CarrierTextController mCarrierTextController; private TestableLooper mTestableLooper; @Before public void setUp() { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); mContext.addMockSystemService(WifiManager.class, mWifiManager); mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager); mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager); mDependency.injectMockDependency(WakefulnessLifecycle.class); mDependency.injectTestDependency(Dependency.MAIN_HANDLER, new Handler(mTestableLooper.getLooper())); mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("", new CharSequence[]{}, false, new int[]{}); when(mTelephonyManager.getPhoneCount()).thenReturn(2); mCarrierTextController = new TestCarrierTextController(mContext, SEPARATOR, true, true, mKeyguardUpdateMonitor); // This should not start listening on any of the real dependencies mCarrierTextController.setListening(mCarrierTextCallback); } @Test public void testWrongSlots() { reset(mCarrierTextCallback); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( IccCardConstants.State.CARD_IO_ERROR); // This should not produce an out of bounds error, even though there are no subscriptions mCarrierTextController.mCallback.onSimStateChanged(0, -3, IccCardConstants.State.CARD_IO_ERROR); mCarrierTextController.mCallback.onSimStateChanged(0, 3, IccCardConstants.State.READY); verify(mCarrierTextCallback, never()).updateCarrierInfo(any()); } @Test public void testMoreSlotsThanSubs() { reset(mCarrierTextCallback); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( IccCardConstants.State.CARD_IO_ERROR); // This should not produce an out of bounds error, even though there are no subscriptions mCarrierTextController.mCallback.onSimStateChanged(0, 1, IccCardConstants.State.CARD_IO_ERROR); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo( any(CarrierTextController.CarrierTextCallbackInfo.class)); } @Test public void testCallback() { reset(mCarrierTextCallback); mCarrierTextController.postToCallback(mCarrierTextCallbackInfo); mTestableLooper.processAllMessages(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( CarrierTextController.CarrierTextCallbackInfo.class); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals(mCarrierTextCallbackInfo, captor.getValue()); } @Test public void testNullingCallback() { reset(mCarrierTextCallback); mCarrierTextController.postToCallback(mCarrierTextCallbackInfo); mCarrierTextController.setListening(null); // This shouldn't produce NPE mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(any()); } @Test public void testCreateInfo_OneValidSubscription() { reset(mCarrierTextCallback); List<SubscriptionInfo> list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( CarrierTextController.CarrierTextCallbackInfo.class); mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(1, info.listOfCarriers.length); assertEquals(TEST_CARRIER, info.listOfCarriers[0]); assertEquals(1, info.subscriptionIds.length); } @Test public void testCreateInfo_OneValidSubscriptionWithRoaming() { reset(mCarrierTextCallback); List<SubscriptionInfo> list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION_ROAMING); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( CarrierTextController.CarrierTextCallbackInfo.class); mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(1, info.listOfCarriers.length); assertTrue(info.listOfCarriers[0].toString().contains(TEST_CARRIER)); assertEquals(1, info.subscriptionIds.length); } @Test public void testCreateInfo_noSubscriptions() { reset(mCarrierTextCallback); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( CarrierTextController.CarrierTextCallbackInfo.class); mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(0, info.listOfCarriers.length); assertEquals(0, info.subscriptionIds.length); } public static class TestCarrierTextController extends CarrierTextController { private KeyguardUpdateMonitor mKUM; public TestCarrierTextController(Context context, CharSequence separator, boolean showAirplaneMode, boolean showMissingSim, KeyguardUpdateMonitor kum) { super(context, separator, showAirplaneMode, showMissingSim); mKUM = kum; } @Override public void setListening(CarrierTextCallback callback) { super.setListening(callback); mKeyguardUpdateMonitor = mKUM; } } } Loading
packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +59 −28 Original line number Diff line number Diff line Loading @@ -52,9 +52,11 @@ public class CarrierTextController { private boolean mTelephonyCapable; private boolean mShowMissingSim; private boolean mShowAirplaneMode; private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @VisibleForTesting protected KeyguardUpdateMonitor mKeyguardUpdateMonitor; private WifiManager mWifiManager; private boolean[] mSimErrorState = new boolean[TelephonyManager.getDefault().getPhoneCount()]; private boolean[] mSimErrorState; private final int mSimSlotsNumber; private CarrierTextCallback mCarrierTextCallback; private Context mContext; private CharSequence mSeparator; Loading @@ -72,7 +74,8 @@ public class CarrierTextController { } }; private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { @VisibleForTesting protected final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { @Override public void onRefreshCarrierInfo() { if (DEBUG) { Loading @@ -93,7 +96,7 @@ public class CarrierTextController { } public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) { if (slotId < 0) { if (slotId < 0 || slotId >= mSimSlotsNumber) { Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId + " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable)); return; Loading Loading @@ -144,21 +147,30 @@ public class CarrierTextController { mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mSeparator = separator; mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); mSimSlotsNumber = ((TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE)).getPhoneCount(); mSimErrorState = new boolean[mSimSlotsNumber]; } /** * Checks if there are faulty cards. Adds the text depending on the slot of the card * * @param text: current carrier text based on the sim state * @param carrierNames names order by subscription order * @param subOrderBySlot array containing the sub index for each slot ID * @param noSims: whether a valid sim card is inserted * @return text */ private CharSequence updateCarrierTextWithSimIoError(CharSequence text, boolean noSims) { private CharSequence updateCarrierTextWithSimIoError(CharSequence text, CharSequence[] carrierNames, int[] subOrderBySlot, boolean noSims) { final CharSequence carrier = ""; CharSequence carrierTextForSimIOError = getCarrierTextForSimState( IccCardConstants.State.CARD_IO_ERROR, carrier); // mSimErrorState has the state of each sim indexed by slotID. for (int index = 0; index < mSimErrorState.length; index++) { if (mSimErrorState[index]) { if (!mSimErrorState[index]) { continue; } // In the case when no sim cards are detected but a faulty card is inserted // overwrite the text and only show "Invalid card" if (noSims) { Loading @@ -166,14 +178,17 @@ public class CarrierTextController { getContext().getText( com.android.internal.R.string.emergency_calls_only), mSeparator); } else if (index == 0) { // prepend "Invalid card" when faulty card is inserted in slot 0 text = concatenate(carrierTextForSimIOError, text, mSeparator); } else if (subOrderBySlot[index] != -1) { int subIndex = subOrderBySlot[index]; // prepend "Invalid card" when faulty card is inserted in slot 0 or 1 carrierNames[subIndex] = concatenate(carrierTextForSimIOError, carrierNames[subIndex], mSeparator); } else { // concatenate "Invalid card" when faulty card is inserted in slot 1 // concatenate "Invalid card" when faulty card is inserted in other slot text = concatenate(text, carrierTextForSimIOError, mSeparator); } } } return text; } Loading Loading @@ -209,16 +224,25 @@ public class CarrierTextController { protected void updateCarrierText() { boolean allSimsMissing = true; boolean anySimReadyAndInService = false; boolean missingSimsWithSubs = false; CharSequence displayText = null; List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false); final int numSubs = subs.size(); final int[] subsIds = new int[numSubs]; // This array will contain in position i, the index of subscription in slot ID i. // -1 if no subscription in that slot final int[] subOrderBySlot = new int[mSimSlotsNumber]; for (int i = 0; i < mSimSlotsNumber; i++) { subOrderBySlot[i] = -1; } final CharSequence[] carrierNames = new CharSequence[numSubs]; if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs); for (int i = 0; i < numSubs; i++) { int subId = subs.get(i).getSubscriptionId(); carrierNames[i] = ""; subsIds[i] = subId; subOrderBySlot[subs.get(i).getSimSlotIndex()] = i; IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId); CharSequence carrierName = subs.get(i).getCarrierName(); CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName); Loading @@ -227,7 +251,7 @@ public class CarrierTextController { } if (carrierTextForSimState != null) { allSimsMissing = false; displayText = concatenate(displayText, carrierTextForSimState, mSeparator); carrierNames[i] = carrierTextForSimState; } if (simState == IccCardConstants.State.READY) { ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId); Loading Loading @@ -256,7 +280,6 @@ public class CarrierTextController { // described above. displayText = makeCarrierStringOnEmergencyCapable( getMissingSimMessage(), subs.get(0).getCarrierName()); missingSimsWithSubs = true; } else { // We don't have a SubscriptionInfo to get the emergency calls only from. // Grab it from the old sticky broadcast if possible instead. We can use it Loading Loading @@ -286,24 +309,32 @@ public class CarrierTextController { } } displayText = updateCarrierTextWithSimIoError(displayText, allSimsMissing); displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot, allSimsMissing); // APM (airplane mode) != no carrier state. There are carrier services // (e.g. WFC = Wi-Fi calling) which may operate in APM. if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) { displayText = getAirplaneModeMessage(); } Handler handler = Dependency.get(Dependency.MAIN_HANDLER); if (TextUtils.isEmpty(displayText)) { displayText = TextUtils.join(mSeparator, carrierNames); } final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo( displayText, displayText.toString().split(mSeparator.toString()), anySimReadyAndInService && !missingSimsWithSubs, carrierNames, !allSimsMissing, subsIds); postToCallback(info); } @VisibleForTesting protected void postToCallback(CarrierTextCallbackInfo info) { Handler handler = Dependency.get(Dependency.MAIN_HANDLER); final CarrierTextCallback callback = mCarrierTextCallback; if (callback != null) { handler.post(() -> callback.updateCarrierInfo(info)); } } private Context getContext() { Loading
packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java +3 −10 Original line number Diff line number Diff line Loading @@ -521,16 +521,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter, } } } else { // If there are sims ready but there are not the same number of carrier names as // subscription ids, just show the full text in the first slot mInfos[0].visible = true; mCarrierTexts[0].setText(info.carrierText); mCarrierGroups[0].setVisibility(View.VISIBLE); for (int i = 1; i < SIM_SLOTS; i++) { mInfos[i].visible = false; mCarrierTexts[i].setText(""); mCarrierGroups[i].setVisibility(View.GONE); } Log.e(TAG, "Carrier information arrays not of same length"); } } else { mInfos[0].visible = false; Loading Loading @@ -612,8 +603,10 @@ public class QSFooterImpl extends FrameLayout implements QSFooter, // Only show marquee when visible if (visibility == VISIBLE) { setEllipsize(TextUtils.TruncateAt.MARQUEE); setSelected(true); } else { setEllipsize(TextUtils.TruncateAt.END); setSelected(false); } } } Loading
packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java 0 → 100644 +245 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.keyguard; import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE; import static android.telephony.SubscriptionManager.DATA_ROAMING_ENABLE; import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; 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.content.Context; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Handler; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.IccCardConstants; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.keyguard.WakefulnessLifecycle; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class CarrierTextControllerTest extends SysuiTestCase { private static final CharSequence SEPARATOR = " \u2014 "; private static final String TEST_CARRIER = "TEST_CARRIER"; private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(0, "", 0, TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", DATA_ROAMING_DISABLE, null, null, null, null, false, null, ""); private static final SubscriptionInfo TEST_SUBSCRIPTION_ROAMING = new SubscriptionInfo(0, "", 0, TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", DATA_ROAMING_ENABLE, null, null, null, null, false, null, ""); @Mock private WifiManager mWifiManager; @Mock private CarrierTextController.CarrierTextCallback mCarrierTextCallback; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock private ConnectivityManager mConnectivityManager; @Mock private TelephonyManager mTelephonyManager; private CarrierTextController.CarrierTextCallbackInfo mCarrierTextCallbackInfo; private CarrierTextController mCarrierTextController; private TestableLooper mTestableLooper; @Before public void setUp() { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); mContext.addMockSystemService(WifiManager.class, mWifiManager); mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager); mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager); mDependency.injectMockDependency(WakefulnessLifecycle.class); mDependency.injectTestDependency(Dependency.MAIN_HANDLER, new Handler(mTestableLooper.getLooper())); mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("", new CharSequence[]{}, false, new int[]{}); when(mTelephonyManager.getPhoneCount()).thenReturn(2); mCarrierTextController = new TestCarrierTextController(mContext, SEPARATOR, true, true, mKeyguardUpdateMonitor); // This should not start listening on any of the real dependencies mCarrierTextController.setListening(mCarrierTextCallback); } @Test public void testWrongSlots() { reset(mCarrierTextCallback); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( IccCardConstants.State.CARD_IO_ERROR); // This should not produce an out of bounds error, even though there are no subscriptions mCarrierTextController.mCallback.onSimStateChanged(0, -3, IccCardConstants.State.CARD_IO_ERROR); mCarrierTextController.mCallback.onSimStateChanged(0, 3, IccCardConstants.State.READY); verify(mCarrierTextCallback, never()).updateCarrierInfo(any()); } @Test public void testMoreSlotsThanSubs() { reset(mCarrierTextCallback); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( IccCardConstants.State.CARD_IO_ERROR); // This should not produce an out of bounds error, even though there are no subscriptions mCarrierTextController.mCallback.onSimStateChanged(0, 1, IccCardConstants.State.CARD_IO_ERROR); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo( any(CarrierTextController.CarrierTextCallbackInfo.class)); } @Test public void testCallback() { reset(mCarrierTextCallback); mCarrierTextController.postToCallback(mCarrierTextCallbackInfo); mTestableLooper.processAllMessages(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( CarrierTextController.CarrierTextCallbackInfo.class); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals(mCarrierTextCallbackInfo, captor.getValue()); } @Test public void testNullingCallback() { reset(mCarrierTextCallback); mCarrierTextController.postToCallback(mCarrierTextCallbackInfo); mCarrierTextController.setListening(null); // This shouldn't produce NPE mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(any()); } @Test public void testCreateInfo_OneValidSubscription() { reset(mCarrierTextCallback); List<SubscriptionInfo> list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( CarrierTextController.CarrierTextCallbackInfo.class); mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(1, info.listOfCarriers.length); assertEquals(TEST_CARRIER, info.listOfCarriers[0]); assertEquals(1, info.subscriptionIds.length); } @Test public void testCreateInfo_OneValidSubscriptionWithRoaming() { reset(mCarrierTextCallback); List<SubscriptionInfo> list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION_ROAMING); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( CarrierTextController.CarrierTextCallbackInfo.class); mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(1, info.listOfCarriers.length); assertTrue(info.listOfCarriers[0].toString().contains(TEST_CARRIER)); assertEquals(1, info.subscriptionIds.length); } @Test public void testCreateInfo_noSubscriptions() { reset(mCarrierTextCallback); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( CarrierTextController.CarrierTextCallbackInfo.class); mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(0, info.listOfCarriers.length); assertEquals(0, info.subscriptionIds.length); } public static class TestCarrierTextController extends CarrierTextController { private KeyguardUpdateMonitor mKUM; public TestCarrierTextController(Context context, CharSequence separator, boolean showAirplaneMode, boolean showMissingSim, KeyguardUpdateMonitor kum) { super(context, separator, showAirplaneMode, showMissingSim); mKUM = kum; } @Override public void setListening(CarrierTextCallback callback) { super.setListening(callback); mKeyguardUpdateMonitor = mKUM; } } }