OutgoingCalls(1/6) - Filling in lifecycle of outgoing call.

This CL adds the following:
1. CallServiceAdapter implementation
2. Setting call-service adapters when the finder receives call services.
3. CallServiceAdapter notifies OutgoingCallManager/OCP about a successful
    outgoing call
4. Switchboard notifies CallsManager of the successful outgoing call
5. CallsManager adds the call to it's call repository.

What remains after this CL:
CallsManager sending the call to the InCall app and listening to
commands from in-call.

depends on: I086443e3f17ae0233b7b0fd5629119e989d06a40

Change-Id: I86f3e7ab02a47485eb2a5fb3557819418f3c4adf
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 0712f03..332eb0a 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -17,11 +17,18 @@
 package com.android.telecomm;
 
 import android.content.Context;
+import android.telecomm.CallState;
+import android.text.TextUtils;
+import android.util.Log;
 
 import com.android.telecomm.exceptions.RestrictedCallException;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * Singleton.
@@ -31,6 +38,7 @@
  * beyond the com.android.telecomm package boundary.
  */
 public final class CallsManager {
+    private static final String TAG = CallsManager.class.getSimpleName();
 
     private static final CallsManager INSTANCE = new CallsManager();
 
@@ -40,6 +48,14 @@
     private final InCallController mInCallController;
 
     /**
+     * The main call repository. Keeps an instance of all live calls keyed by call ID. New incoming
+     * and outgoing calls are added to the map and removed when the calls move to the disconnected
+     * state.
+     * TODO(santoscordon): Add new CallId class and use it in place of String.
+     */
+    private final Map<String, Call> mCalls = Maps.newHashMap();
+
+    /**
      * May be unnecessary per off-line discussions (between santoscordon and gilad) since the set
      * of CallsManager APIs that need to be exposed to the dialer (or any application firing call
      * intents) may be empty.
@@ -65,7 +81,7 @@
      */
     private CallsManager() {
         mSwitchboard = new Switchboard();
-        mInCallController = new InCallController(this);
+        mInCallController = new InCallController();
     }
 
     /**
@@ -90,6 +106,21 @@
     }
 
     /**
+     * Adds a new outgoing call to the list of live calls and notifies the in-call app.
+     *
+     * @param call The new outgoing call.
+     */
+    void handleSuccessfulOutgoingCall(Call call) {
+        // OutgoingCallProcessor sets the call state to DIALING when it receives confirmation of the
+        // placed call from the call service so there is no need to set it here. Instead, check that
+        // the state is appropriate.
+        Preconditions.checkState(call.getState() == CallState.DIALING);
+
+        addCall(call);
+        // TODO(santoscordon): Notify in-call UI.
+    }
+
+    /**
      * Instructs Telecomm to answer the specified call. Intended to be invoked by the in-call
      * app through {@link InCallAdapter} after Telecomm notifies it of an incoming call followed by
      * the user opting to answer said call.
@@ -121,4 +152,57 @@
     void disconnectCall(String callId) {
         // TODO(santoscordon): fill in and check that the call is in the active state.
     }
+
+    void markCallAsRinging(String callId) {
+        setCallState(callId, CallState.RINGING);
+    }
+
+    void markCallAsDialing(String callId) {
+        setCallState(callId, CallState.DIALING);
+    }
+
+    void markCallAsActive(String callId) {
+        setCallState(callId, CallState.ACTIVE);
+    }
+
+    void markCallAsDisconnected(String callId) {
+        setCallState(callId, CallState.DISCONNECTED);
+        mCalls.remove(callId);
+    }
+
+    /**
+     * Sets the specified state on the specified call.
+     *
+     * @param callId The ID of the call to update.
+     * @param state The new state of the call.
+     */
+    private void setCallState(String callId, CallState state) {
+        Preconditions.checkState(!Strings.isNullOrEmpty(callId));
+        Preconditions.checkNotNull(state);
+
+        Call call = mCalls.get(callId);
+        if (call == null) {
+            Log.e(TAG, "Call " + callId + " was not found while attempting to upda the state to " +
+                    state + ".");
+        } else {
+            // Unfortunately, in the telephony world, the radio is king. So if the call notifies us
+            // that the call is in a particular state, we allow it even if it doesn't make sense
+            // (e.g., ACTIVE -> RINGING).
+            // TODO(santoscordon): Consider putting a stop to the above and turning CallState into
+            // a well-defined state machine.
+            // TODO(santoscordon): Define expected state transitions here, and log when an
+            // unexpected transition occurs.
+            call.setState(state);
+            // TODO(santoscordon): Notify the in-call app whenever a call changes state.
+        }
+    }
+
+    /**
+     * Adds the specified call to the main list of live calls.
+     *
+     * @param call The call to add.
+     */
+    private void addCall(Call call) {
+        mCalls.put(call.getId(), call);
+    }
 }