1/*
2 * Copyright (C) 2016 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.internal.telephony.imsphone;
18
19import com.android.internal.telephony.Call;
20import com.android.internal.telephony.CallStateException;
21import com.android.internal.telephony.Connection;
22import com.android.internal.telephony.Phone;
23import com.android.internal.telephony.PhoneConstants;
24import com.android.internal.telephony.UUSInfo;
25
26import android.telephony.Rlog;
27import android.util.Log;
28
29import java.util.Collections;
30import java.util.List;
31import java.util.Set;
32import java.util.concurrent.ConcurrentHashMap;
33
34/**
35 * Represents an IMS call external to the device.  This class is used to represent a call which
36 * takes places on a secondary device associated with this one.  Originates from a Dialog Event
37 * Package.
38 *
39 * Dialog event package information is received from the IMS framework via
40 * {@link com.android.ims.ImsExternalCallState} instances.
41 *
42 * @hide
43 */
44public class ImsExternalConnection extends Connection {
45
46    public interface Listener {
47        void onPullExternalCall(ImsExternalConnection connection);
48    }
49
50    /**
51     * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
52     * load factor before resizing, 1 means we only expect a single thread to
53     * access the map so make only a single shard
54     */
55    private final Set<Listener> mListeners = Collections.newSetFromMap(
56            new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
57
58    /**
59     * The unqiue dialog event package specified ID associated with this external connection.
60     */
61    private int mCallId;
62
63    /**
64     * A backing call associated with this external connection.
65     */
66    private ImsExternalCall mCall;
67
68    /**
69     * Determines if the call is pullable.
70     */
71    private boolean mIsPullable;
72
73    protected ImsExternalConnection(Phone phone, int callId, String address, boolean isPullable) {
74        super(phone.getPhoneType());
75        mCall = new ImsExternalCall(phone, this);
76        mCallId = callId;
77        mAddress = address;
78        mNumberPresentation = PhoneConstants.PRESENTATION_ALLOWED;
79        mIsPullable = isPullable;
80
81        rebuildCapabilities();
82        setActive();
83    }
84
85    /**
86     * @return the unique ID of this connection from the dialog event package data.
87     */
88    public int getCallId() {
89        return mCallId;
90    }
91
92    @Override
93    public Call getCall() {
94        return mCall;
95    }
96
97    @Override
98    public long getDisconnectTime() {
99        return 0;
100    }
101
102    @Override
103    public long getHoldDurationMillis() {
104        return 0;
105    }
106
107    @Override
108    public String getVendorDisconnectCause() {
109        return null;
110    }
111
112    @Override
113    public void hangup() throws CallStateException {
114        // No-op - Hangup is not supported for external calls.
115    }
116
117    @Override
118    public void separate() throws CallStateException {
119        // No-op - Separate is not supported for external calls.
120    }
121
122    @Override
123    public void proceedAfterWaitChar() {
124        // No-op - not supported for external calls.
125    }
126
127    @Override
128    public void proceedAfterWildChar(String str) {
129        // No-op - not supported for external calls.
130    }
131
132    @Override
133    public void cancelPostDial() {
134        // No-op - not supported for external calls.
135    }
136
137    @Override
138    public int getNumberPresentation() {
139        return mNumberPresentation;
140    }
141
142    @Override
143    public UUSInfo getUUSInfo() {
144        return null;
145    }
146
147    @Override
148    public int getPreciseDisconnectCause() {
149        return 0;
150    }
151
152    @Override
153    public boolean isMultiparty() {
154        return false;
155    }
156
157    /**
158     * Called by a {@link android.telecom.Connection} to indicate that this call should be pulled
159     * to the local device.
160     *
161     * Informs all listeners, in this case {@link ImsExternalCallTracker}, of the request to pull
162     * the call.
163     */
164    @Override
165    public void pullExternalCall() {
166        for (Listener listener : mListeners) {
167            listener.onPullExternalCall(this);
168        }
169    }
170
171    /**
172     * Sets this external call as active.
173     */
174    public void setActive() {
175        if (mCall == null) {
176            return;
177        }
178        mCall.setActive();
179    }
180
181    /**
182     * Sets this external call as terminated.
183     */
184    public void setTerminated() {
185        if (mCall == null) {
186            return;
187        }
188
189        mCall.setTerminated();
190    }
191
192    /**
193     * Changes whether the call can be pulled or not.
194     *
195     * @param isPullable {@code true} if the call can be pulled, {@code false} otherwise.
196     */
197    public void setIsPullable(boolean isPullable) {
198        mIsPullable = isPullable;
199        rebuildCapabilities();
200    }
201
202    public void addListener(Listener listener) {
203        mListeners.add(listener);
204    }
205
206    public void removeListener(Listener listener) {
207        mListeners.remove(listener);
208    }
209
210    /**
211     * Build a human representation of a connection instance, suitable for debugging.
212     * Don't log personal stuff unless in debug mode.
213     * @return a string representing the internal state of this connection.
214     */
215    public String toString() {
216        StringBuilder str = new StringBuilder(128);
217        str.append("[ImsExternalConnection dialogCallId:");
218        str.append(mCallId);
219        str.append(" state:");
220        if (mCall.getState() == Call.State.ACTIVE) {
221            str.append("Active");
222        } else if (mCall.getState() == Call.State.DISCONNECTED) {
223            str.append("Disconnected");
224        }
225        str.append("]");
226        return str.toString();
227    }
228
229    /**
230     * Rebuilds the connection capabilities.
231     */
232    private void rebuildCapabilities() {
233        int capabilities = Capability.IS_EXTERNAL_CONNECTION;
234        if (mIsPullable) {
235            capabilities |= Capability.IS_PULLABLE;
236        }
237
238        setConnectionCapabilities(capabilities);
239    }
240}
241