IMS call merge call-back changes.
[android/platform/frameworks/opt/net/ims.git] / src / java / com / android / ims / ImsCall.java
index b7adfb1..778679a 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.ims;
 
+import com.android.internal.R;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -642,6 +644,15 @@ public class ImsCall implements ICall {
     }
 
     /**
+     * Determines if the call is a multiparty call.
+     *
+     * @return {@code True} if the call is a multiparty call.
+     */
+    public boolean isMultiparty() {
+        return mSession.isMultiparty();
+    }
+
+    /**
      * Sets the listener to listen to the IMS call events.
      * The method calls {@link #setListener setListener(listener, false)}.
      *
@@ -808,14 +819,16 @@ public class ImsCall implements ICall {
      * Accepts a call.
      *
      * @see Listener#onCallStarted
+     *
+     * @param callType The call type the user agreed to for accepting the call.
      * @throws ImsException if the IMS service fails to accept the call
      */
-    public void accept() throws ImsException {
+    public void accept(int callType) throws ImsException {
         if (DBG) {
             log("accept :: session=" + mSession);
         }
 
-        accept(ImsCallProfile.CALL_TYPE_VOICE, new ImsStreamMediaProfile());
+        accept(callType, new ImsStreamMediaProfile());
     }
 
     /**
@@ -907,13 +920,23 @@ public class ImsCall implements ICall {
         synchronized(mLockObj) {
             mHold = false;
             mInCall = false;
+            CallGroup callGroup = getCallGroup();
 
             if (mSession != null) {
+                if (callGroup != null && !callGroup.isOwner(ImsCall.this)) {
+                    log("terminate owner of the call group");
+                    ImsCall owner = (ImsCall) callGroup.getOwner();
+                    if (owner != null) {
+                        owner.terminate(reason);
+                        return;
+                    }
+                }
                 mSession.terminate(reason);
             }
         }
     }
 
+
     /**
      * Puts a call on hold. When succeeds, {@link Listener#onCallHeld} is called.
      *
@@ -925,6 +948,20 @@ public class ImsCall implements ICall {
             log("hold :: session=" + mSession);
         }
 
+        // perform operation on owner before doing any local checks: local
+        // call may not have its status updated
+        synchronized (mLockObj) {
+            CallGroup callGroup = mCallGroup;
+            if (callGroup != null && !callGroup.isOwner(ImsCall.this)) {
+                log("hold owner of the call group");
+                ImsCall owner = (ImsCall) callGroup.getOwner();
+                if (owner != null) {
+                    owner.hold();
+                    return;
+                }
+            }
+        }
+
         if (isOnHold()) {
             if (DBG) {
                 log("hold :: call is already on hold");
@@ -963,6 +1000,20 @@ public class ImsCall implements ICall {
             log("resume :: session=" + mSession);
         }
 
+        // perform operation on owner before doing any local checks: local
+        // call may not have its status updated
+        synchronized (mLockObj) {
+            CallGroup callGroup = mCallGroup;
+            if (callGroup != null && !callGroup.isOwner(ImsCall.this)) {
+                log("resume owner of the call group");
+                ImsCall owner = (ImsCall) callGroup.getOwner();
+                if (owner != null) {
+                    owner.resume();
+                    return;
+                }
+            }
+        }
+
         if (!isOnHold()) {
             if (DBG) {
                 log("resume :: call is in conversation");
@@ -1014,7 +1065,10 @@ public class ImsCall implements ICall {
                         ImsReasonInfo.CODE_LOCAL_CALL_TERMINATED);
             }
 
-            if (mHold) {
+            // if skipHoldBeforeMerge = true, IMS service implementation will
+            // merge without explicitly holding the call.
+            if (mHold || (mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.skipHoldBeforeMerge))) {
                 mSession.merge();
                 mUpdateRequest = UPDATE_MERGE;
             } else {
@@ -1170,10 +1224,10 @@ public class ImsCall implements ICall {
      * 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 code the DTMF to send. Value 0 to 15 (inclusive) are valid inputs.
+     * @param char that represents the DTMF digit to send.
      */
-    public void sendDtmf(int code) {
-        sendDtmf(code, null);
+    public void sendDtmf(char c) {
+        sendDtmf(c, null);
     }
 
     /**
@@ -1181,17 +1235,17 @@ public class ImsCall implements ICall {
      * 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 code the DTMF to send. Value 0 to 15 (inclusive) are valid inputs.
-     * @param result the result message to send when done
+     * @param c that represents the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+     * @param result the result message to send when done.
      */
-    public void sendDtmf(int code, Message result) {
+    public void sendDtmf(char c, Message result) {
         if (DBG) {
-            log("sendDtmf :: session=" + mSession + ", code=" + code);
+            log("sendDtmf :: session=" + mSession + ", code=" + c);
         }
 
         synchronized(mLockObj) {
             if (mSession != null) {
-                mSession.sendDtmf(code);
+                mSession.sendDtmf(c);
             }
         }
 
@@ -1259,8 +1313,6 @@ public class ImsCall implements ICall {
 
         ImsCall neutralReferrer = (ImsCall)mCallGroup.getNeutralReferrer();
 
-        mCallGroup.setNeutralReferrer(null);
-
         if (owner == null) {
             // Maintain the call group if the current call has been merged in the past.
             if (!mCallGroup.hasReferrer()) {
@@ -1271,7 +1323,7 @@ public class ImsCall implements ICall {
             mCallGroup.addReferrer(this);
 
             if (neutralReferrer != null) {
-                if (neutralReferrer.isInCall() && (neutralReferrer.getCallGroup() == null)) {
+                if (neutralReferrer.getCallGroup() == null) {
                     neutralReferrer.setCallGroup(mCallGroup);
                     mCallGroup.addReferrer(neutralReferrer);
                 }
@@ -1304,7 +1356,7 @@ public class ImsCall implements ICall {
         mCallGroup = null;
     }
 
-    private CallGroup getCallGroup() {
+    public CallGroup getCallGroup() {
         synchronized(mLockObj) {
             return mCallGroup;
         }
@@ -1420,25 +1472,23 @@ public class ImsCall implements ICall {
         ImsCall.Listener listener;
 
         if (mCallGroup.isOwner(ImsCall.this)) {
-            ArrayList<ICall> referrers = mCallGroup.getReferrers();
-
-            if (referrers != null) {
-                for (int i = 0; i < referrers.size(); ++i) {
-                    ImsCall call = (ImsCall)referrers.get(i);
+            log("Group Owner! Size of referrers list = " + mCallGroup.getReferrers().size());
+            while (mCallGroup.hasReferrer()) {
+                ImsCall call = (ImsCall) mCallGroup.getReferrers().get(0);
+                log("onCallTerminated to be called for the call:: " + call);
 
-                    if (call == null) {
-                        continue;
-                    }
+                if (call == null) {
+                    continue;
+                }
 
-                    listener = call.mListener;
-                    call.clear(reasonInfo);
+                listener = call.mListener;
+                call.clear(reasonInfo);
 
-                    if (listener != null) {
-                        try {
-                            listener.onCallTerminated(call, reasonInfo);
-                        } catch (Throwable t) {
-                            loge("notifyConferenceSessionTerminated :: ", t);
-                        }
+                if (listener != null) {
+                    try {
+                        listener.onCallTerminated(call, reasonInfo);
+                    } catch (Throwable t) {
+                        loge("notifyConferenceSessionTerminated :: ", t);
                     }
                 }
             }
@@ -1458,6 +1508,42 @@ public class ImsCall implements ICall {
         }
     }
 
+    private void notifyConferenceStateUpdatedThroughGroupOwner(int update) {
+        ImsCall.Listener listener;
+
+        if (mCallGroup.isOwner(ImsCall.this)) {
+            log("Group Owner! Size of referrers list = " + mCallGroup.getReferrers().size());
+            for (ICall icall : mCallGroup.getReferrers()) {
+                ImsCall call = (ImsCall) icall;
+                log("notifyConferenceStateUpdatedThroughGroupOwner to be called for the call:: " + call);
+
+                if (call == null) {
+                    continue;
+                }
+
+                listener = call.mListener;
+
+                if (listener != null) {
+                    try {
+                        switch (update) {
+                            case UPDATE_HOLD:
+                                listener.onCallHeld(call);
+                                break;
+                            case UPDATE_RESUME:
+                                listener.onCallResumed(call);
+                                break;
+                            default:
+                                loge("notifyConferenceStateUpdatedThroughGroupOwner :: not handled update "
+                                        + update);
+                        }
+                    } catch (Throwable t) {
+                        loge("notifyConferenceStateUpdatedThroughGroupOwner :: ", t);
+                    }
+                }
+            }
+        }
+    }
+
     private void notifyConferenceStateUpdated(ImsConferenceState state) {
         Set<Entry<String, Bundle>> paticipants = state.mParticipants.entrySet();
 
@@ -1670,6 +1756,10 @@ public class ImsCall implements ICall {
                     loge("callSessionHeld :: ", t);
                 }
             }
+
+            if (mCallGroup != null) {
+                notifyConferenceStateUpdatedThroughGroupOwner(UPDATE_HOLD);
+            }
         }
 
         @Override
@@ -1751,6 +1841,10 @@ public class ImsCall implements ICall {
                     loge("callSessionResumed :: ", t);
                 }
             }
+
+            if (mCallGroup != null) {
+                notifyConferenceStateUpdatedThroughGroupOwner(UPDATE_RESUME);
+            }
         }
 
         @Override
@@ -1802,10 +1896,10 @@ public class ImsCall implements ICall {
         }
 
         @Override
-        public void callSessionMerged(ImsCallSession session,
+        public void callSessionMergeStarted(ImsCallSession session,
                 ImsCallSession newSession, ImsCallProfile profile) {
             if (DBG) {
-                log("callSessionMerged :: session=" + session
+                log("callSessionMergeStarted :: session=" + session
                         + ", newSession=" + newSession + ", profile=" + profile);
             }
 
@@ -1821,6 +1915,8 @@ public class ImsCall implements ICall {
             synchronized(ImsCall.this) {
                 listener = mListener;
                 updateCallGroup(newCall);
+                newCall.setListener(mListener);
+                newCall.setCallGroup(mCallGroup);
                 mUpdateRequest = UPDATE_NONE;
             }
 
@@ -1828,12 +1924,21 @@ public class ImsCall implements ICall {
                 try {
                     listener.onCallMerged(ImsCall.this, newCall);
                 } catch (Throwable t) {
-                    loge("callSessionMerged :: ", t);
+                    loge("callSessionMergeStarted :: ", t);
                 }
             }
         }
 
         @Override
+        public void callSessionMergeComplete(ImsCallSession session) {
+            if (DBG) {
+                log("callSessionMergeComplete :: session=" + session);
+            }
+
+            // TODO handle successful completion of call session merge.
+        }
+
+        @Override
         public void callSessionMergeFailed(ImsCallSession session,
                 ImsReasonInfo reasonInfo) {
             if (DBG) {