Add timeout for displaying 5G icon in SystemUI
SystemUI refer CarrierConfig timeout(Second) to show 5G icon gracefully
System UI will show the 5G icon and post message delay by config value
after the device connect to a 5G cell to make the UX better
System UI stop displaying 5G icon when below conditions matched
1. device disconnect from 5G cell
2. the timer is expired.
Fixes: 136636141
Bug: 136107473
Test: atest SystemUITests
Test: enable SystemUI Demo Mode, simulate mServiceState callback 5G
Test: adb shell am broadcast -a com.android.systemui.demo -e command network
-e mobile show -e datatype 5g -e level 4
Test: adb shell am broadcast -a com.android.systemui.demo -e command network
-e mobile show -e datatype 5g+ -e level 4
Design: go/sysui_5g_signal_timer
Change-Id: I5e723c3edf28d31725fa9d847ed3569a1c322739
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 7acf4fd..dbfb09f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -21,6 +21,7 @@
import android.net.NetworkCapabilities;
import android.os.Handler;
import android.os.Looper;
+import android.os.Message;
import android.provider.Settings.Global;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
@@ -54,6 +55,10 @@
public class MobileSignalController extends SignalController<
MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> {
+
+ // The message to display Nr5G icon gracfully by CarrierConfig timeout
+ private static final int MSG_DISPLAY_GRACE = 1;
+
private final TelephonyManager mPhone;
private final SubscriptionDefaults mDefaults;
private final String mNetworkNameDefault;
@@ -76,8 +81,11 @@
private SignalStrength mSignalStrength;
private MobileIconGroup mDefaultIcons;
private Config mConfig;
+ private final Handler mDisplayGraceHandler;
@VisibleForTesting
boolean mInflateSignalStrengths = false;
+ @VisibleForTesting
+ boolean mIsShowingIconGracefully = false;
// Some specific carriers have 5GE network which is special LTE CA network.
private static final int NETWORK_TYPE_LTE_CA_5GE = TelephonyManager.MAX_NETWORK_TYPE + 1;
@@ -116,6 +124,16 @@
updateTelephony();
}
};
+
+ mDisplayGraceHandler = new Handler(receiverLooper) {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_DISPLAY_GRACE) {
+ mIsShowingIconGracefully = false;
+ updateTelephony();
+ }
+ }
+ };
}
public void setConfiguration(Config config) {
@@ -479,6 +497,10 @@
// When the device is camped on a 5G Non-Standalone network, the data network type is still
// LTE. In this case, we first check which 5G icon should be shown.
MobileIconGroup nr5GIconGroup = getNr5GIconGroup();
+ if (mConfig.nrIconDisplayGracePeriodMs > 0) {
+ nr5GIconGroup = adjustNr5GIconGroupByDisplayGraceTime(nr5GIconGroup);
+ }
+
if (nr5GIconGroup != null) {
mCurrentState.iconGroup = nr5GIconGroup;
} else if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
@@ -555,6 +577,46 @@
return null;
}
+ /**
+ * The function to adjust MobileIconGroup depend on CarrierConfig's time
+ * nextIconGroup == null imply next state could be 2G/3G/4G/4G+
+ * nextIconGroup != null imply next state will be 5G/5G+
+ * Flag : mIsShowingIconGracefully
+ * ---------------------------------------------------------------------------------
+ * | Last state | Current state | Flag | Action |
+ * ---------------------------------------------------------------------------------
+ * | 5G/5G+ | 2G/3G/4G/4G+ | true | return previous IconGroup |
+ * | 5G/5G+ | 5G/5G+ | true | Bypass |
+ * | 2G/3G/4G/4G+ | 5G/5G+ | true | Bypass |
+ * | 2G/3G/4G/4G+ | 2G/3G/4G/4G+ | true | Bypass |
+ * | SS.connected | SS.disconnect | T|F | Reset timer |
+ * |NETWORK_TYPE_LTE|!NETWORK_TYPE_LTE| T|F | Reset timer |
+ * | 5G/5G+ | 2G/3G/4G/4G+ | false| Bypass |
+ * | 5G/5G+ | 5G/5G+ | false| Bypass |
+ * | 2G/3G/4G/4G+ | 5G/5G+ | false| SendMessageDelay(time), flag->true |
+ * | 2G/3G/4G/4G+ | 2G/3G/4G/4G+ | false| Bypass |
+ * ---------------------------------------------------------------------------------
+ */
+ private MobileIconGroup adjustNr5GIconGroupByDisplayGraceTime(
+ MobileIconGroup candidateIconGroup) {
+ if (mIsShowingIconGracefully && candidateIconGroup == null) {
+ candidateIconGroup = (MobileIconGroup) mCurrentState.iconGroup;
+ } else if (!mIsShowingIconGracefully && candidateIconGroup != null
+ && mLastState.iconGroup != candidateIconGroup) {
+ mDisplayGraceHandler.sendMessageDelayed(
+ mDisplayGraceHandler.obtainMessage(MSG_DISPLAY_GRACE),
+ mConfig.nrIconDisplayGracePeriodMs);
+ mIsShowingIconGracefully = true;
+ } else if (!mCurrentState.connected || mDataState == TelephonyManager.DATA_DISCONNECTED
+ || candidateIconGroup == null) {
+ mDisplayGraceHandler.removeMessages(MSG_DISPLAY_GRACE);
+ mIsShowingIconGracefully = false;
+ candidateIconGroup = null;
+ }
+
+ return candidateIconGroup;
+ }
+
private boolean isDataDisabled() {
return !mPhone.isDataCapable();
}
@@ -580,6 +642,7 @@
pw.println(" mDataNetType=" + mDataNetType + ",");
pw.println(" mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
pw.println(" isDataDisabled=" + isDataDisabled() + ",");
+ pw.println(" mIsShowingIconGracefully=" + mIsShowingIconGracefully + ",");
}
class MobilePhoneStateListener extends PhoneStateListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 621b16a..bb37421 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -51,6 +51,7 @@
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.text.format.DateUtils;
import android.util.Log;
import android.util.MathUtils;
import android.util.SparseArray;
@@ -829,6 +830,13 @@
pw.print(" mEmergencySource=");
pw.println(emergencyToString(mEmergencySource));
+ pw.println(" - config ------");
+ pw.print(" patternOfCarrierSpecificDataIcon=");
+ pw.println(mConfig.patternOfCarrierSpecificDataIcon);
+ pw.print(" nr5GIconMap=");
+ pw.println(mConfig.nr5GIconMap.toString());
+ pw.print(" nrIconDisplayGracePeriodMs=");
+ pw.println(mConfig.nrIconDisplayGracePeriodMs);
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.dump(pw);
@@ -992,6 +1000,8 @@
datatype.equals("3g") ? TelephonyIcons.THREE_G :
datatype.equals("4g") ? TelephonyIcons.FOUR_G :
datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS :
+ datatype.equals("5g") ? TelephonyIcons.NR_5G :
+ datatype.equals("5g+") ? TelephonyIcons.NR_5G_PLUS :
datatype.equals("e") ? TelephonyIcons.E :
datatype.equals("g") ? TelephonyIcons.G :
datatype.equals("h") ? TelephonyIcons.H :
@@ -1123,6 +1133,7 @@
boolean inflateSignalStrengths = false;
boolean alwaysShowDataRatIcon = false;
public String patternOfCarrierSpecificDataIcon = "";
+ public long nrIconDisplayGracePeriodMs;
/**
* Mapping from NR 5G status string to an integer. The NR 5G status string should match
@@ -1175,6 +1186,9 @@
add5GIconMapping(pair, config);
}
}
+ setDisplayGraceTime(
+ b.getInt(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT),
+ config);
}
return config;
@@ -1208,5 +1222,18 @@
TelephonyIcons.ICON_NAME_TO_ICON.get(value));
}
}
+
+ /**
+ * Set display gracefully period time(MS) depend on carrierConfig KEY
+ * KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, and this function will convert to ms.
+ * {@link CarrierConfigManager}.
+ *
+ * @param time showing 5G icon gracefully in the period of the time(SECOND)
+ * @param config container that used to store the parsed configs.
+ */
+ @VisibleForTesting
+ static void setDisplayGraceTime(int time, Config config) {
+ config.nrIconDisplayGracePeriodMs = time * DateUtils.SECOND_IN_MILLIS;
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index e691b7d..c03f07e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -30,6 +30,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.app.Instrumentation;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.Network;
@@ -48,6 +49,8 @@
import android.testing.TestableResources;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+
import com.android.internal.telephony.cdma.EriInfo;
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.net.DataUsageController;
@@ -95,6 +98,7 @@
protected SubscriptionDefaults mMockSubDefaults;
protected DeviceProvisionedController mMockProvisionController;
protected DeviceProvisionedListener mUserCallback;
+ protected Instrumentation mInstrumentation;
protected int mSubId;
@@ -116,6 +120,7 @@
@Before
public void setUp() throws Exception {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
Settings.Global.putInt(mContext.getContentResolver(), Global.AIRPLANE_MODE_ON, 0);
TestableResources res = mContext.getOrCreateTestableResources();
res.addOverride(R.string.cell_data_off_content_description, NO_DATA_STRING);
@@ -240,6 +245,16 @@
NetworkControllerImpl.Config.add5GIconMapping("not_restricted_rrc_idle:5g", mConfig);
}
+ public void setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds() {
+ final int enableDisplayGraceTimeSec = 30;
+ NetworkControllerImpl.Config.setDisplayGraceTime(enableDisplayGraceTimeSec, mConfig);
+ }
+
+ public void setupDefaultNr5GIconDisplayGracePeriodTime_disabled() {
+ final int disableDisplayGraceTimeSec = 0;
+ NetworkControllerImpl.Config.setDisplayGraceTime(disableDisplayGraceTimeSec, mConfig);
+ }
+
public void setConnectivityViaBroadcast(
int networkType, boolean validated, boolean isConnected) {
setConnectivityCommon(networkType, validated, isConnected);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index f0394da..3ddfbdac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -1,5 +1,7 @@
package com.android.systemui.statusbar.policy;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -245,6 +247,186 @@
}
@Test
+ public void testNr5GIcon_displayGracePeriodTime_enabled() {
+ setupDefaultNr5GIconConfiguration();
+ setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds();
+ setupDefaultSignal();
+ mNetworkController.handleConfigurationChanged();
+ mPhoneStateListener.onServiceStateChanged(mServiceState);
+
+ ServiceState ss = Mockito.mock(ServiceState.class);
+ // While nrIconDisplayGracePeriodMs > 0 & is Nr5G, mIsShowingIconGracefully should be true
+ doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ mPhoneStateListener.onServiceStateChanged(ss);
+
+ assertTrue(mConfig.nrIconDisplayGracePeriodMs > 0);
+ assertTrue(mMobileSignalController.mIsShowingIconGracefully);
+ }
+
+ @Test
+ public void testNr5GIcon_displayGracePeriodTime_disabled() {
+ setupDefaultNr5GIconConfiguration();
+ setupDefaultNr5GIconDisplayGracePeriodTime_disabled();
+ setupDefaultSignal();
+
+ assertTrue(mConfig.nrIconDisplayGracePeriodMs == 0);
+
+ // While nrIconDisplayGracePeriodMs <= 0, mIsShowingIconGracefully should be false
+ doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(mServiceState).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ assertFalse(mMobileSignalController.mIsShowingIconGracefully);
+ }
+
+ @Test
+ public void testNr5GIcon_enableDisplayGracePeriodTime_showIconGracefully() {
+ setupDefaultNr5GIconConfiguration();
+ setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds();
+ setupDefaultSignal();
+ mNetworkController.handleConfigurationChanged();
+ mPhoneStateListener.onServiceStateChanged(mServiceState);
+
+ ServiceState ss = Mockito.mock(ServiceState.class);
+ doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ mPhoneStateListener.onServiceStateChanged(ss);
+
+ verifyDataIndicators(TelephonyIcons.ICON_5G);
+
+ // Enabled timer Nr5G switch to None Nr5G, showing 5G icon gracefully
+ ServiceState ssLte = Mockito.mock(ServiceState.class);
+ doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(ssLte).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(ssLte).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ mPhoneStateListener.onServiceStateChanged(ssLte);
+
+ verifyDataIndicators(TelephonyIcons.ICON_5G);
+ }
+
+ @Test
+ public void testNr5GIcon_disableDisplayGracePeriodTime_showLatestIconImmediately() {
+ setupDefaultNr5GIconConfiguration();
+ setupDefaultNr5GIconDisplayGracePeriodTime_disabled();
+ setupDefaultSignal();
+ mNetworkController.handleConfigurationChanged();
+
+ doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(mServiceState).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ verifyDataIndicators(TelephonyIcons.ICON_5G);
+
+ doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(mServiceState).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ verifyDataIndicators(TelephonyIcons.ICON_LTE);
+ }
+
+ @Test
+ public void testNr5GIcon_resetDisplayGracePeriodTime_whenDataDisconnected() {
+ setupDefaultNr5GIconConfiguration();
+ setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds();
+ setupDefaultSignal();
+ mNetworkController.handleConfigurationChanged();
+ doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(mServiceState).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ verifyDataIndicators(TelephonyIcons.ICON_5G);
+
+ // Disabled timer, when out of service, reset timer to display latest state
+ updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(mServiceState).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_DISCONNECTED,
+ TelephonyManager.NETWORK_TYPE_UMTS);
+
+ verifyDataIndicators(0);
+ }
+
+ @Test
+ public void testNr5GIcon_enableDisplayGracePeriodTime_show5G_switching_5GPlus() {
+ setupDefaultNr5GIconConfiguration();
+ setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds();
+ setupDefaultSignal();
+ mNetworkController.handleConfigurationChanged();
+ mPhoneStateListener.onServiceStateChanged(mServiceState);
+
+ ServiceState ss5G = Mockito.mock(ServiceState.class);
+ doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss5G).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss5G).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ mPhoneStateListener.onServiceStateChanged(ss5G);
+
+ verifyDataIndicators(TelephonyIcons.ICON_5G);
+
+ // When timeout enabled, 5G/5G+ switching should be updated immediately
+ ServiceState ss5GPlus = Mockito.mock(ServiceState.class);
+ doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss5GPlus).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(ss5GPlus).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ mPhoneStateListener.onServiceStateChanged(ss5GPlus);
+
+ verifyDataIndicators(TelephonyIcons.ICON_5G_PLUS);
+ }
+
+ @Test
+ public void testNr5GIcon_carrierDisabledDisplayGracePeriodTime_shouldUpdateIconImmediately() {
+ setupDefaultNr5GIconConfiguration();
+ setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds();
+ setupDefaultSignal();
+ mNetworkController.handleConfigurationChanged();
+ mPhoneStateListener.onServiceStateChanged(mServiceState);
+
+ ServiceState ss5G = Mockito.mock(ServiceState.class);
+ doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss5G).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss5G).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ mPhoneStateListener.onServiceStateChanged(ss5G);
+
+ verifyDataIndicators(TelephonyIcons.ICON_5G);
+
+ // State from NR_5G to NONE NR_5G with timeout, should show previous 5G icon
+ ServiceState ssLte = Mockito.mock(ServiceState.class);
+ doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(ssLte).getNrState();
+ doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(ssLte).getNrFrequencyRange();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ mPhoneStateListener.onServiceStateChanged(ssLte);
+
+ verifyDataIndicators(TelephonyIcons.ICON_5G);
+
+ // Update nrIconDisplayGracePeriodMs to 0
+ setupDefaultNr5GIconDisplayGracePeriodTime_disabled();
+ mNetworkController.handleConfigurationChanged();
+
+ // State from NR_5G to NONE NR_STATE_RESTRICTED, showing corresponding icon
+ doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(mServiceState).getNrState();
+ doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
+ mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ assertTrue(mConfig.nrIconDisplayGracePeriodMs == 0);
+ verifyDataIndicators(TelephonyIcons.ICON_LTE);
+ }
+
+ @Test
public void testDataDisabledIcon_UserNotSetup() {
setupNetworkController();
when(mMockTm.isDataCapable()).thenReturn(false);