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