1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.telecom.testapps;
18
19import android.net.Uri;
20import android.telecom.CallAudioState;
21import android.telecom.Conference;
22import android.telecom.Connection;
23import android.telecom.ConnectionRequest;
24import android.telecom.ConnectionService;
25import android.telecom.DisconnectCause;
26import android.telecom.PhoneAccountHandle;
27import android.telecom.RemoteConference;
28import android.telecom.RemoteConnection;
29import android.telecom.StatusHints;
30import android.telecom.VideoProfile;
31import android.util.Log;
32
33import java.util.ArrayList;
34import java.util.HashMap;
35import java.util.List;
36import java.util.Map;
37
38/**
39 * Service which acts as a fake ConnectionManager if so configured.
40 * TODO(santoscordon): Rename all classes in the directory to Dummy* (e.g., DummyConnectionService).
41 */
42public class TestConnectionManager extends ConnectionService {
43    public final class TestManagedConnection extends Connection {
44        private final RemoteConnection.Callback mRemoteCallback = new RemoteConnection.Callback() {
45            @Override
46            public void onStateChanged(RemoteConnection connection, int state) {
47                setState(state);
48            }
49
50            @Override
51            public void onDisconnected(
52                    RemoteConnection connection, DisconnectCause disconnectCause) {
53                setDisconnected(disconnectCause);
54                destroy();
55            }
56
57            @Override
58            public void onRingbackRequested(RemoteConnection connection, boolean ringback) {
59                setRingbackRequested(ringback);
60            }
61
62            @Override
63            public void onConnectionCapabilitiesChanged(RemoteConnection connection,
64                    int connectionCapabilities) {
65                setConnectionCapabilities(connectionCapabilities);
66            }
67
68            @Override
69            public void onPostDialWait(RemoteConnection connection, String remainingDigits) {
70                setPostDialWait(remainingDigits);
71            }
72
73            @Override
74            public void onVoipAudioChanged(RemoteConnection connection, boolean isVoip) {
75                setAudioModeIsVoip(isVoip);
76            }
77
78            @Override
79            public void onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints) {
80                setStatusHints(statusHints);
81            }
82
83            @Override
84            public void onVideoStateChanged(RemoteConnection connection, int videoState) {
85                if (videoState == VideoProfile.STATE_BIDIRECTIONAL) {
86                    setVideoProvider(new TestManagedVideoProvider(connection.getVideoProvider()));
87                }
88                setVideoState(videoState);
89            }
90
91            @Override
92            public void onAddressChanged(
93                    RemoteConnection connection, Uri address, int presentation) {
94                setAddress(address, presentation);
95            }
96
97            @Override
98            public void onCallerDisplayNameChanged(
99                    RemoteConnection connection, String callerDisplayName, int presentation) {
100                setCallerDisplayName(callerDisplayName, presentation);
101            }
102
103            @Override
104            public void onDestroyed(RemoteConnection connection) {
105                destroy();
106                mManagedConnectionByRemote.remove(mRemote);
107            }
108
109            @Override
110            public void onConferenceableConnectionsChanged(
111                    RemoteConnection connect,
112                    List<RemoteConnection> conferenceable) {
113                List<Connection> c = new ArrayList<>();
114                for (RemoteConnection remote : conferenceable) {
115                    if (mManagedConnectionByRemote.containsKey(remote)) {
116                        c.add(mManagedConnectionByRemote.get(remote));
117                    }
118                }
119                setConferenceableConnections(c);
120            }
121        };
122
123        private final RemoteConnection mRemote;
124        private final boolean mIsIncoming;
125
126        TestManagedConnection(RemoteConnection remote, boolean isIncoming) {
127            mRemote = remote;
128            mIsIncoming = isIncoming;
129            mRemote.registerCallback(mRemoteCallback);
130            setState(mRemote.getState());
131            setVideoState(mRemote.getVideoState());
132        }
133
134        @Override
135        public void onAbort() {
136            mRemote.abort();
137        }
138
139        /** ${inheritDoc} */
140        @Override
141        public void onAnswer(int videoState) {
142            mRemote.answer(videoState);
143        }
144
145        /** ${inheritDoc} */
146        @Override
147        public void onDisconnect() {
148            mRemote.disconnect();
149        }
150
151        @Override
152        public void onPlayDtmfTone(char c) {
153            mRemote.playDtmfTone(c);
154        }
155
156        /** ${inheritDoc} */
157        @Override
158        public void onHold() {
159            mRemote.hold();
160        }
161
162        /** ${inheritDoc} */
163        @Override
164        public void onReject() {
165            mRemote.reject();
166        }
167
168        /** ${inheritDoc} */
169        @Override
170        public void onUnhold() {
171            mRemote.unhold();
172        }
173
174        @Override
175        public void onCallAudioStateChanged(CallAudioState state) {
176            mRemote.setCallAudioState(state);
177        }
178
179        private void setState(int state) {
180            log("setState: " + state);
181            switch (state) {
182                case STATE_ACTIVE:
183                    setActive();
184                    break;
185                case STATE_HOLDING:
186                    setOnHold();
187                    break;
188                case STATE_DIALING:
189                    setDialing();
190                    break;
191                case STATE_RINGING:
192                    setRinging();
193                    break;
194            }
195        }
196    }
197
198    public final class TestManagedConference extends Conference {
199        private final RemoteConference.Callback mRemoteCallback = new RemoteConference.Callback() {
200            @Override
201            public void onStateChanged(RemoteConference conference, int oldState, int newState) {
202                switch (newState) {
203                    case Connection.STATE_DISCONNECTED:
204                        // See onDisconnected below
205                        break;
206                    case Connection.STATE_HOLDING:
207                        setOnHold();
208                        break;
209                    case Connection.STATE_ACTIVE:
210                        setActive();
211                        break;
212                    default:
213                        log("unrecognized state for Conference: " + newState);
214                        break;
215                }
216            }
217
218            @Override
219            public void onDisconnected(RemoteConference conference,
220                    DisconnectCause disconnectCause) {
221                setDisconnected(disconnectCause);
222            }
223
224            @Override
225            public void onConnectionAdded(
226                    RemoteConference conference,
227                    RemoteConnection connection) {
228                TestManagedConnection c = mManagedConnectionByRemote.get(connection);
229                if (c == null) {
230                    log("onConnectionAdded cannot find remote connection: " + connection);
231                } else {
232                    addConnection(c);
233                }
234            }
235
236            @Override
237            public void onConnectionRemoved(
238                    RemoteConference conference,
239                    RemoteConnection connection) {
240                TestManagedConnection c = mManagedConnectionByRemote.get(connection);
241                if (c == null) {
242                    log("onConnectionRemoved cannot find remote connection: " + connection);
243                } else {
244                    removeConnection(c);
245                }
246            }
247
248            @Override
249            public void onConnectionCapabilitiesChanged(RemoteConference conference,
250                    int connectionCapabilities) {
251                setConnectionCapabilities(connectionCapabilities);
252            }
253
254            @Override
255            public void onDestroyed(RemoteConference conference) {
256                destroy();
257                mRemote.unregisterCallback(mRemoteCallback);
258                mManagedConferenceByRemote.remove(mRemote);
259            }
260
261        };
262
263        @Override
264        public void onPlayDtmfTone(char c) {
265            mRemote.playDtmfTone(c);
266        };
267
268        @Override
269        public void onStopDtmfTone() {
270            mRemote.stopDtmfTone();
271        };
272
273        private final RemoteConference mRemote;
274
275        public TestManagedConference(RemoteConference remote) {
276            super(null);
277            mRemote = remote;
278            remote.registerCallback(mRemoteCallback);
279            setActive();
280            for (RemoteConnection r : remote.getConnections()) {
281                TestManagedConnection c = mManagedConnectionByRemote.get(r);
282                if (c != null) {
283                    addConnection(c);
284                }
285            }
286        }
287    }
288
289    static void log(String msg) {
290        Log.w("telecomtestcs", "[TestConnectionManager] " + msg);
291    }
292
293    private final Map<RemoteConference, TestManagedConference> mManagedConferenceByRemote
294            = new HashMap<>();
295    private final Map<RemoteConnection, TestManagedConnection> mManagedConnectionByRemote
296            = new HashMap<>();
297
298    @Override
299    public Connection onCreateOutgoingConnection(
300            PhoneAccountHandle connectionManagerAccount,
301            final ConnectionRequest request) {
302        return makeConnection(request, false);
303    }
304
305    @Override
306    public Connection onCreateIncomingConnection(
307            PhoneAccountHandle connectionManagerAccount,
308            final ConnectionRequest request) {
309        return makeConnection(request, true);
310    }
311
312    @Override
313    public void onConference(Connection a, Connection b) {
314        conferenceRemoteConnections(
315                ((TestManagedConnection) a).mRemote,
316                ((TestManagedConnection) b).mRemote);
317    }
318
319    @Override
320    public void onRemoteConferenceAdded(RemoteConference remoteConference) {
321        addConference(new TestManagedConference(remoteConference));
322    }
323
324    Map<RemoteConnection, TestManagedConnection> getManagedConnectionByRemote() {
325        return mManagedConnectionByRemote;
326    }
327
328    private Connection makeConnection(ConnectionRequest request, boolean incoming) {
329        RemoteConnection remote = incoming
330                ? createRemoteIncomingConnection(request.getAccountHandle(), request)
331                : createRemoteOutgoingConnection(request.getAccountHandle(), request);
332        TestManagedConnection local = new TestManagedConnection(remote, false);
333        mManagedConnectionByRemote.put(remote, local);
334        return local;
335    }
336}
337