Add new @hide API to pass call direction changes through Telecom

Bug: 153277327
Test: atest TelecomUnitTests
Change-Id: Icad12c4144bf185c24ee80bcbdd1aec29550bf4e
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index f019a9d..bce06e4 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -74,6 +74,7 @@
         public void onConnectionEvent(Conference c, String event, Bundle extras) {}
         public void onCallerDisplayNameChanged(
                 Conference c, String callerDisplayName, int presentation) {}
+        public void onCallDirectionChanged(Conference c, int callDirection) {}
         public void onRingbackRequested(Conference c, boolean ringback) {}
     }
 
@@ -103,6 +104,7 @@
     private int mAddressPresentation;
     private String mCallerDisplayName;
     private int mCallerDisplayNamePresentation;
+    private int mCallDirection;
     private boolean mRingbackRequested = false;
 
     private final Connection.Listener mConnectionDeathListener = new Connection.Listener() {
@@ -1024,6 +1026,25 @@
     }
 
     /**
+     * Sets the call direction of this {@link Conference}. By default, all {@link Conference}s have
+     * a direction of {@link android.telecom.Call.Details.CallDirection#DIRECTION_UNKNOWN}. The
+     * direction of a {@link Conference} is only applicable to the case where
+     * {@link #setConferenceState(boolean)} has been set to {@code false}, otherwise the direction
+     * will be ignored.
+     * @param callDirection The direction of the conference.
+     * @hide
+     */
+    @RequiresPermission(MODIFY_PHONE_STATE)
+    public final void setCallDirection(@Call.Details.CallDirection int callDirection) {
+        Log.d(this, "setDirection %d", callDirection);
+        mCallDirection = callDirection;
+        for (Listener l : mListeners) {
+            l.onCallDirectionChanged(this, callDirection);
+        }
+    }
+
+
+    /**
      * Sets the address of this {@link Conference}.  Used when {@link #setConferenceState(boolean)}
      * is called to mark a conference temporarily as NOT a conference.
      * <p>
@@ -1102,6 +1123,15 @@
     }
 
     /**
+     * @return The call direction of this conference. Only applicable when
+     * {@link #setConferenceState(boolean)} is set to false.
+     * @hide
+     */
+    public final @Call.Details.CallDirection int getCallDirection() {
+        return mCallDirection;
+    }
+
+    /**
      * Sets the caller display name (CNAP) of this {@link Conference}.  Used when
      * {@link #setConferenceState(boolean)} is called to mark a conference temporarily as NOT a
      * conference.
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index ffd25c0..0d66013 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1554,6 +1554,14 @@
         }
 
         @Override
+        public void onCallDirectionChanged(Conference c, int direction) {
+            String id = mIdByConference.get(c);
+            if (id != null) {
+                mAdapter.setCallDirection(id, direction);
+            }
+        }
+
+        @Override
         public void onAddressChanged(Conference c, Uri newAddress, int presentation) {
             String id = mIdByConference.get(c);
             if (id != null) {
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 8f27323..f8a6cf0 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -693,4 +693,20 @@
             }
         }
     }
+
+    /**
+     * Sets the direction of a call. Setting a new direction of an existing call is usually only
+     * applicable during single caller emulation during conferencing, see
+     * {@link Conference#setConferenceState(boolean)} for more information.
+     * @param callId The identifier of the call.
+     * @param direction The new direction of the call.
+     */
+    void setCallDirection(String callId, @Call.Details.CallDirection int direction) {
+        for (IConnectionServiceAdapter a : mAdapters) {
+            try {
+                a.setCallDirection(callId, direction, Log.getExternalSession());
+            } catch (RemoteException e) {
+            }
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 79ad51b..6c1ea32 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -76,6 +76,7 @@
     private static final int MSG_CONNECTION_SERVICE_FOCUS_RELEASED = 35;
     private static final int MSG_SET_CONFERENCE_STATE = 36;
     private static final int MSG_HANDLE_CREATE_CONFERENCE_COMPLETE = 37;
+    private static final int MSG_SET_CALL_DIRECTION = 38;
 
     private final IConnectionServiceAdapter mDelegate;
 
@@ -353,7 +354,7 @@
                 case MSG_CONNECTION_SERVICE_FOCUS_RELEASED:
                     mDelegate.onConnectionServiceFocusReleased(null /*Session.Info*/);
                     break;
-                case MSG_SET_CONFERENCE_STATE:
+                case MSG_SET_CONFERENCE_STATE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
                         mDelegate.setConferenceState((String) args.arg1, (Boolean) args.arg2,
@@ -361,6 +362,17 @@
                     } finally {
                         args.recycle();
                     }
+                    break;
+                }
+                case MSG_SET_CALL_DIRECTION: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        mDelegate.setCallDirection((String) args.arg1, args.argi1,
+                                (Session.Info) args.arg2);
+                    } finally {
+                        args.recycle();
+                    }
+                }
             }
         }
     };
@@ -670,6 +682,16 @@
             args.arg3 = sessionInfo;
             mHandler.obtainMessage(MSG_SET_CONFERENCE_STATE, args).sendToTarget();
         }
+
+        @Override
+        public void setCallDirection(String callId, int direction,
+                Session.Info sessionInfo) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.argi1 = direction;
+            args.arg2 = sessionInfo;
+            mHandler.obtainMessage(MSG_SET_CALL_DIRECTION, args).sendToTarget();
+        }
     };
 
     public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) {
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 76640e0..cad5b70 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -485,6 +485,11 @@
                 Session.Info sessionInfo) {
             // Do nothing
         }
+
+        @Override
+        public void setCallDirection(String callId, int direction, Session.Info sessionInfo) {
+            // Do nothing
+        }
     };
 
     private final ConnectionServiceAdapterServant mServant =
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 4f63e08..3fd7f949 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -132,4 +132,6 @@
     void resetConnectionTime(String callIdi, in Session.Info sessionInfo);
 
     void setConferenceState(String callId, boolean isConference, in Session.Info sessionInfo);
+
+    void setCallDirection(String callId, int direction, in Session.Info sessionInfo);
 }