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
This commit is contained in:
Bill Lin
2019-08-15 20:42:06 +08:00
parent 5e1a48a660
commit 767c0db68a
4 changed files with 287 additions and 0 deletions

View File

@@ -21,6 +21,7 @@ import android.database.ContentObserver;
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 @@ import java.util.regex.Pattern;
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 @@ public class MobileSignalController extends SignalController<
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 @@ public class MobileSignalController extends SignalController<
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 @@ public class MobileSignalController extends SignalController<
// 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 @@ public class MobileSignalController extends SignalController<
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 @@ public class MobileSignalController extends SignalController<
pw.println(" mDataNetType=" + mDataNetType + ",");
pw.println(" mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
pw.println(" isDataDisabled=" + isDataDisabled() + ",");
pw.println(" mIsShowingIconGracefully=" + mIsShowingIconGracefully + ",");
}
class MobilePhoneStateListener extends PhoneStateListener {

View File

@@ -51,6 +51,7 @@ import android.telephony.SubscriptionManager;
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 @@ public class NetworkControllerImpl extends BroadcastReceiver
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 @@ public class NetworkControllerImpl extends BroadcastReceiver
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 @@ public class NetworkControllerImpl extends BroadcastReceiver
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 @@ public class NetworkControllerImpl extends BroadcastReceiver
add5GIconMapping(pair, config);
}
}
setDisplayGraceTime(
b.getInt(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT),
config);
}
return config;
@@ -1208,5 +1222,18 @@ public class NetworkControllerImpl extends BroadcastReceiver
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;
}
}
}

View File

@@ -30,6 +30,7 @@ import static org.mockito.Mockito.doAnswer;
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.TestableLooper;
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 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
protected SubscriptionDefaults mMockSubDefaults;
protected DeviceProvisionedController mMockProvisionController;
protected DeviceProvisionedListener mUserCallback;
protected Instrumentation mInstrumentation;
protected int mSubId;
@@ -116,6 +120,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
@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 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
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);

View File

@@ -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;
@@ -244,6 +246,186 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest {
verifyDataIndicators(TelephonyIcons.ICON_LTE);
}
@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();