Merge "Disable signal strength update if screen off" into main
diff --git a/flags/network.aconfig b/flags/network.aconfig
index 0c7873e..299a2a0 100644
--- a/flags/network.aconfig
+++ b/flags/network.aconfig
@@ -6,3 +6,10 @@
     description: "enabling this flag allows KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY to control N1 mode enablement"
     bug:"302033535"
 }
+
+flag {
+  name: "hide_roaming_icon"
+  namespace: "telephony"
+  description: "Allow carriers to hide the roaming (R) icon when roaming."
+  bug: "301467052"
+}
diff --git a/src/java/com/android/internal/telephony/DisplayInfoController.java b/src/java/com/android/internal/telephony/DisplayInfoController.java
index 567331d..945b640 100644
--- a/src/java/com/android/internal/telephony/DisplayInfoController.java
+++ b/src/java/com/android/internal/telephony/DisplayInfoController.java
@@ -19,9 +19,11 @@
 import android.annotation.NonNull;
 import android.os.Handler;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.telephony.AnomalyReporter;
+import android.telephony.CarrierConfigManager;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyDisplayInfo;
 import android.telephony.TelephonyManager;
@@ -29,6 +31,7 @@
 import android.util.LocalLog;
 import android.util.Pair;
 
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
@@ -66,34 +69,55 @@
 
     /** Event for service state changed (roaming). */
     private static final int EVENT_SERVICE_STATE_CHANGED = 1;
+    /** Event for carrier config changed. */
+    private static final int EVENT_CARRIER_CONFIG_CHANGED = 2;
 
-    private final Phone mPhone;
-    private final NetworkTypeController mNetworkTypeController;
-    private final RegistrantList mTelephonyDisplayInfoChangedRegistrants = new RegistrantList();
-    private @NonNull TelephonyDisplayInfo mTelephonyDisplayInfo;
-    private @NonNull ServiceState mServiceState;
+    @NonNull private final Phone mPhone;
+    @NonNull private final NetworkTypeController mNetworkTypeController;
+    @NonNull private final RegistrantList mTelephonyDisplayInfoChangedRegistrants =
+            new RegistrantList();
+    @NonNull private final FeatureFlags mFeatureFlags;
+    @NonNull private TelephonyDisplayInfo mTelephonyDisplayInfo;
+    @NonNull private ServiceState mServiceState;
+    @NonNull private PersistableBundle mConfigs;
 
-    public DisplayInfoController(Phone phone) {
+    public DisplayInfoController(@NonNull Phone phone, @NonNull FeatureFlags featureFlags) {
         mPhone = phone;
+        mFeatureFlags = featureFlags;
         mLogTag = "DIC-" + mPhone.getPhoneId();
+        mServiceState = mPhone.getServiceStateTracker().getServiceState();
+        mConfigs = new PersistableBundle();
+        try {
+            mConfigs = mPhone.getContext().getSystemService(CarrierConfigManager.class)
+                    .getConfigForSubId(mPhone.getSubId(),
+                            CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL);
+        } catch (Exception ignored) {
+            // CarrierConfigLoader might not be available yet.
+            // Once it's available, configs will be updated through the listener.
+        }
+        mPhone.getServiceStateTracker()
+                .registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
+        mPhone.getContext().getSystemService(CarrierConfigManager.class)
+                .registerCarrierConfigChangeListener(Runnable::run,
+                        (slotIndex, subId, carrierId, specificCarrierId) -> {
+                            if (slotIndex == mPhone.getPhoneId()) {
+                                obtainMessage(EVENT_CARRIER_CONFIG_CHANGED).sendToTarget();
+                            }
+                        });
         mTelephonyDisplayInfo = new TelephonyDisplayInfo(
                 TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
+                TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE,
+                false);
         mNetworkTypeController = new NetworkTypeController(phone, this);
+        // EVENT_UPDATE will transition from DefaultState to the current state
+        // and update the TelephonyDisplayInfo based on the current state.
         mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE);
-
-        mServiceState = mPhone.getServiceStateTracker().getServiceState();
-        post(() -> {
-            mPhone.getServiceStateTracker()
-                    .registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
-            updateTelephonyDisplayInfo();
-        });
     }
 
     /**
      * @return the current TelephonyDisplayInfo
      */
-    public @NonNull TelephonyDisplayInfo getTelephonyDisplayInfo() {
+    @NonNull public TelephonyDisplayInfo getTelephonyDisplayInfo() {
         return mTelephonyDisplayInfo;
     }
 
@@ -105,7 +129,7 @@
         TelephonyDisplayInfo newDisplayInfo = new TelephonyDisplayInfo(
                 mNetworkTypeController.getDataNetworkType(),
                 mNetworkTypeController.getOverrideNetworkType(),
-                mServiceState.getRoaming());
+                isRoaming());
         if (!newDisplayInfo.equals(mTelephonyDisplayInfo)) {
             logl("TelephonyDisplayInfo changed from " + mTelephonyDisplayInfo + " to "
                     + newDisplayInfo);
@@ -117,6 +141,24 @@
     }
 
     /**
+     * Determine the roaming status for icon display only.
+     * If this is {@code true}, the roaming indicator will be shown, and if this is {@code false},
+     * the roaming indicator will not be shown.
+     * To get the actual roaming status, use {@link ServiceState#getRoaming()} instead.
+     *
+     * @return Whether the device is considered roaming for display purposes.
+     */
+    private boolean isRoaming() {
+        boolean roaming = mServiceState.getRoaming();
+        if (roaming && mFeatureFlags.hideRoamingIcon()
+                && !mConfigs.getBoolean(CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL)) {
+            logl("Override roaming for display due to carrier configs.");
+            roaming = false;
+        }
+        return roaming;
+    }
+
+    /**
      * Validate the display info and trigger anomaly report if needed.
      *
      * @param displayInfo The display info to validate.
@@ -175,6 +217,13 @@
                 log("ServiceState updated, isRoaming=" + mServiceState.getRoaming());
                 updateTelephonyDisplayInfo();
                 break;
+            case EVENT_CARRIER_CONFIG_CHANGED:
+                mConfigs = mPhone.getContext().getSystemService(CarrierConfigManager.class)
+                        .getConfigForSubId(mPhone.getSubId(),
+                                CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL);
+                log("Carrier configs updated: " + mConfigs);
+                updateTelephonyDisplayInfo();
+                break;
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 00e0f47..6f30fb5 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -364,7 +364,8 @@
         // DisplayInfoController creates an OverrideNetworkTypeController, which uses
         // DeviceStateMonitor so needs to be crated after it is instantiated.
         mDisplayInfoController = mTelephonyComponentFactory.inject(
-                DisplayInfoController.class.getName()).makeDisplayInfoController(this);
+                DisplayInfoController.class.getName())
+                .makeDisplayInfoController(this, featureFlags);
 
         mDataNetworkController = mTelephonyComponentFactory.inject(
                 DataNetworkController.class.getName())
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 6da47c0..8b832dd 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -452,8 +452,8 @@
     /**
      * Create a new DisplayInfoController.
      */
-    public DisplayInfoController makeDisplayInfoController(Phone phone) {
-        return new DisplayInfoController(phone);
+    public DisplayInfoController makeDisplayInfoController(Phone phone, FeatureFlags featureFlags) {
+        return new DisplayInfoController(phone, featureFlags);
     }
 
     /**
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java
index f729b80..8dd350f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java
@@ -42,11 +42,14 @@
 import android.testing.TestableLooper;
 import android.text.TextUtils;
 
+import com.android.internal.telephony.flags.FeatureFlags;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
 
 import java.util.Collections;
 import java.util.concurrent.Executor;
@@ -54,17 +57,18 @@
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 public class DisplayInfoControllerTest extends TelephonyTest {
-
     private static final int PHONE_ID = 0;
     private static final String MCC = "600";
     private static final String MNC = "01";
     private static final String NUMERIC = MCC + MNC;
     private static final String NETWORK = "TestNet";
 
+    // Mocked classes
+    private FeatureFlags mFeatureFlags;
+
     private DisplayInfoController mDic;
     private ServiceStateTracker mSst;
     private ServiceStateTrackerTestHandler mSstHandler;
-    private SignalStrengthController mSsc;
     private PersistableBundle mBundle;
     private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener;
 
@@ -75,8 +79,8 @@
 
         @Override
         public void onLooperPrepared() {
-            mSsc = new SignalStrengthController(mPhone);
-            doReturn(mSsc).when(mPhone).getSignalStrengthController();
+            SignalStrengthController ssc = new SignalStrengthController(mPhone);
+            doReturn(ssc).when(mPhone).getSignalStrengthController();
             doReturn(new ServiceState()).when(mPhone).getServiceState();
             doReturn(NUMERIC).when(mTelephonyManager).getSimOperatorNumericForPhone(eq(PHONE_ID));
             doReturn(NETWORK).when(mTelephonyManager).getSimOperatorNameForPhone(eq(PHONE_ID));
@@ -101,6 +105,7 @@
         logd("DisplayInfoControllerTest setup!");
         super.setUp(getClass().getSimpleName());
 
+        mFeatureFlags = Mockito.mock(FeatureFlags.class);
         doReturn((Executor) Runnable::run).when(mContext).getMainExecutor();
         mBundle = mContextFixture.getCarrierConfigBundle();
         mSstHandler = new ServiceStateTrackerTestHandler(getClass().getSimpleName());
@@ -191,7 +196,7 @@
         assertFalse(ss.getRoaming()); // home
 
         doReturn(mSst).when(mPhone).getServiceStateTracker();
-        mDic = new DisplayInfoController(mPhone);
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
         mDic.updateTelephonyDisplayInfo();
         TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
 
@@ -211,7 +216,7 @@
         assertFalse(ss.getRoaming()); // home
 
         doReturn(mSst).when(mPhone).getServiceStateTracker();
-        mDic = new DisplayInfoController(mPhone);
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
         mDic.updateTelephonyDisplayInfo();
         TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
 
@@ -232,7 +237,7 @@
         assertTrue(ss1.getRoaming()); // roam
 
         doReturn(mSst).when(mPhone).getServiceStateTracker();
-        mDic = new DisplayInfoController(mPhone);
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
         mDic.updateTelephonyDisplayInfo();
         TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
 
@@ -254,7 +259,7 @@
         assertFalse(ss.getRoaming()); // home
 
         doReturn(mSst).when(mPhone).getServiceStateTracker();
-        mDic = new DisplayInfoController(mPhone);
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
         mDic.updateTelephonyDisplayInfo();
         TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
 
@@ -275,10 +280,32 @@
         assertTrue(ss1.getRoaming()); // roam
 
         doReturn(mSst).when(mPhone).getServiceStateTracker();
-        mDic = new DisplayInfoController(mPhone);
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
         mDic.updateTelephonyDisplayInfo();
         TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
 
         assertTrue(tdi.isRoaming());
     }
+
+    @Test
+    public void testIsRoamingOverride_HideRoamingIndicator() {
+        doReturn(true).when(mPhone).isPhoneTypeGsm();
+        mBundle.putStringArray(
+                CarrierConfigManager.KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, new String[] {NUMERIC});
+        mBundle.putBoolean(CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL, false);
+        doReturn(true).when(mFeatureFlags).hideRoamingIcon();
+        sendCarrierConfigUpdate();
+
+        changeRegState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+        ServiceState ss1 = mSst.getServiceState();
+
+        assertTrue(ss1.getRoaming()); // roam
+
+        doReturn(mSst).when(mPhone).getServiceStateTracker();
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
+        mDic.updateTelephonyDisplayInfo();
+        TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
+
+        assertFalse(tdi.isRoaming()); // display override
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 39543a2..3ed20a7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -591,7 +591,7 @@
         doReturn(mIccPhoneBookIntManager).when(mTelephonyComponentFactory)
                 .makeIccPhoneBookInterfaceManager(nullable(Phone.class));
         doReturn(mDisplayInfoController).when(mTelephonyComponentFactory)
-                .makeDisplayInfoController(nullable(Phone.class));
+                .makeDisplayInfoController(nullable(Phone.class), any(FeatureFlags.class));
         doReturn(mWspTypeDecoder).when(mTelephonyComponentFactory)
                 .makeWspTypeDecoder(nullable(byte[].class));
         doReturn(mImsCT).when(mTelephonyComponentFactory)