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

Commit feefaf43 authored by Tyler Gunn's avatar Tyler Gunn
Browse files

Fix issues with MMI/USSD codes.

There a few issues here:
1. The queuing of MMI codes for handUssdRequest was not working properly.
I have removed it in favor of returning an error if there is an ongoing
MMI code.  The functionality was pretty broken and despite my efforts I
could not sort all of it out well enough to be confident that it could be
fixed.
2. There was no attempt to retry handleUssdRequest calls on IMS.
3. There was a missing fallback to CS for regular MMI requests.

Test: Manual
Bug: 37484804
Merged-In: I8b2ed5ed9c29cdf95532096d60487656946b4cc0
Change-Id: I8b2ed5ed9c29cdf95532096d60487656946b4cc0
(cherry picked from commit 3aa9ed7d)
parent 48d4becf
Loading
Loading
Loading
Loading
+35 −46
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.telephony.cdma.EriManager;
import com.android.internal.telephony.gsm.GsmMmiCode;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.test.SimulatedRadioControl;
import com.android.internal.telephony.uicc.IccCardProxy;
import com.android.internal.telephony.uicc.IccException;
@@ -155,7 +156,6 @@ public class GsmCdmaPhone extends Phone {
    public GsmCdmaCallTracker mCT;
    public ServiceStateTracker mSST;
    private ArrayList <MmiCode> mPendingMMIs = new ArrayList<MmiCode>();
    private final Deque<MmiCode> mMMIQueue = new ArrayDeque<MmiCode>(USSD_MAX_QUEUE);
    private IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
    private DeviceStateMonitor mDeviceStateMonitor;

@@ -1176,16 +1176,6 @@ public class GsmCdmaPhone extends Phone {
        return shouldConfirmCall;
    }

    private synchronized boolean addToMMIQueue(MmiCode mmi) {
        if (mPendingMMIs.size() >= 1) {
            mMMIQueue.offerLast(mmi);
            return true;
        }
        mPendingMMIs.add(mmi);
        mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
        return false;
    }

    @Override
    protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
                                      Bundle intentExtras)
@@ -1210,35 +1200,23 @@ public class GsmCdmaPhone extends Phone {
            String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
            GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this,
                    mUiccApplication.get(), wrappedCallback);
            if (DBG) logd("dialing w/ mmi '" + mmi + "'...");
            if (DBG) logd("dialInternal: dialing w/ mmi '" + mmi + "'...");

            if (mmi == null) {
                return mCT.dial(newDialString, uusInfo, intentExtras);
            } else if (mmi.isTemporaryModeCLIR()) {
                return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
            } else {
                return dialInternal(mmi);
                mPendingMMIs.add(mmi);
                mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
                mmi.processCode();
                return null;
            }
        } else {
            return mCT.dial(newDialString);
        }
    }

    protected Connection dialInternal(MmiCode mmi) {
        if (addToMMIQueue(mmi)) {
            return null;
        }
        try {
            mmi.processCode();
        } catch (CallStateException e) {
            //do nothing
        }

        // FIXME should this return null or something else?
        return null;
    }


   @Override
    public boolean handlePinMmi(String dialString) {
        MmiCode mmi;
@@ -1263,10 +1241,6 @@ public class GsmCdmaPhone extends Phone {
        return false;
    }

    private synchronized boolean isMmiQueueFull() {
        return (mMMIQueue.size() >= USSD_MAX_QUEUE - 1);
    }

    private void sendUssdResponse(String ussdRequest, CharSequence message, int returnCode,
                                   ResultReceiver wrappedCallback) {
        UssdResponse response = new UssdResponse(ussdRequest, message);
@@ -1277,16 +1251,37 @@ public class GsmCdmaPhone extends Phone {

    @Override
    public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) {
        if (!isPhoneTypeGsm() || isMmiQueueFull()) {
        if (!isPhoneTypeGsm() || mPendingMMIs.size() > 0) {
            //todo: replace the generic failure with specific error code.
            sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
                    wrappedCallback );
            return true;
        }

        // Try over IMS if possible.
        Phone imsPhone = mImsPhone;
        if ((imsPhone != null)
                && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
                || imsPhone.isUtEnabled())) {
            try {
                logd("handleUssdRequest: attempting over IMS");
                return imsPhone.handleUssdRequest(ussdRequest, wrappedCallback);
            } catch (CallStateException cse) {
                if (!CS_FALLBACK.equals(cse.getMessage())) {
                    return false;
                }
                // At this point we've tried over IMS but have been informed we need to handover
                // back to GSM.
                logd("handleUssdRequest: fallback to CS required");
            }
        }

        // Try USSD over GSM.
        try {
            dialInternal(ussdRequest, null, VideoProfile.STATE_AUDIO_ONLY, null, wrappedCallback);
            dialInternal(ussdRequest, null, VideoProfile.STATE_AUDIO_ONLY, null,
                    wrappedCallback);
        } catch (Exception e) {
            logd("exception" + e);
            logd("handleUssdRequest: exception" + e);
            return false;
        }
        return true;
@@ -1934,19 +1929,22 @@ public class GsmCdmaPhone extends Phone {
         * The exception is cancellation of an incoming USSD-REQUEST, which is
         * not on the list.
         */
        logd("USSD Response:" + mmi);
        if (mPendingMMIs.remove(mmi) || (isPhoneTypeGsm() && (mmi.isUssdRequest() ||
                ((GsmMmiCode)mmi).isSsInfo()))) {

            ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver();
            if (receiverCallback != null) {
                Rlog.i(LOG_TAG, "onMMIDone: invoking callback: " + mmi);
                int returnCode = (mmi.getState() ==  MmiCode.State.COMPLETE) ?
                    TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE;
                sendUssdResponse(mmi.getDialString(), mmi.getMessage(), returnCode,
                        receiverCallback );
            } else {
                Rlog.i(LOG_TAG, "onMMIDone: notifying registrants: " + mmi);
                mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
            }
        } else {
            Rlog.i(LOG_TAG, "onMMIDone: invalid response or already handled; ignoring: " + mmi);
        }
    }

@@ -2020,15 +2018,6 @@ public class GsmCdmaPhone extends Phone {
                                                   GsmCdmaPhone.this,
                                                   mUiccApplication.get());
            onNetworkInitiatedUssd(mmi);
        } else {
            if (mMMIQueue.peek() != null) {
                try {

                    dialInternal(mMMIQueue.remove());
                } catch (Exception e) {
                    logd("Exception:" + e);
                }
            }
        }
    }

+6 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import com.android.ims.ImsConfig;
import com.android.ims.ImsManager;
import com.android.internal.R;
import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
import com.android.internal.telephony.test.SimulatedRadioControl;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
@@ -278,6 +279,11 @@ public abstract class Phone extends Handler implements PhoneInternalInterface {
    protected TelephonyComponentFactory mTelephonyComponentFactory;

    //IMS
    /**
     * {@link CallStateException} message text used to indicate that an IMS call has failed because
     * it needs to be retried using GSM or CDMA (e.g. CS fallback).
     * TODO: Replace this with a proper exception; {@link CallStateException} doesn't make sense.
     */
    public static final String CS_FALLBACK = "cs_fallback";
    public static final String EXTRA_KEY_ALERT_TITLE = "alertTitle";
    public static final String EXTRA_KEY_ALERT_MESSAGE = "alertMessage";
+2 −15
Original line number Diff line number Diff line
@@ -16,32 +16,18 @@

package com.android.internal.telephony;

import android.content.Context;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.WorkSource;
import android.os.ResultReceiver;
import android.telephony.CellInfo;
import android.telephony.CellLocation;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;

import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.RadioCapability;
import com.android.internal.telephony.test.SimulatedRadioControl;
import com.android.internal.telephony.uicc.IsimRecords;
import com.android.internal.telephony.uicc.UiccCard;
import com.android.internal.telephony.uicc.UsimServiceTable;

import com.android.internal.telephony.PhoneConstants.*; // ????

import java.util.List;
import java.util.Locale;

/**
 * Internal interface used to control the phone; SDK developers cannot
@@ -456,7 +442,8 @@ public interface PhoneInternalInterface {
     * @param ussdRequest the USSD command to be executed.
     * @param wrappedCallback receives the callback result.
     */
    boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback);
    boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback)
            throws CallStateException;

    /**
     * Handles in-call MMI commands. While in a call, or while receiving a
+5 −2
Original line number Diff line number Diff line
@@ -1629,8 +1629,11 @@ public final class GsmMmiCode extends Handler implements MmiCode {
        if (mSib != null) sb.append(" sib=" + Rlog.pii(LOG_TAG, mSib));
        if (mSic != null) sb.append(" sic=" + Rlog.pii(LOG_TAG, mSic));
        if (mPoundString != null) sb.append(" poundString=" + Rlog.pii(LOG_TAG, mPoundString));
        if (mDialingNumber != null) sb.append(" dialingNumber=" + mDialingNumber);
        if (mPwd != null) sb.append(" pwd=" + mPwd);
        if (mDialingNumber != null) {
            sb.append(" dialingNumber=" + Rlog.pii(LOG_TAG, mDialingNumber));
        }
        if (mPwd != null) sb.append(" pwd=" + Rlog.pii(LOG_TAG, mPwd));
        if (mCallbackReceiver != null) sb.append(" hasReceiver");
        sb.append("}");
        return sb.toString();
    }
+36 −45
Original line number Diff line number Diff line
@@ -139,9 +139,6 @@ public class ImsPhone extends ImsPhoneBase {
    ImsPhoneCallTracker mCT;
    ImsExternalCallTracker mExternalCallTracker;
    private ArrayList <ImsPhoneMmiCode> mPendingMMIs = new ArrayList<ImsPhoneMmiCode>();
    private final Deque<ImsPhoneMmiCode> mMMIQueue =
            new ArrayDeque<ImsPhoneMmiCode>(USSD_MAX_QUEUE);

    private ServiceState mSS = new ServiceState();

    // To redial silently through GSM or CDMA when dialing through IMS fails
@@ -375,10 +372,6 @@ public class ImsPhone extends ImsPhoneBase {
        return true;
    }

    private synchronized boolean isMmiQueueFull() {
        return (mMMIQueue.size() >= USSD_MAX_QUEUE - 1);
    }

    private void sendUssdResponse(String ussdRequest, CharSequence message, int returnCode,
                                   ResultReceiver wrappedCallback) {
        UssdResponse response = new UssdResponse(ussdRequest, message);
@@ -389,17 +382,29 @@ public class ImsPhone extends ImsPhoneBase {
    }

    @Override
    public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) {
        if (isMmiQueueFull()) {
            //todo: replace the generic failure with specific error code.
    public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback)
            throws CallStateException {
        if (mPendingMMIs.size() > 0) {
            // There are MMI codes in progress; fail attempt now.
            Rlog.i(LOG_TAG, "handleUssdRequest: queue full: " + Rlog.pii(LOG_TAG, ussdRequest));
            sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
                    wrappedCallback );
            return true;
        }
        try {
            dialInternal(ussdRequest, VideoProfile.STATE_AUDIO_ONLY, null, wrappedCallback);
        } catch (CallStateException cse) {
            if (CS_FALLBACK.equals(cse.getMessage())) {
                throw cse;
            } else {
                Rlog.w(LOG_TAG, "Could not execute USSD " + cse);
                sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
                        wrappedCallback);
            }
        } catch (Exception e) {
            Rlog.d(LOG_TAG, "exception" + e);
            Rlog.w(LOG_TAG, "Could not execute USSD " + e);
            sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
                    wrappedCallback);
            return false;
        }
        return true;
@@ -580,16 +585,6 @@ public class ImsPhone extends ImsPhoneBase {
        mDefaultPhone.notifyForVideoCapabilityChanged(isVideoCapable);
    }

    protected synchronized boolean addToMMIQueue(ImsPhoneMmiCode mmi) {
        if (mPendingMMIs.size() >= 1) {
            mMMIQueue.offerLast(mmi);
            return true;
        }
        mPendingMMIs.add(mmi);
        mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
        return false;
    }

    @Override
    public Connection
    dial(String dialString, int videoState) throws CallStateException {
@@ -627,9 +622,9 @@ public class ImsPhone extends ImsPhoneBase {
        // Only look at the Network portion for mmi
        String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
        ImsPhoneMmiCode mmi =
                ImsPhoneMmiCode.newFromDialString(networkPortion, this);
                ImsPhoneMmiCode.newFromDialString(networkPortion, this, wrappedCallback);
        if (DBG) Rlog.d(LOG_TAG,
                "dialing w/ mmi '" + mmi + "'...");
                "dialInternal: dialing w/ mmi '" + mmi + "'...");

        if (mmi == null) {
            return mCT.dial(dialString, videoState, intentExtras);
@@ -638,25 +633,30 @@ public class ImsPhone extends ImsPhoneBase {
        } else if (!mmi.isSupportedOverImsPhone()) {
            // If the mmi is not supported by IMS service,
            // try to initiate dialing with default phone
            // Note: This code is never reached; there is a bug in isSupportedOverImsPhone which
            // causes it to return true even though the "processCode" method ultimately throws the
            // exception.
            Rlog.i(LOG_TAG, "dialInternal: USSD not supported by IMS; fallback to CS.");
            throw new CallStateException(CS_FALLBACK);
        } else {
            return dialInternal(mmi);
        }
    }
            mPendingMMIs.add(mmi);
            mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));

    protected Connection dialInternal(ImsPhoneMmiCode mmi) {
        if (addToMMIQueue(mmi)) {
            return null;
        }
            try {
                mmi.processCode();
        } catch (CallStateException e) {
            //do nothing
            } catch (CallStateException cse) {
                if (CS_FALLBACK.equals(cse.getMessage())) {
                    Rlog.i(LOG_TAG, "dialInternal: fallback to GSM required.");
                    // Make sure we remove from the list of pending MMIs since it will handover to
                    // GSM.
                    mPendingMMIs.remove(mmi);
                    throw cse;
                }
            }

        // FIXME should this return null or something else?
            return null;
        }
    }

    @Override
    public void
@@ -1087,15 +1087,6 @@ public class ImsPhone extends ImsPhoneBase {
                        isUssdRequest,
                        this);
                onNetworkInitiatedUssd(mmi);
        } else {
            if (mMMIQueue.peek() != null) {
                try {

                    dialInternal(mMMIQueue.remove());
                } catch (Exception e) {
                    Rlog.d(LOG_TAG,"Exception:" + e);
                }
            }
        }
    }

Loading