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

Commit 6286afc8 authored by Brad Ebinger's avatar Brad Ebinger Committed by android-build-merger
Browse files

Merge "Refactor IMS to use Helper class for polling" am: bc6cdac4

am: 06d47f42

Change-Id: If69516657ac3c946dadef702deb3fe0963b16535
parents b02007fb 06d47f42
Loading
Loading
Loading
Loading
+25 −111
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@
package com.android.internal.telephony;

import android.os.RemoteException;
import android.os.Message;
import android.provider.Telephony.Sms.Intents;
import android.telephony.Rlog;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.aidl.IImsSmsListener;
@@ -26,12 +26,10 @@ import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.telephony.ims.stub.ImsSmsImplBase;
import android.telephony.ims.stub.ImsSmsImplBase.SendStatusResult;
import android.provider.Telephony.Sms.Intents;
import android.util.Pair;

import com.android.ims.ImsException;
import com.android.ims.ImsManager;
import com.android.ims.MmTelFeatureConnection;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
import com.android.internal.telephony.util.SMSDispatcherUtil;
@@ -47,12 +45,8 @@ import java.util.concurrent.atomic.AtomicInteger;
 * @hide
 */
public class ImsSmsDispatcher extends SMSDispatcher {
    // Initial condition for ims connection retry.
    private static final int IMS_RETRY_STARTING_TIMEOUT_MS = 500; // ms
    // Ceiling bitshift amount for service query timeout, calculated as:
    // 2^mImsServiceRetryCount * IMS_RETRY_STARTING_TIMEOUT_MS, where
    // mImsServiceRetryCount ∊ [0, CEILING_SERVICE_RETRY_COUNT].
    private static final int CEILING_SERVICE_RETRY_COUNT = 6;

    private static final String TAG = "ImsSmsDispacher";

    @VisibleForTesting
    public Map<Integer, SmsTracker> mTrackers = new ConcurrentHashMap<>();
@@ -62,20 +56,7 @@ public class ImsSmsDispatcher extends SMSDispatcher {
    private volatile boolean mIsSmsCapable;
    private volatile boolean mIsImsServiceUp;
    private volatile boolean mIsRegistered;
    private volatile int mImsServiceRetryCount;

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

    private final ImsManager.Connector mImsManagerConnector;
    /**
     * Listen to the IMS service state change
     *
@@ -120,45 +101,6 @@ public class ImsSmsDispatcher extends SMSDispatcher {
                }
    };

    // Callback fires when ImsManager MMTel Feature changes state
    private MmTelFeatureConnection.IFeatureUpdate mNotifyStatusChangedCallback =
            new MmTelFeatureConnection.IFeatureUpdate() {
                @Override
                public void notifyStateChanged() {
                    try {
                        int status = getImsManager().getImsServiceState();
                        Rlog.d(TAG, "Status Changed: " + status);
                        switch (status) {
                            case android.telephony.ims.feature.ImsFeature.STATE_READY: {
                                synchronized (mLock) {
                                    setListeners();
                                    mIsImsServiceUp = true;
                                }
                                break;
                            }
                            case android.telephony.ims.feature.ImsFeature.STATE_INITIALIZING:
                                // fall through
                            case ImsFeature.STATE_UNAVAILABLE:
                                synchronized (mLock) {
                                    mIsImsServiceUp = false;
                                }
                                break;
                            default: {
                                Rlog.w(TAG, "Unexpected State!");
                            }
                        }
                    } catch (ImsException e) {
                        // Could not get the ImsService, retry!
                        retryGetImsService();
                    }
                }

                @Override
                public void notifyUnavailable() {
                    retryGetImsService();
                }
            };

    private final IImsSmsListener mImsSmsListener = new IImsSmsListener.Stub() {
        @Override
        public void onSendSmsResult(int token, int messageRef, @SendStatusResult int status,
@@ -235,36 +177,26 @@ public class ImsSmsDispatcher extends SMSDispatcher {
    public ImsSmsDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) {
        super(phone, smsDispatchersController);

        mImsServiceRetryCount = 0;
        // Send a message to connect to the Ims Service and open a connection through
        // getImsService().
        sendEmptyMessage(EVENT_GET_IMS_SERVICE);
        mImsManagerConnector = new ImsManager.Connector(mContext, mPhone.getPhoneId(),
                new ImsManager.Connector.Listener() {
                    @Override
                    public void connectionReady(ImsManager manager) throws ImsException {
                        Rlog.d(TAG, "ImsManager: connection ready.");
                        synchronized (mLock) {
                            setListeners();
                            mIsImsServiceUp = true;
                        }
                    }

                    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case EVENT_GET_IMS_SERVICE:
                try {
                    getImsService();
                } catch (ImsException e) {
                    Rlog.e(TAG, "setListeners: " + e);
                    retryGetImsService();
                }
                break;
            default:
                super.handleMessage(msg);
                    public void connectionUnavailable() {
                        Rlog.d(TAG, "ImsManager: connection unavailable.");
                        synchronized (mLock) {
                            mIsImsServiceUp = false;
                        }
                    }

    private void getImsService() throws ImsException {
        Rlog.d(TAG, "getImsService");
        // Adding to set, will be safe adding multiple times. If the ImsService is not active yet,
        // this method will throw an ImsException.
        getImsManager().addNotifyStatusChangedCallbackIfAvailable(mNotifyStatusChangedCallback);
        // Wait for ImsService.STATE_READY to start listening for SMS.
        // Call the callback right away for compatibility with older devices that do not use states.
        mNotifyStatusChangedCallback.notifyStateChanged();
                });
        mImsManagerConnector.connect();
    }

    private void setListeners() throws ImsException {
@@ -272,25 +204,12 @@ public class ImsSmsDispatcher extends SMSDispatcher {
        getImsManager().addCapabilitiesCallback(mCapabilityCallback);
        getImsManager().setSmsListener(mImsSmsListener);
        getImsManager().onSmsReady();
        mImsServiceRetryCount = 0;
    }

    private void retryGetImsService() {
        // The binder connection is already up. Do not try to get it again.
        if (getImsManager().isServiceAvailable()) {
            return;
        }
        // remove callback so we do not receive updates from old MmTelFeatureConnection when switching
        // between ImsServices.
        getImsManager().removeNotifyStatusChangedCallback(mNotifyStatusChangedCallback);
        // Exponential backoff during retry, limited to 32 seconds.
        Rlog.e(TAG, "getImsService: Retrying getting ImsService...");
        removeMessages(EVENT_GET_IMS_SERVICE);
        sendEmptyMessageDelayed(EVENT_GET_IMS_SERVICE, mRetryTimeout.get());
    }

    public boolean isAvailable() {
        synchronized (mLock) {
            Rlog.d(TAG, "isAvailable: up=" + mIsImsServiceUp + ", reg= " + mIsRegistered
                    + ", cap= " + mIsSmsCapable);
            return mIsImsServiceUp && mIsRegistered && mIsSmsCapable;
        }
    }
@@ -382,9 +301,4 @@ public class ImsSmsDispatcher extends SMSDispatcher {
    protected boolean isCdmaMo() {
        return mSmsDispatchersController.isCdmaFormat(getFormat());
    }

    @VisibleForTesting
    public interface IRetryTimeout {
        int get();
    }
}
+28 −97
Original line number Diff line number Diff line
@@ -74,7 +74,6 @@ import com.android.ims.ImsException;
import com.android.ims.ImsManager;
import com.android.ims.ImsMultiEndpoint;
import com.android.ims.ImsUtInterface;
import com.android.ims.MmTelFeatureConnection;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsVideoCallProvider;
import com.android.ims.internal.ImsVideoCallProviderWrapper;
@@ -273,20 +272,12 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
    private static final int EVENT_EXIT_ECBM_BEFORE_PENDINGMO = 21;
    private static final int EVENT_VT_DATA_USAGE_UPDATE = 22;
    private static final int EVENT_DATA_ENABLED_CHANGED = 23;
    private static final int EVENT_GET_IMS_SERVICE = 24;
    private static final int EVENT_CHECK_FOR_WIFI_HANDOVER = 25;
    private static final int EVENT_ON_FEATURE_CAPABILITY_CHANGED = 26;
    private static final int EVENT_SUPP_SERVICE_INDICATION = 27;

    private static final int TIMEOUT_HANGUP_PENDINGMO = 500;

    // Initial condition for ims connection retry.
    private static final int IMS_RETRY_STARTING_TIMEOUT_MS = 500; // ms
    // Ceiling bitshift amount for service query timeout, calculated as:
    // 2^mImsServiceRetryCount * IMS_RETRY_STARTING_TIMEOUT_MS, where
    // mImsServiceRetryCount ∊ [0, CEILING_SERVICE_RETRY_COUNT].
    private static final int CEILING_SERVICE_RETRY_COUNT = 6;

    private static final int HANDOVER_TO_WIFI_TIMEOUT_MS = 60000; // ms

    //***** Instance Variables
@@ -325,7 +316,6 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {

    private PhoneConstants.State mState = PhoneConstants.State.IDLE;

    private int mImsServiceRetryCount;
    private ImsManager mImsManager;
    private ImsUtInterface mUtInterface;

@@ -677,58 +667,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        return PhoneNumberUtils.isEmergencyNumber(string);
    };

    // Callback fires when ImsManager MMTel Feature changes state
    private MmTelFeatureConnection.IFeatureUpdate mNotifyStatusChangedCallback =
            new MmTelFeatureConnection.IFeatureUpdate() {
                @Override
                public void notifyStateChanged() {
                    try {
                        int status = mImsManager.getImsServiceState();
                        log("Status Changed: " + status);
                        switch (status) {
                            case ImsFeature.STATE_READY: {
                                startListeningForCalls();
                                break;
                            }
                            case ImsFeature.STATE_INITIALIZING:
                                // fall through
                            case ImsFeature.STATE_UNAVAILABLE: {
                                stopListeningForCalls();
                                break;
                            }
                            default: {
                                Log.w(LOG_TAG, "Unexpected State!");
                            }
                        }
                    } catch (ImsException e) {
                        // Could not get the ImsService, retry!
                        retryGetImsService();
                    }
                }

                @Override
                public void notifyUnavailable() {
                    retryGetImsService();
                }
            };

    @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;
    };
    private final ImsManager.Connector mImsManagerConnector;

    //***** Events

@@ -749,8 +688,6 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        mPhone.getDefaultPhone().registerForDataEnabledChanged(
                this, EVENT_DATA_ENABLED_CHANGED, null);

        mImsServiceRetryCount = 0;

        final TelecomManager telecomManager =
                (TelecomManager) mPhone.getContext().getSystemService(Context.TELECOM_SERVICE);
        mDefaultDialerUid.set(
@@ -760,9 +697,20 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        mVtDataUsageSnapshot = new NetworkStats(currentTime, 1);
        mVtDataUsageUidSnapshot = new NetworkStats(currentTime, 1);

        // Send a message to connect to the Ims Service and open a connection through
        // getImsService().
        sendEmptyMessage(EVENT_GET_IMS_SERVICE);
        mImsManagerConnector = new ImsManager.Connector(phone.getContext(), phone.getPhoneId(),
                new ImsManager.Connector.Listener() {
                    @Override
                    public void connectionReady(ImsManager manager) throws ImsException {
                        mImsManager = manager;
                        startListeningForCalls();
                    }

                    @Override
                    public void connectionUnavailable() {
                        stopListeningForCalls();
                    }
                });
        mImsManagerConnector.connect();
    }

    /**
@@ -784,6 +732,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        mPhoneNumberUtilsProxy = phoneNumberUtilsProxy;
    }

    /**
     * Test-only method used to set the ImsService retry timeout.
     */
    @VisibleForTesting
    public void setRetryTimeout(ImsManager.Connector.RetryTimeout retryTimeout) {
        mImsManagerConnector.mRetryTimeout = retryTimeout;
    }

    private int getPackageUid(Context context, String pkg) {
        if (pkg == null) {
            return NetworkStats.UID_ALL;
@@ -800,19 +756,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        return uid;
    }

    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. 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.notifyStateChanged();
    }

    private void startListeningForCalls() throws ImsException {
        mImsServiceRetryCount = 0;
        log("startListeningForCalls");
        mImsManager.open(mMmTelFeatureListener);
        mImsManager.addRegistrationCallback(mImsRegistrationCallback);
        mImsManager.addCapabilitiesCallback(mImsCapabilityCallback);
@@ -852,6 +797,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
    }

    private void stopListeningForCalls() {
        log("stopListeningForCalls");
        resetImsCapabilities();
        // Only close on valid session.
        if (mImsManager != null) {
@@ -877,7 +823,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        }
        mPhone.getContext().unregisterReceiver(mReceiver);
        mPhone.getDefaultPhone().unregisterForDataEnabledChanged(this);
        removeMessages(EVENT_GET_IMS_SERVICE);
        mImsManagerConnector.disconnect();
    }

    @Override
@@ -3089,14 +3035,6 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
                    onDataEnabledChanged(p.first, p.second);
                }
                break;
            case EVENT_GET_IMS_SERVICE:
                try {
                    getImsService();
                } catch (ImsException e) {
                    loge("getImsService: " + e);
                    retryGetImsService();
                }
                break;
            case EVENT_CHECK_FOR_WIFI_HANDOVER:
                if (msg.obj instanceof ImsCall) {
                    ImsCall imsCall = (ImsCall) msg.obj;
@@ -3347,15 +3285,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        if (mImsManager.isServiceAvailable()) {
            return;
        }
        // remove callback so we do not receive updates from old ImsServiceProxy when switching
        // between ImsServices.
        mImsManager.removeNotifyStatusChangedCallback(mNotifyStatusChangedCallback);
        //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, mRetryTimeout.get());

        mImsManagerConnector.connect();
    }

    private void setVideoCallProvider(ImsPhoneConnection conn, ImsCall imsCall)
+5 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ 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.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
@@ -223,6 +224,8 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {

        doReturn(mImsConfig).when(mImsManager).getConfigInterface();

        doNothing().when(mImsManager).addNotifyStatusChangedCallbackIfAvailable(any());

        mImsCTHandlerThread = new ImsCTHandlerThread(this.getClass().getSimpleName());
        mImsCTHandlerThread.start();

@@ -615,7 +618,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
    public void testDialImsServiceUnavailable() throws ImsException {
        doThrow(new ImsException("Test Exception", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN)).when(
                mImsManager).createCallProfile(anyInt(), anyInt());
        mCTUT.mRetryTimeout = () -> 0; //ms
        mCTUT.setRetryTimeout(() -> 0);
        assertEquals(Call.State.IDLE, mCTUT.mForegroundCall.getState());
        assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());

@@ -644,7 +647,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
                mImsManager).setUiTTYMode(nullable(Context.class), anyInt(),
                nullable(Message.class));
        // Remove retry timeout delay
        mCTUT.mRetryTimeout = () -> 0; //ms
        mCTUT.setRetryTimeout(() -> 0); //ms

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