198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang/*
298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Copyright (C) 2010 The Android Open Source Project
398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *
498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Licensed under the Apache License, Version 2.0 (the "License");
598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * you may not use this file except in compliance with the License.
698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * You may obtain a copy of the License at
798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *
898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      http://www.apache.org/licenses/LICENSE-2.0
998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *
1098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Unless required by applicable law or agreed to in writing, software
1198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * distributed under the License is distributed on an "AS IS" BASIS,
1298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * See the License for the specific language governing permissions and
1498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * limitations under the License.
1598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */
1698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
1798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangpackage android.net.sip;
1898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
19845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyanimport android.app.PendingIntent;
2098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.content.Context;
2198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.content.Intent;
2269d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyanimport android.content.pm.PackageManager;
2398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.os.IBinder;
2498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.os.RemoteException;
2598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.os.ServiceManager;
269329db04f13480ccdff013dcc00cdb96f12a921cWink Savilleimport android.telephony.Rlog;
2798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
2898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport java.text.ParseException;
2998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
3098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang/**
3116b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * Provides APIs for SIP tasks, such as initiating SIP connections, and provides access to related
3216b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * SIP services. This class is the starting point for any SIP actions. You can acquire an instance
3316b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * of it with {@link #newInstance newInstance()}.</p>
3416b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * <p>The APIs in this class allows you to:</p>
3598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * <ul>
3616b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * <li>Create a {@link SipSession} to get ready for making calls or listen for incoming calls. See
3716b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * {@link #createSipSession createSipSession()} and {@link #getSessionFor getSessionFor()}.</li>
3816b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * <li>Initiate and receive generic SIP calls or audio-only SIP calls. Generic SIP calls may
3916b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * be video, audio, or other, and are initiated with {@link #open open()}. Audio-only SIP calls
4016b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * should be handled with a {@link SipAudioCall}, which you can acquire with {@link
4116b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * #makeAudioCall makeAudioCall()} and {@link #takeAudioCall takeAudioCall()}.</li>
4216b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * <li>Register and unregister with a SIP service provider, with
4316b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main *      {@link #register register()} and {@link #unregister unregister()}.</li>
4416b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * <li>Verify session connectivity, with {@link #isOpened isOpened()} and
4516b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main *      {@link #isRegistered isRegistered()}.</li>
4698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * </ul>
4716b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * <p class="note"><strong>Note:</strong> Not all Android-powered devices support VOIP calls using
4816b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * SIP. You should always call {@link android.net.sip.SipManager#isVoipSupported
4916b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * isVoipSupported()} to verify that the device supports VOIP calling and {@link
5016b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * android.net.sip.SipManager#isApiSupported isApiSupported()} to verify that the device supports
51b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * the SIP APIs. Your application must also request the {@link
5216b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * android.Manifest.permission#INTERNET} and {@link android.Manifest.permission#USE_SIP}
5316b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * permissions.</p>
54b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez *
55b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * <div class="special reference">
56b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * <h3>Developer Guides</h3>
57b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * <p>For more information about using SIP, read the
58b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * <a href="{@docRoot}guide/topics/network/sip.html">Session Initiation Protocol</a>
59b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * developer guide.</p>
60b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * </div>
6198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */
6298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangpublic class SipManager {
633adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    /**
64845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * The result code to be sent back with the incoming call
65845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * {@link PendingIntent}.
66845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @see #open(SipProfile, PendingIntent, SipRegistrationListener)
67845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     */
68845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan    public static final int INCOMING_CALL_RESULT_CODE = 101;
69845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan
704e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan    /**
714e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * Key to retrieve the call ID from an incoming call intent.
724e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @see #open(SipProfile, PendingIntent, SipRegistrationListener)
734e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     */
74845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan    public static final String EXTRA_CALL_ID = "android:sipCallID";
75845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan
764e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan    /**
774e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * Key to retrieve the offered session description from an incoming call
784e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * intent.
794e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @see #open(SipProfile, PendingIntent, SipRegistrationListener)
804e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     */
81845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan    public static final String EXTRA_OFFER_SD = "android:sipOfferSD";
82845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan
83845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan    /**
8422523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan     * Action to broadcast when SipService is up.
8522523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan     * Internal use only.
8622523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan     * @hide
8722523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan     */
8822523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan    public static final String ACTION_SIP_SERVICE_UP =
8922523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan            "android.net.sip.SIP_SERVICE_UP";
9022523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan    /**
913adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Action string for the incoming call intent for the Phone app.
923adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Internal use only.
933adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @hide
943adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     */
953adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static final String ACTION_SIP_INCOMING_CALL =
9698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            "com.android.phone.SIP_INCOMING_CALL";
973adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    /**
983adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Action string for the add-phone intent.
993adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Internal use only.
1003adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @hide
1013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     */
1023adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static final String ACTION_SIP_ADD_PHONE =
10398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            "com.android.phone.SIP_ADD_PHONE";
1043adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    /**
1053adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Action string for the remove-phone intent.
1063adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Internal use only.
1073adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @hide
1083adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     */
1093adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static final String ACTION_SIP_REMOVE_PHONE =
11098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            "com.android.phone.SIP_REMOVE_PHONE";
111cf38b8464007ebf626fc0d61a646491fc3d794cdTyler Gunn
112cf38b8464007ebf626fc0d61a646491fc3d794cdTyler Gunn    /**
113cf38b8464007ebf626fc0d61a646491fc3d794cdTyler Gunn     * Action string for the SIP call option configuration changed intent.
114cf38b8464007ebf626fc0d61a646491fc3d794cdTyler Gunn     * This is used to communicate  change to the SIP call option, triggering re-registration of
115cf38b8464007ebf626fc0d61a646491fc3d794cdTyler Gunn     * the SIP phone accounts.
116cf38b8464007ebf626fc0d61a646491fc3d794cdTyler Gunn     * Internal use only.
117cf38b8464007ebf626fc0d61a646491fc3d794cdTyler Gunn     * @hide
118cf38b8464007ebf626fc0d61a646491fc3d794cdTyler Gunn     */
119cf38b8464007ebf626fc0d61a646491fc3d794cdTyler Gunn    public static final String ACTION_SIP_CALL_OPTION_CHANGED =
120cf38b8464007ebf626fc0d61a646491fc3d794cdTyler Gunn            "com.android.phone.SIP_CALL_OPTION_CHANGED";
121cf38b8464007ebf626fc0d61a646491fc3d794cdTyler Gunn
1223adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    /**
1233adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Part of the ACTION_SIP_ADD_PHONE and ACTION_SIP_REMOVE_PHONE intents.
1243adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Internal use only.
1253adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @hide
1263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     */
1273adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static final String EXTRA_LOCAL_URI = "android:localSipUri";
12898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
129e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan    private static final String TAG = "SipManager";
130e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan
13198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private ISipService mSipService;
1323adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    private Context mContext;
13398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
13498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
1353adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Creates a manager instance. Returns null if SIP API is not supported.
13698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
1373adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @param context application context for creating the manager object
13869d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan     * @return the manager instance or null if SIP API is not supported
13998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
1403adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static SipManager newInstance(Context context) {
1413adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        return (isApiSupported(context) ? new SipManager(context) : null);
14269d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    }
14369d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan
14469d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    /**
14569d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan     * Returns true if the SIP API is supported by the system.
14669d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan     */
14769d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    public static boolean isApiSupported(Context context) {
14869d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan        return context.getPackageManager().hasSystemFeature(
14969d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan                PackageManager.FEATURE_SIP);
15069d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    }
15169d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan
15269d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    /**
15338ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan     * Returns true if the system supports SIP-based VOIP API.
15469d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan     */
15569d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    public static boolean isVoipSupported(Context context) {
15669d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan        return context.getPackageManager().hasSystemFeature(
15769d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan                PackageManager.FEATURE_SIP_VOIP) && isApiSupported(context);
15898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
15998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
160d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan    /**
161d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan     * Returns true if SIP is only available on WIFI.
162d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan     */
163d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan    public static boolean isSipWifiOnly(Context context) {
164d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan        return context.getResources().getBoolean(
165d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan                com.android.internal.R.bool.config_sip_wifi_only);
166d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan    }
167d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan
1683adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    private SipManager(Context context) {
1693adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        mContext = context;
17069d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan        createSipService();
17198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
17298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
17369d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    private void createSipService() {
174f08fe9659343327dc29da410b64597b33613c732Brad Ebinger        if (mSipService == null) {
175f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            IBinder b = ServiceManager.getService(Context.SIP_SERVICE);
176f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            mSipService = ISipService.Stub.asInterface(b);
177f08fe9659343327dc29da410b64597b33613c732Brad Ebinger        }
178f08fe9659343327dc29da410b64597b33613c732Brad Ebinger    }
179f08fe9659343327dc29da410b64597b33613c732Brad Ebinger
180f08fe9659343327dc29da410b64597b33613c732Brad Ebinger    private void checkSipServiceConnection() throws SipException {
181f08fe9659343327dc29da410b64597b33613c732Brad Ebinger        createSipService();
182f08fe9659343327dc29da410b64597b33613c732Brad Ebinger        if (mSipService == null) {
183f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            throw new SipException("SipService is dead and is restarting...", new Exception());
184f08fe9659343327dc29da410b64597b33613c732Brad Ebinger        }
18598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
18698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
18798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
18816b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main     * Opens the profile for making generic SIP calls. The caller may make subsequent calls
1893adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * through {@link #makeAudioCall}. If one also wants to receive calls on the
190845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * profile, use
191845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)}
1923adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * instead.
19398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
19498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to make calls from
19598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if the profile contains incorrect settings or
19698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      calling the SIP service results in an error
19798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
19898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void open(SipProfile localProfile) throws SipException {
19998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
200f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
201d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            mSipService.open(localProfile, mContext.getOpPackageName());
20298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
20398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("open()", e);
20498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
20598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
20698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
20798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
20816b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main     * Opens the profile for making calls and/or receiving generic SIP calls. The caller may
2093adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * make subsequent calls through {@link #makeAudioCall}. If the
2103adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * auto-registration option is enabled in the profile, the SIP service
2113adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * will register the profile to the corresponding SIP provider periodically
2124e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * in order to receive calls from the provider. When the SIP service
2134e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * receives a new call, it will send out an intent with the provided action
2144e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * string. The intent contains a call ID extra and an offer session
2154e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * description string extra. Use {@link #getCallId} and
2164e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * {@link #getOfferSessionDescription} to retrieve those extras.
21798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
21898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to receive incoming calls for
219845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @param incomingCallPendingIntent When an incoming call is received, the
220845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     *      SIP service will call
221845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     *      {@link PendingIntent#send(Context, int, Intent)} to send back the
222845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     *      intent to the caller with {@link #INCOMING_CALL_RESULT_CODE} as the
223845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     *      result code and the intent to fill in the call ID and session
224845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     *      description information. It cannot be null.
22598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to registration events; can be null
226845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @see #getCallId
227845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @see #getOfferSessionDescription
228845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @see #takeAudioCall
229845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @throws NullPointerException if {@code incomingCallPendingIntent} is null
23098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if the profile contains incorrect settings or
23198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      calling the SIP service results in an error
2324e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @see #isIncomingCallIntent
2334e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @see #getCallId
2344e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @see #getOfferSessionDescription
23598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
23698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void open(SipProfile localProfile,
237845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            PendingIntent incomingCallPendingIntent,
23898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
239845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        if (incomingCallPendingIntent == null) {
240845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            throw new NullPointerException(
241845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    "incomingCallPendingIntent cannot be null");
242845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        }
24398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
244f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
245845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            mSipService.open3(localProfile, incomingCallPendingIntent,
246d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                    createRelay(listener, localProfile.getUriString()),
247d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                    mContext.getOpPackageName());
24898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
24998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("open()", e);
25098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
25198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
25298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
25398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
25498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Sets the listener to listen to registration events. No effect if the
255845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * profile has not been opened to receive calls (see
256845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)}).
25798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
25898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile
25998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to registration events; can be null
26098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
26198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
26298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void setRegistrationListener(String localProfileUri,
26398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
26498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
265f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
26698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mSipService.setRegistrationListener(
267d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                    localProfileUri, createRelay(listener, localProfileUri),
268d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                    mContext.getOpPackageName());
26998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
27098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("setRegistrationListener()", e);
27198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
27298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
27398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
27498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
27598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Closes the specified profile to not make/receive calls. All the resources
27698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * that were allocated to the profile are also released.
27798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
27898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile to close
27998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
28098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
28198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void close(String localProfileUri) throws SipException {
28298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
283f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
284d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            mSipService.close(localProfileUri, mContext.getOpPackageName());
28598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
28698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("close()", e);
28798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
28898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
28998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
29098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
2913adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Checks if the specified profile is opened in the SIP service for
2923adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * making and/or receiving calls.
29398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
29498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile in question
29598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return true if the profile is enabled to receive calls
29698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
29798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
29898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public boolean isOpened(String localProfileUri) throws SipException {
29998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
300f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
301d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return mSipService.isOpened(localProfileUri, mContext.getOpPackageName());
30298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
30398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("isOpened()", e);
30498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
30598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
30698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
30798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
3083adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Checks if the SIP service has successfully registered the profile to the
3093adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * SIP provider (specified in the profile) for receiving calls. Returning
3103adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * true from this method also implies the profile is opened
3113adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * ({@link #isOpened}).
31298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
31398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile in question
3143adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @return true if the profile is registered to the SIP provider; false if
3153adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     *        the profile has not been opened in the SIP service or the SIP
3163adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     *        service has not yet successfully registered the profile to the SIP
3173adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     *        provider
31898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
31998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
32098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public boolean isRegistered(String localProfileUri) throws SipException {
32198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
322f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
323d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return mSipService.isRegistered(localProfileUri, mContext.getOpPackageName());
32498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
32598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("isRegistered()", e);
32698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
32798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
32898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
32998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
330f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * Creates a {@link SipAudioCall} to make a call. The attempt will be timed
331f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * out if the call is not established within {@code timeout} seconds and
33216b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main     * {@link SipAudioCall.Listener#onError onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
333f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * will be called.
33498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
33598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to make the call from
33698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param peerProfile the SIP profile to make the call to
33798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
33898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      can be null
3394e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @param timeout the timeout value in seconds. Default value (defined by
3404e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     *        SIP protocol) is used if {@code timeout} is zero or negative.
34198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return a {@link SipAudioCall} object
34238ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan     * @throws SipException if calling the SIP service results in an error or
34338ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan     *      VOIP API is not supported by the device
34416b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main     * @see SipAudioCall.Listener#onError
34538ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan     * @see #isVoipSupported
34698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
3473adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public SipAudioCall makeAudioCall(SipProfile localProfile,
348f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan            SipProfile peerProfile, SipAudioCall.Listener listener, int timeout)
34998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throws SipException {
35038ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan        if (!isVoipSupported(mContext)) {
35138ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan            throw new SipException("VOIP API is not supported");
35238ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan        }
3533adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        SipAudioCall call = new SipAudioCall(mContext, localProfile);
35498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        call.setListener(listener);
3557a4ec7268fbfb56e22f1cb8497d37ed733d8aa8eHung-ying Tyan        SipSession s = createSipSession(localProfile, null);
3567a4ec7268fbfb56e22f1cb8497d37ed733d8aa8eHung-ying Tyan        call.makeCall(peerProfile, s, timeout);
35798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return call;
35898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
35998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
36098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
361845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * Creates a {@link SipAudioCall} to make an audio call. The attempt will be
362845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * timed out if the call is not established within {@code timeout} seconds
363845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * and
36416b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main     * {@link SipAudioCall.Listener#onError onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
365f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * will be called.
36698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
36798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri URI of the SIP profile to make the call from
36898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param peerProfileUri URI of the SIP profile to make the call to
36998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
37098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      can be null
3714e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @param timeout the timeout value in seconds. Default value (defined by
3724e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     *        SIP protocol) is used if {@code timeout} is zero or negative.
37398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return a {@link SipAudioCall} object
37438ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan     * @throws SipException if calling the SIP service results in an error or
37538ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan     *      VOIP API is not supported by the device
37616b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main     * @see SipAudioCall.Listener#onError
37738ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan     * @see #isVoipSupported
37898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
3793adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public SipAudioCall makeAudioCall(String localProfileUri,
380f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan            String peerProfileUri, SipAudioCall.Listener listener, int timeout)
38198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throws SipException {
38238ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan        if (!isVoipSupported(mContext)) {
38338ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan            throw new SipException("VOIP API is not supported");
38438ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan        }
38598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
3863adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            return makeAudioCall(
38798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    new SipProfile.Builder(localProfileUri).build(),
388f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan                    new SipProfile.Builder(peerProfileUri).build(), listener,
389f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan                    timeout);
39098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (ParseException e) {
39198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("build SipProfile", e);
39298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
39398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
39498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
39598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
39698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Creates a {@link SipAudioCall} to take an incoming call. Before the call
39798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * is returned, the listener will receive a
398901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan     * {@link SipAudioCall.Listener#onRinging}
39998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * callback.
40098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
40198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
40298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
40398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      can be null
40498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return a {@link SipAudioCall} object
40598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
40698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
4073adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public SipAudioCall takeAudioCall(Intent incomingCallIntent,
4086577ac4cc93ee3670a5aceceb9a95260d41fe570Hung-ying Tyan            SipAudioCall.Listener listener) throws SipException {
409b030e52a52acaf28ce68b1010aac007af909478dHung-ying Tyan        if (incomingCallIntent == null) {
410b030e52a52acaf28ce68b1010aac007af909478dHung-ying Tyan            throw new SipException("Cannot retrieve session with null intent");
411b030e52a52acaf28ce68b1010aac007af909478dHung-ying Tyan        }
41298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
41398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        String callId = getCallId(incomingCallIntent);
41498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (callId == null) {
41598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("Call ID missing in incoming call intent");
41698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
41798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
4186d0ef774a2492b0996ded3a43c300c7f72a94897Chia-chi Yeh        String offerSd = getOfferSessionDescription(incomingCallIntent);
41998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (offerSd == null) {
42098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("Session description missing in incoming "
42198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    + "call intent");
42298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
42398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
42498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
425f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
426d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            ISipSession session = mSipService.getPendingSession(callId,
427d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                    mContext.getOpPackageName());
428b030e52a52acaf28ce68b1010aac007af909478dHung-ying Tyan            if (session == null) {
429b030e52a52acaf28ce68b1010aac007af909478dHung-ying Tyan                throw new SipException("No pending session for the call");
430b030e52a52acaf28ce68b1010aac007af909478dHung-ying Tyan            }
4313adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            SipAudioCall call = new SipAudioCall(
4323adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan                    mContext, session.getLocalProfile());
4333adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            call.attachCall(new SipSession(session), offerSd);
43498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            call.setListener(listener);
43598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return call;
43698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (Throwable t) {
43798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("takeAudioCall()", t);
43898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
43998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
44098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
44198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
44298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Checks if the intent is an incoming call broadcast intent.
44398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
44498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param intent the intent in question
44598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return true if the intent is an incoming call broadcast intent
44698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
44798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static boolean isIncomingCallIntent(Intent intent) {
44898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (intent == null) return false;
44998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        String callId = getCallId(intent);
4506d0ef774a2492b0996ded3a43c300c7f72a94897Chia-chi Yeh        String offerSd = getOfferSessionDescription(intent);
45198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return ((callId != null) && (offerSd != null));
45298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
45398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
45498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
45598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Gets the call ID from the specified incoming call broadcast intent.
45698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
45798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
45898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the call ID or null if the intent does not contain it
45998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
46098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static String getCallId(Intent incomingCallIntent) {
4613adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        return incomingCallIntent.getStringExtra(EXTRA_CALL_ID);
46298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
46398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
46498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
46598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Gets the offer session description from the specified incoming call
46698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * broadcast intent.
46798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
46898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
46998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the offer session description or null if the intent does not
47098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      have it
47198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
4726d0ef774a2492b0996ded3a43c300c7f72a94897Chia-chi Yeh    public static String getOfferSessionDescription(Intent incomingCallIntent) {
4733adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        return incomingCallIntent.getStringExtra(EXTRA_OFFER_SD);
47498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
47598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
47698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
47798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Creates an incoming call broadcast intent.
47898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
47998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param callId the call ID of the incoming call
48098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param sessionDescription the session description of the incoming call
48198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the incoming call intent
48298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @hide
48398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
4843adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static Intent createIncomingCallBroadcast(String callId,
4853adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            String sessionDescription) {
4863adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        Intent intent = new Intent();
4873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        intent.putExtra(EXTRA_CALL_ID, callId);
4883adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        intent.putExtra(EXTRA_OFFER_SD, sessionDescription);
48998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return intent;
49098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
49198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
49298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
4933adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Manually registers the profile to the corresponding SIP provider for
494845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * receiving calls.
495845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)} is
496845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * still needed to be called at least once in order for the SIP service to
49716b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main     * notify the caller with the {@link android.app.PendingIntent} when an incoming call is
498845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * received.
49998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
50098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to register with
501901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan     * @param expiryTime registration expiration time (in seconds)
50298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the registration events
50398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
50498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
50598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void register(SipProfile localProfile, int expiryTime,
50698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
50798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
508f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
509f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan            ISipSession session = mSipService.createSession(localProfile,
510d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                    createRelay(listener, localProfile.getUriString()),
511d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                    mContext.getOpPackageName());
512088ef46d8b5a849d80a257670bb2a809713b7bf0Masahiko Endo            if (session == null) {
513088ef46d8b5a849d80a257670bb2a809713b7bf0Masahiko Endo                throw new SipException(
514088ef46d8b5a849d80a257670bb2a809713b7bf0Masahiko Endo                        "SipService.createSession() returns null");
515088ef46d8b5a849d80a257670bb2a809713b7bf0Masahiko Endo            }
51698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            session.register(expiryTime);
51798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
51898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("register()", e);
51998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
52098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
52198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
52298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
5233adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Manually unregisters the profile from the corresponding SIP provider for
5243adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * stop receiving further calls. This may interference with the auto
5253adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * registration process in the SIP service if the auto-registration option
5263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * in the profile is enabled.
52798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
52898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to register with
52998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the registration events
53098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
53198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
53298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void unregister(SipProfile localProfile,
53398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
53498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
535f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
536f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan            ISipSession session = mSipService.createSession(localProfile,
537d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                    createRelay(listener, localProfile.getUriString()),
538d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                    mContext.getOpPackageName());
539088ef46d8b5a849d80a257670bb2a809713b7bf0Masahiko Endo            if (session == null) {
540088ef46d8b5a849d80a257670bb2a809713b7bf0Masahiko Endo                throw new SipException(
541088ef46d8b5a849d80a257670bb2a809713b7bf0Masahiko Endo                        "SipService.createSession() returns null");
542088ef46d8b5a849d80a257670bb2a809713b7bf0Masahiko Endo            }
54398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            session.unregister();
54498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
54598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("unregister()", e);
54698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
54798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
54898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
54998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
5504e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * Gets the {@link SipSession} that handles the incoming call. For audio
55198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * calls, consider to use {@link SipAudioCall} to handle the incoming call.
552901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan     * See {@link #takeAudioCall}. Note that the method may be called only once
553901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan     * for the same intent. For subsequent calls on the same intent, the method
554901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan     * returns null.
55598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
55698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
55798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the session object that handles the incoming call
55898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
5594e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan    public SipSession getSessionFor(Intent incomingCallIntent)
56098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throws SipException {
56198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
562f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
56398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            String callId = getCallId(incomingCallIntent);
564d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            ISipSession s = mSipService.getPendingSession(callId,
565d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                    mContext.getOpPackageName());
566088ef46d8b5a849d80a257670bb2a809713b7bf0Masahiko Endo            return ((s == null) ? null : new SipSession(s));
56798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
56898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("getSessionFor()", e);
56998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
57098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
57198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
57298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private static ISipSessionListener createRelay(
573f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan            SipRegistrationListener listener, String uri) {
574f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan        return ((listener == null) ? null : new ListenerRelay(listener, uri));
57598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
57698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
57798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
5784e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * Creates a {@link SipSession} with the specified profile. Use other
5794e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * methods, if applicable, instead of interacting with {@link SipSession}
58098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * directly.
58198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
58298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile the session is associated with
58398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to SIP session events
58498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
5853adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public SipSession createSipSession(SipProfile localProfile,
5863adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            SipSession.Listener listener) throws SipException {
58798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
588f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
589d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            ISipSession s = mSipService.createSession(localProfile, null,
590d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                    mContext.getOpPackageName());
591b030e52a52acaf28ce68b1010aac007af909478dHung-ying Tyan            if (s == null) {
592b030e52a52acaf28ce68b1010aac007af909478dHung-ying Tyan                throw new SipException(
593b030e52a52acaf28ce68b1010aac007af909478dHung-ying Tyan                        "Failed to create SipSession; network unavailable?");
594b030e52a52acaf28ce68b1010aac007af909478dHung-ying Tyan            }
5953adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            return new SipSession(s, listener);
59698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
59798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("createSipSession()", e);
59898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
59998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
60098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
60198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
60298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Gets the list of profiles hosted by the SIP service. The user information
60398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * (username, password and display name) are crossed out.
60498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @hide
60598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
606f08fe9659343327dc29da410b64597b33613c732Brad Ebinger    public SipProfile[] getListOfProfiles() throws SipException {
60798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
608f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            checkSipServiceConnection();
609d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return mSipService.getListOfProfiles(mContext.getOpPackageName());
61098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
611b030e52a52acaf28ce68b1010aac007af909478dHung-ying Tyan            return new SipProfile[0];
61298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
61398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
61498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
61598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private static class ListenerRelay extends SipSessionAdapter {
61698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        private SipRegistrationListener mListener;
617f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan        private String mUri;
61898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
61998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        // listener must not be null
620f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan        public ListenerRelay(SipRegistrationListener listener, String uri) {
62198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener = listener;
622f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan            mUri = uri;
62398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
62498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
62598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        private String getUri(ISipSession session) {
62698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            try {
627d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                return ((session == null)
628f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan                        ? mUri
629d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                        : session.getLocalProfile().getUriString());
630e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan            } catch (Throwable e) {
631e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan                // SipService died? SIP stack died?
6329329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                Rlog.e(TAG, "getUri(): ", e);
633e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan                return null;
63498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            }
63598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
63698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
63798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
63898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        public void onRegistering(ISipSession session) {
63998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener.onRegistering(getUri(session));
64098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
64198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
64298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
64398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        public void onRegistrationDone(ISipSession session, int duration) {
64498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            long expiryTime = duration;
64598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            if (duration > 0) expiryTime += System.currentTimeMillis();
64698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener.onRegistrationDone(getUri(session), expiryTime);
64798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
64898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
64998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
650a0171082cfc4b860a82dcf5ebbd498b253f1032fHung-ying Tyan        public void onRegistrationFailed(ISipSession session, int errorCode,
65198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                String message) {
652a0171082cfc4b860a82dcf5ebbd498b253f1032fHung-ying Tyan            mListener.onRegistrationFailed(getUri(session), errorCode, message);
65398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
65498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
65598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
65698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        public void onRegistrationTimeout(ISipSession session) {
65798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener.onRegistrationFailed(getUri(session),
6581ab079168ccc185408a8691c6b804021d79f7376Hung-ying Tyan                    SipErrorCode.TIME_OUT, "registration timed out");
65998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
66098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
66198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang}
662