summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/keyguard/CarrierTextController.java87
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java245
3 files changed, 307 insertions, 38 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 1539582ef18b..64517bae6d6b 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -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;
@@ -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) {
@@ -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;
@@ -144,36 +147,48 @@ 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]) {
- // 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) {
- return concatenate(carrierTextForSimIOError,
- 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 {
- // concatenate "Invalid card" when faulty card is inserted in slot 1
- text = concatenate(text, carrierTextForSimIOError, mSeparator);
- }
+ 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) {
+ return concatenate(carrierTextForSimIOError,
+ getContext().getText(
+ com.android.internal.R.string.emergency_calls_only),
+ 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 other slot
+ text = concatenate(text, carrierTextForSimIOError, mSeparator);
}
+
}
return text;
}
@@ -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);
@@ -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);
@@ -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
@@ -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() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index f91c9d944439..bbd8de333d79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -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;
@@ -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);
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
new file mode 100644
index 000000000000..8e061cc84396
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -0,0 +1,245 @@
+/*
+ * 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;
+ }
+ }
+}