1 /*
2  * Copyright (C) 2014 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.services.telephony;
18 
19 import android.net.Uri;
20 import android.telecom.Connection;
21 import android.telecom.DisconnectCause;
22 import android.telephony.SubscriptionInfo;
23 import android.text.TextUtils;
24 
25 import com.android.ims.internal.ConferenceParticipant;
26 import com.android.internal.telephony.Phone;
27 import com.android.internal.telephony.PhoneConstants;
28 import com.android.telephony.Rlog;
29 
30 /**
31  * Represents a participant in a conference call.
32  */
33 public class ConferenceParticipantConnection extends Connection {
34 
35     private static final String LOG_TAG = "ConferenceParticipantConnection";
36 
37     /**
38      * The user entity URI For the conference participant.
39      */
40     private final Uri mUserEntity;
41 
42     /**
43      * The endpoint URI For the conference participant.
44      */
45     private final Uri mEndpoint;
46 
47     /**
48      * The connection which owns this participant.
49      */
50     private final com.android.internal.telephony.Connection mParentConnection;
51 
52     /**
53      * Creates a new instance.
54      *
55      * @param participant The conference participant to create the instance for.
56      * @param isRemotelyHosted {@code true} if this participant is part of a conference remotely
57      *                         hosted on another device, {@code false} otherwise.
58      */
ConferenceParticipantConnection( com.android.internal.telephony.Connection parentConnection, ConferenceParticipant participant, boolean isRemotelyHosted)59     public ConferenceParticipantConnection(
60             com.android.internal.telephony.Connection parentConnection,
61             ConferenceParticipant participant,
62             boolean isRemotelyHosted) {
63 
64         mParentConnection = parentConnection;
65 
66         int presentation = participant.getParticipantPresentation();
67         Uri address;
68         if (presentation != PhoneConstants.PRESENTATION_ALLOWED) {
69             address = null;
70         } else {
71             String countryIso = getCountryIso(parentConnection.getCall().getPhone());
72             address = ConferenceParticipant.getParticipantAddress(participant.getHandle(),
73                     countryIso);
74         }
75         setAddress(address, presentation);
76         setVideoState(parentConnection.getVideoState());
77         setCallerDisplayName(participant.getDisplayName(), presentation);
78 
79         mUserEntity = participant.getHandle();
80         mEndpoint = participant.getEndpoint();
81 
82         setCapabilitiesAndProperties(isRemotelyHosted);
83     }
84 
85     /**
86      * Changes the state of the conference participant.
87      *
88      * @param newState The new state.
89      */
updateState(int newState)90     public void updateState(int newState) {
91         Log.v(this, "updateState endPoint: %s state: %s", Rlog.pii(LOG_TAG, mEndpoint),
92                 Connection.stateToString(newState));
93         if (newState == getState()) {
94             return;
95         }
96 
97         switch (newState) {
98             case STATE_INITIALIZING:
99                 setInitializing();
100                 break;
101             case STATE_RINGING:
102                 setRinging();
103                 break;
104             case STATE_DIALING:
105                 setDialing();
106                 break;
107             case STATE_HOLDING:
108                 setOnHold();
109                 break;
110             case STATE_ACTIVE:
111                 setActive();
112                 break;
113             case STATE_DISCONNECTED:
114                 setDisconnected(new DisconnectCause(DisconnectCause.CANCELED));
115                 destroy();
116                 break;
117             default:
118                 setActive();
119         }
120     }
121 
122     /**
123      * Disconnects the current {@code ConferenceParticipantConnection} from the conference.
124      * <p>
125      * Sends a participant disconnect signal to the associated parent connection.  The participant
126      * connection is not disconnected and cleaned up here.  On successful disconnection of the
127      * participant, the conference server will send an update to the conference controller
128      * indicating the disconnection was successful.
129      */
130     @Override
onDisconnect()131     public void onDisconnect() {
132         mParentConnection.onDisconnectConferenceParticipant(mUserEntity);
133     }
134 
135     /**
136      * Retrieves the user handle for this connection.
137      *
138      * @return The userEntity.
139      */
getUserEntity()140     public Uri getUserEntity() {
141         return mUserEntity;
142     }
143 
144     /**
145      * Retrieves the endpoint for this connection.
146      *
147      * @return The endpoint.
148      */
getEndpoint()149     public Uri getEndpoint() {
150         return mEndpoint;
151     }
152 
153     /**
154      * Configures the capabilities and properties applicable to this connection.  A
155      * conference participant can only be disconnected from a conference since there is not
156      * actual connection to the participant which could be split from the conference.
157      * @param isRemotelyHosted {@code true} if this participant is part of a conference hosted
158      *                         hosted on a remote device, {@code false} otherwise.
159      */
setCapabilitiesAndProperties(boolean isRemotelyHosted)160     private void setCapabilitiesAndProperties(boolean isRemotelyHosted) {
161         int capabilities = CAPABILITY_DISCONNECT_FROM_CONFERENCE;
162         setConnectionCapabilities(capabilities);
163 
164         if (isRemotelyHosted) {
165             setConnectionProperties(PROPERTY_REMOTELY_HOSTED);
166         }
167     }
168 
169     /**
170      * Given a {@link Phone} instance, determines the country ISO associated with the phone's
171      * subscription.
172      *
173      * @param phone The phone instance.
174      * @return The country ISO.
175      */
getCountryIso(Phone phone)176     private String getCountryIso(Phone phone) {
177         if (phone == null) {
178             return null;
179         }
180 
181         int subId = phone.getSubId();
182 
183         SubscriptionInfo subInfo = TelecomAccountRegistry.getInstance(null).
184                 getSubscriptionManager().getActiveSubscriptionInfo(subId);
185 
186         if (subInfo == null || TextUtils.isEmpty(subInfo.getCountryIso())) {
187             return null;
188         }
189         // The SubscriptionInfo reports ISO country codes in lower case.  Convert to upper case,
190         // since ultimately we use this ISO when formatting the CEP phone number, and the phone
191         // number formatting library expects uppercase ISO country codes.
192         return subInfo.getCountryIso().toUpperCase();
193     }
194 
195     /**
196      * Builds a string representation of this conference participant connection.
197      *
198      * @return String representation of connection.
199      */
200     @Override
toString()201     public String toString() {
202         StringBuilder sb = new StringBuilder();
203         sb.append("[ConferenceParticipantConnection objId:");
204         sb.append(System.identityHashCode(this));
205         sb.append(" endPoint:");
206         sb.append(Rlog.pii(LOG_TAG, mEndpoint));
207         sb.append(" address:");
208         sb.append(Rlog.pii(LOG_TAG, getAddress()));
209         sb.append(" addressPresentation:");
210         sb.append(getAddressPresentation());
211         sb.append(" parentConnection:");
212         sb.append(Rlog.pii(LOG_TAG, mParentConnection.getAddress()));
213         sb.append(" state:");
214         sb.append(Connection.stateToString(getState()));
215         sb.append(" connectTime:");
216         sb.append(getConnectTimeMillis());
217         sb.append(" connectElapsedTime:");
218         sb.append(getConnectionStartElapsedRealtimeMillis());
219         sb.append("]");
220 
221         return sb.toString();
222     }
223 }
224