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

Commit cbb3a99f authored by Hwangoo Park's avatar Hwangoo Park
Browse files

Apply emergency SMS domain selection for multipart-text/retry

If the user sends an emergency SMS using a long text in the NR network
(ESFB support) environment, the emergency SMS transmission fails because
the AP doesn't set the emergency mode.
Currently, emergency SMS only applies to the sendText. However, even if
the user sends long text as an emergency SMS, emergency domain selection
should be performed. In particular, if the emergency SMS is being sent
via ESFB in the NR network, emergency domain selection should be
performed to move NGRAN to EUTRAN for emergency service.

Bug: 330784003
Test: atest EmergencyStateTrackerTest, SmsDispatchersControllerTest
Test: manual (verified long text and retry SMS on device when SMS domain
selection enabled)

Change-Id: I23a421f0da1235c7c28a918904406ecf2dbb023f
parent c2077bac
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -203,7 +203,8 @@ public class ImsSmsDispatcher extends SMSDispatcher {
                        mTrackers.remove(token);
                        mPhone.notifySmsSent(tracker.mDestAddress);
                        mSmsDispatchersController.notifySmsSentToEmergencyStateTracker(
                                tracker.mDestAddress, tracker.mMessageId, true);
                                tracker.mDestAddress, tracker.mMessageId, true,
                                tracker.isSinglePartOrLastPart());
                        break;
                    case ImsSmsImplBase.SEND_STATUS_ERROR:
                        tracker.onFailed(mContext, reason, networkReasonCode);
+10 −1
Original line number Diff line number Diff line
@@ -1054,7 +1054,8 @@ public abstract class SMSDispatcher extends Handler {
            tracker.onSent(mContext);
            mPhone.notifySmsSent(tracker.mDestAddress);
            mSmsDispatchersController.notifySmsSentToEmergencyStateTracker(
                    tracker.mDestAddress, tracker.mMessageId, false);
                    tracker.mDestAddress, tracker.mMessageId, false,
                    tracker.isSinglePartOrLastPart());

            mPhone.getSmsStats().onOutgoingSms(
                    tracker.mImsRetry > 0 /* isOverIms */,
@@ -2612,6 +2613,14 @@ public abstract class SMSDispatcher extends Handler {
            return SystemClock.elapsedRealtime() - mTimestamp;
        }

        /**
         * Returns the flag specifying whether this {@link SmsTracker} is a single part or
         * the last part of multipart message.
         */
        protected boolean isSinglePartOrLastPart() {
            return mUnsentPartCount != null ? (mUnsentPartCount.get() == 0) : true;
        }

        /**
         * Persist a sent SMS if required:
         * 1. It is a text message
+40 −11
Original line number Diff line number Diff line
@@ -112,6 +112,9 @@ public class SmsDispatchersController extends Handler {
    /** Called when MT SMS is received via IMS. */
    private static final int EVENT_SMS_RECEIVED_VIA_IMS = 21;

    /** Called when the domain selection should be performed. */
    private static final int EVENT_REQUEST_DOMAIN_SELECTION = 22;

    /** Delete any partial message segments after being IN_SERVICE for 1 day. */
    private static final long PARTIAL_SEGMENT_WAIT_DURATION = (long) (60 * 60 * 1000) * 24;
    /** Constant for invalid time */
@@ -491,9 +494,10 @@ public class SmsDispatchersController extends Handler {
                Long messageId = (Long) args.arg2;
                Boolean success = (Boolean) args.arg3;
                Boolean isOverIms = (Boolean) args.arg4;
                Boolean isLastSmsPart = (Boolean) args.arg5;
                try {
                    handleSmsSentCompletedUsingDomainSelection(
                            destAddr, messageId, success, isOverIms);
                            destAddr, messageId, success, isOverIms, isLastSmsPart);
                } finally {
                    args.recycle();
                }
@@ -508,6 +512,19 @@ public class SmsDispatchersController extends Handler {
                handleSmsReceivedViaIms((String) msg.obj);
                break;
            }
            case EVENT_REQUEST_DOMAIN_SELECTION: {
                SomeArgs args = (SomeArgs) msg.obj;
                DomainSelectionConnectionHolder holder =
                        (DomainSelectionConnectionHolder) args.arg1;
                PendingRequest request = (PendingRequest) args.arg2;
                String logTag = (String) args.arg3;
                try {
                    requestDomainSelection(holder, request, logTag);
                } finally {
                    args.recycle();
                }
                break;
            }
            default:
                if (isCdmaMo()) {
                    mCdmaDispatcher.handleMessage(msg);
@@ -762,16 +779,22 @@ public class SmsDispatchersController extends Handler {

        if (!tracker.mUsesImsServiceForIms) {
            if (isSmsDomainSelectionEnabled()) {
                DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false);
                TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
                boolean isEmergency = tm.isEmergencyNumber(tracker.mDestAddress);
                DomainSelectionConnectionHolder holder = getDomainSelectionConnection(isEmergency);

                // If the DomainSelectionConnection is not available,
                // fallback to the legacy implementation.
                if (holder != null && holder.getConnection() != null) {
                    sendSmsUsingDomainSelection(holder,
                            new PendingRequest(PendingRequest.TYPE_RETRY_SMS, tracker,
                    // This may be invoked by another thread, so this operation is posted and
                    // handled through the execution flow of SmsDispatchersController.
                    SomeArgs args = SomeArgs.obtain();
                    args.arg1 = holder;
                    args.arg2 = new PendingRequest(PendingRequest.TYPE_RETRY_SMS, tracker,
                            null, null, null, null, null, false, null, 0, null, null, false,
                                    0, false, 0, 0L, false),
                            "sendRetrySms");
                            0, false, 0, 0L, false);
                    args.arg3 = "sendRetrySms";
                    sendMessage(obtainMessage(EVENT_REQUEST_DOMAIN_SELECTION, args));
                    return;
                }
            }
@@ -1157,15 +1180,17 @@ public class SmsDispatchersController extends Handler {
     * @param messageId The message id for SMS.
     * @param success A flag specifying whether MO SMS is successfully sent or not.
     * @param isOverIms A flag specifying whether MO SMS is sent over IMS or not.
     * @param isLastSmsPart A flag specifying whether this result is for the last SMS part or not.
     */
    private void handleSmsSentCompletedUsingDomainSelection(@NonNull String destAddr,
            long messageId, boolean success, boolean isOverIms) {
            long messageId, boolean success, boolean isOverIms, boolean isLastSmsPart) {
        if (mEmergencyStateTracker != null) {
            TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
            if (tm.isEmergencyNumber(destAddr)) {
                mEmergencyStateTracker.endSms(String.valueOf(messageId), success,
                        isOverIms ? NetworkRegistrationInfo.DOMAIN_PS
                                  : NetworkRegistrationInfo.DOMAIN_CS);
                                  : NetworkRegistrationInfo.DOMAIN_CS,
                        isLastSmsPart);
            }
        }
    }
@@ -1174,7 +1199,7 @@ public class SmsDispatchersController extends Handler {
     * Called when MO SMS is successfully sent.
     */
    protected void notifySmsSentToEmergencyStateTracker(@NonNull String destAddr, long messageId,
            boolean isOverIms) {
            boolean isOverIms, boolean isLastSmsPart) {
        if (isSmsDomainSelectionEnabled()) {
            // Run on main thread for interworking with EmergencyStateTracker.
            SomeArgs args = SomeArgs.obtain();
@@ -1182,6 +1207,7 @@ public class SmsDispatchersController extends Handler {
            args.arg2 = Long.valueOf(messageId);
            args.arg3 = Boolean.TRUE;
            args.arg4 = Boolean.valueOf(isOverIms);
            args.arg5 = Boolean.valueOf(isLastSmsPart);
            sendMessage(obtainMessage(EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION, args));
        }
    }
@@ -1198,6 +1224,7 @@ public class SmsDispatchersController extends Handler {
            args.arg2 = Long.valueOf(messageId);
            args.arg3 = Boolean.FALSE;
            args.arg4 = Boolean.valueOf(isOverIms);
            args.arg5 = Boolean.TRUE; // Ignored when sending SMS is failed.
            sendMessage(obtainMessage(EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION, args));
        }
    }
@@ -1932,7 +1959,9 @@ public class SmsDispatchersController extends Handler {
        }

        if (isSmsDomainSelectionEnabled()) {
            DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false);
            TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
            boolean isEmergency = tm.isEmergencyNumber(destAddr);
            DomainSelectionConnectionHolder holder = getDomainSelectionConnection(isEmergency);

            // If the DomainSelectionConnection is not available,
            // fallback to the legacy implementation.
+15 −3
Original line number Diff line number Diff line
@@ -1091,6 +1091,9 @@ public class EmergencyStateTracker {
     */
    @VisibleForTesting
    public boolean isEmergencyCallbackModeSupported(Phone phone) {
        if (phone == null) {
            return false;
        }
        int subId = phone.getSubId();
        int phoneId = phone.getPhoneId();
        if (!isSimReady(phoneId, subId)) {
@@ -1363,10 +1366,17 @@ public class EmergencyStateTracker {
     * @param success the flag specifying whether an emergency SMS is successfully sent or not.
     *                {@code true} if SMS is successfully sent, {@code false} otherwise.
     * @param domain the domain that MO SMS was sent.
     * @param isLastSmsPart the flag specifying whether this result is for the last SMS part or not.
     */
    public void endSms(@NonNull String smsId, boolean success,
            @NetworkRegistrationInfo.Domain int domain) {
            @NetworkRegistrationInfo.Domain int domain, boolean isLastSmsPart) {
        if (success && !isLastSmsPart) {
            // Waits until all SMS parts are sent successfully.
            // Ensures that all SMS parts are sent while in the emergency mode.
            Rlog.i(TAG, "endSms: wait for additional SMS parts to be sent.");
        } else {
            mOngoingEmergencySmsIds.remove(smsId);
        }

        // If the outgoing emergency SMSs are empty, we can try to exit the emergency mode.
        if (mOngoingEmergencySmsIds.isEmpty()) {
@@ -1389,7 +1399,9 @@ public class EmergencyStateTracker {
                // Sets the emergency mode to CALLBACK without re-initiating SCBM timer.
                setEmergencyCallbackMode(mSmsPhone, EMERGENCY_TYPE_SMS);
            } else {
                if (mSmsPhone != null) {
                    exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS);
                }
                clearEmergencySmsInfo();
            }
        }
+90 −15
Original line number Diff line number Diff line
@@ -111,8 +111,8 @@ public class SmsDispatchersControllerTest extends TelephonyTest {
        }

        public void testNotifySmsSentToEmergencyStateTracker(String destAddr, long messageId,
                boolean isOverIms) {
            notifySmsSentToEmergencyStateTracker(destAddr, messageId, isOverIms);
                boolean isOverIms, boolean isLastSmsPart) {
            notifySmsSentToEmergencyStateTracker(destAddr, messageId, isOverIms, isLastSmsPart);
        }

        public void testNotifySmsSentFailedToEmergencyStateTracker(String destAddr,
@@ -456,7 +456,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest {

    @Test
    @SmallTest
    public void testSendEmergencyTextWhenDomainPs() throws Exception {
    public void testSendTextForEmergencyWhenDomainPs() throws Exception {
        setUpDomainSelectionConnection();
        setUpSmsDispatchers();
        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);
@@ -488,7 +488,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest {

    @Test
    @SmallTest
    public void testSendEmergencyTextWhenEmergencyStateTrackerReturnsFailure() throws Exception {
    public void testSendTextForEmergencyWhenEmergencyStateTrackerReturnsFailure() throws Exception {
        setUpDomainSelectionConnection();
        setUpSmsDispatchers();
        setUpEmergencyStateTracker(DisconnectCause.OUT_OF_SERVICE);
@@ -501,18 +501,90 @@ public class SmsDispatchersControllerTest extends TelephonyTest {
        verify(mEmergencySmsDsc).requestDomainSelection(any(), any());
    }

    @Test
    @SmallTest
    public void testSendMultipartTextForEmergencyWhenDomainPs() throws Exception {
        setUpDomainSelectionConnection();
        setUpSmsDispatchers();
        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);

        ArrayList<String> parts = new ArrayList<>();
        ArrayList<PendingIntent> sentIntents = new ArrayList<>();
        ArrayList<PendingIntent> deliveryIntents = new ArrayList<>();
        mSmsDispatchersController.testSendMultipartText("911", "2222", parts, sentIntents,
                deliveryIntents, null, "test-app", false, 0, false, 10, 1L);
        processAllMessages();

        SmsDispatchersController.DomainSelectionConnectionHolder holder =
                mSmsDispatchersController.testGetDomainSelectionConnectionHolder(true);
        verify(mEmergencySmsDsc).requestDomainSelection(any(), any());
        assertNotNull(holder);
        assertNotNull(holder.getConnection());
        assertTrue(holder.isEmergency());
        assertTrue(holder.isDomainSelectionRequested());
        assertEquals(1, holder.getPendingRequests().size());

        mDscFuture.complete(NetworkRegistrationInfo.DOMAIN_PS);
        processAllMessages();

        verify(mEmergencySmsDsc).finishSelection();
        verify(mImsSmsDispatcher).sendMultipartText(eq("911"), eq("2222"), eq(parts),
                eq(sentIntents), eq(deliveryIntents), any(), eq("test-app"), eq(false), eq(0),
                eq(false), eq(10), eq(1L));
        assertNull(holder.getConnection());
        assertFalse(holder.isDomainSelectionRequested());
        assertEquals(0, holder.getPendingRequests().size());
    }

    @Test
    @SmallTest
    public void testSendRetrySmsForEmergencyWhenDomainPs() throws Exception {
        setUpDomainSelectionConnection();
        setUpSmsDispatchers();
        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);

        when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM);
        when(mImsSmsDispatcher.getFormat()).thenReturn(SmsConstants.FORMAT_3GPP);
        when(mCdmaSmsDispatcher.getFormat()).thenReturn(SmsConstants.FORMAT_3GPP2);
        when(mGsmSmsDispatcher.getFormat()).thenReturn(SmsConstants.FORMAT_3GPP);
        replaceInstance(SMSDispatcher.SmsTracker.class,
                "mFormat", mTracker, SmsConstants.FORMAT_3GPP);
        replaceInstance(SMSDispatcher.SmsTracker.class, "mDestAddress", mTracker, "911");

        mSmsDispatchersController.sendRetrySms(mTracker);
        processAllMessages();

        SmsDispatchersController.DomainSelectionConnectionHolder holder =
                mSmsDispatchersController.testGetDomainSelectionConnectionHolder(true);
        verify(mEmergencySmsDsc).requestDomainSelection(any(), any());
        assertNotNull(holder);
        assertNotNull(holder.getConnection());
        assertTrue(holder.isEmergency());
        assertTrue(holder.isDomainSelectionRequested());
        assertEquals(1, holder.getPendingRequests().size());

        mDscFuture.complete(NetworkRegistrationInfo.DOMAIN_PS);
        processAllMessages();

        verify(mEmergencySmsDsc).finishSelection();
        verify(mImsSmsDispatcher).sendSms(eq(mTracker));
        assertNull(holder.getConnection());
        assertFalse(holder.isDomainSelectionRequested());
        assertEquals(0, holder.getPendingRequests().size());
    }

    @Test
    @SmallTest
    public void testNotifySmsSentToEmergencyStateTrackerOnDomainCs() throws Exception {
        setUpDomainSelectionEnabled(true);
        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);

        mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("911", 1L, false);
        mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("911", 1L, false, true);
        processAllMessages();

        verify(mTelephonyManager).isEmergencyNumber(eq("911"));
        verify(mEmergencyStateTracker)
                .endSms(eq("1"), eq(true), eq(NetworkRegistrationInfo.DOMAIN_CS));
                .endSms(eq("1"), eq(true), eq(NetworkRegistrationInfo.DOMAIN_CS), eq(true));
    }

    @Test
@@ -521,12 +593,12 @@ public class SmsDispatchersControllerTest extends TelephonyTest {
        setUpDomainSelectionEnabled(true);
        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);

        mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("911", 1L, true);
        mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("911", 1L, true, true);
        processAllMessages();

        verify(mTelephonyManager).isEmergencyNumber(eq("911"));
        verify(mEmergencyStateTracker)
                .endSms(eq("1"), eq(true), eq(NetworkRegistrationInfo.DOMAIN_PS));
                .endSms(eq("1"), eq(true), eq(NetworkRegistrationInfo.DOMAIN_PS), eq(true));
    }

    @Test
@@ -535,11 +607,12 @@ public class SmsDispatchersControllerTest extends TelephonyTest {
        setUpDomainSelectionEnabled(true);
        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);

        mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("1234", 1L, true);
        mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("1234", 1L, true, true);
        processAllMessages();

        verify(mTelephonyManager).isEmergencyNumber(eq("1234"));
        verify(mEmergencyStateTracker, never()).endSms(anyString(), anyBoolean(), anyInt());
        verify(mEmergencyStateTracker, never())
                .endSms(anyString(), anyBoolean(), anyInt(), anyBoolean());
    }

    @Test
@@ -547,7 +620,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest {
    public void testNotifySmsSentToEmergencyStateTrackerWithoutEmergencyStateTracker()
            throws Exception {
        setUpDomainSelectionEnabled(true);
        mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("911", 1L, true);
        mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("911", 1L, true, true);

        verify(mTelephonyManager, never()).isEmergencyNumber(anyString());
    }
@@ -563,7 +636,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest {

        verify(mTelephonyManager).isEmergencyNumber(eq("911"));
        verify(mEmergencyStateTracker)
                .endSms(eq("1"), eq(false), eq(NetworkRegistrationInfo.DOMAIN_CS));
                .endSms(eq("1"), eq(false), eq(NetworkRegistrationInfo.DOMAIN_CS), eq(true));
    }

    @Test
@@ -577,7 +650,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest {

        verify(mTelephonyManager).isEmergencyNumber(eq("911"));
        verify(mEmergencyStateTracker)
                .endSms(eq("1"), eq(false), eq(NetworkRegistrationInfo.DOMAIN_PS));
                .endSms(eq("1"), eq(false), eq(NetworkRegistrationInfo.DOMAIN_PS), eq(true));
    }

    @Test
@@ -591,7 +664,8 @@ public class SmsDispatchersControllerTest extends TelephonyTest {
        processAllMessages();

        verify(mTelephonyManager).isEmergencyNumber(eq("1234"));
        verify(mEmergencyStateTracker, never()).endSms(anyString(), anyBoolean(), anyInt());
        verify(mEmergencyStateTracker, never())
                .endSms(anyString(), anyBoolean(), anyInt(), anyBoolean());
    }

    @Test
@@ -843,7 +917,8 @@ public class SmsDispatchersControllerTest extends TelephonyTest {
                mSmsDispatchersController, mEmergencyStateTracker);
        when(mEmergencyStateTracker.startEmergencySms(any(Phone.class), anyString(), anyBoolean()))
                .thenReturn(mEmergencySmsFuture);
        doNothing().when(mEmergencyStateTracker).endSms(anyString(), anyBoolean(), anyInt());
        doNothing().when(mEmergencyStateTracker)
                .endSms(anyString(), anyBoolean(), anyInt(), anyBoolean());
        mEmergencySmsFuture.complete(result);
        when(mTelephonyManager.isEmergencyNumber(eq("911"))).thenReturn(true);
    }
Loading