Merge "Replace hard-coded configuration with resource configuration" into main
diff --git a/OWNERS b/OWNERS
index 2c7aed3..53b9401 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,5 @@
 include platform/frameworks/opt/telephony:/OWNERS
 
 per-file *SimPhonebookProvider* = file:platform/packages/apps/Contacts:/OWNERS
+
+per-file config.xml=hwangoo@google.com,forestchoi@google.com,avinashmp@google.com,mkoon@google.com,seheele@google.com,radhikaagrawal@google.com
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 518003f..3cd9a8b 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -64,6 +64,8 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.TelephonyCapabilities;
+import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.flags.FeatureFlagsImpl;
 import com.android.internal.telephony.util.NotificationChannelController;
 import com.android.phone.settings.VoicemailSettingsActivity;
 
@@ -146,6 +148,9 @@
     // maps each subId to selected network operator name.
     private SparseArray<String> mSelectedNetworkOperatorName = new SparseArray<>();
 
+    // feature flags
+    private final FeatureFlags mFeatureFlags;
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -177,6 +182,7 @@
         mSubscriptionManager = SubscriptionManager.from(mContext);
         mTelecomManager = app.getSystemService(TelecomManager.class);
         mTelephonyManager = (TelephonyManager) app.getSystemService(Context.TELEPHONY_SERVICE);
+        mFeatureFlags = new FeatureFlagsImpl();
     }
 
     /**
@@ -828,6 +834,12 @@
      * @param subId The subscription ID
      */
     void updateNetworkSelection(int serviceState, int subId) {
+        if (!mFeatureFlags.dismissNetworkSelectionNotificationOnSimDisable()) {
+            updateNetworkSelectionForFeatureDisabled(serviceState, subId);
+            return;
+        }
+
+        // for dismissNetworkSelectionNotificationOnSimDisable feature enabled.
         int phoneId = SubscriptionManager.getPhoneId(subId);
         Phone phone = SubscriptionManager.isValidPhoneId(phoneId) ?
                 PhoneFactory.getPhone(phoneId) : PhoneFactory.getDefaultPhone();
@@ -868,6 +880,62 @@
                     clearUpNetworkSelectionNotificationParam(subId);
                 }
             } else {
+                if (DBG) {
+                    log("updateNetworkSelection()... state = " + serviceState
+                            + " not updating network due to invalid subId " + subId);
+                }
+                dismissNetworkSelectionNotificationForInactiveSubId();
+            }
+        }
+    }
+
+    /**
+     * Update notification about no service of user selected operator.
+     * For dismissNetworkSelectionNotificationOnSimDisable feature disabled.
+     *
+     * @param serviceState Phone service state
+     * @param subId The subscription ID
+     */
+    private void updateNetworkSelectionForFeatureDisabled(int serviceState, int subId) {
+        int phoneId = SubscriptionManager.getPhoneId(subId);
+        Phone phone = SubscriptionManager.isValidPhoneId(phoneId)
+                ? PhoneFactory.getPhone(phoneId) : PhoneFactory.getDefaultPhone();
+        if (TelephonyCapabilities.supportsNetworkSelection(phone)) {
+            if (SubscriptionManager.isValidSubscriptionId(subId)) {
+                SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+                String selectedNetworkOperatorName =
+                        sp.getString(Phone.NETWORK_SELECTION_NAME_KEY + subId, "");
+                // get the shared preference of network_selection.
+                // empty is auto mode, otherwise it is the operator alpha name
+                // in case there is no operator name, check the operator numeric
+                if (TextUtils.isEmpty(selectedNetworkOperatorName)) {
+                    selectedNetworkOperatorName =
+                            sp.getString(Phone.NETWORK_SELECTION_KEY + subId, "");
+                }
+                boolean isManualSelection;
+                // if restoring manual selection is controlled by framework, then get network
+                // selection from shared preference, otherwise get from real network indicators.
+                boolean restoreSelection = !mContext.getResources().getBoolean(
+                        com.android.internal.R.bool.skip_restoring_network_selection);
+                if (restoreSelection) {
+                    isManualSelection = !TextUtils.isEmpty(selectedNetworkOperatorName);
+                } else {
+                    isManualSelection = phone.getServiceStateTracker().mSS.getIsManualSelection();
+                }
+
+                if (DBG) {
+                    log("updateNetworkSelection()..." + "state = " + serviceState + " new network "
+                            + (isManualSelection ? selectedNetworkOperatorName : ""));
+                }
+
+                if (isManualSelection) {
+                    mSelectedNetworkOperatorName.put(subId, selectedNetworkOperatorName);
+                    shouldShowNotification(serviceState, subId);
+                } else {
+                    dismissNetworkSelectionNotification(subId);
+                    clearUpNetworkSelectionNotificationParam(subId);
+                }
+            } else {
                 if (DBG) log("updateNetworkSelection()..." + "state = " +
                         serviceState + " not updating network due to invalid subId " + subId);
                 dismissNetworkSelectionNotificationForInactiveSubId();
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 4773a83..483a706 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -17,6 +17,7 @@
 package com.android.phone;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.KeyguardManager;
 import android.app.ProgressDialog;
@@ -217,6 +218,14 @@
      */
     private ArraySet<String> mShownNotificationReasons = new ArraySet<>();
 
+    // For reorganize_roaming_notification feature disabled.
+    @RoamingNotification
+    private int mPrevRoamingNotification = ROAMING_NOTIFICATION_NO_NOTIFICATION;
+
+    // For reorganize_roaming_notification feature disabled.
+    /** Operator numerics for which we've shown is-roaming notifications. **/
+    private ArraySet<String> mPrevRoamingOperatorNumerics = new ArraySet<>();
+
     private WakeState mWakeState = WakeState.SLEEP;
 
     private PowerManager mPowerManager;
@@ -240,6 +249,8 @@
     // fine or coarse location since we only use ServiceState for
     private PhoneAppCallback[] mTelephonyCallbacks;
 
+    private FeatureFlags mFeatureFlags;
+
     private class PhoneAppCallback extends TelephonyCallback implements
             TelephonyCallback.ServiceStateListener {
         private final int mSubId;
@@ -385,11 +396,19 @@
                     //TODO: handle message here;
                     break;
                 case EVENT_DATA_ROAMING_SETTINGS_CHANGED:
-                    updateDataRoamingStatus(
-                            ROAMING_NOTIFICATION_REASON_DATA_ROAMING_SETTING_CHANGED);
+                    if (mFeatureFlags.reorganizeRoamingNotification()) {
+                        updateDataRoamingStatus(
+                                ROAMING_NOTIFICATION_REASON_DATA_ROAMING_SETTING_CHANGED);
+                    } else {
+                        updateDataRoamingStatusForFeatureDisabled(null);
+                    }
                     break;
                 case EVENT_MOBILE_DATA_SETTINGS_CHANGED:
-                    updateDataRoamingStatus(ROAMING_NOTIFICATION_REASON_DATA_SETTING_CHANGED);
+                    if (mFeatureFlags.reorganizeRoamingNotification()) {
+                        updateDataRoamingStatus(ROAMING_NOTIFICATION_REASON_DATA_SETTING_CHANGED);
+                    } else {
+                        updateDataRoamingStatusForFeatureDisabled(null);
+                    }
                     break;
                 case EVENT_CARRIER_CONFIG_CHANGED:
                     int subId = (Integer) msg.obj;
@@ -480,8 +499,8 @@
                     getResources().getBoolean(R.bool.config_enable_aosp_domain_selection));
 
             // Initialize the telephony framework
-            FeatureFlags featureFlags = new FeatureFlagsImpl();
-            PhoneFactory.makeDefaultPhones(this, featureFlags);
+            mFeatureFlags = new FeatureFlagsImpl();
+            PhoneFactory.makeDefaultPhones(this, mFeatureFlags);
 
             // Initialize the DomainSelectionResolver after creating the Phone instance
             // to check the Radio HAL version.
@@ -539,7 +558,7 @@
 
             // Create the SatelliteController singleton, which acts as a backend service for
             // {@link android.telephony.satellite.SatelliteManager}.
-            SatelliteController.make(this, featureFlags);
+            SatelliteController.make(this, mFeatureFlags);
 
             // Create an instance of CdmaPhoneCallState and initialize it to IDLE
             cdmaPhoneCallState = new CdmaPhoneCallState();
@@ -554,7 +573,7 @@
 
             mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
 
-            phoneMgr = PhoneInterfaceManager.init(this, featureFlags);
+            phoneMgr = PhoneInterfaceManager.init(this, mFeatureFlags);
 
             imsRcsController = ImsRcsController.init(this);
 
@@ -599,12 +618,16 @@
             intentFilter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
             intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
             registerReceiver(mReceiver, intentFilter);
-            int defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
-            if (SubscriptionManager.isValidSubscriptionId(defaultDataSubId)) {
-                if (VDBG) Log.v(LOG_TAG, "Loaded initial default data sub: " + defaultDataSubId);
-                mDefaultDataSubId = defaultDataSubId;
-                registerSettingsObserver();
-                updateDataRoamingStatus(ROAMING_NOTIFICATION_REASON_DEFAULT_DATA_SUBS_CHANGED);
+            if (mFeatureFlags.loadDdsOnCreate()) {
+                int defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+                if (SubscriptionManager.isValidSubscriptionId(defaultDataSubId)) {
+                    if (VDBG) {
+                        Log.v(LOG_TAG, "Loaded initial default data sub: " + defaultDataSubId);
+                    }
+                    mDefaultDataSubId = defaultDataSubId;
+                    registerSettingsObserver();
+                    updateDataRoamingStatus(ROAMING_NOTIFICATION_REASON_DEFAULT_DATA_SUBS_CHANGED);
+                }
             }
 
             PhoneConfigurationManager.registerForMultiSimConfigChange(
@@ -808,7 +831,11 @@
     /** Clear fields on power off radio **/
     private void clearCacheOnRadioOff() {
         // Re-show is-roaming notifications after APM mode
-        mShownNotificationReasons.clear();
+        if (mFeatureFlags.reorganizeRoamingNotification()) {
+            mShownNotificationReasons.clear();
+        } else {
+            mPrevRoamingOperatorNumerics.clear();
+        }
     }
 
     private void setRadioPowerOn() {
@@ -905,7 +932,11 @@
             } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
                 // Roaming status could be overridden by carrier config, so we need to update it.
                 if (VDBG) Log.v(LOG_TAG, "carrier config changed.");
-                updateDataRoamingStatus(ROAMING_NOTIFICATION_REASON_CARRIER_CONFIG_CHANGED);
+                if (mFeatureFlags.reorganizeRoamingNotification()) {
+                    updateDataRoamingStatus(ROAMING_NOTIFICATION_REASON_CARRIER_CONFIG_CHANGED);
+                } else {
+                    updateDataRoamingStatusForFeatureDisabled(null);
+                }
                 updateLimitedSimFunctionForDualSim();
                 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
@@ -920,7 +951,12 @@
                 registerSettingsObserver();
                 Phone phone = getPhone(mDefaultDataSubId);
                 if (phone != null) {
-                    updateDataRoamingStatus(ROAMING_NOTIFICATION_REASON_DEFAULT_DATA_SUBS_CHANGED);
+                    if (mFeatureFlags.reorganizeRoamingNotification()) {
+                        updateDataRoamingStatus(
+                                ROAMING_NOTIFICATION_REASON_DEFAULT_DATA_SUBS_CHANGED);
+                    } else {
+                        updateDataRoamingStatusForFeatureDisabled(null);
+                    }
                 }
             }
         }
@@ -936,7 +972,11 @@
                     + mDefaultDataSubId + ", ss roaming=" + serviceState.getDataRoaming());
         }
         if (subId == mDefaultDataSubId) {
-            updateDataRoamingStatus(ROAMING_NOTIFICATION_REASON_SERVICE_STATE_CHANGED);
+            if (mFeatureFlags.reorganizeRoamingNotification()) {
+                updateDataRoamingStatus(ROAMING_NOTIFICATION_REASON_SERVICE_STATE_CHANGED);
+            } else {
+                updateDataRoamingStatusForFeatureDisabled(serviceState.getOperatorNumeric());
+            }
         }
     }
 
@@ -1083,6 +1123,87 @@
         return mCurrentRoamingNotification;
     }
 
+    // For reorganize_roaming_notification feature disabled.
+    /**
+     * When roaming, if mobile data cannot be established due to data roaming not enabled, we need
+     * to notify the user so they can enable it through settings. Vise versa if the condition
+     * changes, we need to dismiss the notification.
+     * @param roamingOperatorNumeric The operator numeric for the current roaming. {@code null} if
+     *                               the current roaming operator numeric didn't change.
+     */
+    private void updateDataRoamingStatusForFeatureDisabled(
+            @Nullable String roamingOperatorNumeric) {
+        if (VDBG) Log.v(LOG_TAG, "updateDataRoamingStatusForFeatureDisabled");
+        Phone phone = getPhone(mDefaultDataSubId);
+        if (phone == null) {
+            Log.w(LOG_TAG, "Can't get phone with sub id = " + mDefaultDataSubId);
+            return;
+        }
+
+        boolean dataAllowed;
+        boolean notAllowedDueToRoamingOff;
+        List<DataDisallowedReason> reasons = phone.getDataNetworkController()
+                .getInternetDataDisallowedReasons();
+        dataAllowed = reasons.isEmpty();
+        notAllowedDueToRoamingOff = (reasons.size() == 1
+                && reasons.contains(DataDisallowedReason.ROAMING_DISABLED));
+        mDataRoamingNotifLog.log("dataAllowed=" + dataAllowed + ", reasons=" + reasons
+                + ", roamingOperatorNumeric=" + roamingOperatorNumeric);
+        if (VDBG) {
+            Log.v(LOG_TAG, "dataAllowed=" + dataAllowed + ", reasons=" + reasons
+                    + ", roamingOperatorNumeric=" + roamingOperatorNumeric);
+        }
+
+        if (!dataAllowed && notAllowedDueToRoamingOff) {
+            // Don't show roaming notification if we've already shown for this MccMnc
+            if (roamingOperatorNumeric != null
+                    && !mPrevRoamingOperatorNumerics.add(roamingOperatorNumeric)) {
+                Log.d(LOG_TAG, "Skip roaming disconnected notification since already shown in "
+                        + "MccMnc " + roamingOperatorNumeric);
+                return;
+            }
+            // No need to show it again if we never cancelled it explicitly.
+            if (mPrevRoamingNotification == ROAMING_NOTIFICATION_DISCONNECTED) return;
+            // If the only reason of no data is data roaming disabled, then we notify the user
+            // so the user can turn on data roaming.
+            mPrevRoamingNotification = ROAMING_NOTIFICATION_DISCONNECTED;
+            Log.d(LOG_TAG, "Show roaming disconnected notification");
+            mDataRoamingNotifLog.log("Show roaming off.");
+            Message msg = mHandler.obtainMessage(EVENT_DATA_ROAMING_DISCONNECTED);
+            msg.arg1 = mDefaultDataSubId;
+            msg.sendToTarget();
+        } else if (dataAllowed && dataIsNowRoaming(mDefaultDataSubId)) {
+            boolean isShowRoamingNotificationEnabled = getCarrierConfigForSubId(mDefaultDataSubId)
+                    .getBoolean(CarrierConfigManager
+                            .KEY_SHOW_DATA_CONNECTED_ROAMING_NOTIFICATION_BOOL);
+            if (!isShowRoamingNotificationEnabled) return;
+            // Don't show roaming notification if we've already shown for this MccMnc
+            if (roamingOperatorNumeric != null
+                    && !mPrevRoamingOperatorNumerics.add(roamingOperatorNumeric)) {
+                Log.d(LOG_TAG, "Skip roaming connected notification since already shown in "
+                        + "MccMnc " + roamingOperatorNumeric);
+                return;
+            }
+            // No need to show it again if we never cancelled it explicitly, or carrier config
+            // indicates this is not needed.
+            if (mPrevRoamingNotification == ROAMING_NOTIFICATION_CONNECTED) return;
+            mPrevRoamingNotification = ROAMING_NOTIFICATION_CONNECTED;
+            Log.d(LOG_TAG, "Show roaming connected notification");
+            mDataRoamingNotifLog.log("Show roaming on.");
+            Message msg = mHandler.obtainMessage(EVENT_DATA_ROAMING_CONNECTED);
+            msg.arg1 = mDefaultDataSubId;
+            msg.sendToTarget();
+        } else if (mPrevRoamingNotification != ROAMING_NOTIFICATION_NO_NOTIFICATION) {
+            // Otherwise we either 1) we are not roaming or 2) roaming is off but ROAMING_DISABLED
+            // is not the only data disable reason. In this case we dismiss the notification we
+            // showed earlier.
+            mPrevRoamingNotification = ROAMING_NOTIFICATION_NO_NOTIFICATION;
+            Log.d(LOG_TAG, "Dismiss roaming notification");
+            mDataRoamingNotifLog.log("Hide. data allowed=" + dataAllowed);
+            mHandler.sendEmptyMessage(EVENT_DATA_ROAMING_OK);
+        }
+    }
+
     /**
      *
      * @param subId to check roaming on
@@ -1179,7 +1300,19 @@
         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
         pw.println("------- PhoneGlobals -------");
         pw.increaseIndent();
-        pw.println("mCurrentRoamingNotification=" + mCurrentRoamingNotification);
+        pw.println("FeatureFlags:");
+        pw.increaseIndent();
+        pw.println("loadDdsOnCreate=" + mFeatureFlags.loadDdsOnCreate());
+        pw.println("reorganizeRoamingNotification="
+                + mFeatureFlags.reorganizeRoamingNotification());
+        pw.println("dismissNetworkSelectionNotificationOnSimDisable="
+                + mFeatureFlags.dismissNetworkSelectionNotificationOnSimDisable());
+        pw.decreaseIndent();
+        if (mFeatureFlags.reorganizeRoamingNotification()) {
+            pw.println("mCurrentRoamingNotification=" + mCurrentRoamingNotification);
+        } else {
+            pw.println("mPrevRoamingNotification=" + mPrevRoamingNotification);
+        }
         pw.println("mDefaultDataSubId=" + mDefaultDataSubId);
         pw.println("isSmsCapable=" + TelephonyManager.from(this).isSmsCapable());
         pw.println("mDataRoamingNotifLog:");
@@ -1220,7 +1353,11 @@
             mDomainSelectionService.dump(fd, pw, args);
         }
         pw.decreaseIndent();
-        pw.println("mShownNotificationReasons=" + mShownNotificationReasons);
+        if (mFeatureFlags.reorganizeRoamingNotification()) {
+            pw.println("mShownNotificationReasons=" + mShownNotificationReasons);
+        } else {
+            pw.println("mPrevRoamingOperatorNumerics:" + mPrevRoamingOperatorNumerics);
+        }
         pw.println("------- End PhoneGlobals -------");
     }
 }
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 9553132..6a560f6 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -12744,6 +12744,32 @@
     }
 
     /**
+     * This API can be used by only CTS to override the cached value for the device overlay config
+     * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether
+     * outgoing satellite datagrams should be sent to modem in demo mode.
+     *
+     * @param shouldSendToModemInDemoMode Whether send datagram in demo mode should be sent to
+     * satellite modem or not.
+     *
+     * @return {@code true} if the operation is successful, {@code false} otherwise.
+     */
+    public boolean setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode) {
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            Log.d(LOG_TAG, "shouldSendDatagramToModemInDemoMode: oemEnabledSatelliteFlag is "
+                    + "disabled");
+            return false;
+        }
+        Log.d(LOG_TAG, "setShouldSendDatagramToModemInDemoMode");
+        TelephonyPermissions.enforceShellOnly(
+                Binder.getCallingUid(), "setShouldSendDatagramToModemInDemoMode");
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp,
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+                "setShouldSendDatagramToModemInDemoMode");
+        return mSatelliteController.setShouldSendDatagramToModemInDemoMode(
+                shouldSendToModemInDemoMode);
+    }
+
+    /**
      * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
      *
      * <p>This method behaves in one of the following ways:
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index d6ecc48..5986a7c 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -191,6 +191,8 @@
             "set-satellite-device-aligned-timeout-duration";
     private static final String SET_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE =
             "set-emergency-call-to-satellite-handover-type";
+    private static final String SET_SHOULD_SEND_DATAGRAM_TO_MODEM_IN_DEMO_MODE =
+            "set-should-send-datagram-to-modem-in-demo-mode";
 
     private static final String INVALID_ENTRY_ERROR = "An emergency number (only allow '0'-'9', "
             + "'*', '#' or '+') needs to be specified after -a in the command ";
@@ -384,6 +386,8 @@
                 return handleSettSatelliteDeviceAlignedTimeoutDuration();
             case SET_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE:
                 return handleSetEmergencyCallToSatelliteHandoverType();
+            case SET_SHOULD_SEND_DATAGRAM_TO_MODEM_IN_DEMO_MODE:
+                return handleSetShouldSendDatagramToModemInDemoMode();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -3342,6 +3346,54 @@
         return 0;
     }
 
+    private int handleSetShouldSendDatagramToModemInDemoMode() {
+        PrintWriter errPw = getErrPrintWriter();
+        String opt;
+        boolean shouldSendToDemoMode;
+
+        if ((opt = getNextArg()) == null) {
+            errPw.println(
+                    "adb shell cmd phone set-should-send-datagram-to-modem-in-demo-mode :"
+                            + " Invalid Argument");
+            return -1;
+        } else {
+            switch (opt) {
+                case "true": {
+                    shouldSendToDemoMode = true;
+                    break;
+                }
+                case "false": {
+                    shouldSendToDemoMode = false;
+                    break;
+                }
+                default:
+                    errPw.println(
+                            "adb shell cmd phone set-should-send-datagram-to-modem-in-demo-mode :"
+                                    + " Invalid Argument");
+                    return -1;
+            }
+        }
+
+        Log.d(LOG_TAG,
+                "handleSetShouldSendDatagramToModemInDemoMode(" + shouldSendToDemoMode + ")");
+
+        try {
+            boolean result = mInterface.setShouldSendDatagramToModemInDemoMode(
+                    shouldSendToDemoMode);
+            if (VDBG) {
+                Log.v(LOG_TAG, "handleSetShouldSendDatagramToModemInDemoMode returns: "
+                        + result);
+            }
+            getOutPrintWriter().println(false);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "setShouldSendDatagramToModemInDemoMode(" + shouldSendToDemoMode
+                    + "), error = " + e.getMessage());
+            errPw.println("Exception: " + e.getMessage());
+            return -1;
+        }
+        return 0;
+    }
+
     private int handleCarrierRestrictionStatusCommand() {
         try {
             String MOCK_MODEM_SERVICE_NAME = "android.telephony.mockmodem.MockModemService";
diff --git a/src/com/android/services/telephony/domainselection/OWNERS b/src/com/android/services/telephony/domainselection/OWNERS
new file mode 100644
index 0000000..b9112be
--- /dev/null
+++ b/src/com/android/services/telephony/domainselection/OWNERS
@@ -0,0 +1,8 @@
+# automatically inherit owners from fw/opt/telephony
+
+hwangoo@google.com
+forestchoi@google.com
+avinashmp@google.com
+mkoon@google.com
+seheele@google.com
+radhikaagrawal@google.com
diff --git a/testapps/TestSatelliteApp/res/layout/activity_SatelliteTestApp.xml b/testapps/TestSatelliteApp/res/layout/activity_SatelliteTestApp.xml
index 90a6f94..0753b82 100644
--- a/testapps/TestSatelliteApp/res/layout/activity_SatelliteTestApp.xml
+++ b/testapps/TestSatelliteApp/res/layout/activity_SatelliteTestApp.xml
@@ -68,7 +68,7 @@
             android:id="@+id/TestSatelliteWrapper"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingRight="4dp"
+            android:paddingEnd="4dp"
             android:text="@string/TestSatelliteWrapper"/>
     </LinearLayout>
 </LinearLayout>
diff --git a/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml b/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
index 3365bb9..c136ce7 100644
--- a/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
+++ b/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
@@ -21,78 +21,84 @@
     android:layout_height="wrap_content"
     android:orientation="vertical"
     android:gravity="center"
-    android:paddingLeft="4dp">
+    android:paddingStart="4dp">
 
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="0dp"
+        android:layout_weight="0"
+        android:textColor="@android:color/holo_blue_dark"
+        android:textSize="20dp"
+        android:text="Satellite Wrapper Test"/>
+    <Button
+        android:id="@+id/requestNtnSignalStrength"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingRight="4dp"
+        android:text="@string/requestNtnSignalStrength"/>
+    <Button
+        android:id="@+id/registerForNtnSignalStrengthChanged"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingRight="4dp"
+        android:text="@string/registerForNtnSignalStrengthChanged"/>
+    <Button
+        android:id="@+id/unregisterForNtnSignalStrengthChanged"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingRight="4dp"
+        android:text="@string/unregisterForNtnSignalStrengthChanged"/>
+    <Button
+        android:id="@+id/isOnlyNonTerrestrialNetworkSubscription"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingRight="4dp"
+        android:text="@string/isOnlyNonTerrestrialNetworkSubscription"/>
+    <Button
+        android:id="@+id/registerForSatelliteCapabilitiesChanged"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingRight="4dp"
+        android:text="@string/registerForSatelliteCapabilitiesChanged"/>
+    <Button
+        android:id="@+id/unregisterForSatelliteCapabilitiesChanged"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingRight="4dp"
+        android:text="@string/unregisterForSatelliteCapabilitiesChanged"/>
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="vertical" >
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="0"
+        android:orientation="horizontal">
+         <Button
+            android:id="@+id/Back"
+            android:onClick="Back"
             android:textColor="@android:color/holo_blue_dark"
-            android:textSize="20dp"
-            android:text="Satellite Wrapper Test"/>
-        <Button
-            android:id="@+id/requestNtnSignalStrength"
-            android:layout_width="match_parent"
+            android:layout_marginTop="10dp"
+            android:layout_marginBottom="10dp"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
+            android:layout_weight="1"
             android:paddingRight="4dp"
-            android:text="@string/requestNtnSignalStrength"/>
+            android:text="@string/Back"/>
         <Button
-            android:id="@+id/registerForNtnSignalStrengthChanged"
-            android:layout_width="match_parent"
+            android:id="@+id/ClearLog"
+            android:onClick="ClearLog"
+            android:textColor="@android:color/holo_blue_dark"
+            android:layout_marginTop="10dp"
+            android:layout_marginBottom="10dp"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
+            android:layout_weight="1"
             android:paddingRight="4dp"
-            android:text="@string/registerForNtnSignalStrengthChanged"/>
-        <Button
-            android:id="@+id/unregisterForNtnSignalStrengthChanged"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingRight="4dp"
-            android:text="@string/unregisterForNtnSignalStrengthChanged"/>
-        <Button
-            android:id="@+id/isOnlyNonTerrestrialNetworkSubscription"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingRight="4dp"
-            android:text="@string/isOnlyNonTerrestrialNetworkSubscription"/>
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-             <Button
-                android:id="@+id/Back"
-                android:onClick="Back"
-                android:textColor="@android:color/holo_blue_dark"
-                android:layout_marginTop="10dp"
-                android:layout_marginBottom="10dp"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:paddingRight="4dp"
-                android:text="@string/Back"/>
-            <Button
-                android:id="@+id/ClearLog"
-                android:onClick="ClearLog"
-                android:textColor="@android:color/holo_blue_dark"
-                android:layout_marginTop="10dp"
-                android:layout_marginBottom="10dp"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:paddingRight="4dp"
-                android:text="@string/ClearLog"/>
-        </LinearLayout>
-        <ListView
-            android:id="@+id/logListView"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:capitalize="characters"
-            android:textColor="@android:color/holo_blue_light"
-            android:layout_centerVertical="true"
-            android:textSize="8dp" />
+            android:text="@string/ClearLog"/>
     </LinearLayout>
+    <ListView
+        android:id="@+id/logListView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:capitalize="characters"
+        android:textColor="@android:color/holo_blue_light"
+        android:layout_centerVertical="true"
+        android:textSize="8dp" />
 </LinearLayout>
diff --git a/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
index 5ab2475..8ebe5f3 100644
--- a/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
+++ b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
@@ -62,6 +62,8 @@
     <string name="registerForNtnSignalStrengthChanged">registerForNtnSignalStrengthChanged</string>
     <string name="unregisterForNtnSignalStrengthChanged">unregisterForNtnSignalStrengthChanged</string>
     <string name="isOnlyNonTerrestrialNetworkSubscription">isOnlyNonTerrestrialNetworkSubscription</string>
+    <string name="registerForSatelliteCapabilitiesChanged">registerForSatelliteCapabilitiesChanged</string>
+    <string name="unregisterForSatelliteCapabilitiesChanged">unregisterForSatelliteCapabilitiesChanged</string>
 
     <string name="Back">Back</string>
     <string name="ClearLog">Clear Log</string>
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
index 13b31f3..20efecb 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
@@ -25,6 +25,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.satellite.wrapper.NtnSignalStrengthCallbackWrapper;
 import android.telephony.satellite.wrapper.NtnSignalStrengthWrapper;
+import android.telephony.satellite.wrapper.SatelliteCapabilitiesCallbackWrapper;
 import android.telephony.satellite.wrapper.SatelliteManagerWrapper;
 import android.util.Log;
 import android.view.View;
@@ -51,7 +52,9 @@
     private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
     private SatelliteManagerWrapper mSatelliteManagerWrapper;
     private NtnSignalStrengthCallback mNtnSignalStrengthCallback = null;
+    private SatelliteCapabilitiesCallbackWrapper mSatelliteCapabilitiesCallback;
     private SubscriptionManager mSubscriptionManager;
+
     private ListView mLogListView;
 
     @Override
@@ -69,6 +72,10 @@
                 .setOnClickListener(this::unregisterForNtnSignalStrengthChanged);
         findViewById(R.id.isOnlyNonTerrestrialNetworkSubscription)
                 .setOnClickListener(this::isOnlyNonTerrestrialNetworkSubscription);
+        findViewById(R.id.registerForSatelliteCapabilitiesChanged)
+                .setOnClickListener(this::registerForSatelliteCapabilitiesChanged);
+        findViewById(R.id.unregisterForSatelliteCapabilitiesChanged)
+                .setOnClickListener(this::unregisterForSatelliteCapabilitiesChanged);
         findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
@@ -99,10 +106,17 @@
     protected void onDestroy() {
         super.onDestroy();
 
-        if (mSatelliteManagerWrapper != null && mNtnSignalStrengthCallback != null) {
-            Log.d(TAG, "unregisterForNtnSignalStrengthChanged()");
-            mSatelliteManagerWrapper.unregisterForNtnSignalStrengthChanged(
-                    mNtnSignalStrengthCallback);
+        if (mSatelliteManagerWrapper != null) {
+            if (mNtnSignalStrengthCallback != null) {
+                Log.d(TAG, "unregisterForNtnSignalStrengthChanged()");
+                mSatelliteManagerWrapper.unregisterForNtnSignalStrengthChanged(
+                        mNtnSignalStrengthCallback);
+            }
+            if (mSatelliteCapabilitiesCallback != null) {
+                Log.d(TAG, "unregisterForSatelliteCapabilitiesChanged()");
+                mSatelliteManagerWrapper.unregisterForSatelliteCapabilitiesChanged(
+                        mSatelliteCapabilitiesCallback);
+            }
         }
     }
 
@@ -191,6 +205,42 @@
         }
     }
 
+    private void registerForSatelliteCapabilitiesChanged(View view) {
+        addLogMessage("registerForSatelliteCapabilitiesChanged");
+        Log.d(TAG, "registerForSatelliteCapabilitiesChanged()");
+        if (mSatelliteCapabilitiesCallback == null) {
+            mSatelliteCapabilitiesCallback =
+                    SatelliteCapabilities -> {
+                        String message = "Received SatelliteCapabillities : "
+                                + SatelliteCapabilities;
+                        Log.d(TAG, message);
+                        runOnUiThread(() -> addLogMessage(message));
+                    };
+        }
+
+        int result = mSatelliteManagerWrapper.registerForSatelliteCapabilitiesChanged(mExecutor,
+                mSatelliteCapabilitiesCallback);
+        if (result != SatelliteManagerWrapper.SATELLITE_RESULT_SUCCESS) {
+            String onError = translateResultCodeToString(result);
+            Log.d(TAG, onError);
+            addLogMessage(onError);
+            mSatelliteCapabilitiesCallback = null;
+        }
+    }
+
+    private void unregisterForSatelliteCapabilitiesChanged(View view) {
+        addLogMessage("unregisterForSatelliteCapabilitiesChanged");
+        Log.d(TAG, "unregisterForSatelliteCapabilitiesChanged()");
+        if (mSatelliteCapabilitiesCallback != null) {
+            mSatelliteManagerWrapper.unregisterForSatelliteCapabilitiesChanged(
+                    mSatelliteCapabilitiesCallback);
+            mSatelliteCapabilitiesCallback = null;
+            addLogMessage("mSatelliteCapabilitiesCallback was unregistered");
+        } else {
+            addLogMessage("mSatelliteCapabilitiesCallback is null, ignored.");
+        }
+    }
+
     public class NtnSignalStrengthCallback implements NtnSignalStrengthCallbackWrapper {
         @Override
         public void onNtnSignalStrengthChanged(
diff --git a/tests/src/com/android/services/telephony/domainselection/OWNERS b/tests/src/com/android/services/telephony/domainselection/OWNERS
new file mode 100644
index 0000000..b9112be
--- /dev/null
+++ b/tests/src/com/android/services/telephony/domainselection/OWNERS
@@ -0,0 +1,8 @@
+# automatically inherit owners from fw/opt/telephony
+
+hwangoo@google.com
+forestchoi@google.com
+avinashmp@google.com
+mkoon@google.com
+seheele@google.com
+radhikaagrawal@google.com