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

Commit a3659232 authored by Wink Saville's avatar Wink Saville
Browse files

Fix bug 2040024 phone rings only once sometimes.

The phone only rang once on rings that did't loop. In the GSM phones
the vendor ril sends a RIL_UNSOL_CALL_RING event to cause the phone
to properly play non-looping ring tones. To reproduce select a non-looping
ring tone such as "Digital Phone" and call it from another phone, the
phone will only ring once.

Three solutions were discussed:

*) Have all ring tones loop; rejected because to more space would be taken
by the silence.

*) Require all vendor RIL's to send RIL_UNSOL_CALL_RING; rejected because
it is inefficient to send a notification from the bottom of the stack.

*) Modify the PhoneApp or the audio layer; rejected because it would be
to big of change.

*) Modify the framework; this is the solution accepted.

The framework was modified to use two now properties to control the
call ring notification.

ro.telephony.multiple_call_ring: a boolean that if true the vendor ril
is assumed to send multiple RIL_UNSOL_CALL_RING messages. If false
only one is assumed and the framework will generate additional events.
(The default if absent is true).

ro.telephony.call_ring_delay: the delay in milli-seconds between
the generated events. (default if absent is 3000)

To minimize code duplication this change does some reorganization
of the PhoneBase class hierarchy and PhoneBase becomes a handler
and implements a default handleMessage method handles events associated
with call ring notification. This handler is overridden by derived
classes, CDMAPhone and GSMPhone which will pass unknown events
to PhoneBase.handleMessage and thus handle call notification for any
derived class.

Change-Id: I5b147b2b69b647d9987052f16ada41c9b66e4bf1
parent 6d45accc
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1388,7 +1388,7 @@ public interface Phone {
     */
    String getIccSerialNumber();

    //***** CDMA support methods
    /* CDMA support methods */

    /*
     * TODO(Moto) TODO(Teleca): can getCdmaMin, getEsn, getMeid use more generic calls
+131 −31
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import android.os.SystemProperties;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.text.TextUtils;
import android.util.Log;

@@ -55,7 +54,7 @@ import java.util.Locale;
 *
 */

public abstract class PhoneBase implements Phone {
public abstract class PhoneBase extends Handler implements Phone {
    private static final String LOG_TAG = "PHONE";
    private static final boolean LOCAL_DEBUG = true;

@@ -68,7 +67,7 @@ public abstract class PhoneBase implements Phone {
    // Key used to read/write "disable data connection on boot" pref (used for testing)
    public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key";

    //***** Event Constants
    /* Event Constants */
    protected static final int EVENT_RADIO_AVAILABLE             = 1;
    /** Supplementary Service Notification received. */
    protected static final int EVENT_SSN                         = 2;
@@ -84,20 +83,22 @@ public abstract class PhoneBase implements Phone {
    protected static final int EVENT_SET_CALL_FORWARD_DONE       = 12;
    protected static final int EVENT_GET_CALL_FORWARD_DONE       = 13;
    protected static final int EVENT_CALL_RING                   = 14;
    protected static final int EVENT_CALL_RING_CONTINUE          = 15;

    // Used to intercept the carrier selection calls so that
    // we can save the values.
    protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE    = 15;
    protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 16;
    protected static final int EVENT_SET_CLIR_COMPLETE              = 17;
    protected static final int EVENT_REGISTERED_TO_NETWORK          = 18;
    protected static final int EVENT_SET_VM_NUMBER_DONE             = 19;
    protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE    = 16;
    protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 17;
    protected static final int EVENT_SET_CLIR_COMPLETE              = 18;
    protected static final int EVENT_REGISTERED_TO_NETWORK          = 19;
    protected static final int EVENT_SET_VM_NUMBER_DONE             = 20;
    // Events for CDMA support
    protected static final int EVENT_GET_DEVICE_IDENTITY_DONE       = 20;
    protected static final int EVENT_RUIM_RECORDS_LOADED            = 21;
    protected static final int EVENT_NV_READY                       = 22;
    protected static final int EVENT_SET_ENHANCED_VP                = 23;
    protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER  = 24;
    protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 25;
    protected static final int EVENT_GET_DEVICE_IDENTITY_DONE       = 21;
    protected static final int EVENT_RUIM_RECORDS_LOADED            = 22;
    protected static final int EVENT_NV_READY                       = 23;
    protected static final int EVENT_SET_ENHANCED_VP                = 24;
    protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER  = 25;
    protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 26;

    // Key used to read/write current CLIR setting
    public static final String CLIR_KEY = "clir_key";
@@ -105,11 +106,14 @@ public abstract class PhoneBase implements Phone {
    // Key used to read/write "disable DNS server check" pref (used for testing)
    public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key";

    //***** Instance Variables
    /* Instance Variables */
    public CommandsInterface mCM;
    protected IccFileHandler mIccFileHandler;
    boolean mDnsCheckDisabled = false;
    public DataConnectionTracker mDataConnection;
    boolean mDoesRilSendMultipleCallRing;
    int mCallRingContinueToken = 0;
    int mCallRingDelay;

    /**
     * Set a system property, unless we're in unit test mode
@@ -172,8 +176,8 @@ public abstract class PhoneBase implements Phone {
     * @param notifier An instance of DefaultPhoneNotifier,
     * unless unit testing.
     */
    protected PhoneBase(PhoneNotifier notifier, Context context) {
        this(notifier, context, false);
    protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci) {
        this(notifier, context, ci, false);
    }

    /**
@@ -185,11 +189,12 @@ public abstract class PhoneBase implements Phone {
     * @param unitTestMode when true, prevents notifications
     * of state change events
     */
    protected PhoneBase(PhoneNotifier notifier, Context context,
    protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci,
            boolean unitTestMode) {
        this.mNotifier = notifier;
        this.mContext = context;
        mLooper = Looper.myLooper();
        mCM = ci;

        setPropertiesByCarrier();

@@ -197,6 +202,70 @@ public abstract class PhoneBase implements Phone {

        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
        mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);
        mCM.setOnCallRing(this, EVENT_CALL_RING, null);

        /**
         *  Some RIL's don't always send RIL_UNSOL_CALL_RING so it needs
         *  to be generated locally. Ideally all ring tones should be loops
         * and this wouldn't be necessary. But to minimize changes to upper
         * layers it is requested that it be generated by lower layers.
         *
         * By default old phones won't have the property set but do generate
         * the RIL_UNSOL_CALL_RING so the default if there is no property is
         * true.
         */
        mDoesRilSendMultipleCallRing = SystemProperties.getBoolean(
                TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true);
        Log.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);

        mCallRingDelay = SystemProperties.getInt(
                TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000);
        Log.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);
    }

    public void dispose() {
        synchronized(PhoneProxy.lockForRadioTechnologyChange) {
            mCM.unSetOnCallRing(this);
        }
    }

    /**
     * When overridden the derived class needs to call
     * super.handleMessage(msg) so this method has a
     * a chance to process the message.
     *
     * @param msg
     */
    @Override
    public void handleMessage(Message msg) {
        AsyncResult ar;

        switch(msg.what) {
            case EVENT_CALL_RING:
                Log.d(LOG_TAG, "Event EVENT_CALL_RING Received state=" + getState());
                ar = (AsyncResult)msg.obj;
                if (ar.exception == null) {
                    Phone.State state = getState();
                    if ((!mDoesRilSendMultipleCallRing)
                            && ((state == Phone.State.RINGING) || (state == Phone.State.IDLE))) {
                        mCallRingContinueToken += 1;
                        sendIncomingCallRingNotification(mCallRingContinueToken);
                    } else {
                        notifyIncomingRing();
                    }
                }
                break;

            case EVENT_CALL_RING_CONTINUE:
                Log.d(LOG_TAG, "Event EVENT_CALL_RING_CONTINUE Received stat=" + getState());
                if (getState() == Phone.State.RINGING) {
                    sendIncomingCallRingNotification(msg.arg1);
                }
                break;

            default:
                throw new RuntimeException("unexpected event not handled");
        }
    }

    // Inherited documentation suffices.
@@ -290,16 +359,6 @@ public abstract class PhoneBase implements Phone {
        mCM.unregisterForInCallVoicePrivacyOff(h);
    }

    /**
     * Notifiy registrants of a new ringing Connection.
     * Subclasses of Phone probably want to replace this with a
     * version scoped to their packages
     */
    protected void notifyNewRingingConnectionP(Connection cn) {
        AsyncResult ar = new AsyncResult(null, cn, null);
        mNewRingingConnectionRegistrants.notifyRegistrants(ar);
    }

    // Inherited documentation suffices.
    public void registerForIncomingRing(
            Handler h, int what, Object obj) {
@@ -553,16 +612,22 @@ public abstract class PhoneBase implements Phone {
        }
    }

    /*
     * Retrieves the Handler of the Phone instance
    /**
     * Get state
     */
    public abstract Handler getHandler();
    public abstract Phone.State getState();

    /**
     * Retrieves the IccFileHandler of the Phone instance
     */
    public abstract IccFileHandler getIccFileHandler();

    /*
     * Retrieves the Handler of the Phone instance
     */
    public Handler getHandler() {
        return this;
    }

    /**
     *  Query the status of the CDMA roaming preference
@@ -902,4 +967,39 @@ public abstract class PhoneBase implements Phone {
        mDataConnection.setState(dcState);
        notifyDataConnection(null);
    }

    /**
     * Notifiy registrants of a new ringing Connection.
     * Subclasses of Phone probably want to replace this with a
     * version scoped to their packages
     */
    protected void notifyNewRingingConnectionP(Connection cn) {
        AsyncResult ar = new AsyncResult(null, cn, null);
        mNewRingingConnectionRegistrants.notifyRegistrants(ar);
    }

    /**
     * Notify registrants of a RING event.
     */
    private void notifyIncomingRing() {
        AsyncResult ar = new AsyncResult(null, this, null);
        mIncomingRingRegistrants.notifyRegistrants(ar);
    }

    /**
     * Send the incoming call Ring notification if conditions are right.
     */
    private void sendIncomingCallRingNotification(int token) {
        if (!mDoesRilSendMultipleCallRing && (token == mCallRingContinueToken)) {
            Log.d(LOG_TAG, "Sending notifyIncomingRing");
            notifyIncomingRing();
            sendMessageDelayed(
                    obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay);
        } else {
            Log.d(LOG_TAG, "Ignoring ring notification request,"
                    + " mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing
                    + " token=" + token
                    + " mCallRingContinueToken=" + mCallRingContinueToken);
        }
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -120,4 +120,14 @@ public interface TelephonyProperties
     */
    static final String PROPERTY_DISABLE_CALL = "ro.telephony.disable-call";

    /**
     * Set to true for vendor RIL's that send multiple UNSOL_CALL_RING notifications.
     */
    static final String PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING =
        "ro.telephony.call_ring.multiple";

    /**
     * The number of milli-seconds between CALL_RING notifications.
     */
    static final String PROPERTY_CALL_RING_DELAY = "ro.telephony.call_ring.delay";
}
+107 −145
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import android.database.SQLException;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
@@ -35,7 +34,6 @@ import android.os.RegistrantList;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.provider.Telephony;
import android.telephony.CellLocation;
import android.telephony.PhoneNumberUtils;
@@ -96,20 +94,20 @@ public class CDMAPhone extends PhoneBase {
    static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
    static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer

    //***** Instance Variables
    // Instance Variables
    CdmaCallTracker mCT;
    CdmaSMSDispatcher mSMS;
    CdmaServiceStateTracker mSST;
    RuimFileHandler mRuimFileHandler;
    RuimRecords mRuimRecords;
    RuimCard mRuimCard;
    MyHandler h;
    RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager;
    RuimSmsInterfaceManager mRuimSmsInterfaceManager;
    PhoneSubInfo mSubInfo;
    EriManager mEriManager;
    WakeLock mWakeLock;


    // mNvLoadedRegistrants are informed after the EVENT_NV_READY
    private RegistrantList mNvLoadedRegistrants = new RegistrantList();

@@ -139,17 +137,14 @@ public class CDMAPhone extends PhoneBase {
    Registrant mPostDialHandler;


    //***** Constructors
    // Constructors
    public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
        this(context,ci,notifier, false);
    }

    public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
            boolean unitTestMode) {
        super(notifier, context, unitTestMode);

        h = new MyHandler();
        mCM = ci;
        super(notifier, context, ci, unitTestMode);

        mCM.setPhoneType(RILConstants.CDMA_PHONE);
        mCT = new CdmaCallTracker(this);
@@ -164,15 +159,14 @@ public class CDMAPhone extends PhoneBase {
        mSubInfo = new PhoneSubInfo(this);
        mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);

        mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null);
        mRuimRecords.registerForRecordsLoaded(h, EVENT_RUIM_RECORDS_LOADED, null);
        mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
        mCM.registerForOn(h, EVENT_RADIO_ON, null);
        mCM.setOnSuppServiceNotification(h, EVENT_SSN, null);
        mCM.setOnCallRing(h, EVENT_CALL_RING, null);
        mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null);
        mCM.registerForNVReady(h, EVENT_NV_READY, null);
        mCM.setEmergencyCallbackMode(h, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
        mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
        mRuimRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
        mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
        mCM.registerForOn(this, EVENT_RADIO_ON, null);
        mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
        mSST.registerForNetworkAttach(this, EVENT_REGISTERED_TO_NETWORK, null);
        mCM.registerForNVReady(this, EVENT_NV_READY, null);
        mCM.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);

        PowerManager pm
            = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -207,23 +201,23 @@ public class CDMAPhone extends PhoneBase {
        // Updates MCC MNC device configuration information
        updateMccMncConfiguration(operatorNumeric);


        // Notify voicemails.
        notifier.notifyMessageWaitingChanged(this);
    }

    public void dispose() {
        synchronized(PhoneProxy.lockForRadioTechnologyChange) {
            super.dispose();

            //Unregister from all former registered events
            mRuimRecords.unregisterForRecordsLoaded(h); //EVENT_RUIM_RECORDS_LOADED
            mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE
            mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
            mCM.unregisterForOn(h); //EVENT_RADIO_ON
            mCM.unregisterForNVReady(h); //EVENT_NV_READY
            mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK
            mCM.unSetOnSuppServiceNotification(h);
            mCM.unSetOnCallRing(h);

            mRuimRecords.unregisterForRecordsLoaded(this); //EVENT_RUIM_RECORDS_LOADED
            mCM.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE
            mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
            mCM.unregisterForOn(this); //EVENT_RADIO_ON
            mCM.unregisterForNVReady(this); //EVENT_NV_READY
            mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK
            mCM.unSetOnSuppServiceNotification(this);

            //Force all referenced classes to unregister their former registered events
            mCT.dispose();
@@ -262,8 +256,6 @@ public class CDMAPhone extends PhoneBase {
        }
    }


    //***** Overridden from Phone
    public ServiceState getServiceState() {
        return mSST.ss;
    }
@@ -701,7 +693,7 @@ public class CDMAPhone extends PhoneBase {
                                   Message onComplete) {
        Message resp;
        mVmNumber = voiceMailNumber;
        resp = h.obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
        resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
        mRuimRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
    }

@@ -826,14 +818,6 @@ public class CDMAPhone extends PhoneBase {
        super.notifyNewRingingConnectionP(c);
    }

    /**
     * Notifiy registrants of a RING event.
     */
    void notifyIncomingRing() {
        AsyncResult ar = new AsyncResult(null, this, null);
        mIncomingRingRegistrants.notifyRegistrants(ar);
    }

    /*package*/ void notifyDisconnect(Connection cn) {
        mDisconnectRegistrants.notifyResult(cn);
    }
@@ -883,7 +867,7 @@ public class CDMAPhone extends PhoneBase {
            mWakeLock.release();
        }
        // Send a message which will invoke handleExitEmergencyCallbackMode
        mCM.exitEmergencyCallbackMode(h.obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
        mCM.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
    }

    private void handleEnterEmergencyCallbackMode(Message msg) {
@@ -902,7 +886,7 @@ public class CDMAPhone extends PhoneBase {
            // if no one invokes exitEmergencyCallbackMode() directly.
            long delayInMillis = SystemProperties.getLong(
                    TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
            h.postDelayed(mExitEcmRunnable, delayInMillis);
            postDelayed(mExitEcmRunnable, delayInMillis);
            // We don't want to go to sleep while in Ecm
            mWakeLock.acquire();
        }
@@ -915,7 +899,7 @@ public class CDMAPhone extends PhoneBase {
                    + ar.exception + mIsPhoneInEcmState);
        }
        // Remove pending exit Ecm runnable, if any
        h.removeCallbacks(mExitEcmRunnable);
        removeCallbacks(mExitEcmRunnable);

        if (mEcmExitRespRegistrant != null) {
            mEcmExitRespRegistrant.notifyRegistrant(ar);
@@ -941,13 +925,13 @@ public class CDMAPhone extends PhoneBase {
    void handleTimerInEmergencyCallbackMode(int action) {
        switch(action) {
        case CANCEL_ECM_TIMER:
            h.removeCallbacks(mExitEcmRunnable);
            removeCallbacks(mExitEcmRunnable);
            mEcmTimerResetRegistrants.notifyResult(new Boolean(true));
            break;
        case RESTART_ECM_TIMER:
            long delayInMillis = SystemProperties.getLong(
                    TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
            h.postDelayed(mExitEcmRunnable, delayInMillis);
            postDelayed(mExitEcmRunnable, delayInMillis);
            mEcmTimerResetRegistrants.notifyResult(new Boolean(false));
            break;
        default:
@@ -969,15 +953,6 @@ public class CDMAPhone extends PhoneBase {
        mEcmTimerResetRegistrants.remove(h);
    }

    //***** Inner Classes
    class MyHandler extends Handler {
        MyHandler() {
        }

        MyHandler(Looper l) {
            super(l);
        }

    @Override
    public void handleMessage(Message msg) {
        AsyncResult ar;
@@ -1045,11 +1020,6 @@ public class CDMAPhone extends PhoneBase {
            }
            break;

                case EVENT_CALL_RING:{
                    Log.d(LOG_TAG, "Event EVENT_CALL_RING Received");
                }
                break;

            case EVENT_REGISTERED_TO_NETWORK:{
                Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received");
            }
@@ -1084,8 +1054,7 @@ public class CDMAPhone extends PhoneBase {
            break;

            default:{
                    throw new RuntimeException("unexpected event not handled");
                }
                super.handleMessage(msg);
            }
        }
    }
@@ -1137,13 +1106,6 @@ public class CDMAPhone extends PhoneBase {
        super.setSystemProperty(property, value);
    }

    /**
     * {@inheritDoc}
     */
    public Handler getHandler() {
        return h;
    }

    /**
     * {@inheritDoc}
     */
+4 −2
Original line number Diff line number Diff line
@@ -146,7 +146,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
    };


    //***** Constructor
    /* Constructor */

    CdmaDataConnectionTracker(CDMAPhone p) {
        super(p);
@@ -174,7 +174,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);

        p.getContext().registerReceiver(mIntentReceiver, filter, null, p.h);
        // TODO: Why is this registering the phone as the receiver of the intent
        //       and not its own handler?
        p.getContext().registerReceiver(mIntentReceiver, filter, null, p);

        mDataConnectionTracker = this;

Loading