Renaming Telecomm to Telecom.

- Changing package from android.telecomm to android.telecom
- Changing package from com.android.telecomm to
com.android.server.telecomm.
- Renaming TelecommManager to TelecomManager.

Bug: 17364651
Change-Id: I192cb5d189f55db012ea72ee82ccc5aedbc21638
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
new file mode 100644
index 0000000..bfd7c51
--- /dev/null
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -0,0 +1,385 @@
+/*
+ * 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 android.telecom;
+
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.RemoteException;
+import android.telephony.DisconnectCause;
+
+import com.android.internal.telecom.IConnectionService;
+import com.android.internal.telecom.IConnectionServiceAdapter;
+import com.android.internal.telecom.IVideoProvider;
+import com.android.internal.telecom.RemoteServiceCallback;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Remote connection service which other connection services can use to place calls on their behalf.
+ *
+ * @hide
+ */
+final class RemoteConnectionService {
+
+    private static final RemoteConnection NULL_CONNECTION =
+            new RemoteConnection("NULL", null, null);
+
+    private static final RemoteConference NULL_CONFERENCE =
+            new RemoteConference("NULL", null);
+
+    private final IConnectionServiceAdapter mServantDelegate = new IConnectionServiceAdapter() {
+        @Override
+        public void handleCreateConnectionComplete(
+                String id,
+                ConnectionRequest request,
+                ParcelableConnection parcel) {
+            RemoteConnection connection =
+                    findConnectionForAction(id, "handleCreateConnectionSuccessful");
+            if (connection != NULL_CONNECTION && mPendingConnections.contains(connection)) {
+                mPendingConnections.remove(connection);
+                // Unconditionally initialize the connection ...
+                connection.setCallCapabilities(parcel.getCapabilities());
+                connection.setAddress(
+                        parcel.getHandle(), parcel.getHandlePresentation());
+                connection.setCallerDisplayName(
+                        parcel.getCallerDisplayName(),
+                        parcel.getCallerDisplayNamePresentation());
+                // Set state after handle so that the client can identify the connection.
+                connection.setState(parcel.getState());
+                List<RemoteConnection> conferenceable = new ArrayList<>();
+                for (String confId : parcel.getConferenceableConnectionIds()) {
+                    if (mConnectionById.containsKey(confId)) {
+                        conferenceable.add(mConnectionById.get(confId));
+                    }
+                }
+                connection.setConferenceableConnections(conferenceable);
+                connection.setVideoState(parcel.getVideoState());
+                if (connection.getState() == Connection.STATE_DISCONNECTED) {
+                    // ... then, if it was created in a disconnected state, that indicates
+                    // failure on the providing end, so immediately mark it destroyed
+                    connection.setDestroyed();
+                }
+            }
+        }
+
+        @Override
+        public void setActive(String callId) {
+            if (mConnectionById.containsKey(callId)) {
+                findConnectionForAction(callId, "setActive")
+                        .setState(Connection.STATE_ACTIVE);
+            } else {
+                findConferenceForAction(callId, "setActive")
+                        .setState(Connection.STATE_ACTIVE);
+            }
+        }
+
+        @Override
+        public void setRinging(String callId) {
+            findConnectionForAction(callId, "setRinging")
+                    .setState(Connection.STATE_RINGING);
+        }
+
+        @Override
+        public void setDialing(String callId) {
+            findConnectionForAction(callId, "setDialing")
+                    .setState(Connection.STATE_DIALING);
+        }
+
+        @Override
+        public void setDisconnected(String callId, int disconnectCause,
+                String disconnectMessage) {
+            if (mConnectionById.containsKey(callId)) {
+                findConnectionForAction(callId, "setDisconnected")
+                        .setDisconnected(disconnectCause, disconnectMessage);
+            } else {
+                findConferenceForAction(callId, "setDisconnected")
+                        .setDisconnected(disconnectCause, disconnectMessage);
+            }
+        }
+
+        @Override
+        public void setOnHold(String callId) {
+            if (mConnectionById.containsKey(callId)) {
+                findConnectionForAction(callId, "setOnHold")
+                        .setState(Connection.STATE_HOLDING);
+            } else {
+                findConferenceForAction(callId, "setOnHold")
+                        .setState(Connection.STATE_HOLDING);
+            }
+        }
+
+        @Override
+        public void setRingbackRequested(String callId, boolean ringing) {
+            findConnectionForAction(callId, "setRingbackRequested")
+                    .setRingbackRequested(ringing);
+        }
+
+        @Override
+        public void setCallCapabilities(String callId, int callCapabilities) {
+            if (mConnectionById.containsKey(callId)) {
+                findConnectionForAction(callId, "setCallCapabilities")
+                        .setCallCapabilities(callCapabilities);
+            } else {
+                findConferenceForAction(callId, "setCallCapabilities")
+                        .setCallCapabilities(callCapabilities);
+            }
+        }
+
+        @Override
+        public void setIsConferenced(String callId, String conferenceCallId) {
+            // Note: callId should not be null; conferenceCallId may be null
+            RemoteConnection connection =
+                    findConnectionForAction(callId, "setIsConferenced");
+            if (connection != NULL_CONNECTION) {
+                if (conferenceCallId == null) {
+                    // 'connection' is being split from its conference
+                    if (connection.getConference() != null) {
+                        connection.getConference().removeConnection(connection);
+                    }
+                } else {
+                    RemoteConference conference =
+                            findConferenceForAction(conferenceCallId, "setIsConferenced");
+                    if (conference != NULL_CONFERENCE) {
+                        conference.addConnection(connection);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void addConferenceCall(
+                final String callId,
+                ParcelableConference parcel) {
+            RemoteConference conference = new RemoteConference(callId,
+                    mOutgoingConnectionServiceRpc);
+
+            for (String id : parcel.getConnectionIds()) {
+                RemoteConnection c = mConnectionById.get(id);
+                if (c != null) {
+                    conference.addConnection(c);
+                }
+            }
+
+            if (conference.getConnections().size() == 0) {
+                // A conference was created, but none of its connections are ones that have been
+                // created by, and therefore being tracked by, this remote connection service. It
+                // is of no interest to us.
+                return;
+            }
+
+            conference.setState(parcel.getState());
+            conference.setCallCapabilities(parcel.getCapabilities());
+            mConferenceById.put(callId, conference);
+            conference.registerCallback(new RemoteConference.Callback() {
+                @Override
+                public void onDestroyed(RemoteConference c) {
+                    mConferenceById.remove(callId);
+                    maybeDisconnectAdapter();
+                }
+            });
+
+            mOurConnectionServiceImpl.addRemoteConference(conference);
+        }
+
+        @Override
+        public void removeCall(String callId) {
+            if (mConnectionById.containsKey(callId)) {
+                findConnectionForAction(callId, "removeCall")
+                        .setDestroyed();
+            } else {
+                findConferenceForAction(callId, "removeCall")
+                        .setDestroyed();
+            }
+        }
+
+        @Override
+        public void onPostDialWait(String callId, String remaining) {
+            findConnectionForAction(callId, "onPostDialWait")
+                    .setPostDialWait(remaining);
+        }
+
+        @Override
+        public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
+            // Not supported from remote connection service.
+        }
+
+        @Override
+        public void setVideoProvider(String callId, IVideoProvider videoProvider) {
+            findConnectionForAction(callId, "setVideoProvider")
+                    .setVideoProvider(new RemoteConnection.VideoProvider(videoProvider));
+        }
+
+        @Override
+        public void setVideoState(String callId, int videoState) {
+            findConnectionForAction(callId, "setVideoState")
+                    .setVideoState(videoState);
+        }
+
+        @Override
+        public void setIsVoipAudioMode(String callId, boolean isVoip) {
+            findConnectionForAction(callId, "setIsVoipAudioMode")
+                    .setIsVoipAudioMode(isVoip);
+        }
+
+        @Override
+        public void setStatusHints(String callId, StatusHints statusHints) {
+            findConnectionForAction(callId, "setStatusHints")
+                    .setStatusHints(statusHints);
+        }
+
+        @Override
+        public void setAddress(String callId, Uri address, int presentation) {
+            findConnectionForAction(callId, "setAddress")
+                    .setAddress(address, presentation);
+        }
+
+        @Override
+        public void setCallerDisplayName(String callId, String callerDisplayName,
+                int presentation) {
+            findConnectionForAction(callId, "setCallerDisplayName")
+                    .setCallerDisplayName(callerDisplayName, presentation);
+        }
+
+        @Override
+        public IBinder asBinder() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public final void setConferenceableConnections(
+                String callId, List<String> conferenceableConnectionIds) {
+            List<RemoteConnection> conferenceable = new ArrayList<>();
+            for (String id : conferenceableConnectionIds) {
+                if (mConnectionById.containsKey(id)) {
+                    conferenceable.add(mConnectionById.get(id));
+                }
+            }
+
+            findConnectionForAction(callId, "setConferenceableConnections")
+                    .setConferenceableConnections(conferenceable);
+        }
+    };
+
+    private final ConnectionServiceAdapterServant mServant =
+            new ConnectionServiceAdapterServant(mServantDelegate);
+
+    private final DeathRecipient mDeathRecipient = new DeathRecipient() {
+        @Override
+        public void binderDied() {
+            for (RemoteConnection c : mConnectionById.values()) {
+                c.setDestroyed();
+            }
+            for (RemoteConference c : mConferenceById.values()) {
+                c.setDestroyed();
+            }
+            mConnectionById.clear();
+            mConferenceById.clear();
+            mPendingConnections.clear();
+            mOutgoingConnectionServiceRpc.asBinder().unlinkToDeath(mDeathRecipient, 0);
+        }
+    };
+
+    private final IConnectionService mOutgoingConnectionServiceRpc;
+    private final ConnectionService mOurConnectionServiceImpl;
+    private final Map<String, RemoteConnection> mConnectionById = new HashMap<>();
+    private final Map<String, RemoteConference> mConferenceById = new HashMap<>();
+    private final Set<RemoteConnection> mPendingConnections = new HashSet<>();
+
+    RemoteConnectionService(
+            IConnectionService outgoingConnectionServiceRpc,
+            ConnectionService ourConnectionServiceImpl) throws RemoteException {
+        mOutgoingConnectionServiceRpc = outgoingConnectionServiceRpc;
+        mOutgoingConnectionServiceRpc.asBinder().linkToDeath(mDeathRecipient, 0);
+        mOurConnectionServiceImpl = ourConnectionServiceImpl;
+    }
+
+    @Override
+    public String toString() {
+        return "[RemoteCS - " + mOutgoingConnectionServiceRpc.asBinder().toString() + "]";
+    }
+
+    final RemoteConnection createRemoteConnection(
+            PhoneAccountHandle connectionManagerPhoneAccount,
+            ConnectionRequest request,
+            boolean isIncoming) {
+        final String id = UUID.randomUUID().toString();
+        final ConnectionRequest newRequest = new ConnectionRequest(
+                request.getAccountHandle(),
+                request.getAddress(),
+                request.getExtras(),
+                request.getVideoState());
+        try {
+            if (mConnectionById.isEmpty()) {
+                mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub());
+            }
+            RemoteConnection connection =
+                    new RemoteConnection(id, mOutgoingConnectionServiceRpc, newRequest);
+            mPendingConnections.add(connection);
+            mConnectionById.put(id, connection);
+            mOutgoingConnectionServiceRpc.createConnection(
+                    connectionManagerPhoneAccount,
+                    id,
+                    newRequest,
+                    isIncoming);
+            connection.registerCallback(new RemoteConnection.Callback() {
+                @Override
+                public void onDestroyed(RemoteConnection connection) {
+                    mConnectionById.remove(id);
+                    maybeDisconnectAdapter();
+                }
+            });
+            return connection;
+        } catch (RemoteException e) {
+            return RemoteConnection
+                    .failure(DisconnectCause.ERROR_UNSPECIFIED, e.toString());
+        }
+    }
+
+    private RemoteConnection findConnectionForAction(
+            String callId, String action) {
+        if (mConnectionById.containsKey(callId)) {
+            return mConnectionById.get(callId);
+        }
+        Log.w(this, "%s - Cannot find Connection %s", action, callId);
+        return NULL_CONNECTION;
+    }
+
+    private RemoteConference findConferenceForAction(
+            String callId, String action) {
+        if (mConferenceById.containsKey(callId)) {
+            return mConferenceById.get(callId);
+        }
+        Log.w(this, "%s - Cannot find Conference %s", action, callId);
+        return NULL_CONFERENCE;
+    }
+
+    private void maybeDisconnectAdapter() {
+        if (mConnectionById.isEmpty() && mConferenceById.isEmpty()) {
+            try {
+                mOutgoingConnectionServiceRpc.removeConnectionServiceAdapter(mServant.getStub());
+            } catch (RemoteException e) {
+            }
+        }
+    }
+}