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

Commit 938f7da8 authored by Brad Ebinger's avatar Brad Ebinger Committed by android-build-merger
Browse files

Merge "Better handle MSIM DDS changed event"

am: 651b4582

Change-Id: Ie7873dc36b74e36c5cf4add6da13cd79ced6cb54
parents d223132d 651b4582
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -184,7 +184,8 @@ public class ImsServiceController {

            @Override
            public void notifyImsFeatureStatus(int featureStatus) throws RemoteException {
                Log.i(LOG_TAG, "notifyImsFeatureStatus");
                Log.i(LOG_TAG, "notifyImsFeatureStatus: slot=" + mSlotId + ", feature="
                        + mFeatureType + ", status=" + featureStatus);
                sendImsFeatureStatusChanged(mSlotId, mFeatureType, featureStatus);
            }
        };
+2 −2
Original line number Diff line number Diff line
@@ -954,8 +954,8 @@ public class ImsPhone extends ImsPhoneBase {
        }
    }

    /* package */
    void sendErrorResponse(Message onComplete, Throwable e) {
    @VisibleForTesting
    public void sendErrorResponse(Message onComplete, Throwable e) {
        Rlog.d(LOG_TAG, "sendErrorResponse");
        if (onComplete != null) {
            AsyncResult.forMessage(onComplete, null, getCommandException(e));
+68 −18
Original line number Diff line number Diff line
@@ -580,10 +580,25 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
     */
    private boolean mShouldUpdateImsConfigOnDisconnect = false;

    private ImsServiceProxy.INotifyStatusChanged mNotifyFeatureRemovedCallback = () -> {
    // Callback fires when ImsManager MMTel Feature changes state
    private ImsServiceProxy.INotifyStatusChanged mNotifyStatusChangedCallback = () -> {
        try {
            if (mImsManager.getImsServiceStatus() != ImsFeature.STATE_READY) {
                retryGetImsService();
            int status = mImsManager.getImsServiceStatus();
            log("Status Changed: " + status);
            switch(status) {
                case ImsFeature.STATE_READY: {
                    startListeningForCalls();
                    break;
                }
                case ImsFeature.STATE_INITIALIZING:
                    // fall through
                case ImsFeature.STATE_NOT_AVAILABLE: {
                    stopListeningForCalls();
                    break;
                }
                default: {
                    Log.w(LOG_TAG, "Unexpected State!");
                }
            }
        } catch (ImsException e) {
            // Could not get the ImsService, retry!
@@ -591,6 +606,24 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        }
    };

    @VisibleForTesting
    public interface IRetryTimeout {
        int get();
    }

    /**
     * Default implementation of interface that calculates the ImsService retry timeout.
     * Override-able for testing.
     */
    @VisibleForTesting
    public IRetryTimeout mRetryTimeout = () -> {
        int timeout = (1 << mImsServiceRetryCount) * IMS_RETRY_STARTING_TIMEOUT_MS;
        if (mImsServiceRetryCount <= CEILING_SERVICE_RETRY_COUNT) {
            mImsServiceRetryCount++;
        }
        return timeout;
    };

    //***** Events


@@ -626,13 +659,15 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
    private void getImsService() throws ImsException {
        if (DBG) log("getImsService");
        mImsManager = ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId());
        // Adding to set, will be safe adding multiple times.
        mImsManager.addNotifyStatusChangedCallback(mNotifyFeatureRemovedCallback);
        if (mImsManager.getImsServiceStatus() != ImsFeature.STATE_READY) {
            // We can not call "open" until the ims service is ready
            throw new ImsException("getImsServiceStatus()",
                    ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
        // Adding to set, will be safe adding multiple times. If the ImsService is not active yet,
        // this method will throw an ImsException.
        mImsManager.addNotifyStatusChangedCallbackIfAvailable(mNotifyStatusChangedCallback);
        // Wait for ImsService.STATE_READY to start listening for calls.
        // Call the callback right away for compatibility with older devices that do not use states.
        mNotifyStatusChangedCallback.notifyStatusChanged();
    }

    private void startListeningForCalls() throws ImsException {
        mImsServiceRetryCount = 0;
        mServiceId = mImsManager.open(ImsServiceClass.MMTEL,
                createIncomingCallPendingIntent(),
@@ -659,6 +694,18 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        }
    }

    private void stopListeningForCalls() {
        try {
            // Only close on valid session.
            if (mImsManager != null && mServiceId > 0) {
                mImsManager.close(mServiceId);
                mServiceId = -1;
            }
        } catch (ImsException e) {
            // If the binder is unavailable, then the ImsService doesn't need to close.
        }
    }

    public void dispose() {
        if (DBG) log("dispose");
        mRingingCall.dispose();
@@ -967,6 +1014,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
            loge("dialInternal : " + e);
            conn.setDisconnectCause(DisconnectCause.ERROR_UNSPECIFIED);
            sendEmptyMessageDelayed(EVENT_HANGUP_PENDINGMO, TIMEOUT_HANGUP_PENDINGMO);
            retryGetImsService();
        } catch (RemoteException e) {
        }
    }
@@ -1291,6 +1339,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        } catch (ImsException e) {
            loge("setTTYMode : " + e);
            mPhone.sendErrorResponse(onComplete, e);
            retryGetImsService();
        }
    }

@@ -1490,6 +1539,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        } catch (ImsException e) {
            loge("sendUSSD : " + e);
            mPhone.sendErrorResponse(response, e);
            retryGetImsService();
        }
    }

@@ -2862,16 +2912,16 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
    }

    private void retryGetImsService() {
        // The binder connection is already up. Do not try to get it again.
        if (mImsManager.isServiceAvailable()) {
            return;
        }
        //Leave mImsManager as null, then CallStateException will be thrown when dialing
        mImsManager = null;
        // Exponential backoff during retry, limited to 32 seconds.
        loge("getImsService: Retrying getting ImsService...");
        removeMessages(EVENT_GET_IMS_SERVICE);
        sendEmptyMessageDelayed(EVENT_GET_IMS_SERVICE,
                (1 << mImsServiceRetryCount) * IMS_RETRY_STARTING_TIMEOUT_MS);
        if (mImsServiceRetryCount <= CEILING_SERVICE_RETRY_COUNT) {
            mImsServiceRetryCount++;
        }
        sendEmptyMessageDelayed(EVENT_GET_IMS_SERVICE, mRetryTimeout.get());
    }

    private void setVideoCallProvider(ImsPhoneConnection conn, ImsCall imsCall)
+1 −1
Original line number Diff line number Diff line
@@ -353,7 +353,7 @@ public abstract class TelephonyTest {
        doReturn(mImsExternalCallTracker).when(mTelephonyComponentFactory)
                .makeImsExternalCallTracker(nullable(ImsPhone.class));
        doReturn(mCarrierSignalAgent).when(mTelephonyComponentFactory)
                .makeCarrierActionAgent(nullable(Phone.class));
                .makeCarrierSignalAgent(nullable(Phone.class));
        doReturn(mCarrierActionAgent).when(mTelephonyComponentFactory)
                .makeCarrierActionAgent(nullable(Phone.class));
        doReturn(mDeviceStateMonitor).when(mTelephonyComponentFactory)
+60 −2
Original line number Diff line number Diff line
@@ -16,24 +16,29 @@
package com.android.internal.telephony.imsphone;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.test.filters.FlakyTest;
import android.telephony.PhoneNumberUtils;
import android.telephony.ims.feature.ImsFeature;
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.LargeTest;

import com.android.ims.ImsCall;
import com.android.ims.ImsCallProfile;
import com.android.ims.ImsConfig;
import com.android.ims.ImsConnectionStateListener;
import com.android.ims.ImsException;
import com.android.ims.ImsManager;
import com.android.ims.ImsReasonInfo;
import com.android.ims.ImsServiceClass;
import com.android.ims.internal.ImsCallSession;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyTest;
@@ -50,14 +55,20 @@ import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -73,6 +84,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
    private int mServiceId;
    @Mock
    private ImsCallSession mImsCallSession;
    private Handler mCTHander;

    private class ImsCTHandlerThread extends HandlerThread {

@@ -87,6 +99,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
                    ImsReasonInfo.CODE_ANSWERED_ELSEWHERE);
            mCTUT.addReasonCodeRemapping(510, "Call answered elsewhere.",
                    ImsReasonInfo.CODE_ANSWERED_ELSEWHERE);
            mCTHander = new Handler(mCTUT.getLooper());
            setReady(true);
        }
    }
@@ -191,8 +204,8 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {

        waitUntilReady();
        logd("ImsPhoneCallTracker initiated");
        /* Make sure getImsService is triggered on a separate thread */
        waitForMs(100);
        /* Make sure getImsService is triggered on handler */
        waitForHandlerAction(mCTHander, 100);
    }

    @After
@@ -436,4 +449,49 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
        assertEquals(90210, mCTUT.maybeRemapReasonCode(new ImsReasonInfo(90210, 1,
                "Call answered elsewhere.")));
    }


    @Test
    @SmallTest
    public void testDialImsServiceUnavailable() throws ImsException {
        doThrow(new ImsException("Test Exception", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN)).when(
                mImsManager).createCallProfile(anyInt(), anyInt(), anyInt());
        mCTUT.mRetryTimeout = () -> 0; //ms
        assertEquals(Call.State.IDLE, mCTUT.mForegroundCall.getState());
        assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());

        try {
            mCTUT.dial("+17005554141", ImsCallProfile.CALL_TYPE_VOICE, null);
        } catch (Exception e) {
            Assert.fail();
        }

        // wait for handler to process ImsService connection retry
        waitForHandlerAction(mCTHander, 1000); // 1 second timeout
        verify(mImsManager, never()).makeCall(anyInt(), nullable(ImsCallProfile.class),
                eq(new String[]{"+17005554141"}), nullable(ImsCall.Listener.class));
        // Make sure that open is called in ImsPhoneCallTracker when it was first connected and
        // again after retry.
        verify(mImsManager, times(2)).open(anyInt(), nullable(PendingIntent.class),
                nullable(ImsConnectionStateListener.class));
    }

    @Test
    @SmallTest
    public void testTTYImsServiceUnavailable() throws ImsException {
        doThrow(new ImsException("Test Exception", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN)).when(
                mImsManager).setUiTTYMode(nullable(Context.class), anyInt(),
                nullable(Message.class));
        // Remove retry timeout delay
        mCTUT.mRetryTimeout = () -> 0; //ms

        mCTUT.setUiTTYMode(0, new Message());

        // wait for handler to process ImsService connection retry
        waitForHandlerAction(mCTHander, 100);
        // Make sure that open is called in ImsPhoneCallTracker to re-establish connection to
        // ImsService
        verify(mImsManager, times(2)).open(anyInt(), nullable(PendingIntent.class),
                nullable(ImsConnectionStateListener.class));
    }
}