Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8eff0711 authored by Aishwarya Mallampati's avatar Aishwarya Mallampati
Browse files

Add onCarrierRoamingNtnEligibleStateChanged callback.

Mark a phone object as carrier roaming ntn eligible if:
- Phone supports P2P SMS over satellite
- Device is not connected to Wi-Fi
- Phone is OUT_OF_SERVICE

Moved isCellularAvailable() from SatelliteSOSMessageRecommender to
SatelliteServiceUtils so that it can be used easily by other classes.

Bug: 350396906
Test: atest SatelliteControllerTest, atest DefaultPhontNotifierTest,
atest TelephonyRegistryTest, atest TelephonyCountryDetectorTest, atest
SatelliteServiceUtilsTest
Manual Test: b/353971031
Flag: com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn

Change-Id: I2b9e8d90147d6751092e63b27131ee00ffbe7b08
parent 70500a17
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -324,6 +324,12 @@ public class DefaultPhoneNotifier implements PhoneNotifier {
        mTelephonyRegistryMgr.notifyCarrierRoamingNtnModeChanged(sender.getSubId(), active);
    }

    @Override
    public void notifyCarrierRoamingNtnEligibleStateChanged(Phone sender, boolean eligible) {
        mTelephonyRegistryMgr.notifyCarrierRoamingNtnEligibleStateChanged(
                sender.getSubId(), eligible);
    }

    /**
     * Convert the {@link Call.State} enum into the PreciseCallState.PRECISE_CALL_STATE_* constants
     * for the public API.
+21 −0
Original line number Diff line number Diff line
@@ -5326,6 +5326,27 @@ public abstract class Phone extends Handler implements PhoneInternalInterface {
        mNotifier.notifyCarrierRoamingNtnModeChanged(this, active);
    }

    /**
     * Notify external listeners that the device eligibility to connect to carrier roaming
     * non-terrestrial network changed.
     *
     * @param eligible {@code true} when the device is eligible for satellite
     * communication if all the following conditions are met:
     * <ul>
     * <li>Any subscription on the device supports P2P satellite messaging which is defined by
     * {@link CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} </li>
     * <li>{@link CarrierConfigManager#KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT} set to
     * {@link CarrierConfigManager#CARRIER_ROAMING_NTN_CONNECT_MANUAL} </li>
     * <li>The device is in {@link ServiceState#STATE_OUT_OF_SERVICE}, not connected to Wi-Fi,
     * and the hysteresis timer defined by {@link CarrierConfigManager
     * #KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT} is expired. </li>
     * </ul>
     */
    public void notifyCarrierRoamingNtnEligibleStateChanged(boolean eligible) {
        logd("notifyCarrierRoamingNtnEligibleStateChanged eligible:" + eligible);
        mNotifier.notifyCarrierRoamingNtnEligibleStateChanged(this, eligible);
    }

    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        pw.println("Phone: subId=" + getSubId());
        pw.println(" mPhoneId=" + mPhoneId);
+3 −0
Original line number Diff line number Diff line
@@ -156,4 +156,7 @@ public interface PhoneNotifier {

    /** Notify carrier roaming non-terrestrial network mode changed. **/
    void notifyCarrierRoamingNtnModeChanged(Phone sender, boolean active);

    /** Notify eligibility to connect to carrier roaming non-terrestrial network changed. */
    void notifyCarrierRoamingNtnEligibleStateChanged(Phone sender, boolean eligible);
}
+29 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.RegistrantList;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.telephony.Rlog;
@@ -83,6 +84,8 @@ public class TelephonyCountryDetector extends Handler {
    @NonNull private final Geocoder mGeocoder;
    @NonNull private final LocationManager mLocationManager;
    @NonNull private final ConnectivityManager mConnectivityManager;
    @NonNull private final RegistrantList mWifiConnectivityStateChangedRegistrantList =
            new RegistrantList();
    @NonNull private final Object mLock = new Object();
    @NonNull
    @GuardedBy("mLock")
@@ -286,6 +289,8 @@ public class TelephonyCountryDetector extends Handler {
                handleNetworkCountryCodeChangedEvent((NetworkCountryCodeInfo) msg.obj);
                break;
            case EVENT_WIFI_CONNECTIVITY_STATE_CHANGED:
                handleEventWifiConnectivityStateChanged();
                break;
            case EVENT_LOCATION_UPDATE_REQUEST_QUOTA_RESET:
                evaluateRequestingLocationUpdates();
                break;
@@ -470,6 +475,11 @@ public class TelephonyCountryDetector extends Handler {
        evaluateRequestingLocationUpdates();
    }

    private void handleEventWifiConnectivityStateChanged() {
        mWifiConnectivityStateChangedRegistrantList.notifyResult(isWifiNetworkConnected());
        evaluateRequestingLocationUpdates();
    }

    private void setLocationCountryCode(@NonNull Pair<String, Long> countryCodeInfo) {
        logd("Set location country code to: " + countryCodeInfo.first);
        if (!isValid(countryCodeInfo.first)) {
@@ -542,6 +552,25 @@ public class TelephonyCountryDetector extends Handler {
                && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
    }

    /**
     * Register a callback to receive Wi-Fi connectivity state changes.
     * @param h Handler for notification message
     * @param what User-defined message code.
     * @param obj User object.
     */
    public void registerForWifiConnectivityStateChanged(@NonNull Handler h, int what,
            @Nullable Object obj) {
        mWifiConnectivityStateChangedRegistrantList.add(h, what, obj);
    }

    /**
     * Unregisters for Wi-Fi connectivity state changes.
     * @param h Handler to be removed from the registrant list.
     */
    public void unregisterForWifiConnectivityStateChanged(@NonNull Handler h) {
        mWifiConnectivityStateChangedRegistrantList.remove(h);
    }

    /**
     * Check whether this is a valid country code.
     *
+243 −1
Original line number Diff line number Diff line
@@ -17,7 +17,10 @@
package com.android.internal.telephony.satellite;

import static android.provider.Settings.ACTION_SATELLITE_SETTING;
import static android.telephony.CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_MANUAL;
import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT;
import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY;
import static android.telephony.CarrierConfigManager.KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT;
import static android.telephony.CarrierConfigManager.KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE;
import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT;
import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL;
@@ -121,6 +124,7 @@ import com.android.internal.telephony.DeviceStateMonitor;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyCountryDetector;
import com.android.internal.telephony.configupdate.ConfigParser;
import com.android.internal.telephony.configupdate.ConfigProviderAdaptor;
import com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver;
@@ -229,6 +233,8 @@ public class SatelliteController extends Handler {
    private static final int EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION = 43;
    private static final int CMD_PROVISION_SATELLITE_TOKEN_UPDATED = 44;
    private static final int EVENT_PROVISION_SATELLITE_TOKEN_UPDATED = 45;
    private static final int EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT = 46;
    private static final int EVENT_WIFI_CONNECTIVITY_STATE_CHANGED = 47;

    @NonNull private static SatelliteController sInstance;
    @NonNull private final Context mContext;
@@ -242,9 +248,15 @@ public class SatelliteController extends Handler {
    @NonNull private SessionMetricsStats mSessionMetricsStats;
    @NonNull private CarrierRoamingSatelliteControllerStats mCarrierRoamingSatelliteControllerStats;
    @NonNull private final SubscriptionManagerService mSubscriptionManagerService;
    @NonNull private final TelephonyCountryDetector mCountryDetector;
    private final CommandsInterface mCi;
    private ContentResolver mContentResolver;
    private final DeviceStateMonitor mDSM;
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    protected final Object mSatellitePhoneLock = new Object();
    @GuardedBy("mSatellitePhoneLock")
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    protected Phone mSatellitePhone = null;

    private final Object mRadioStateLock = new Object();

@@ -391,6 +403,13 @@ public class SatelliteController extends Handler {
    @GuardedBy("mSatelliteConnectedLock")
    @NonNull private final SparseBooleanArray mInitialized = new SparseBooleanArray();

    /**
     * Boolean set to {@code true} when device is eligible to connect to carrier roaming
     * non-terrestrial network else set to {@code false}.
     */
    @GuardedBy("mSatellitePhoneLock")
    private Boolean mLastNotifiedNtnEligibility = null;

    @GuardedBy("mSatelliteConnectedLock")
    @NonNull private final Map<Integer, CarrierRoamingSatelliteSessionStats>
            mCarrierRoamingSatelliteSessionStatsMap = new HashMap<>();
@@ -472,6 +491,10 @@ public class SatelliteController extends Handler {
    // Variable for backup and restore device's screen rotation settings.
    private String mDeviceRotationLockToBackupAndRestore = null;

    private final Object mIsWifiConnectedLock = new Object();
    @GuardedBy("mIsWifiConnectedLock")
    private boolean mIsWifiConnected = false;

    /**
     * @return The singleton instance of SatelliteController.
     */
@@ -522,6 +545,9 @@ public class SatelliteController extends Handler {
        // to the satellite service and HAL interface.
        mSatelliteModemInterface = SatelliteModemInterface.make(
                mContext, this, mFeatureFlags);
        mCountryDetector = TelephonyCountryDetector.getInstance(context);
        mCountryDetector.registerForWifiConnectivityStateChanged(this,
                EVENT_WIFI_CONNECTIVITY_STATE_CHANGED, null);

        // Create the PointingUIController singleton,
        // which is used to manage interactions with PointingUI app.
@@ -1508,6 +1534,18 @@ public class SatelliteController extends Handler {
                break;
            }

            case EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT: {
                synchronized (mSatellitePhoneLock) {
                    boolean eligible = isCarrierRoamingNtnEligible(mSatellitePhone);
                    plogd("EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT:"
                            + " isCarrierRoamingNtnEligible=" + eligible);
                    if (eligible) {
                        updateLastNotifiedNtnEligibilityAndNotify(true);
                    }
                }
                break;
            }

            case EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION: {
                evaluateESOSProfilesPrioritization();
                break;
@@ -1519,11 +1557,13 @@ public class SatelliteController extends Handler {
                        (RequestProvisionSatelliteArgument) request.argument;
                onCompleted = obtainMessage(EVENT_PROVISION_SATELLITE_TOKEN_UPDATED, request);
                // only pass to index 0.
                // TODO: Select the subscription with highest priority and set it to mSatelliteSubId
                int subId = -1;
                synchronized (mSatelliteTokenProvisionedLock) {
                    subId = mSubscriberIdPerSub.getOrDefault(
                            argument.mProvisionSubscriberIdList.get(0).getSubscriberId(), -1);
                }
                setSatellitePhone(subId);
                String iccId = mSubscriptionManagerService.getSubscriptionInfo(subId).getIccId();
                logd("CMD_PROVISION_SATELLITE_TOKEN_UPDATED: subId=" + subId + ", iccId=" + iccId);
                mSatelliteModemInterface.updateSatelliteSubscription(iccId, onCompleted);
@@ -1553,6 +1593,17 @@ public class SatelliteController extends Handler {
                break;
            }

            case EVENT_WIFI_CONNECTIVITY_STATE_CHANGED: {
                synchronized (mIsWifiConnectedLock) {
                    ar = (AsyncResult) msg.obj;
                    mIsWifiConnected = (boolean) ar.result;
                    plogd("EVENT_WIFI_CONNECTIVITY_STATE_CHANGED: mIsWifiConnected="
                            + mIsWifiConnected);
                    handleStateChangedForCarrierRoamingNtnEligibility();
                }
                break;
            }

            default:
                Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " +
                        msg.what);
@@ -4106,7 +4157,10 @@ public class SatelliteController extends Handler {
                    KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY,
                    KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL,
                    KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT,
                    KEY_SATELLITE_ESOS_SUPPORTED_BOOL);
                    KEY_SATELLITE_ESOS_SUPPORTED_BOOL,
                    KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT,
                    KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT
            );
        }
        if (config == null || config.isEmpty()) {
            config = CarrierConfigManager.getDefaultConfig();
@@ -4129,6 +4183,7 @@ public class SatelliteController extends Handler {
        updateSupportedSatelliteServicesForActiveSubscriptions();
        processNewCarrierConfigData(subId);
        resetCarrierRoamingSatelliteModeParams(subId);
        handleStateChangedForCarrierRoamingNtnEligibility();
        sendMessageDelayed(obtainMessage(EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
                TimeUnit.MINUTES.toMillis(1));
    }
@@ -4235,6 +4290,14 @@ public class SatelliteController extends Handler {
                .getBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL);
    }

    private boolean isSatelliteEsosSupported(int subId) {
        return getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ESOS_SUPPORTED_BOOL);
    }

    private int getCarrierRoamingNtnConnectType(int subId) {
        return getConfigForSubId(subId).getInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT);
    }

    /**
     * Check if satellite attach is enabled by user for the carrier associated with the
     * {@code subId}.
@@ -4529,6 +4592,7 @@ public class SatelliteController extends Handler {
    }

    private void handleEventServiceStateChanged() {
        handleStateChangedForCarrierRoamingNtnEligibility();
        handleServiceStateForSatelliteConnectionViaCarrier();
        determineSystemNotification();
    }
@@ -4634,12 +4698,104 @@ public class SatelliteController extends Handler {
        }
    }

    private void handleStateChangedForCarrierRoamingNtnEligibility() {
        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
            plogd("handleStateChangedForCarrierRoamingNtnEligibility: "
                    + "carrierRoamingNbIotNtn flag is disabled");
            return;
        }

        synchronized (mSatellitePhoneLock) {
            boolean eligible = isCarrierRoamingNtnEligible(mSatellitePhone);
            plogd("handleStateChangedForCarrierRoamingNtnEligibility: "
                    + "isCarrierRoamingNtnEligible=" + eligible);

            if (eligible) {
                if (shouldStartNtnEligibilityHysteresisTimer(eligible)) {
                    startNtnEligibilityHysteresisTimer();
                }
            } else {
                stopNtnEligibilityHysteresisTimer();
                updateLastNotifiedNtnEligibilityAndNotify(false);
            }
        }
    }

    private boolean shouldStartNtnEligibilityHysteresisTimer(boolean eligible) {
        if (!eligible) {
            return false;
        }

        if (hasMessages(EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT)) {
            plogd("shouldStartNtnEligibilityHysteresisTimer: Timer is already running.");
            return false;
        }

        synchronized (mSatellitePhoneLock) {
            if (mLastNotifiedNtnEligibility != null && mLastNotifiedNtnEligibility) {
                return false;
            }
        }

        return true;
    }

    private void startNtnEligibilityHysteresisTimer() {
        synchronized (mSatellitePhoneLock) {
            if (mSatellitePhone == null) {
                ploge("startNtnEligibilityHysteresisTimer: mSatellitePhone is null.");
                return;
            }

            int subId = mSatellitePhone.getSubId();
            long timeout = getCarrierSupportedSatelliteNotificationHysteresisTimeMillis(subId);
            plogd("startNtnEligibilityHysteresisTimer: sendMessageDelayed subId=" + subId
                    + ", phoneId=" + mSatellitePhone.getPhoneId() + ", timeout=" + timeout);
            sendMessageDelayed(obtainMessage(EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT),
                    timeout);
        }
    }

    private void stopNtnEligibilityHysteresisTimer() {
        if (hasMessages(EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT)) {
            removeMessages(EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT);
        }
    }

    private void updateLastNotifiedNtnEligibilityAndNotify(boolean currentNtnEligibility) {
        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
            plogd("notifyNtnEligibility: carrierRoamingNbIotNtn flag is disabled");
            return;
        }

        synchronized (mSatellitePhoneLock) {
            if (mSatellitePhone == null) {
                ploge("notifyNtnEligibility: mSatellitePhone is null");
                return;
            }

            plogd("notifyNtnEligibility: phoneId=" + mSatellitePhone.getPhoneId()
                    + " currentNtnEligibility=" + currentNtnEligibility);
            if (mLastNotifiedNtnEligibility == null
                    || mLastNotifiedNtnEligibility != currentNtnEligibility) {
                mLastNotifiedNtnEligibility = currentNtnEligibility;
                mSatellitePhone.notifyCarrierRoamingNtnEligibleStateChanged(currentNtnEligibility);
            }
        }
    }

    private long getSatelliteConnectionHysteresisTimeMillis(int subId) {
        PersistableBundle config = getPersistableBundle(subId);
        return (config.getInt(
                KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT) * 1000L);
    }

    private long getCarrierSupportedSatelliteNotificationHysteresisTimeMillis(int subId) {
        PersistableBundle config = getPersistableBundle(subId);
        return (config.getInt(
                KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT) * 1000L);
    }

    private void persistOemEnabledSatelliteProvisionStatus(boolean isProvisioned) {
        synchronized (mSatelliteViaOemProvisionLock) {
            plogd("persistOemEnabledSatelliteProvisionStatus: isProvisioned=" + isProvisioned);
@@ -5422,4 +5578,90 @@ public class SatelliteController extends Handler {
                result);
        sendRequestAsync(CMD_PROVISION_SATELLITE_TOKEN_UPDATED, request, null);
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    protected void setSatellitePhone(int subId) {
        synchronized (mSatellitePhoneLock) {
            mSatellitePhone = SatelliteServiceUtils.getPhone(subId);
            if (mSatellitePhone == null) {
                mSatellitePhone = SatelliteServiceUtils.getPhone();
            }
            plogd("mSatellitePhone:" + (mSatellitePhone != null) + ", subId=" + subId);
        }
    }

    /**
     * Get whether phone is eligible to connect to carrier roaming non-terrestrial network.
     *
     * @param phone phone object
     * return {@code true} when the subscription is eligible for satellite
     * communication if all the following conditions are met:
     * <ul>
     * <li>Subscription supports P2P satellite messaging which is defined by
     * {@link CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} </li>
     * <li>{@link CarrierConfigManager#KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT} set to
     * {@link CarrierConfigManager#CARRIER_ROAMING_NTN_CONNECT_MANUAL} </li>
     * <li>The device is in {@link ServiceState#STATE_OUT_OF_SERVICE}, not connected to Wi-Fi. </li>
     * </ul>
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    public boolean isCarrierRoamingNtnEligible(@Nullable Phone phone) {
        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
            plogd("isCarrierRoamingNtnEligible: carrierRoamingNbIotNtn flag is disabled");
            return false;
        }

        if (phone == null) {
            plogd("isCarrierRoamingNtnEligible: phone is null");
            return false;
        }

        int subId = phone.getSubId();
        if (!isSatelliteSupportedViaCarrier(subId)) {
            plogd("isCarrierRoamingNtnEligible[phoneId=" + phone.getPhoneId()
                    + "]: satellite is not supported via carrier");
            return false;
        }

        if (!isSatelliteServiceSupportedByCarrier(subId,
                NetworkRegistrationInfo.SERVICE_TYPE_SMS)) {
            plogd("isCarrierRoamingNtnEligible[phoneId=" + phone.getPhoneId()
                    + "]: SMS is not supported by carrier");
            return false;
        }

        int carrierRoamingNtnConnectType = getCarrierRoamingNtnConnectType(subId);
        if (carrierRoamingNtnConnectType != CARRIER_ROAMING_NTN_CONNECT_MANUAL) {
            plogd("isCarrierRoamingNtnEligible[phoneId=" + phone.getPhoneId() + "]: not manual "
                    + "connect. carrierRoamingNtnConnectType = " + carrierRoamingNtnConnectType);
            return false;
        }

        if (SatelliteServiceUtils.isCellularAvailable()) {
            plogd("isCarrierRoamingNtnEligible[phoneId=" + phone.getPhoneId()
                    + "]: cellular is available");
            return false;
        }

        synchronized (mIsWifiConnectedLock) {
            if (mIsWifiConnected) {
                plogd("isCarrierRoamingNtnEligible[phoneId=" + phone.getPhoneId()
                        + "]: Wi-Fi is connected");
                return false;
            }
        }

        return true;
    }

    private boolean isSatelliteServiceSupportedByCarrier(int subId,
            @NetworkRegistrationInfo.ServiceType int serviceType) {
        List<String> satellitePlmnList = getSatellitePlmnsForCarrier(subId);
        for (String satellitePlmn : satellitePlmnList) {
            if (getSupportedSatelliteServices(subId, satellitePlmn).contains(serviceType)) {
                return true;
            }
        }
        return false;
    }
}
Loading