Merge "Implement multi-SIM capabilities (4/6) [DO NOT MERGE]" into lmp-dev
diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java
index 78aa64b..5c7188e 100644
--- a/InCallUI/src/com/android/incallui/AnswerPresenter.java
+++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java
@@ -75,7 +75,7 @@
         // getting updates here.
         Log.d(this, "onIncomingCall: " + this);
         if (getUi() != null) {
-            if (!call.getCallId().equals(mCallId)) {
+            if (!call.getId().equals(mCallId)) {
                 // A new call is coming in.
                 processIncomingCall(call);
             }
@@ -83,14 +83,14 @@
     }
 
     private void processIncomingCall(Call call) {
-        mCallId = call.getCallId();
+        mCallId = call.getId();
         mCall = call;
 
         // Listen for call updates for the current call.
         CallList.getInstance().addCallUpdateListener(mCallId, this);
 
         Log.d(TAG, "Showing incoming for call id: " + mCallId + " " + this);
-        final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getCallId());
+        final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId());
         getUi().showAnswerUi(true);
 
         if (call.can(CallCapabilities.RESPOND_VIA_TEXT) && textMsgs != null) {
@@ -123,7 +123,7 @@
         }
 
         Log.d(this, "onAnswer " + mCallId);
-        TelecommAdapter.getInstance().answerCall(mCall.getCallId());
+        TelecommAdapter.getInstance().answerCall(mCall.getId());
     }
 
     /**
@@ -132,7 +132,7 @@
      */
     public void onDecline() {
         Log.d(this, "onDecline " + mCallId);
-        TelecommAdapter.getInstance().rejectCall(mCall.getCallId(), false, null);
+        TelecommAdapter.getInstance().rejectCall(mCall.getId(), false, null);
     }
 
     public void onText() {
@@ -143,7 +143,7 @@
 
     public void rejectCallWithMessage(String message) {
         Log.d(this, "sendTextToDefaultActivity()...");
-        TelecommAdapter.getInstance().rejectCall(mCall.getCallId(), true, message);
+        TelecommAdapter.getInstance().rejectCall(mCall.getId(), true, message);
 
         onDismissDialog();
     }
diff --git a/InCallUI/src/com/android/incallui/AudioModeProvider.java b/InCallUI/src/com/android/incallui/AudioModeProvider.java
index 407aa3a..f3c7da6 100644
--- a/InCallUI/src/com/android/incallui/AudioModeProvider.java
+++ b/InCallUI/src/com/android/incallui/AudioModeProvider.java
@@ -20,23 +20,47 @@
 
 import com.android.services.telephony.common.AudioMode;
 
+import android.telecomm.CallAudioState;
+import android.telecomm.Phone;
+
 import java.util.List;
 
 /**
  * Proxy class for getting and setting the audio mode.
  */
-/* package */ class AudioModeProvider {
+/* package */ class AudioModeProvider implements InCallPhoneListener {
 
     private static AudioModeProvider sAudioModeProvider = new AudioModeProvider();
     private int mAudioMode = AudioMode.EARPIECE;
     private boolean mMuted = false;
     private int mSupportedModes = AudioMode.ALL_MODES;
     private final List<AudioModeListener> mListeners = Lists.newArrayList();
+    private Phone mPhone;
+
+    private Phone.Listener mPhoneListener = new Phone.Listener() {
+        @Override
+        public void onAudioStateChanged(Phone phone, CallAudioState audioState) {
+            onAudioModeChange(audioState.route, audioState.isMuted);
+            onSupportedAudioModeChange(audioState.supportedRouteMask);
+        }
+    };
 
     public static AudioModeProvider getInstance() {
         return sAudioModeProvider;
     }
 
+    @Override
+    public void setPhone(Phone phone) {
+        mPhone = phone;
+        mPhone.addListener(mPhoneListener);
+    }
+
+    @Override
+    public void clearPhone() {
+        mPhone.removeListener(mPhoneListener);
+        mPhone = null;
+    }
+
     public void onAudioModeChange(int newMode, boolean muted) {
         if (mAudioMode != newMode) {
             mAudioMode = newMode;
diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java
index c8a21e9..5dbd038 100644
--- a/InCallUI/src/com/android/incallui/Call.java
+++ b/InCallUI/src/com/android/incallui/Call.java
@@ -17,19 +17,13 @@
 package com.android.incallui;
 
 import android.net.Uri;
-import android.os.RemoteException;
 import android.telecomm.CallCapabilities;
-import android.telecomm.CallPropertyPresentation;
-import android.telecomm.CallServiceDescriptor;
 import android.telecomm.PhoneAccount;
 import android.telecomm.RemoteCallVideoProvider;
 import android.telecomm.GatewayInfo;
 import android.telephony.DisconnectCause;
 
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.primitives.Ints;
-
-import java.util.Collections;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
@@ -100,58 +94,154 @@
         }
     }
 
-    private String mCallId;
-    private int mState = State.INVALID;
-    private int mDisconnectCause = DisconnectCause.NOT_VALID;
-    private List<String> mCannedSmsResponses = Collections.EMPTY_LIST;
-    private int mCapabilities;
-    private long mConnectTimeMillis = 0;
-    private Uri mHandle;
-    private int mNumberPresentation;
-    private String mCnapName;
-    private int mCnapNamePresentation;
-    private GatewayInfo mGatewayInfo;
-    private PhoneAccount mAccount;
-    private CallServiceDescriptor mCurrentCallServiceDescriptor;
-    private RemoteCallVideoProvider mCallVideoProvider;
-    private String mParentCallId;
-    private List<String> mChildCallIds;
+    private static final String ID_PREFIX = Call.class.getSimpleName() + "_";
+    private static int sIdCounter = 0;
 
+    private android.telecomm.Call.Listener mTelecommCallListener =
+            new android.telecomm.Call.Listener() {
+                @Override
+                public void onStateChanged(android.telecomm.Call call, int newState) {
+                    update();
+                }
+
+                @Override
+                public void onParentChanged(android.telecomm.Call call,
+                        android.telecomm.Call newParent) {
+                    update();
+                }
+
+                @Override
+                public void onChildrenChanged(android.telecomm.Call call,
+                        List<android.telecomm.Call> children) {
+                    update();
+                }
+
+                @Override
+                public void onDetailsChanged(android.telecomm.Call call,
+                        android.telecomm.Call.Details details) {
+                    update();
+                }
+
+                @Override
+                public void onCannedTextResponsesLoaded(android.telecomm.Call call,
+                        List<String> cannedTextResponses) {
+                    update();
+                }
+
+                @Override
+                public void onPostDial(android.telecomm.Call call,
+                        String remainingPostDialSequence) {
+                    update();
+                }
+
+                @Override
+                public void onPostDialWait(android.telecomm.Call call,
+                        String remainingPostDialSequence) {
+                    update();
+                }
+
+                @Override
+                public void onCallVideoProviderChanged(android.telecomm.Call call,
+                        RemoteCallVideoProvider callVideoProvider) {
+                    update();
+                }
+
+                @Override
+                public void onCallDestroyed(android.telecomm.Call call) {
+                    call.removeListener(mTelecommCallListener);
+                }
+            };
+
+    private final android.telecomm.Call mTelecommCall;
+    private final String mId;
+    private int mState = State.INVALID;
+    private int mDisconnectCause;
+    private String mParentCallId;
+    private final List<String> mChildCallIds = new ArrayList<>();
     private InCallVideoClient mCallVideoClient;
 
-    public Call(String callId) {
-        mCallId = callId;
+    public Call(android.telecomm.Call telecommCall) {
+        mTelecommCall = telecommCall;
+        mId = ID_PREFIX + Integer.toString(sIdCounter++);
+        updateFromTelecommCall();
+        if (getState() == Call.State.INCOMING) {
+            CallList.getInstance().onIncoming(this, getCannedSmsResponses());
+        } else {
+            CallList.getInstance().onUpdate(this);
+        }
+        mTelecommCall.addListener(mTelecommCallListener);
     }
 
-    public String getCallId() {
-        return mCallId;
+    public android.telecomm.Call getTelecommCall() {
+        return mTelecommCall;
+    }
+
+    private void update() {
+        int oldState = getState();
+        updateFromTelecommCall();
+        if (oldState != getState() && getState() == Call.State.DISCONNECTED) {
+            CallList.getInstance().onDisconnect(this);
+        } else {
+            CallList.getInstance().onUpdate(this);
+        }
+    }
+
+    private void updateFromTelecommCall() {
+        setState(translateState(mTelecommCall.getState()));
+        setDisconnectCause(mTelecommCall.getDetails().getDisconnectCauseCode());
+
+        if (mTelecommCall.getParent() != null) {
+            mParentCallId = CallList.getInstance().getCallByTelecommCall(
+                    mTelecommCall.getParent()).getId();
+        }
+
+        if (mTelecommCall.getCallVideoProvider() != null) {
+            if (mCallVideoClient == null) {
+                mCallVideoClient = new InCallVideoClient();
+            }
+            mTelecommCall.getCallVideoProvider().setCallVideoClient(mCallVideoClient);
+        }
+
+        mChildCallIds.clear();
+        for (int i = 0; i < mTelecommCall.getChildren().size(); i++) {
+            mChildCallIds.add(
+                    CallList.getInstance().getCallByTelecommCall(
+                            mTelecommCall.getChildren().get(i)).getId());
+        }
+    }
+
+    private static int translateState(int state) {
+        switch (state) {
+            case android.telecomm.Call.STATE_DIALING:
+            case android.telecomm.Call.STATE_NEW:
+                return Call.State.DIALING;
+            case android.telecomm.Call.STATE_RINGING:
+                return Call.State.INCOMING;
+            case android.telecomm.Call.STATE_ACTIVE:
+                return Call.State.ACTIVE;
+            case android.telecomm.Call.STATE_HOLDING:
+                return Call.State.ONHOLD;
+            case android.telecomm.Call.STATE_DISCONNECTED:
+                return Call.State.DISCONNECTED;
+            default:
+                return Call.State.INVALID;
+        }
+    }
+
+    public String getId() {
+        return mId;
     }
 
     public String getNumber() {
-        if (mGatewayInfo != null) {
-            return mGatewayInfo.getOriginalHandle().getSchemeSpecificPart();
+        if (mTelecommCall.getDetails().getGatewayInfo() != null) {
+            return mTelecommCall.getDetails().getGatewayInfo()
+                    .getOriginalHandle().getSchemeSpecificPart();
         }
-        return mHandle == null ? null : mHandle.getSchemeSpecificPart();
+        return getHandle() == null ? null : getHandle().getSchemeSpecificPart();
     }
 
     public Uri getHandle() {
-        return mHandle;
-    }
-
-    public void setHandle(Uri handle) {
-        mHandle = handle;
-    }
-
-    public void setNumberPresentation(int presentation) {
-        mNumberPresentation = presentation;
-    }
-
-    public void setCnapName(String cnapName) {
-        mCnapName = cnapName;
-    }
-
-    public void setCnapNamePresentation(int presentation) {
-        mCnapNamePresentation = presentation;
+        return mTelecommCall.getDetails().getHandle();
     }
 
     public int getState() {
@@ -167,15 +257,15 @@
     }
 
     public int getNumberPresentation() {
-        return mNumberPresentation;
+        return getTelecommCall().getDetails().getHandlePresentation();
     }
 
     public int getCnapNamePresentation() {
-        return mCnapNamePresentation;
+        return getTelecommCall().getDetails().getCallerDisplayNamePresentation();
     }
 
     public String getCnapName() {
-        return mCnapName;
+        return getTelecommCall().getDetails().getCallerDisplayName();
     }
 
     /** Returns call disconnect cause; values are defined in {@link DisconnectCause}. */
@@ -187,39 +277,23 @@
         return DisconnectCause.NOT_DISCONNECTED;
     }
 
-    /** Sets the call disconnect cause; values are defined in {@link DisconnectCause}. */
-    public void setDisconnectCause(int cause) {
-        mDisconnectCause = cause;
-    }
-
-    /** Sets the possible text message responses. */
-    public void setCannedSmsResponses(List<String> cannedSmsResponses) {
-        mCannedSmsResponses = cannedSmsResponses;
+    public void setDisconnectCause(int disconnectCause) {
+        mDisconnectCause = disconnectCause;
     }
 
     /** Returns the possible text message responses. */
     public List<String> getCannedSmsResponses() {
-        return mCannedSmsResponses;
-    }
-
-    /** Sets a bit mask of capabilities unique to this call. */
-    public void setCapabilities(int capabilities) {
-        mCapabilities = (CallCapabilities.ALL & capabilities);
+        return mTelecommCall.getCannedTextResponses();
     }
 
     /** Checks if the call supports the given set of capabilities supplied as a bit mask. */
     public boolean can(int capabilities) {
-        return (capabilities == (capabilities & mCapabilities));
-    }
-
-    /** Sets the time when the call first became active. */
-    public void setConnectTimeMillis(long connectTimeMillis) {
-        mConnectTimeMillis = connectTimeMillis;
+        return (capabilities == (capabilities & mTelecommCall.getDetails().getCapabilities()));
     }
 
     /** Gets the time when the call first became active. */
     public long getConnectTimeMillis() {
-        return mConnectTimeMillis;
+        return mTelecommCall.getDetails().getConnectTimeMillis();
     }
 
     public boolean isConferenceCall() {
@@ -227,60 +301,21 @@
     }
 
     public GatewayInfo getGatewayInfo() {
-        return mGatewayInfo;
-    }
-
-    public void setGatewayInfo(GatewayInfo gatewayInfo) {
-        mGatewayInfo = gatewayInfo;
+        return mTelecommCall.getDetails().getGatewayInfo();
     }
 
     public PhoneAccount getAccount() {
-        return mAccount;
-    }
-
-    public void setAccount(PhoneAccount account) {
-        mAccount = account;
-    }
-
-    /** The descriptor for the call service currently routing this call. */
-    public CallServiceDescriptor getCurrentCallServiceDescriptor() {
-        return mCurrentCallServiceDescriptor;
-    }
-
-    public void setCurrentCallServiceDescriptor(CallServiceDescriptor descriptor) {
-        mCurrentCallServiceDescriptor = descriptor;
+        return mTelecommCall.getDetails().getAccount();
     }
 
     public RemoteCallVideoProvider getCallVideoProvider() {
-        return mCallVideoProvider;
-    }
-
-    public void setCallVideoProvider(RemoteCallVideoProvider callVideoProvider) {
-        mCallVideoProvider = callVideoProvider;
-
-        if (mCallVideoProvider != null) {
-            try {
-                if (mCallVideoClient == null) {
-                    mCallVideoClient = new InCallVideoClient();
-                }
-                mCallVideoProvider.setCallVideoClient(mCallVideoClient);
-            } catch (RemoteException ignored) {
-            }
-        }
-    }
-
-    public void setChildCallIds(List<String> callIds) {
-        mChildCallIds = callIds;
+        return mTelecommCall.getCallVideoProvider();
     }
 
     public List<String> getChildCallIds() {
         return mChildCallIds;
     }
 
-    public void setParentId(String callId) {
-        mParentCallId = callId;
-    }
-
     public String getParentId() {
         return mParentCallId;
     }
@@ -288,9 +323,9 @@
     @Override
     public String toString() {
         return String.format(Locale.US, "[%s, %s, %s, children:%s, parent:%s]",
-                mCallId,
+                mId,
                 State.toString(mState),
-                CallCapabilities.toString(mCapabilities),
+                CallCapabilities.toString(mTelecommCall.getDetails().getCapabilities()),
                 mChildCallIds,
                 mParentCallId);
     }
diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
index d9fee5f..84cb8ac 100644
--- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
@@ -203,15 +203,15 @@
         }
         if (checked) {
             Log.i(this, "Putting the call on hold: " + mCall);
-            TelecommAdapter.getInstance().holdCall(mCall.getCallId());
+            TelecommAdapter.getInstance().holdCall(mCall.getId());
         } else {
             Log.i(this, "Removing the call from hold: " + mCall);
-            TelecommAdapter.getInstance().unholdCall(mCall.getCallId());
+            TelecommAdapter.getInstance().unholdCall(mCall.getId());
         }
     }
 
     public void mergeClicked() {
-        TelecommAdapter.getInstance().merge(mCall.getCallId());
+        TelecommAdapter.getInstance().merge(mCall.getId());
     }
 
     public void addCallClicked() {
@@ -225,7 +225,7 @@
     }
 
     public void swapClicked() {
-        TelecommAdapter.getInstance().swap(mCall.getCallId());
+        TelecommAdapter.getInstance().swap(mCall.getId());
     }
 
     public void showDialpadClicked(boolean checked) {
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index 552998e..9e400d7 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -21,7 +21,6 @@
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
 import android.telecomm.CallCapabilities;
-import android.telecomm.CallServiceDescriptor;
 import android.telecomm.PhoneAccount;
 import android.telecomm.TelecommManager;
 import android.telephony.DisconnectCause;
@@ -230,7 +229,7 @@
         if (mPrimary == null) {
             return;
         }
-        TelecommAdapter.getInstance().phoneAccountClicked(mPrimary.getCallId());
+        TelecommAdapter.getInstance().phoneAccountClicked(mPrimary.getId());
     }
 
     private boolean areCallsSame(Call call1, Call call2) {
@@ -241,7 +240,7 @@
         }
 
         // otherwise compare call Ids
-        return call1.getCallId().equals(call2.getCallId());
+        return call1.getId().equals(call2.getId());
     }
 
     private void maybeStartSearch(Call call, boolean isPrimary) {
@@ -276,7 +275,7 @@
                         return;
                     }
                     if (entry.photo != null) {
-                        if (mPrimary != null && callId.equals(mPrimary.getCallId())) {
+                        if (mPrimary != null && callId.equals(mPrimary.getId())) {
                             getUi().setPrimaryImage(entry.photo);
                         }
                     }
@@ -496,7 +495,7 @@
         }
 
         Log.i(this, "Swapping call to foreground: " + mSecondary);
-        TelecommAdapter.getInstance().unholdCall(mSecondary.getCallId());
+        TelecommAdapter.getInstance().unholdCall(mSecondary.getId());
     }
 
     public void endCallClicked() {
@@ -505,7 +504,7 @@
         }
 
         Log.i(this, "Disconnecting call: " + mPrimary);
-        TelecommAdapter.getInstance().disconnectCall(mPrimary.getCallId());
+        TelecommAdapter.getInstance().disconnectCall(mPrimary.getId());
     }
 
     public interface CallCardUi extends Ui {
diff --git a/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java
index 343a943..f89d8aa 100644
--- a/InCallUI/src/com/android/incallui/CallList.java
+++ b/InCallUI/src/com/android/incallui/CallList.java
@@ -23,6 +23,7 @@
 
 import android.os.Handler;
 import android.os.Message;
+import android.telecomm.Phone;
 import android.telephony.DisconnectCause;
 
 import java.util.HashMap;
@@ -34,7 +35,7 @@
  * as they are received from the telephony stack. Primary listener of changes to this class is
  * InCallPresenter.
  */
-public class CallList {
+public class CallList implements InCallPhoneListener {
 
     private static final int DISCONNECTED_CALL_SHORT_TIMEOUT_MS = 200;
     private static final int DISCONNECTED_CALL_MEDIUM_TIMEOUT_MS = 2000;
@@ -44,12 +45,14 @@
 
     private static CallList sInstance = new CallList();
 
-    private final HashMap<String, Call> mCallMap = Maps.newHashMap();
+    private final HashMap<String, Call> mCallById = new HashMap<>();
+    private final HashMap<android.telecomm.Call, Call> mCallByTelecommCall = new HashMap<>();
     private final HashMap<String, List<String>> mCallTextReponsesMap = Maps.newHashMap();
     private final Set<Listener> mListeners = Sets.newHashSet();
     private final HashMap<String, List<CallUpdateListener>> mCallUpdateListenerMap = Maps
             .newHashMap();
 
+    private Phone mPhone;
 
     /**
      * Static singleton accessor method.
@@ -58,12 +61,38 @@
         return sInstance;
     }
 
+    private Phone.Listener mPhoneListener = new Phone.Listener() {
+        @Override
+        public void onCallAdded(Phone phone, android.telecomm.Call call) {
+            // TODO(ihab): The Call adds itself to various singletons within its ctor. Refactor
+            // so that this is done more explicitly; otherwise, the below looks like we're creating
+            // an object and never using it.
+            new Call(call);
+        }
+        @Override
+        public void onCallRemoved(Phone phone, android.telecomm.Call call) {
+            // Handled by disconnection cascade from the Call itself
+        }
+    };
+
     /**
      * Private constructor.  Instance should only be acquired through getInstance().
      */
     private CallList() {
     }
 
+    @Override
+    public void setPhone(Phone phone) {
+        mPhone = phone;
+        mPhone.addListener(mPhoneListener);
+    }
+
+    @Override
+    public void clearPhone() {
+        mPhone.removeListener(mPhoneListener);
+        mPhone = null;
+    }
+
     /**
      * Called when a single call disconnects.
      */
@@ -100,27 +129,12 @@
      */
     public void onUpdate(Call call) {
         Log.d(this, "onUpdate - ", call);
-
         onUpdateCall(call);
         notifyGenericListeners();
     }
 
-    /**
-     * Called when multiple calls have changed.
-     */
-    public void onUpdate(List<Call> callsToUpdate) {
-        Log.d(this, "onUpdate(...)");
-
-        Preconditions.checkNotNull(callsToUpdate);
-        for (Call call : callsToUpdate) {
-            onUpdateCall(call);
-        }
-
-        notifyGenericListeners();
-    }
-
     public void notifyCallUpdateListeners(Call call) {
-        final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getCallId());
+        final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getId());
         if (listeners != null) {
             for (CallUpdateListener listener : listeners) {
                 listener.onCallChanged(call);
@@ -245,17 +259,12 @@
         return result;
     }
 
-    public Call getCall(String callId) {
-        return mCallMap.get(callId);
+    public Call getCallById(String callId) {
+        return mCallById.get(callId);
     }
 
-    public boolean existsLiveCall() {
-        for (Call call : mCallMap.values()) {
-            if (!isCallDead(call)) {
-                return true;
-            }
-        }
-        return false;
+    public Call getCallByTelecommCall(android.telecomm.Call telecommCall) {
+        return mCallByTelecommCall.get(telecommCall);
     }
 
     public List<String> getTextResponses(String callId) {
@@ -276,7 +285,7 @@
     public Call getCallWithState(int state, int positionToFind) {
         Call retval = null;
         int position = 0;
-        for (Call call : mCallMap.values()) {
+        for (Call call : mCallById.values()) {
             if (call.getState() == state) {
                 if (position >= positionToFind) {
                     retval = call;
@@ -297,7 +306,7 @@
      * there can be no active calls, so this is relatively safe thing to do.
      */
     public void clearOnDisconnect() {
-        for (Call call : mCallMap.values()) {
+        for (Call call : mCallById.values()) {
             final int state = call.getState();
             if (state != Call.State.IDLE &&
                     state != Call.State.INVALID &&
@@ -350,7 +359,7 @@
 
         if (call.getState() == Call.State.DISCONNECTED) {
             // update existing (but do not add!!) disconnected calls
-            if (mCallMap.containsKey(call.getCallId())) {
+            if (mCallById.containsKey(call.getId())) {
 
                 // For disconnected calls, we want to keep them alive for a few seconds so that the
                 // UI has a chance to display anything it needs when a call is disconnected.
@@ -359,14 +368,17 @@
                 final Message msg = mHandler.obtainMessage(EVENT_DISCONNECTED_TIMEOUT, call);
                 mHandler.sendMessageDelayed(msg, getDelayForDisconnect(call));
 
-                mCallMap.put(call.getCallId(), call);
+                mCallById.put(call.getId(), call);
+                mCallByTelecommCall.put(call.getTelecommCall(), call);
                 updated = true;
             }
         } else if (!isCallDead(call)) {
-            mCallMap.put(call.getCallId(), call);
+            mCallById.put(call.getId(), call);
+            mCallByTelecommCall.put(call.getTelecommCall(), call);
             updated = true;
-        } else if (mCallMap.containsKey(call.getCallId())) {
-            mCallMap.remove(call.getCallId());
+        } else if (mCallById.containsKey(call.getId())) {
+            mCallById.remove(call.getId());
+            mCallByTelecommCall.remove(call.getTelecommCall());
             updated = true;
         }
 
@@ -404,10 +416,10 @@
 
         if (!isCallDead(call)) {
             if (textResponses != null) {
-                mCallTextReponsesMap.put(call.getCallId(), textResponses);
+                mCallTextReponsesMap.put(call.getId(), textResponses);
             }
-        } else if (mCallMap.containsKey(call.getCallId())) {
-            mCallTextReponsesMap.remove(call.getCallId());
+        } else if (mCallById.containsKey(call.getId())) {
+            mCallTextReponsesMap.remove(call.getId());
         }
     }
 
diff --git a/InCallUI/src/com/android/incallui/ContactInfoCache.java b/InCallUI/src/com/android/incallui/ContactInfoCache.java
index 19b0267..ba1dca7 100644
--- a/InCallUI/src/com/android/incallui/ContactInfoCache.java
+++ b/InCallUI/src/com/android/incallui/ContactInfoCache.java
@@ -109,7 +109,7 @@
         Preconditions.checkState(Looper.getMainLooper().getThread() == Thread.currentThread());
         Preconditions.checkNotNull(callback);
 
-        final String callId = call.getCallId();
+        final String callId = call.getId();
         final ContactCacheEntry cacheEntry = mInfoMap.get(callId);
         Set<ContactInfoCacheCallback> callBacks = mCallBacks.get(callId);
 
@@ -149,7 +149,7 @@
 
     private void findInfoQueryComplete(Call call, CallerInfo callerInfo, boolean isIncoming,
             boolean didLocalLookup) {
-        final String callId = call.getCallId();
+        final String callId = call.getId();
         int presentationMode = call.getNumberPresentation();
         if (callerInfo.contactExists || callerInfo.isEmergencyNumber() ||
                 callerInfo.isVoiceMailNumber()) {
diff --git a/InCallUI/src/com/android/incallui/DialpadPresenter.java b/InCallUI/src/com/android/incallui/DialpadPresenter.java
index b381864..0778b1e 100644
--- a/InCallUI/src/com/android/incallui/DialpadPresenter.java
+++ b/InCallUI/src/com/android/incallui/DialpadPresenter.java
@@ -16,7 +16,6 @@
 
 package com.android.incallui;
 
-import android.telecomm.InCallAdapter;
 import android.telephony.PhoneNumberUtils;
 
 /**
@@ -60,7 +59,7 @@
             // Append this key to the "digits" widget.
             getUi().appendDigitsToField(c);
             // Plays the tone through Telecomm.
-            TelecommAdapter.getInstance().playDtmfTone(mCall.getCallId(), c);
+            TelecommAdapter.getInstance().playDtmfTone(mCall.getId(), c);
         } else {
             Log.d(this, "ignoring dtmf request for '" + c + "'");
         }
@@ -72,7 +71,7 @@
     public void stopTone() {
         if (mCall != null) {
             Log.d(this, "stopping remote tone");
-            TelecommAdapter.getInstance().stopDtmfTone(mCall.getCallId());
+            TelecommAdapter.getInstance().stopDtmfTone(mCall.getId());
         }
     }
 
diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java
index 4e6bc50..24e5762 100644
--- a/InCallUI/src/com/android/incallui/InCallActivity.java
+++ b/InCallUI/src/com/android/incallui/InCallActivity.java
@@ -34,7 +34,6 @@
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
-import android.widget.Toast;
 
 import com.android.phone.common.animation.AnimationListenerAdapter;
 import com.android.incallui.Call.State;
@@ -400,7 +399,7 @@
             // wants to use the dialpad toward the exact line, so un-hold the holding line.
             final Call call = CallList.getInstance().getActiveOrBackgroundCall();
             if (call != null && call.getState() == State.ONHOLD) {
-                TelecommAdapter.getInstance().unholdCall(call.getCallId());
+                TelecommAdapter.getInstance().unholdCall(call.getId());
             }
         }
     }
diff --git a/InCallUI/src/com/android/incallui/InCallPhoneListener.java b/InCallUI/src/com/android/incallui/InCallPhoneListener.java
new file mode 100644
index 0000000..c2be3e6
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/InCallPhoneListener.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.incallui;
+
+import android.telecomm.Phone;
+
+/**
+ * Interface implemented by In-Call components that maintain a reference to the Telecomm API
+ * {@code Phone} object. Clarifies the expectations associated with the relevant method calls.
+ */
+public interface InCallPhoneListener {
+
+    /**
+     * Called once at {@code InCallService} startup time with a valid {@code Phone}. At
+     * that time, there will be no existing {@code Call}s.
+     *
+     * @param phone The {@code Phone} object.
+     */
+    void setPhone(Phone phone);
+
+    /**
+     * Called once at {@code InCallService} shutdown time. At that time, any {@code Call}s
+     * will have transitioned through the disconnected state and will no longer exist.
+     */
+    void clearPhone();
+}
diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java
index 5ef7c5a..5c6283e 100644
--- a/InCallUI/src/com/android/incallui/InCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/InCallPresenter.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.telecomm.CallCapabilities;
+import android.telecomm.Phone;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Sets;
@@ -36,7 +37,7 @@
  * that want to listen in on the in-call state changes.
  * TODO: This class has become more of a state machine at this point.  Consider renaming.
  */
-public class InCallPresenter implements CallList.Listener {
+public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
 
     private static InCallPresenter sInCallPresenter;
 
@@ -53,6 +54,32 @@
     private ProximitySensor mProximitySensor;
     private boolean mServiceConnected = false;
 
+    private final Phone.Listener mPhoneListener = new Phone.Listener() {
+        @Override
+        public void onBringToForeground(Phone phone, boolean showDialpad) {
+            Log.i(this, "Bringing UI to foreground.");
+            bringToForeground(showDialpad);
+        }
+        @Override
+        public void onCallAdded(Phone phone, android.telecomm.Call call) {
+            call.addListener(mCallListener);
+        }
+        @Override
+        public void onCallRemoved(Phone phone, android.telecomm.Call call) {
+            call.removeListener(mCallListener);
+        }
+    };
+
+    private final android.telecomm.Call.Listener mCallListener =
+            new android.telecomm.Call.Listener() {
+        @Override
+        public void onPostDialWait(android.telecomm.Call call, String remainingPostDialSequence) {
+            onPostDialCharWait(
+                    CallList.getInstance().getCallByTelecommCall(call).getId(),
+                    remainingPostDialSequence);
+        }
+    };
+
     /**
      * Is true when the activity has been previously started. Some code needs to know not just if
      * the activity is currently up, but if it had been previously shown in foreground for this
@@ -61,6 +88,8 @@
      */
     private boolean mIsActivityPreviouslyStarted = false;
 
+    private Phone mPhone;
+
     public static synchronized InCallPresenter getInstance() {
         if (sInCallPresenter == null) {
             sInCallPresenter = new InCallPresenter();
@@ -68,6 +97,18 @@
         return sInCallPresenter;
     }
 
+    @Override
+    public void setPhone(Phone phone) {
+        mPhone = phone;
+        mPhone.addListener(mPhoneListener);
+    }
+
+    @Override
+    public void clearPhone() {
+        mPhone.removeListener(mPhoneListener);
+        mPhone = null;
+    }
+
     public InCallState getInCallState() {
         return mInCallState;
     }
@@ -343,7 +384,7 @@
         }
 
         if (call != null) {
-            TelecommAdapter.getInstance().disconnectCall(call.getCallId());
+            TelecommAdapter.getInstance().disconnectCall(call.getId());
         }
     }
 
@@ -360,7 +401,7 @@
 
         Call call = mCallList.getIncomingCall();
         if (call != null) {
-            TelecommAdapter.getInstance().answerCall(call.getCallId());
+            TelecommAdapter.getInstance().answerCall(call.getId());
             showInCall(false, false/* newOutgoingCall */);
         }
     }
@@ -378,7 +419,7 @@
 
         Call call = mCallList.getIncomingCall();
         if (call != null) {
-            TelecommAdapter.getInstance().rejectCall(call.getCallId(), false, null);
+            TelecommAdapter.getInstance().rejectCall(call.getId(), false, null);
         }
     }
 
@@ -463,7 +504,7 @@
 
         // (1) Attempt to answer a call
         if (incomingCall != null) {
-            TelecommAdapter.getInstance().answerCall(incomingCall.getCallId());
+            TelecommAdapter.getInstance().answerCall(incomingCall.getId());
             return true;
         }
 
@@ -484,17 +525,17 @@
             // (2) Attempt actions on Generic conference calls
             if (activeCall.isConferenceCall() && isGeneric) {
                 if (canMerge) {
-                    TelecommAdapter.getInstance().merge(activeCall.getCallId());
+                    TelecommAdapter.getInstance().merge(activeCall.getId());
                     return true;
                 } else if (canSwap) {
-                    TelecommAdapter.getInstance().swap(activeCall.getCallId());
+                    TelecommAdapter.getInstance().swap(activeCall.getId());
                     return true;
                 }
             }
 
             // (3) Swap calls
             if (canSwap) {
-                TelecommAdapter.getInstance().swap(activeCall.getCallId());
+                TelecommAdapter.getInstance().swap(activeCall.getId());
                 return true;
             }
         }
@@ -512,7 +553,7 @@
 
             // (4) unhold call
             if (heldCall.getState() == Call.State.ONHOLD && canHold) {
-                TelecommAdapter.getInstance().unholdCall(heldCall.getCallId());
+                TelecommAdapter.getInstance().unholdCall(heldCall.getId());
                 return true;
             }
         }
diff --git a/InCallUI/src/com/android/incallui/InCallServiceImpl.java b/InCallUI/src/com/android/incallui/InCallServiceImpl.java
index 9fed90c..c69571a 100644
--- a/InCallUI/src/com/android/incallui/InCallServiceImpl.java
+++ b/InCallUI/src/com/android/incallui/InCallServiceImpl.java
@@ -16,14 +16,11 @@
 
 package com.android.incallui;
 
-import android.os.RemoteException;
-import android.telecomm.CallAudioState;
-import android.telecomm.CallState;
-import android.telecomm.InCallAdapter;
-import android.telecomm.InCallCall;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
 import android.telecomm.InCallService;
-
-import com.google.common.collect.ImmutableList;
+import android.telecomm.Phone;
 
 /**
  * Used to receive updates about calls from the Telecomm component.  This service is bound to
@@ -31,132 +28,38 @@
  * dialing (outgoing), and active calls. When the last call is disconnected, Telecomm will unbind to
  * the service triggering InCallActivity (via CallList) to finish soon after.
  */
-public class InCallServiceImpl extends InCallService {
-    private static final ImmutableList<String> EMPTY_RESPONSE_TEXTS = ImmutableList.of();
+public class InCallServiceImpl extends Service {
 
-    /** {@inheritDoc} */
-    @Override public void onCreate() {
-        Log.v(this, "onCreate");
-        InCallPresenter inCallPresenter = InCallPresenter.getInstance();
-        inCallPresenter.setUp(
-                getApplicationContext(), CallList.getInstance(), AudioModeProvider.getInstance());
-        TelecommAdapter.getInstance().setContext(this);
-    }
-
-    /** {@inheritDoc} */
-    @Override public void onDestroy() {
-        Log.v(this, "onDestroy");
-        // Tear down the InCall system
-        TelecommAdapter.getInstance().setAdapter(null);
-        TelecommAdapter.getInstance().setContext(null);
-        CallList.getInstance().clearOnDisconnect();
-        InCallPresenter.getInstance().tearDown();
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void onAdapterAttached(InCallAdapter inCallAdapter) {
-        Log.v(this, "onAdapterAttached");
-        TelecommAdapter.getInstance().setAdapter(inCallAdapter);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void addCall(InCallCall telecommCall) {
-        Call call = new Call(telecommCall.getId());
-        updateCall(call, telecommCall);
-        Log.i(this, "addCall: " + call);
-
-        if (call.getState() == Call.State.INCOMING) {
-            CallList.getInstance().onIncoming(call, call.getCannedSmsResponses());
-        } else {
-            CallList.getInstance().onUpdate(call);
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void updateCall(InCallCall telecommCall) {
-        Call call = CallList.getInstance().getCall(telecommCall.getId());
-        if (call == null) {
-            Log.v(this, "updateCall for unknown call: " + telecommCall.getId());
-            return;
+    private final InCallService mInCallServiceInstance = new InCallService() {
+        @Override
+        public void onPhoneCreated(Phone phone) {
+            Log.v(this, "onPhoneCreated");
+            CallList.getInstance().setPhone(phone);
+            AudioModeProvider.getInstance().setPhone(phone);
+            TelecommAdapter.getInstance().setPhone(phone);
+            InCallPresenter.getInstance().setPhone(phone);
+            InCallPresenter.getInstance().setUp(
+                    getApplicationContext(),
+                    CallList.getInstance(),
+                    AudioModeProvider.getInstance());
+            TelecommAdapter.getInstance().setContext(InCallServiceImpl.this);
         }
 
-        int oldState = call.getState();
-        updateCall(call, telecommCall);
-        Log.i(this, "updateCall: " + telecommCall + " => " + call);
-
-        if (oldState != call.getState() && call.getState() == Call.State.DISCONNECTED) {
-            CallList.getInstance().onDisconnect(call);
-        } else {
-            CallList.getInstance().onUpdate(call);
+        @Override
+        public void onPhoneDestroyed(Phone phone) {
+            Log.v(this, "onPhoneDestroyed");
+            // Tear down the InCall system
+            CallList.getInstance().clearPhone();
+            AudioModeProvider.getInstance().clearPhone();
+            TelecommAdapter.getInstance().clearPhone();
+            TelecommAdapter.getInstance().setContext(null);
+            CallList.getInstance().clearOnDisconnect();
+            InCallPresenter.getInstance().tearDown();
         }
-    }
+    };
 
-    /** {@inheritDoc} */
     @Override
-    protected void setPostDial(String callId, String remaining) {
-        // TODO(ihab): Add post-dial state to user interface
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void setPostDialWait(String callId, String remaining) {
-        InCallPresenter.getInstance().onPostDialCharWait(callId, remaining);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void onAudioStateChanged(CallAudioState audioState) {
-        AudioModeProvider.getInstance().onAudioModeChange(audioState.route, audioState.isMuted);
-        AudioModeProvider.getInstance().onSupportedAudioModeChange(audioState.supportedRouteMask);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void bringToForeground(boolean showDialpad) {
-        Log.i(this, "Bringing UI to foreground.");
-        InCallPresenter.getInstance().bringToForeground(showDialpad);
-    }
-
-    private void updateCall(Call call, InCallCall telecommCall) {
-        call.setHandle(telecommCall.getHandle());
-        call.setNumberPresentation(telecommCall.getHandlePresentation());
-        call.setCnapName(telecommCall.getCallerDisplayName());
-        call.setCnapNamePresentation(telecommCall.getCallerDisplayNamePresentation());
-        call.setDisconnectCause(telecommCall.getDisconnectCauseCode());
-        call.setCannedSmsResponses(telecommCall.getCannedSmsResponses());
-        call.setCapabilities(telecommCall.getCapabilities());
-        call.setConnectTimeMillis(telecommCall.getConnectTimeMillis());
-        call.setGatewayInfo(telecommCall.getGatewayInfo());
-        call.setAccount(telecommCall.getAccount());
-        call.setCurrentCallServiceDescriptor(telecommCall.getCurrentCallServiceDescriptor());
-        call.setState(translateState(telecommCall.getState()));
-        call.setParentId(telecommCall.getParentCallId());
-        call.setChildCallIds(telecommCall.getChildCallIds());
-
-        try {
-            call.setCallVideoProvider(telecommCall.getCallVideoProvider());
-        } catch (RemoteException ignore) {
-            // Do nothing.
-        }
-    }
-
-    private static int translateState(CallState state) {
-        switch (state) {
-            case DIALING:
-            case NEW:
-                return Call.State.DIALING;
-            case RINGING:
-                return Call.State.INCOMING;
-            case POST_DIAL:
-            case POST_DIAL_WAIT:
-            case ACTIVE:
-                return Call.State.ACTIVE;
-            case ON_HOLD:
-                return Call.State.ONHOLD;
-            case DISCONNECTED:
-                return Call.State.DISCONNECTED;
-            default:
-                return Call.State.INVALID;
-        }
+    public IBinder onBind(Intent intent) {
+        return mInCallServiceInstance.getBinder();
     }
 }
diff --git a/InCallUI/src/com/android/incallui/StatusBarNotifier.java b/InCallUI/src/com/android/incallui/StatusBarNotifier.java
index 43aaa4a..1208527 100644
--- a/InCallUI/src/com/android/incallui/StatusBarNotifier.java
+++ b/InCallUI/src/com/android/incallui/StatusBarNotifier.java
@@ -227,7 +227,7 @@
         mContactInfoCache.findInfo(call, isIncoming, new ContactInfoCacheCallback() {
                 @Override
                 public void onContactInfoComplete(String callId, ContactCacheEntry entry) {
-                    Call call = CallList.getInstance().getCall(callId);
+                    Call call = CallList.getInstance().getCallById(callId);
                     if (call != null) {
                         buildAndSendNotification(call, entry);
                     }
@@ -235,7 +235,7 @@
 
                 @Override
                 public void onImageLoadComplete(String callId, ContactCacheEntry entry) {
-                    Call call = CallList.getInstance().getCall(callId);
+                    Call call = CallList.getInstance().getCallById(callId);
                     if (call != null) {
                         buildAndSendNotification(call, entry);
                     }
@@ -251,7 +251,7 @@
         // back. However, it can happen much later. Before we continue, we need to make sure that
         // the call being passed in is still the one we want to show in the notification.
         final Call call = getCallToShow(CallList.getInstance());
-        if (call == null || !call.getCallId().equals(originalCall.getCallId())) {
+        if (call == null || !call.getId().equals(originalCall.getId())) {
             return;
         }
 
diff --git a/InCallUI/src/com/android/incallui/TelecommAdapter.java b/InCallUI/src/com/android/incallui/TelecommAdapter.java
index d22cb15..6d0e0a6 100644
--- a/InCallUI/src/com/android/incallui/TelecommAdapter.java
+++ b/InCallUI/src/com/android/incallui/TelecommAdapter.java
@@ -21,16 +21,17 @@
 import android.content.Intent;
 import android.os.Looper;
 import android.telecomm.InCallAdapter;
+import android.telecomm.Phone;
 
 import com.google.common.base.Preconditions;
 
 /** Wrapper around {@link InCallAdapter} that only forwards calls to the adapter when it's valid. */
-final class TelecommAdapter {
+final class TelecommAdapter implements InCallPhoneListener {
     private static final String ADD_CALL_MODE_KEY = "add_call_mode";
 
     private static TelecommAdapter sInstance;
     private Context mContext;
-    private InCallAdapter mAdapter;
+    private Phone mPhone;
 
     static TelecommAdapter getInstance() {
         Preconditions.checkState(Looper.getMainLooper().getThread() == Thread.currentThread());
@@ -47,85 +48,95 @@
         mContext = context;
     }
 
-    void setAdapter(InCallAdapter adapter) {
-        mAdapter = adapter;
+    @Override
+    public void setPhone(Phone phone) {
+        mPhone = phone;
+    }
+
+    @Override
+    public void clearPhone() {
+        mPhone = null;
+    }
+
+    private android.telecomm.Call getTelecommCallById(String callId) {
+        return CallList.getInstance().getCallById(callId).getTelecommCall();
     }
 
     void answerCall(String callId) {
-        if (mAdapter != null) {
-            mAdapter.answerCall(callId);
+        if (mPhone != null) {
+            getTelecommCallById(callId).answer();
         } else {
-            Log.e(this, "error answerCall, mAdapter is null");
+            Log.e(this, "error answerCall, mPhone is null");
         }
     }
 
     void rejectCall(String callId, boolean rejectWithMessage, String message) {
-        if (mAdapter != null) {
-            mAdapter.rejectCall(callId, rejectWithMessage, message);
+        if (mPhone != null) {
+            getTelecommCallById(callId).reject(rejectWithMessage, message);
         } else {
-            Log.e(this, "error rejectCall, mAdapter is null");
+            Log.e(this, "error rejectCall, mPhone is null");
         }
     }
 
     void disconnectCall(String callId) {
-        if (mAdapter != null) {
-            mAdapter.disconnectCall(callId);
+        if (mPhone != null) {
+            getTelecommCallById(callId).disconnect();
         } else {
-            Log.e(this, "error disconnectCall, mAdapter is null");
+            Log.e(this, "error disconnectCall, mPhone is null");
         }
     }
 
     void holdCall(String callId) {
-        if (mAdapter != null) {
-            mAdapter.holdCall(callId);
+        if (mPhone != null) {
+            getTelecommCallById(callId).hold();
         } else {
-            Log.e(this, "error holdCall, mAdapter is null");
+            Log.e(this, "error holdCall, mPhone is null");
         }
     }
 
     void unholdCall(String callId) {
-        if (mAdapter != null) {
-            mAdapter.unholdCall(callId);
+        if (mPhone != null) {
+            getTelecommCallById(callId).unhold();
         } else {
-            Log.e(this, "error unholdCall, mAdapter is null");
+            Log.e(this, "error unholdCall, mPhone is null");
         }
     }
 
     void mute(boolean shouldMute) {
-        if (mAdapter != null) {
-            mAdapter.mute(shouldMute);
+        if (mPhone != null) {
+            mPhone.setMuted(shouldMute);
         } else {
-            Log.e(this, "error mute, mAdapter is null");
+            Log.e(this, "error mute, mPhone is null");
         }
     }
 
     void setAudioRoute(int route) {
-        if (mAdapter != null) {
-            mAdapter.setAudioRoute(route);
+        if (mPhone != null) {
+            mPhone.setAudioRoute(route);
         } else {
-            Log.e(this, "error setAudioRoute, mAdapter is null");
+            Log.e(this, "error setAudioRoute, mPhone is null");
         }
     }
 
     void separateCall(String callId) {
-        if (mAdapter != null) {
-            mAdapter.splitFromConference(callId);
+        if (mPhone != null) {
+            getTelecommCallById(callId).splitFromConference();
         } else {
-            Log.e(this, "error separateCall, mAdapter is null.");
+            Log.e(this, "error separateCall, mPhone is null.");
         }
     }
 
     void merge(String callId) {
-        if (mAdapter != null) {
-            mAdapter.conference(callId);
+        if (mPhone != null) {
+            getTelecommCallById(callId).conference();
         } else {
-            Log.e(this, "error merge, mAdapter is null.");
+            Log.e(this, "error merge, mPhone is null.");
         }
     }
 
     void swap(String callId) {
-         if (mAdapter != null) {
-            mAdapter.swapWithBackgroundCall(callId);
+         if (mPhone != null) {
+            getTelecommCallById(callId).swapWithBackgroundCall();
         } else {
             Log.e(this, "error swapWithBackgroundCall, mAdapter is null.");
         }
@@ -153,34 +164,34 @@
     }
 
     void playDtmfTone(String callId, char digit) {
-        if (mAdapter != null) {
-            mAdapter.playDtmfTone(callId, digit);
+        if (mPhone != null) {
+            getTelecommCallById(callId).playDtmfTone(digit);
         } else {
-            Log.e(this, "error playDtmfTone, mAdapter is null");
+            Log.e(this, "error playDtmfTone, mPhone is null");
         }
     }
 
     void stopDtmfTone(String callId) {
-        if (mAdapter != null) {
-            mAdapter.stopDtmfTone(callId);
+        if (mPhone != null) {
+            getTelecommCallById(callId).stopDtmfTone();
         } else {
-            Log.e(this, "error stopDtmfTone, mAdapter is null");
+            Log.e(this, "error stopDtmfTone, mPhone is null");
         }
     }
 
     void postDialContinue(String callId, boolean proceed) {
-        if (mAdapter != null) {
-            mAdapter.postDialContinue(callId, proceed);
+        if (mPhone != null) {
+            getTelecommCallById(callId).postDialContinue(proceed);
         } else {
-            Log.e(this, "error postDialContinue, mAdapter is null");
+            Log.e(this, "error postDialContinue, mPhone is null");
         }
     }
 
     void phoneAccountClicked(String callId) {
-        if (mAdapter != null) {
-            mAdapter.phoneAccountClicked(callId);
+        if (mPhone != null) {
+            getTelecommCallById(callId).phoneAccountClicked();
         } else {
-            Log.e(this, "error phoneAccountClicked, mAdapter is null");
+            Log.e(this, "error phoneAccountClicked, mPhone is null");
         }
     }
 }