Adds State to the Call Objects.

Also, updates the onUpdate method of ICallHandlerService to get called
when a call changes state.

Change-Id: I8fe830cdd8c7f4b92e985c518b5e1a60d6552284
diff --git a/common/src/com/android/services/telephony/common/Call.java b/common/src/com/android/services/telephony/common/Call.java
index 0b0c80c..700227d 100644
--- a/common/src/com/android/services/telephony/common/Call.java
+++ b/common/src/com/android/services/telephony/common/Call.java
@@ -27,9 +27,32 @@
 
     public static final int INVALID_CALL_ID = -1;
 
+    /* Defines different states of this call */
+    public static class State {
+        public static final int INVALID = 0;
+
+        // The call is idle.  Nothing active.
+        public static final int IDLE = 1;
+
+        // There is an active call.
+        public static final int ACTIVE = 2;
+
+        // A normal incoming phone call.
+        public static final int INCOMING = 3;
+
+        // An incoming phone call while another call is active.
+        public static final int CALL_WAITING = 4;
+
+        // A Mobile-originating (MO) call. This call is dialing out.
+        public static final int DIALING = 5;
+
+        // An active phone call placed on hold.
+        public static final int ONHOLD = 6;
+    }
+
     private int mCallId = INVALID_CALL_ID;
     private String mNumber = "";
-    // TODO(klp): Add call state type
+    private int mState = State.INVALID;
 
     public Call(int callId) {
         mCallId = callId;
@@ -43,6 +66,14 @@
         return mNumber;
     }
 
+    public int getState() {
+        return mState;
+    }
+
+    public void setState(int state) {
+        mState = state;
+    }
+
     /**
      * Parcelable implementation
      */
@@ -51,6 +82,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mCallId);
         dest.writeString(mNumber);
+        dest.writeInt(mState);
     }
 
     @Override
@@ -73,6 +105,7 @@
     private Call(Parcel in) {
         mCallId = in.readInt();
         mNumber = in.readString();
+        mState = in.readInt();
     }
 
 }
diff --git a/common/src/com/android/services/telephony/common/ICallHandlerService.aidl b/common/src/com/android/services/telephony/common/ICallHandlerService.aidl
index cd8e252..b24230f 100644
--- a/common/src/com/android/services/telephony/common/ICallHandlerService.aidl
+++ b/common/src/com/android/services/telephony/common/ICallHandlerService.aidl
@@ -46,7 +46,7 @@
      * TODO(klp): Should this replace onIncomingCall and onDisconnect?
      * TODO(klp): Should this take in a Collection of calls to update in bulk.
      */
-    void onCallUpdate(in Call call);
+    void onUpdate(in List<Call> call);
 
     /**
      * Called when a call disconnects.
diff --git a/src/com/android/phone/CallHandlerServiceProxy.java b/src/com/android/phone/CallHandlerServiceProxy.java
index c4d1468..24641c0 100644
--- a/src/com/android/phone/CallHandlerServiceProxy.java
+++ b/src/com/android/phone/CallHandlerServiceProxy.java
@@ -32,6 +32,8 @@
 import com.android.services.telephony.common.ICallHandlerService;
 import com.android.services.telephony.common.ICallCommandService;
 
+import java.util.List;
+
 /**
  * This class is responsible for passing through call state changes to the CallHandlerService.
  */
@@ -82,6 +84,17 @@
         }
     }
 
+    @Override
+    public void onUpdate(List<Call> calls) {
+        if (mCallHandlerService != null) {
+            try {
+                mCallHandlerService.onUpdate(calls);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote exception handling onUpdate", e);
+            }
+        }
+    }
+
     /**
      * Sets up the connection with ICallHandlerService
      */
diff --git a/src/com/android/phone/CallModeler.java b/src/com/android/phone/CallModeler.java
index b6504eb..5d735a4 100644
--- a/src/com/android/phone/CallModeler.java
+++ b/src/com/android/phone/CallModeler.java
@@ -25,8 +25,11 @@
 import android.os.Message;
 import android.util.Log;
 
+import com.android.internal.telephony.CallManager;
 import com.android.internal.telephony.Connection;
+import com.android.internal.telephony.PhoneConstants;
 import com.android.services.telephony.common.Call;
+import com.android.services.telephony.common.Call.State;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -68,12 +71,14 @@
     private static final int CALL_ID_START_VALUE = 1;
 
     private CallStateMonitor mCallStateMonitor;
+    private CallManager mCallManager;
     private HashMap<Connection, Call> mCallMap = Maps.newHashMap();
     private List<Listener> mListeners = Lists.newArrayList();
     private AtomicInteger mNextCallId = new AtomicInteger(CALL_ID_START_VALUE);
 
-    public CallModeler(CallStateMonitor callStateMonitor) {
+    public CallModeler(CallStateMonitor callStateMonitor, CallManager callManager) {
         mCallStateMonitor = callStateMonitor;
+        mCallManager = callManager;
 
         mCallStateMonitor.addListener(this);
     }
@@ -104,6 +109,7 @@
     private void onNewRingingConnection(AsyncResult r) {
         final Connection conn = (Connection) r.result;
         final Call call = getCallFromConnection(conn, true);
+        call.setState(Call.State.INCOMING);
 
         if (call != null) {
             for (Listener l : mListeners) {
@@ -125,7 +131,63 @@
         }
     }
 
+    /**
+     * Called when the phone state changes.
+     * The telephony layer maintains a certain amount of preallocated telephony::Call instances
+     * that change throughout the lifetime of the phone.  When we get an alert that the state
+     * changes, we need to go through the telephony::Calls and determine what changed.
+     */
     private void onPhoneStateChanged(AsyncResult r) {
+        final List<com.android.internal.telephony.Call> telephonyCalls = Lists.newArrayList();
+        telephonyCalls.addAll(mCallManager.getRingingCalls());
+        telephonyCalls.addAll(mCallManager.getForegroundCalls());
+        telephonyCalls.addAll(mCallManager.getBackgroundCalls());
+
+        final List<Call> updatedCalls = Lists.newArrayList();
+
+        // Cycle through all the Connections on all the Calls. Update our Call objects
+        // to reflect any new state and send the updated Call objects to the handler service.
+        for (com.android.internal.telephony.Call telephonyCall : telephonyCalls) {
+            final int state = translateStateFromTelephony(telephonyCall.getState());
+
+            for (Connection connection : telephonyCall.getConnections()) {
+                final Call call = getCallFromConnection(connection, true);
+
+                if (call.getState() != state) {
+                    call.setState(state);
+                    updatedCalls.add(call);
+                }
+            }
+        }
+
+        for (Listener l : mListeners) {
+            l.onUpdate(updatedCalls);
+        }
+    }
+
+    private int translateStateFromTelephony(com.android.internal.telephony.Call.State teleState) {
+        int retval = State.IDLE;
+        switch (teleState) {
+            case ACTIVE:
+                retval = State.ACTIVE;
+                break;
+            case INCOMING:
+                retval = State.INCOMING;
+                break;
+            case DIALING:
+            case ALERTING:
+                retval = State.DIALING;
+                break;
+            case WAITING:
+                retval = State.CALL_WAITING;
+                break;
+            case HOLDING:
+                retval = State.ONHOLD;
+                break;
+            default:
+        }
+
+        return retval;
     }
 
     /**
@@ -168,5 +230,6 @@
     public interface Listener {
         void onNewCall(Call call);
         void onDisconnect(Call call);
+        void onUpdate(List<Call> calls);
     }
 }
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index d96bfce..36687ce 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -546,7 +546,7 @@
             callCommandService = new CallCommandService(this, mCM);
 
             // Creates call models for use with CallHandlerService.
-            callModeler = new CallModeler(callStateMonitor);
+            callModeler = new CallModeler(callStateMonitor, mCM);
 
             // Sends call state to the UI
             callHandlerServiceProxy = new CallHandlerServiceProxy(this, callModeler,