Merge changes from topic "ims_apis"
am: de65acb915

Change-Id: I717387907dde9f10fd61bbeb20e3533aeaeab220
diff --git a/api/system-current.txt b/api/system-current.txt
index c99eaf1..97e8264 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4721,6 +4721,7 @@
   }
 
   public final class ImsSuppServiceNotification implements android.os.Parcelable {
+    ctor public ImsSuppServiceNotification(int, int, int, int, java.lang.String, java.lang.String[]);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.ims.ImsSuppServiceNotification> CREATOR;
@@ -4788,7 +4789,6 @@
   public abstract class ImsFeature {
     ctor public ImsFeature();
     method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
-    method public final int getFeatureState();
     method public abstract void onFeatureReady();
     method public abstract void onFeatureRemoved();
     method public final void setFeatureState(int);
@@ -4817,10 +4817,12 @@
     method public android.telephony.ims.stub.ImsUtImplBase getUt();
     method public final void notifyCapabilitiesStatusChanged(android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
     method public final void notifyIncomingCall(android.telephony.ims.stub.ImsCallSessionImplBase, android.os.Bundle);
+    method public final void notifyVoiceMessageCountUpdate(int);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
     method public boolean queryCapabilityConfiguration(int, int);
     method public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
+    method public void setUiTtyMode(int, android.os.Message);
     method public int shouldProcessCall(java.lang.String[]);
     field public static final int PROCESS_CALL_CSFB = 1; // 0x1
     field public static final int PROCESS_CALL_EMERGENCY_CSFB = 2; // 0x2
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 52a6ab9..7b77491 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -421,13 +421,13 @@
 
     // For main reason code
     /** @hide */
-    public final int mCode;
+    public int mCode;
     // For the extra code value; it depends on the code value.
     /** @hide */
-    public final int mExtraCode;
+    public int mExtraCode;
     // For the additional message of the reason info.
     /** @hide */
-    public final String mExtraMessage;
+    public String mExtraMessage;
 
     /** @hide */
     public ImsReasonInfo() {
diff --git a/telephony/java/android/telephony/ims/ImsSuppServiceNotification.java b/telephony/java/android/telephony/ims/ImsSuppServiceNotification.java
index e6f6f1b..efaade8 100644
--- a/telephony/java/android/telephony/ims/ImsSuppServiceNotification.java
+++ b/telephony/java/android/telephony/ims/ImsSuppServiceNotification.java
@@ -46,6 +46,17 @@
     /** List of forwarded numbers, if any */
     public final String[] history;
 
+
+    public ImsSuppServiceNotification(int notificationType, int code, int index, int type,
+            String number, String[] history) {
+        this.notificationType = notificationType;
+        this.code = code;
+        this.index = index;
+        this.type = type;
+        this.number = number;
+        this.history = history;
+    }
+
     /** @hide */
     public ImsSuppServiceNotification(Parcel in) {
         notificationType = in.readInt();
diff --git a/telephony/java/android/telephony/ims/compat/feature/MMTelFeature.java b/telephony/java/android/telephony/ims/compat/feature/MMTelFeature.java
index 7a1b1b2..d3d17f4 100644
--- a/telephony/java/android/telephony/ims/compat/feature/MMTelFeature.java
+++ b/telephony/java/android/telephony/ims/compat/feature/MMTelFeature.java
@@ -22,6 +22,7 @@
 
 import android.telephony.ims.ImsCallProfile;
 import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
 import com.android.ims.internal.IImsConfig;
 import com.android.ims.internal.IImsEcbm;
 import com.android.ims.internal.IImsMMTelFeature;
@@ -29,6 +30,10 @@
 import com.android.ims.internal.IImsRegistrationListener;
 import com.android.ims.internal.IImsUt;
 import android.telephony.ims.ImsCallSession;
+import android.telephony.ims.compat.stub.ImsCallSessionImplBase;
+import android.telephony.ims.stub.ImsEcbmImplBase;
+import android.telephony.ims.stub.ImsMultiEndpointImplBase;
+import android.telephony.ims.stub.ImsUtImplBase;
 
 /**
  * Base implementation for MMTel.
@@ -110,7 +115,7 @@
         public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile)
                 throws RemoteException {
             synchronized (mLock) {
-                return MMTelFeature.this.createCallSession(sessionId, profile);
+                return MMTelFeature.this.createCallSession(sessionId, profile, null);
             }
         }
 
@@ -125,7 +130,8 @@
         @Override
         public IImsUt getUtInterface() throws RemoteException {
             synchronized (mLock) {
-                return MMTelFeature.this.getUtInterface();
+                ImsUtImplBase implBase = MMTelFeature.this.getUtInterface();
+                return implBase != null ? implBase.getInterface() : null;
             }
         }
 
@@ -153,7 +159,8 @@
         @Override
         public IImsEcbm getEcbmInterface() throws RemoteException {
             synchronized (mLock) {
-                return MMTelFeature.this.getEcbmInterface();
+                ImsEcbmImplBase implBase = MMTelFeature.this.getEcbmInterface();
+                return implBase != null ? implBase.getImsEcbm() : null;
             }
         }
 
@@ -167,7 +174,8 @@
         @Override
         public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
             synchronized (mLock) {
-                return MMTelFeature.this.getMultiEndpointInterface();
+                ImsMultiEndpointImplBase implBase = MMTelFeature.this.getMultiEndpointInterface();
+                return implBase != null ? implBase.getIImsMultiEndpoint() : null;
             }
         }
     };
@@ -281,7 +289,8 @@
      * @param sessionId a session id which is obtained from {@link #startSession}
      * @param profile a call profile to make the call
      */
-    public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile) {
+    public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+            IImsCallSessionListener listener) {
         return null;
     }
 
@@ -298,7 +307,7 @@
     /**
      * @return The Ut interface for the supplementary service configuration.
      */
-    public IImsUt getUtInterface() {
+    public ImsUtImplBase getUtInterface() {
         return null;
     }
 
@@ -324,7 +333,7 @@
     /**
      * @return The Emergency call-back mode interface for emergency VoLTE calls that support it.
      */
-    public IImsEcbm getEcbmInterface() {
+    public ImsEcbmImplBase getEcbmInterface() {
         return null;
     }
 
@@ -339,7 +348,7 @@
     /**
      * @return MultiEndpoint interface for DEP notifications
      */
-    public IImsMultiEndpoint getMultiEndpointInterface() {
+    public ImsMultiEndpointImplBase getMultiEndpointInterface() {
         return null;
     }
 
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
index 48a5a75..00cb1e2 100644
--- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
@@ -16,16 +16,18 @@
 
 package android.telephony.ims.compat.stub;
 
+import android.os.Message;
 import android.os.RemoteException;
-import android.telephony.ims.ImsCallSessionListener;
 
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsConferenceState;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsStreamMediaProfile;
 import android.telephony.ims.ImsSuppServiceNotification;
+import android.telephony.ims.aidl.IImsCallSessionListener;
 import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsVideoCallProvider;
+
 import android.telephony.ims.ImsCallSession;
 
 /**
@@ -37,10 +39,12 @@
  * @hide
  */
 
-public class ImsCallSessionImplBase extends android.telephony.ims.stub.ImsCallSessionImplBase {
+public class ImsCallSessionImplBase extends IImsCallSession.Stub {
 
     @Override
-    public final void setListener(ImsCallSessionListener listener) {
+    // convert to old implementation of listener
+    public final void setListener(IImsCallSessionListener listener)
+            throws RemoteException {
         setListener(new ImsCallSessionListenerConverter(listener));
     }
 
@@ -51,21 +55,326 @@
      *
      * @param listener to listen to the session events of this object
      */
-    public void setListener(IImsCallSessionListener listener) {
+    public void setListener(com.android.ims.internal.IImsCallSessionListener listener) {
 
     }
 
     /**
+     * Closes the object. This {@link ImsCallSessionImplBase} is not usable after being closed.
+     */
+    @Override
+    public void close() {
+
+    }
+
+    /**
+     * @return A String containing the unique call ID of this {@link ImsCallSessionImplBase}.
+     */
+    @Override
+    public String getCallId() {
+        return null;
+    }
+
+    /**
+     * @return The {@link ImsCallProfile} that this {@link ImsCallSessionImplBase} is associated
+     * with.
+     */
+    @Override
+    public ImsCallProfile getCallProfile() {
+        return null;
+    }
+
+    /**
+     * @return The local {@link ImsCallProfile} that this {@link ImsCallSessionImplBase} is
+     * associated with.
+     */
+    @Override
+    public ImsCallProfile getLocalCallProfile() {
+        return null;
+    }
+
+    /**
+     * @return The remote {@link ImsCallProfile} that this {@link ImsCallSessionImplBase} is
+     * associated with.
+     */
+    @Override
+    public ImsCallProfile getRemoteCallProfile() {
+        return null;
+    }
+
+    /**
+     * @param name The String extra key.
+     * @return The string extra value associated with the specified property.
+     */
+    @Override
+    public String getProperty(String name) {
+        return null;
+    }
+
+    /**
+     * @return The {@link ImsCallSessionImplBase} state.
+     */
+    @Override
+    public int getState() {
+        return -1;
+    }
+
+    /**
+     * @return true if the {@link ImsCallSessionImplBase} is in a call, false otherwise.
+     */
+    @Override
+    public boolean isInCall() {
+        return false;
+    }
+
+    /**
+     * Mutes or unmutes the mic for the active call.
+     *
+     * @param muted true if the call should be muted, false otherwise.
+     */
+    @Override
+    public void setMute(boolean muted) {
+    }
+
+    /**
+     * Initiates an IMS call with the specified number and call profile.
+     * The session listener set in {@link #setListener(IImsCallSessionListener)} is called back upon
+     * defined session events.
+     * Only valid to call when the session state is in
+     * {@link ImsCallSession.State#IDLE}.
+     *
+     * @param callee dialed string to make the call to
+     * @param profile call profile to make the call with the specified service type,
+     *      call type and media information
+     * @see {@link ImsCallSession.Listener#callSessionStarted},
+     * {@link ImsCallSession.Listener#callSessionStartFailed}
+     */
+    @Override
+    public void start(String callee, ImsCallProfile profile) {
+    }
+
+    /**
+     * Initiates an IMS call with the specified participants and call profile.
+     * The session listener set in {@link #setListener(IImsCallSessionListener)} is called back upon
+     * defined session events.
+     * The method is only valid to call when the session state is in
+     * {@link ImsCallSession.State#IDLE}.
+     *
+     * @param participants participant list to initiate an IMS conference call
+     * @param profile call profile to make the call with the specified service type,
+     *      call type and media information
+     * @see {@link ImsCallSession.Listener#callSessionStarted},
+     * {@link ImsCallSession.Listener#callSessionStartFailed}
+     */
+    @Override
+    public void startConference(String[] participants, ImsCallProfile profile) {
+    }
+
+    /**
+     * Accepts an incoming call or session update.
+     *
+     * @param callType call type specified in {@link ImsCallProfile} to be answered
+     * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered
+     * @see {@link ImsCallSession.Listener#callSessionStarted}
+     */
+    @Override
+    public void accept(int callType, ImsStreamMediaProfile profile) {
+    }
+
+    /**
+     * Rejects an incoming call or session update.
+     *
+     * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}.
+     * {@link ImsCallSession.Listener#callSessionStartFailed}
+     */
+    @Override
+    public void reject(int reason) {
+    }
+
+    /**
+     * Terminates a call.
+     *
+     * @param reason reason code to terminate a call, defined in {@link ImsReasonInfo}.
+     *
+     * @see {@link ImsCallSession.Listener#callSessionTerminated}
+     */
+    @Override
+    public void terminate(int reason) {
+    }
+
+    /**
+     * Puts a call on hold. When it succeeds, {@link ImsCallSession.Listener#callSessionHeld} is
+     * called.
+     *
+     * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call
+     * @see {@link ImsCallSession.Listener#callSessionHeld},
+     * {@link ImsCallSession.Listener#callSessionHoldFailed}
+     */
+    @Override
+    public void hold(ImsStreamMediaProfile profile) {
+    }
+
+    /**
+     * Continues a call that's on hold. When it succeeds,
+     * {@link ImsCallSession.Listener#callSessionResumed} is called.
+     *
+     * @param profile stream media profile with {@link ImsStreamMediaProfile} to resume the call
+     * @see {@link ImsCallSession.Listener#callSessionResumed},
+     * {@link ImsCallSession.Listener#callSessionResumeFailed}
+     */
+    @Override
+    public void resume(ImsStreamMediaProfile profile) {
+    }
+
+    /**
+     * Merges the active and held call. When the merge starts,
+     * {@link ImsCallSession.Listener#callSessionMergeStarted} is called.
+     * {@link ImsCallSession.Listener#callSessionMergeComplete} is called if the merge is
+     * successful, and {@link ImsCallSession.Listener#callSessionMergeFailed} is called if the merge
+     * fails.
+     *
+     * @see {@link ImsCallSession.Listener#callSessionMergeStarted},
+     * {@link ImsCallSession.Listener#callSessionMergeComplete},
+     *      {@link ImsCallSession.Listener#callSessionMergeFailed}
+     */
+    @Override
+    public void merge() {
+    }
+
+    /**
+     * Updates the current call's properties (ex. call mode change: video upgrade / downgrade).
+     *
+     * @param callType call type specified in {@link ImsCallProfile} to be updated
+     * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated
+     * @see {@link ImsCallSession.Listener#callSessionUpdated},
+     * {@link ImsCallSession.Listener#callSessionUpdateFailed}
+     */
+    @Override
+    public void update(int callType, ImsStreamMediaProfile profile) {
+    }
+
+    /**
+     * Extends this call to the conference call with the specified recipients.
+     *
+     * @param participants participant list to be invited to the conference call after extending the
+     * call
+     * @see {@link ImsCallSession.Listener#callSessionConferenceExtended},
+     * {@link ImsCallSession.Listener#callSessionConferenceExtendFailed}
+     */
+    @Override
+    public void extendToConference(String[] participants) {
+    }
+
+    /**
+     * Requests the conference server to invite an additional participants to the conference.
+     *
+     * @param participants participant list to be invited to the conference call
+     * @see {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestDelivered},
+     *      {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestFailed}
+     */
+    @Override
+    public void inviteParticipants(String[] participants) {
+    }
+
+    /**
+     * Requests the conference server to remove the specified participants from the conference.
+     *
+     * @param participants participant list to be removed from the conference call
+     * @see {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestDelivered},
+     *      {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestFailed}
+     */
+    @Override
+    public void removeParticipants(String[] participants) {
+    }
+
+    /**
+     * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+     * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+     * and event flash to 16. Currently, event flash is not supported.
+     *
+     * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+     */
+    @Override
+    public void sendDtmf(char c, Message result) {
+    }
+
+    /**
+     * Start a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+     * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+     * and event flash to 16. Currently, event flash is not supported.
+     *
+     * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+     */
+    @Override
+    public void startDtmf(char c) {
+    }
+
+    /**
+     * Stop a DTMF code.
+     */
+    @Override
+    public void stopDtmf() {
+    }
+
+    /**
+     * Sends an USSD message.
+     *
+     * @param ussdMessage USSD message to send
+     */
+    @Override
+    public void sendUssd(String ussdMessage) {
+    }
+
+    @Override
+    public IImsVideoCallProvider getVideoCallProvider() {
+        return null;
+    }
+
+    /**
+     * Determines if the current session is multiparty.
+     * @return {@code True} if the session is multiparty.
+     */
+    @Override
+    public boolean isMultiparty() {
+        return false;
+    }
+
+    /**
+     * Device issues RTT modify request
+     * @param toProfile The profile with requested changes made
+     */
+    @Override
+    public void sendRttModifyRequest(ImsCallProfile toProfile) {
+    }
+
+    /**
+     * Device responds to Remote RTT modify request
+     * @param status true if the the request was accepted or false of the request is defined.
+     */
+    @Override
+    public void sendRttModifyResponse(boolean status) {
+    }
+
+    /**
+     * Device sends RTT message
+     * @param rttMessage RTT message to be sent
+     */
+    @Override
+    public void sendRttMessage(String rttMessage) {
+    }
+
+    /**
      * There are two different ImsCallSessionListeners that need to reconciled here, we need to
      * convert the "old" version of the com.android.ims.internal.IImsCallSessionListener to the
      * "new" version of the Listener android.telephony.ims.ImsCallSessionListener when calling
      * back to the framework.
      */
-    private class ImsCallSessionListenerConverter extends IImsCallSessionListener.Stub {
+    private class ImsCallSessionListenerConverter
+            extends com.android.ims.internal.IImsCallSessionListener.Stub {
 
-        private final ImsCallSessionListener mNewListener;
+        private final IImsCallSessionListener mNewListener;
 
-        public ImsCallSessionListenerConverter(ImsCallSessionListener listener) {
+        public ImsCallSessionListenerConverter(IImsCallSessionListener listener) {
             mNewListener = listener;
         }
 
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java
index b5417e7..2c325ba8 100644
--- a/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,15 +16,23 @@
 
 package android.telephony.ims.compat.stub;
 
+import android.content.Context;
+import android.content.Intent;
 import android.os.RemoteException;
+import android.util.Log;
 
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsConfigListener;
 import com.android.ims.internal.IImsConfig;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+
 
 /**
- * Base implementation of ImsConfig, which implements stub versions of the methods
- * in the IImsConfig AIDL. Override the methods that your implementation of ImsConfig supports.
+ * Base implementation of ImsConfig.
+ * Override the methods that your implementation of ImsConfig supports.
  *
  * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
  * will break other implementations of ImsConfig maintained by other ImsServices.
@@ -34,10 +42,25 @@
  * 1) Items provisioned by the operator.
  * 2) Items configured by user. Mainly service feature class.
  *
+ * The inner class {@link ImsConfigStub} implements methods of IImsConfig AIDL interface.
+ * The IImsConfig AIDL interface is called by ImsConfig, which may exist in many other processes.
+ * ImsConfigImpl access to the configuration parameters may be arbitrarily slow, especially in
+ * during initialization, or times when a lot of configuration parameters are being set/get
+ * (such as during boot up or SIM card change). By providing a cache in ImsConfigStub, we can speed
+ * up access to these configuration parameters, so a query to the ImsConfigImpl does not have to be
+ * performed every time.
  * @hide
  */
 
-public class ImsConfigImplBase extends IImsConfig.Stub {
+public class ImsConfigImplBase {
+
+    static final private String TAG = "ImsConfigImplBase";
+
+    ImsConfigStub mImsConfigStub;
+
+    public ImsConfigImplBase(Context context) {
+        mImsConfigStub = new ImsConfigStub(this, context);
+    }
 
     /**
      * Gets the value for ims service/capabilities parameters from the provisioned
@@ -46,7 +69,6 @@
      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
      * @return value in Integer format.
      */
-    @Override
     public int getProvisionedValue(int item) throws RemoteException {
         return -1;
     }
@@ -58,7 +80,6 @@
      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
      * @return value in String format.
      */
-    @Override
     public String getProvisionedStringValue(int item) throws RemoteException {
         return null;
     }
@@ -72,7 +93,6 @@
      * @param value in Integer format.
      * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
      */
-    @Override
     public int setProvisionedValue(int item, int value) throws RemoteException {
         return ImsConfig.OperationStatusConstants.FAILED;
     }
@@ -86,7 +106,6 @@
      * @param value in String format.
      * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
      */
-    @Override
     public int setProvisionedStringValue(int item, String value) throws RemoteException {
         return ImsConfig.OperationStatusConstants.FAILED;
     }
@@ -100,7 +119,6 @@
      * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
      * @param listener feature value returned asynchronously through listener.
      */
-    @Override
     public void getFeatureValue(int feature, int network, ImsConfigListener listener)
             throws RemoteException {
     }
@@ -115,7 +133,6 @@
      * @param value as defined in com.android.ims.ImsConfig#FeatureValueConstants.
      * @param listener, provided if caller needs to be notified for set result.
      */
-    @Override
     public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
             throws RemoteException {
     }
@@ -124,7 +141,6 @@
      * Gets the value for IMS VoLTE provisioned.
      * This should be the same as the operator provisioned value if applies.
      */
-    @Override
     public boolean getVolteProvisioned() throws RemoteException {
         return false;
     }
@@ -134,7 +150,6 @@
      *
      * @param listener Video quality value returned asynchronously through listener.
      */
-    @Override
     public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
     }
 
@@ -144,7 +159,233 @@
      * @param quality, defines the value of video quality.
      * @param listener, provided if caller needs to be notified for set result.
      */
-    @Override
     public void setVideoQuality(int quality, ImsConfigListener listener) throws RemoteException {
     }
-}
+
+    public IImsConfig getIImsConfig() { return mImsConfigStub; }
+
+    /**
+     * Updates provisioning value and notifies the framework of the change.
+     * Doesn't call #setProvisionedValue and assumes the result succeeded.
+     * This should only be used by modem when they implicitly changed provisioned values.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @param value in Integer format.
+     */
+    public final void notifyProvisionedValueChanged(int item, int value) {
+        mImsConfigStub.updateCachedValue(item, value, true);
+    }
+
+    /**
+     * Updates provisioning value and notifies the framework of the change.
+     * Doesn't call #setProvisionedValue and assumes the result succeeded.
+     * This should only be used by modem when they implicitly changed provisioned values.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @param value in String format.
+     */
+    public final void notifyProvisionedValueChanged(int item, String value) {
+        mImsConfigStub.updateCachedValue(item, value, true);
+    }
+
+    /**
+     * Implements the IImsConfig AIDL interface, which is called by potentially many processes
+     * in order to get/set configuration parameters.
+     *
+     * It holds an object of ImsConfigImplBase class which is usually extended by ImsConfigImpl
+     * with actual implementations from vendors. This class caches provisioned values from
+     * ImsConfigImpl layer because queries through ImsConfigImpl can be slow. When query goes in,
+     * it first checks cache layer. If missed, it will call the vendor implementation of
+     * ImsConfigImplBase API.
+     * and cache the return value if the set succeeds.
+     *
+     * Provides APIs to get/set the IMS service feature/capability/parameters.
+     * The config items include:
+     * 1) Items provisioned by the operator.
+     * 2) Items configured by user. Mainly service feature class.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    static public class ImsConfigStub extends IImsConfig.Stub {
+        Context mContext;
+        WeakReference<ImsConfigImplBase> mImsConfigImplBaseWeakReference;
+        private HashMap<Integer, Integer> mProvisionedIntValue = new HashMap<>();
+        private HashMap<Integer, String> mProvisionedStringValue = new HashMap<>();
+
+        @VisibleForTesting
+        public ImsConfigStub(ImsConfigImplBase imsConfigImplBase, Context context) {
+            mContext = context;
+            mImsConfigImplBaseWeakReference =
+                    new WeakReference<ImsConfigImplBase>(imsConfigImplBase);
+        }
+
+        /**
+         * Gets the value for ims service/capabilities parameters. It first checks its local cache,
+         * if missed, it will call ImsConfigImplBase.getProvisionedValue.
+         * Synchronous blocking call.
+         *
+         * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+         * @return value in Integer format.
+         */
+        @Override
+        public synchronized int getProvisionedValue(int item) throws RemoteException {
+            if (mProvisionedIntValue.containsKey(item)) {
+                return mProvisionedIntValue.get(item);
+            } else {
+                int retVal = getImsConfigImpl().getProvisionedValue(item);
+                if (retVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
+                    updateCachedValue(item, retVal, false);
+                }
+                return retVal;
+            }
+        }
+
+        /**
+         * Gets the value for ims service/capabilities parameters. It first checks its local cache,
+         * if missed, it will call #ImsConfigImplBase.getProvisionedValue.
+         * Synchronous blocking call.
+         *
+         * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+         * @return value in String format.
+         */
+        @Override
+        public synchronized String getProvisionedStringValue(int item) throws RemoteException {
+            if (mProvisionedIntValue.containsKey(item)) {
+                return mProvisionedStringValue.get(item);
+            } else {
+                String retVal = getImsConfigImpl().getProvisionedStringValue(item);
+                if (retVal != null) {
+                    updateCachedValue(item, retVal, false);
+                }
+                return retVal;
+            }
+        }
+
+        /**
+         * Sets the value for IMS service/capabilities parameters by the operator device
+         * management entity. It sets the config item value in the provisioned storage
+         * from which the master value is derived, and write it into local cache.
+         * Synchronous blocking call.
+         *
+         * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+         * @param value in Integer format.
+         * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+         */
+        @Override
+        public synchronized int setProvisionedValue(int item, int value) throws RemoteException {
+            mProvisionedIntValue.remove(item);
+            int retVal = getImsConfigImpl().setProvisionedValue(item, value);
+            if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
+                updateCachedValue(item, value, true);
+            } else {
+                Log.d(TAG, "Set provision value of " + item +
+                        " to " + value + " failed with error code " + retVal);
+            }
+
+            return retVal;
+        }
+
+        /**
+         * Sets the value for IMS service/capabilities parameters by the operator device
+         * management entity. It sets the config item value in the provisioned storage
+         * from which the master value is derived, and write it into local cache.
+         * Synchronous blocking call.
+         *
+         * @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
+         * @param value in String format.
+         * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+         */
+        @Override
+        public synchronized int setProvisionedStringValue(int item, String value)
+                throws RemoteException {
+            mProvisionedStringValue.remove(item);
+            int retVal = getImsConfigImpl().setProvisionedStringValue(item, value);
+            if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
+                updateCachedValue(item, value, true);
+            }
+
+            return retVal;
+        }
+
+        /**
+         * Wrapper function to call ImsConfigImplBase.getFeatureValue.
+         */
+        @Override
+        public void getFeatureValue(int feature, int network, ImsConfigListener listener)
+                throws RemoteException {
+            getImsConfigImpl().getFeatureValue(feature, network, listener);
+        }
+
+        /**
+         * Wrapper function to call ImsConfigImplBase.setFeatureValue.
+         */
+        @Override
+        public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
+                throws RemoteException {
+            getImsConfigImpl().setFeatureValue(feature, network, value, listener);
+        }
+
+        /**
+         * Wrapper function to call ImsConfigImplBase.getVolteProvisioned.
+         */
+        @Override
+        public boolean getVolteProvisioned() throws RemoteException {
+            return getImsConfigImpl().getVolteProvisioned();
+        }
+
+        /**
+         * Wrapper function to call ImsConfigImplBase.getVideoQuality.
+         */
+        @Override
+        public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
+            getImsConfigImpl().getVideoQuality(listener);
+        }
+
+        /**
+         * Wrapper function to call ImsConfigImplBase.setVideoQuality.
+         */
+        @Override
+        public void setVideoQuality(int quality, ImsConfigListener listener)
+                throws RemoteException {
+            getImsConfigImpl().setVideoQuality(quality, listener);
+        }
+
+        private ImsConfigImplBase getImsConfigImpl() throws RemoteException {
+            ImsConfigImplBase ref = mImsConfigImplBaseWeakReference.get();
+            if (ref == null) {
+                throw new RemoteException("Fail to get ImsConfigImpl");
+            } else {
+                return ref;
+            }
+        }
+
+        private void sendImsConfigChangedIntent(int item, int value) {
+            sendImsConfigChangedIntent(item, Integer.toString(value));
+        }
+
+        private void sendImsConfigChangedIntent(int item, String value) {
+            Intent configChangedIntent = new Intent(ImsConfig.ACTION_IMS_CONFIG_CHANGED);
+            configChangedIntent.putExtra(ImsConfig.EXTRA_CHANGED_ITEM, item);
+            configChangedIntent.putExtra(ImsConfig.EXTRA_NEW_VALUE, value);
+            if (mContext != null) {
+                mContext.sendBroadcast(configChangedIntent);
+            }
+        }
+
+        protected synchronized void updateCachedValue(int item, int value, boolean notifyChange) {
+            mProvisionedIntValue.put(item, value);
+            if (notifyChange) {
+                sendImsConfigChangedIntent(item, value);
+            }
+        }
+
+        protected synchronized void updateCachedValue(
+                int item, String value, boolean notifyChange) {
+            mProvisionedStringValue.put(item, value);
+            if (notifyChange) {
+                sendImsConfigChangedIntent(item, value);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index a23ce63..bfdd453 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -363,8 +363,9 @@
     /**
      * @return The current state of the feature, defined as {@link #STATE_UNAVAILABLE},
      * {@link #STATE_INITIALIZING}, or {@link #STATE_READY}.
+     * @hide
      */
-    public final int getFeatureState() {
+    public int getFeatureState() {
         synchronized (mLock) {
             return mState;
         }
@@ -489,7 +490,7 @@
      */
     @VisibleForTesting
     public final void requestChangeEnabledCapabilities(CapabilityChangeRequest request,
-            IImsCapabilityCallback c) throws RemoteException {
+            IImsCapabilityCallback c) {
         if (request == null) {
             throw new IllegalArgumentException(
                     "ImsFeature#requestChangeEnabledCapabilities called with invalid params.");
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 2baf076..09267fc 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -70,7 +70,11 @@
         @Override
         public int getFeatureState() throws RemoteException {
             synchronized (mLock) {
-                return MmTelFeature.this.getFeatureState();
+                try {
+                    return MmTelFeature.this.getFeatureState();
+                } catch (Exception e) {
+                    throw new RemoteException(e.getMessage());
+                }
             }
         }
 
@@ -79,15 +83,18 @@
         public ImsCallProfile createCallProfile(int callSessionType, int callType)
                 throws RemoteException {
             synchronized (mLock) {
-                return MmTelFeature.this.createCallProfile(callSessionType,  callType);
+                try {
+                    return MmTelFeature.this.createCallProfile(callSessionType, callType);
+                } catch (Exception e) {
+                    throw new RemoteException(e.getMessage());
+                }
             }
         }
 
         @Override
         public IImsCallSession createCallSession(ImsCallProfile profile) throws RemoteException {
             synchronized (mLock) {
-                ImsCallSessionImplBase s = MmTelFeature.this.createCallSession(profile);
-                return s != null ? s.getServiceImpl() : null;
+                return createCallSessionInterface(profile);
             }
         }
 
@@ -101,30 +108,32 @@
         @Override
         public IImsUt getUtInterface() throws RemoteException {
             synchronized (mLock) {
-                return MmTelFeature.this.getUt().getInterface();
+                return MmTelFeature.this.getUtInterface();
             }
         }
 
         @Override
         public IImsEcbm getEcbmInterface() throws RemoteException {
             synchronized (mLock) {
-                ImsEcbmImplBase ecbm = MmTelFeature.this.getEcbm();
-                return ecbm != null ? ecbm.getImsEcbm() : null;
+                return MmTelFeature.this.getEcbmInterface();
             }
         }
 
         @Override
         public void setUiTtyMode(int uiTtyMode, Message onCompleteMessage) throws RemoteException {
             synchronized (mLock) {
-                MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage);
+                try {
+                    MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage);
+                } catch (Exception e) {
+                    throw new RemoteException(e.getMessage());
+                }
             }
         }
 
         @Override
         public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
             synchronized (mLock) {
-                ImsMultiEndpointImplBase multiEndPoint = MmTelFeature.this.getMultiEndpoint();
-                return multiEndPoint != null ? multiEndPoint.getIImsMultiEndpoint() : null;
+                return MmTelFeature.this.getMultiEndpointInterface();
             }
         }
 
@@ -317,18 +326,18 @@
     }
 
     /**
-     * To be returned by {@link #shouldProcessCall(Uri[])} when the ImsService should process the
+     * To be returned by {@link #shouldProcessCall(String[])} when the ImsService should process the
      * outgoing call as IMS.
      */
     public static final int PROCESS_CALL_IMS = 0;
     /**
-     * To be returned by {@link #shouldProcessCall(Uri[])} when the telephony framework should not
-     * process the outgoing NON_EMERGENCY call as IMS and should instead use circuit switch.
+     * To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should
+     * not process the outgoing NON_EMERGENCY call as IMS and should instead use circuit switch.
      */
     public static final int PROCESS_CALL_CSFB = 1;
     /**
-     * To be returned by {@link #shouldProcessCall(Uri[])} when the telephony framework should not
-     * process the outgoing EMERGENCY call as IMS and should instead use circuit switch.
+     * To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should
+     * not process the outgoing EMERGENCY call as IMS and should instead use circuit switch.
      */
     public static final int PROCESS_CALL_EMERGENCY_CSFB = 2;
 
@@ -401,10 +410,7 @@
     /**
      * Notify the framework of an incoming call.
      * @param c The {@link ImsCallSessionImplBase} of the new incoming call.
-     *
-     * @throws RuntimeException if the connection to the framework is not available. If this
-     * happens, the call should be no longer considered active and should be cleaned up.
-     * */
+     */
     public final void notifyIncomingCall(ImsCallSessionImplBase c, Bundle extras) {
         synchronized (mLock) {
             if (mListener == null) {
@@ -419,6 +425,40 @@
     }
 
     /**
+     *
+     * @hide
+     */
+    public final void notifyIncomingCallSession(IImsCallSession c, Bundle extras) {
+        synchronized (mLock) {
+            if (mListener == null) {
+                throw new IllegalStateException("Session is not available.");
+            }
+            try {
+                mListener.onIncomingCall(c, extras);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Notify the framework of a change in the Voice Message count.
+     * @link count the new Voice Message count.
+     */
+    public final void notifyVoiceMessageCountUpdate(int count) {
+        synchronized (mLock) {
+            if (mListener == null) {
+                throw new IllegalStateException("Session is not available.");
+            }
+            try {
+                mListener.onVoiceMessageCountUpdate(count);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
      * Provides the MmTelFeature with the ability to return the framework Capability Configuration
      * for a provided Capability. If the framework calls {@link #changeEnabledCapabilities} and
      * includes a capability A to enable or disable, this method should return the correct enabled
@@ -474,6 +514,15 @@
     }
 
     /**
+     * @hide
+     */
+    public IImsCallSession createCallSessionInterface(ImsCallProfile profile)
+            throws RemoteException {
+        ImsCallSessionImplBase s = MmTelFeature.this.createCallSession(profile);
+        return s != null ? s.getServiceImpl() : null;
+    }
+
+    /**
      * Creates an {@link ImsCallSession} with the specified call profile.
      * Use other methods, if applicable, instead of interacting with
      * {@link ImsCallSession} directly.
@@ -489,7 +538,7 @@
      * Called by the framework to determine if the outgoing call, designated by the outgoing
      * {@link Uri}s, should be processed as an IMS call or CSFB call.
      * @param numbers An array of {@link String}s that will be used for placing the call. There can
-     *         be multiple {@link Strings}s listed in the case when we want to place an outgoing
+     *         be multiple {@link String}s listed in the case when we want to place an outgoing
      *         call as a conference.
      * @return a {@link ProcessCallResult} to the framework, which will be used to determine if the
      *        call wil lbe placed over IMS or via CSFB.
@@ -499,6 +548,31 @@
     }
 
     /**
+     *
+     * @hide
+     */
+    protected IImsUt getUtInterface() throws RemoteException {
+        ImsUtImplBase utImpl = getUt();
+        return utImpl != null ? utImpl.getInterface() : null;
+    }
+
+    /**
+     * @hide
+     */
+    protected IImsEcbm getEcbmInterface() throws RemoteException {
+        ImsEcbmImplBase ecbmImpl = getEcbm();
+        return ecbmImpl != null ? ecbmImpl.getImsEcbm() : null;
+    }
+
+    /**
+     * @hide
+     */
+    public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
+        ImsMultiEndpointImplBase multiendpointImpl = getMultiEndpoint();
+        return multiendpointImpl != null ? multiendpointImpl.getIImsMultiEndpoint() : null;
+    }
+
+    /**
      * @return The {@link ImsUtImplBase} Ut interface implementation for the supplementary service
      * configuration.
      */
@@ -534,7 +608,7 @@
      *         {@link TelecomManager#TTY_MODE_VCO}
      * @param onCompleteMessage A {@link Message} to be used when the mode has been set.
      */
-    void setUiTtyMode(int mode, Message onCompleteMessage) {
+    public void setUiTtyMode(int mode, Message onCompleteMessage) {
         // Base Implementation - Should be overridden
     }
 
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index fa30ad3..c6e5ddb 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -147,7 +147,7 @@
             mProvisionedIntValue.remove(item);
             int retVal = getImsConfigImpl().setConfig(item, value);
             if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
-                updateCachedValue(item, retVal, true);
+                updateCachedValue(item, value, true);
             } else {
                 Log.d(TAG, "Set provision value of " + item +
                         " to " + value + " failed with error code " + retVal);
@@ -173,7 +173,7 @@
             mProvisionedStringValue.remove(item);
             int retVal = getImsConfigImpl().setConfig(item, value);
             if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
-                updateCachedValue(item, retVal, true);
+                updateCachedValue(item, value, true);
             }
 
             return retVal;