1a1079194649f48af827eb879e32af661d716116fTyler Gunn/*
2a1079194649f48af827eb879e32af661d716116fTyler Gunn * Copyright (C) 2014 The Android Open Source Project
3a1079194649f48af827eb879e32af661d716116fTyler Gunn *
4a1079194649f48af827eb879e32af661d716116fTyler Gunn * Licensed under the Apache License, Version 2.0 (the "License");
5a1079194649f48af827eb879e32af661d716116fTyler Gunn * you may not use this file except in compliance with the License.
6a1079194649f48af827eb879e32af661d716116fTyler Gunn * You may obtain a copy of the License at
7a1079194649f48af827eb879e32af661d716116fTyler Gunn *
8a1079194649f48af827eb879e32af661d716116fTyler Gunn *      http://www.apache.org/licenses/LICENSE-2.0
9a1079194649f48af827eb879e32af661d716116fTyler Gunn *
10a1079194649f48af827eb879e32af661d716116fTyler Gunn * Unless required by applicable law or agreed to in writing, software
11a1079194649f48af827eb879e32af661d716116fTyler Gunn * distributed under the License is distributed on an "AS IS" BASIS,
12a1079194649f48af827eb879e32af661d716116fTyler Gunn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a1079194649f48af827eb879e32af661d716116fTyler Gunn * See the License for the specific language governing permissions and
14a1079194649f48af827eb879e32af661d716116fTyler Gunn * limitations under the License
15a1079194649f48af827eb879e32af661d716116fTyler Gunn */
16a1079194649f48af827eb879e32af661d716116fTyler Gunn
17a1079194649f48af827eb879e32af661d716116fTyler Gunnpackage com.android.services.telephony;
18a1079194649f48af827eb879e32af661d716116fTyler Gunn
19a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunnimport com.android.internal.telephony.Phone;
20a1079194649f48af827eb879e32af661d716116fTyler Gunnimport com.android.internal.telephony.PhoneConstants;
21a1079194649f48af827eb879e32af661d716116fTyler Gunn
22a1079194649f48af827eb879e32af661d716116fTyler Gunnimport android.net.Uri;
23a1079194649f48af827eb879e32af661d716116fTyler Gunnimport android.telecom.Connection;
242c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunnimport android.telecom.ConferenceParticipant;
25a1079194649f48af827eb879e32af661d716116fTyler Gunnimport android.telecom.DisconnectCause;
264bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunnimport android.telecom.PhoneAccount;
27a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunnimport android.telephony.PhoneNumberUtils;
28a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunnimport android.telephony.SubscriptionInfo;
29be622845acb8492b19fad5036e64f6247ab7a89aAnthony Leeimport android.text.TextUtils;
30a1079194649f48af827eb879e32af661d716116fTyler Gunn
31a1079194649f48af827eb879e32af661d716116fTyler Gunn/**
32a1079194649f48af827eb879e32af661d716116fTyler Gunn * Represents a participant in a conference call.
33a1079194649f48af827eb879e32af661d716116fTyler Gunn */
34a1079194649f48af827eb879e32af661d716116fTyler Gunnpublic class ConferenceParticipantConnection extends Connection {
35fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn    /**
36fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn     * RFC5767 states that a SIP URI with an unknown number should use an address of
37fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn     * {@code anonymous@anonymous.invalid}.  E.g. the host name is anonymous.invalid.
38fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn     */
39fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn    private static final String ANONYMOUS_INVALID_HOST = "anonymous.invalid";
40a1079194649f48af827eb879e32af661d716116fTyler Gunn
41a1079194649f48af827eb879e32af661d716116fTyler Gunn    /**
42af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn     * The user entity URI For the conference participant.
43af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn     */
44af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn    private final Uri mUserEntity;
45af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn
46af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn    /**
47a1079194649f48af827eb879e32af661d716116fTyler Gunn     * The endpoint URI For the conference participant.
48a1079194649f48af827eb879e32af661d716116fTyler Gunn     */
49a1079194649f48af827eb879e32af661d716116fTyler Gunn    private final Uri mEndpoint;
50a1079194649f48af827eb879e32af661d716116fTyler Gunn
51a1079194649f48af827eb879e32af661d716116fTyler Gunn    /**
52a1079194649f48af827eb879e32af661d716116fTyler Gunn     * The connection which owns this participant.
53a1079194649f48af827eb879e32af661d716116fTyler Gunn     */
542c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn    private final com.android.internal.telephony.Connection mParentConnection;
55a1079194649f48af827eb879e32af661d716116fTyler Gunn
56a1079194649f48af827eb879e32af661d716116fTyler Gunn    /**
57a1079194649f48af827eb879e32af661d716116fTyler Gunn     * Creates a new instance.
58a1079194649f48af827eb879e32af661d716116fTyler Gunn     *
59a1079194649f48af827eb879e32af661d716116fTyler Gunn     * @param participant The conference participant to create the instance for.
60a1079194649f48af827eb879e32af661d716116fTyler Gunn     */
61a1079194649f48af827eb879e32af661d716116fTyler Gunn    public ConferenceParticipantConnection(
622c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn            com.android.internal.telephony.Connection parentConnection,
632c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn            ConferenceParticipant participant) {
64a1079194649f48af827eb879e32af661d716116fTyler Gunn
65a1079194649f48af827eb879e32af661d716116fTyler Gunn        mParentConnection = parentConnection;
66a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn
67fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        int presentation = getParticipantPresentation(participant);
68fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        Uri address;
69fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        if (presentation != PhoneConstants.PRESENTATION_ALLOWED) {
70fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn            address = null;
71fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        } else {
72a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn            String countryIso = getCountryIso(parentConnection.getCall().getPhone());
73a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn            address = getParticipantAddress(participant, countryIso);
74fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        }
75fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        setAddress(address, presentation);
76fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        setCallerDisplayName(participant.getDisplayName(), presentation);
77b4edaf1c5ff88460e4b3d8161e390567ce4cef34Tyler Gunn
78af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn        mUserEntity = participant.getHandle();
79a1079194649f48af827eb879e32af661d716116fTyler Gunn        mEndpoint = participant.getEndpoint();
80fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn
81a1079194649f48af827eb879e32af661d716116fTyler Gunn        setCapabilities();
82a1079194649f48af827eb879e32af661d716116fTyler Gunn    }
83a1079194649f48af827eb879e32af661d716116fTyler Gunn
84a1079194649f48af827eb879e32af661d716116fTyler Gunn    /**
85a1079194649f48af827eb879e32af661d716116fTyler Gunn     * Changes the state of the conference participant.
86a1079194649f48af827eb879e32af661d716116fTyler Gunn     *
87a1079194649f48af827eb879e32af661d716116fTyler Gunn     * @param newState The new state.
88a1079194649f48af827eb879e32af661d716116fTyler Gunn     */
89a1079194649f48af827eb879e32af661d716116fTyler Gunn    public void updateState(int newState) {
902c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        Log.v(this, "updateState endPoint: %s state: %s", Log.pii(mEndpoint),
912c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn                Connection.stateToString(newState));
92bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn        if (newState == getState()) {
93bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn            return;
94bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn        }
95bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn
96a1079194649f48af827eb879e32af661d716116fTyler Gunn        switch (newState) {
97a1079194649f48af827eb879e32af661d716116fTyler Gunn            case STATE_INITIALIZING:
98a1079194649f48af827eb879e32af661d716116fTyler Gunn                setInitializing();
99a1079194649f48af827eb879e32af661d716116fTyler Gunn                break;
100a1079194649f48af827eb879e32af661d716116fTyler Gunn            case STATE_RINGING:
101a1079194649f48af827eb879e32af661d716116fTyler Gunn                setRinging();
102a1079194649f48af827eb879e32af661d716116fTyler Gunn                break;
103a1079194649f48af827eb879e32af661d716116fTyler Gunn            case STATE_DIALING:
104a1079194649f48af827eb879e32af661d716116fTyler Gunn                setDialing();
105a1079194649f48af827eb879e32af661d716116fTyler Gunn                break;
106a1079194649f48af827eb879e32af661d716116fTyler Gunn            case STATE_HOLDING:
107a1079194649f48af827eb879e32af661d716116fTyler Gunn                setOnHold();
108a1079194649f48af827eb879e32af661d716116fTyler Gunn                break;
109a1079194649f48af827eb879e32af661d716116fTyler Gunn            case STATE_ACTIVE:
110a1079194649f48af827eb879e32af661d716116fTyler Gunn                setActive();
111a1079194649f48af827eb879e32af661d716116fTyler Gunn                break;
112a1079194649f48af827eb879e32af661d716116fTyler Gunn            case STATE_DISCONNECTED:
113bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn                setDisconnected(new DisconnectCause(DisconnectCause.CANCELED));
114bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn                destroy();
115a1079194649f48af827eb879e32af661d716116fTyler Gunn                break;
116a1079194649f48af827eb879e32af661d716116fTyler Gunn            default:
117a1079194649f48af827eb879e32af661d716116fTyler Gunn                setActive();
118a1079194649f48af827eb879e32af661d716116fTyler Gunn        }
119a1079194649f48af827eb879e32af661d716116fTyler Gunn    }
120a1079194649f48af827eb879e32af661d716116fTyler Gunn
121a1079194649f48af827eb879e32af661d716116fTyler Gunn    /**
122bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn     * Disconnects the current {@code ConferenceParticipantConnection} from the conference.
123bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn     * <p>
124bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn     * Sends a participant disconnect signal to the associated parent connection.  The participant
125bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn     * connection is not disconnected and cleaned up here.  On successful disconnection of the
126bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn     * participant, the conference server will send an update to the conference controller
127bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn     * indicating the disconnection was successful.
128bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn     */
129bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn    @Override
130bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn    public void onDisconnect() {
131af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn        mParentConnection.onDisconnectConferenceParticipant(mUserEntity);
132af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn    }
133af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn
134af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn    /**
135af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn     * Retrieves the user handle for this connection.
136af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn     *
137af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn     * @return The userEntity.
138af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn     */
139af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn    public Uri getUserEntity() {
140af7f8126ef3c6dea3caa453a9564183fea0f2a42Tyler Gunn        return mUserEntity;
141bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn    }
142bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn
143bfc5d010e0c313a081fce393504133b91190fe39Tyler Gunn    /**
1442c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn     * Retrieves the endpoint for this connection.
1452c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn     *
1462c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn     * @return The endpoint.
1472c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn     */
1482c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn    public Uri getEndpoint() {
1492c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        return mEndpoint;
1502c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn    }
1512c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn
1522c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn    /**
1533cc8121590b5b05af65a9aeaa8948834e4983adcIhab Awad     * Configures the capabilities applicable to this connection.  A
154a1079194649f48af827eb879e32af661d716116fTyler Gunn     * conference participant can only be disconnected from a conference since there is not
155a1079194649f48af827eb879e32af661d716116fTyler Gunn     * actual connection to the participant which could be split from the conference.
156a1079194649f48af827eb879e32af661d716116fTyler Gunn     */
157a1079194649f48af827eb879e32af661d716116fTyler Gunn    private void setCapabilities() {
1583cc8121590b5b05af65a9aeaa8948834e4983adcIhab Awad        int capabilities = CAPABILITY_DISCONNECT_FROM_CONFERENCE;
1593cc8121590b5b05af65a9aeaa8948834e4983adcIhab Awad        setConnectionCapabilities(capabilities);
160a1079194649f48af827eb879e32af661d716116fTyler Gunn    }
1612c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn
1622c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn    /**
163fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn     * Determines the number presentation for a conference participant.  Per RFC5767, if the host
164fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn     * name contains {@code anonymous.invalid} we can assume that there is no valid caller ID
165fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn     * information for the caller, otherwise we'll assume that the URI can be shown.
166fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn     *
167fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn     * @param participant The conference participant.
168fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn     * @return The number presentation.
169fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn     */
170fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn    private int getParticipantPresentation(ConferenceParticipant participant) {
171fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        Uri address = participant.getHandle();
172fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        if (address == null) {
173fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn            return PhoneConstants.PRESENTATION_RESTRICTED;
174fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        }
175fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn
176fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        String number = address.getSchemeSpecificPart();
177fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        // If no number, bail early and set restricted presentation.
178fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        if (TextUtils.isEmpty(number)) {
179fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn            return PhoneConstants.PRESENTATION_RESTRICTED;
180fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        }
181df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn        // Per RFC3261, the host name portion can also potentially include extra information:
182df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn        // E.g. sip:anonymous1@anonymous.invalid;legid=1
183df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn        // In this case, hostName will be anonymous.invalid and there is an extra parameter for
184df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn        // legid=1.
185df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn        // Parameters are optional, and the address (e.g. test@test.com) will always be the first
186df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn        // part, with any parameters coming afterwards.
187df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn        String hostParts[] = number.split("[;]");
188df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn        String addressPart = hostParts[0];
189df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn
190df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn        // Get the number portion from the address part.
191df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn        // This will typically be formatted similar to: 6505551212@test.com
192df5e5d809d0d4f16684765cd50cdc179ae2e8ce8Tyler Gunn        String numberParts[] = addressPart.split("[@]");
193fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn
194fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        // If we can't parse the host name out of the URI, then there is probably other data
195fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        // present, and is likely a valid SIP URI.
196fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        if (numberParts.length != 2) {
197fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn            return PhoneConstants.PRESENTATION_ALLOWED;
198fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        }
199fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        String hostName = numberParts[1];
200fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn
201fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        // If the hostname portion of the SIP URI is the invalid host string, presentation is
202fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        // restricted.
203fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        if (hostName.equals(ANONYMOUS_INVALID_HOST)) {
204fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn            return PhoneConstants.PRESENTATION_RESTRICTED;
205fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        }
206fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn
207fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn        return PhoneConstants.PRESENTATION_ALLOWED;
208fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn    }
209fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn
210fba56da6dca7f4bb2a2708d70086cf884de2cc4dTyler Gunn    /**
2114bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn     * Attempts to build a tel: style URI from a conference participant.
2124bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn     * Conference event package data contains SIP URIs, so we try to extract the phone number and
2134bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn     * format into a typical tel: style URI.
2144bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn     *
2154bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn     * @param participant The conference participant.
216a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn     * @param countryIso The country ISO of the current subscription; used when formatting the
217a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn     *                   participant phone number to E.164 format.
2184bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn     * @return The participant's address URI.
2194bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn     */
220a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn    private Uri getParticipantAddress(ConferenceParticipant participant, String countryIso) {
2214bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        Uri address = participant.getHandle();
222be622845acb8492b19fad5036e64f6247ab7a89aAnthony Lee        if (address == null) {
223be622845acb8492b19fad5036e64f6247ab7a89aAnthony Lee            return address;
224be622845acb8492b19fad5036e64f6247ab7a89aAnthony Lee        }
2254bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn
2264bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // If the participant's address is already a TEL scheme, just return it as is.
227be622845acb8492b19fad5036e64f6247ab7a89aAnthony Lee        if (PhoneAccount.SCHEME_TEL.equals(address.getScheme())) {
2284bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn            return address;
2294bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        }
2304bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn
2314bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // Conference event package participants are identified using SIP URIs (see RFC3261).
2324bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // A valid SIP uri has the format: sip:user:password@host:port;uri-parameters?headers
2334bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // Per RFC3261, the "user" can be a telephone number.
2344bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // For example: sip:1650555121;phone-context=blah.com@host.com
2354bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // In this case, the phone number is in the user field of the URI, and the parameters can be
2364bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // ignored.
2374bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        //
2384bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // A SIP URI can also specify a phone number in a format similar to:
2394bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // sip:+1-212-555-1212@something.com;user=phone
2404bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // In this case, the phone number is again in user field and the parameters can be ignored.
2414bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // We can get the user field in these instances by splitting the string on the @, ;, or :
2424bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        // and looking at the first found item.
2434bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        String number = address.getSchemeSpecificPart();
244be622845acb8492b19fad5036e64f6247ab7a89aAnthony Lee        if (TextUtils.isEmpty(number)) {
245be622845acb8492b19fad5036e64f6247ab7a89aAnthony Lee            return address;
246be622845acb8492b19fad5036e64f6247ab7a89aAnthony Lee        }
2474bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn
248be622845acb8492b19fad5036e64f6247ab7a89aAnthony Lee        String numberParts[] = number.split("[@;:]");
2494bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        if (numberParts.length == 0) {
2504bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn            return address;
2514bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        }
2524bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn        number = numberParts[0];
2534bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn
254a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        // Attempt to format the number in E.164 format and use that as part of the TEL URI.
255a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        // RFC2806 recommends to format telephone numbers using E.164 since it is independent of
256a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        // how the dialing of said numbers takes place.
257a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        // If conversion to E.164 fails, the returned value is null.  In that case, fallback to the
258a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        // number which was in the CEP data.
259a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        String formattedNumber = null;
260a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        if (!TextUtils.isEmpty(countryIso)) {
261a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn            formattedNumber = PhoneNumberUtils.formatNumberToE164(number, countryIso);
262a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        }
263a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn
264a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        return Uri.fromParts(PhoneAccount.SCHEME_TEL,
265a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn                formattedNumber != null ? formattedNumber : number, null);
266a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn    }
267a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn
268a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn    /**
269a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn     * Given a {@link Phone} instance, determines the country ISO associated with the phone's
270a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn     * subscription.
271a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn     *
272a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn     * @param phone The phone instance.
273a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn     * @return The country ISO.
274a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn     */
275a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn    private String getCountryIso(Phone phone) {
276a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        if (phone == null) {
277a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn            return null;
278a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        }
279a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn
280a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        int subId = phone.getSubId();
281a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn
282a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        SubscriptionInfo subInfo = TelecomAccountRegistry.getInstance(null).
283a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn                getSubscriptionManager().getActiveSubscriptionInfo(subId);
284a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn
285a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        if (subInfo == null) {
286a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn            return null;
287a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        }
288a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        // The SubscriptionInfo reports ISO country codes in lower case.  Convert to upper case,
289a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        // since ultimately we use this ISO when formatting the CEP phone number, and the phone
290a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        // number formatting library expects uppercase ISO country codes.
291a12cf375b0579f8c28b5a92689a4517470c171e6Tyler Gunn        return subInfo.getCountryIso().toUpperCase();
2924bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn    }
2934bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn
2944bfafa3591562639a2ba59963b3fa3f55312e5a3Tyler Gunn    /**
2952c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn     * Builds a string representation of this conference participant connection.
2962c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn     *
2972c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn     * @return String representation of connection.
2982c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn     */
2992c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn    @Override
3002c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn    public String toString() {
3012c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        StringBuilder sb = new StringBuilder();
3022c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        sb.append("[ConferenceParticipantConnection objId:");
3032c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        sb.append(System.identityHashCode(this));
3042c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        sb.append(" endPoint:");
3052c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        sb.append(Log.pii(mEndpoint));
306309a758b73a978bf38447ca997f70d23355d3564Tyler Gunn        sb.append(" address:");
307309a758b73a978bf38447ca997f70d23355d3564Tyler Gunn        sb.append(Log.pii(getAddress()));
308309a758b73a978bf38447ca997f70d23355d3564Tyler Gunn        sb.append(" addressPresentation:");
309309a758b73a978bf38447ca997f70d23355d3564Tyler Gunn        sb.append(getAddressPresentation());
3102c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        sb.append(" parentConnection:");
3112c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        sb.append(Log.pii(mParentConnection.getAddress()));
3122c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        sb.append(" state:");
3132c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        sb.append(Connection.stateToString(getState()));
3142c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        sb.append("]");
3152c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn
3162c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn        return sb.toString();
3172c248f38ac4c7fefc50fb9c595b6cbf2798c0632Tyler Gunn    }
318a1079194649f48af827eb879e32af661d716116fTyler Gunn}
319