SipManager.java revision 4e22f5d6687c18440e2f38c7e242d66ad834d1d7
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.Looper;
2598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.os.RemoteException;
2698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.os.ServiceManager;
27e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyanimport android.util.Log;
2898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
2998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport java.text.ParseException;
3098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
3198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang/**
3298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * The class provides API for various SIP related tasks. Specifically, the API
33901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan * allows an application to:
3498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * <ul>
353adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * <li>open a {@link SipProfile} to get ready for making outbound calls or have
363adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan *      the background SIP service listen to incoming calls and broadcast them
373adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan *      with registered command string. See
38845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan *      {@link #open(SipProfile, PendingIntent, SipRegistrationListener)},
39901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan *      {@link #open(SipProfile)}, {@link #close}, {@link #isOpened} and
40901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan *      {@link #isRegistered}. It also facilitates handling of the incoming call
41901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan *      broadcast intent. See
42901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan *      {@link #isIncomingCallIntent}, {@link #getCallId},
43901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan *      {@link #getOfferSessionDescription} and {@link #takeAudioCall}.</li>
4498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * <li>make/take SIP-based audio calls. See
45901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan *      {@link #makeAudioCall} and {@link #takeAudioCall}.</li>
463adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * <li>register/unregister with a SIP service provider manually. See
47901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan *      {@link #register} and {@link #unregister}.</li>
483adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * <li>process SIP events directly with a {@link SipSession} created by
49901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan *      {@link #createSipSession}.</li>
5098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * </ul>
514e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan * {@code SipManager} can only be instantiated if SIP API is supported by the
524e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan * device. (See {@link #isApiSupported}).
5398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */
5498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangpublic class SipManager {
553adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    /**
56845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * The result code to be sent back with the incoming call
57845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * {@link PendingIntent}.
58845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @see #open(SipProfile, PendingIntent, SipRegistrationListener)
59845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     */
60845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan    public static final int INCOMING_CALL_RESULT_CODE = 101;
61845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan
624e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan    /**
634e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * Key to retrieve the call ID from an incoming call intent.
644e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @see #open(SipProfile, PendingIntent, SipRegistrationListener)
654e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     */
66845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan    public static final String EXTRA_CALL_ID = "android:sipCallID";
67845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan
684e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan    /**
694e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * Key to retrieve the offered session description from an incoming call
704e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * intent.
714e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @see #open(SipProfile, PendingIntent, SipRegistrationListener)
724e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     */
73845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan    public static final String EXTRA_OFFER_SD = "android:sipOfferSD";
74845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan
75845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan    /**
7622523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan     * Action to broadcast when SipService is up.
7722523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan     * Internal use only.
7822523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan     * @hide
7922523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan     */
8022523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan    public static final String ACTION_SIP_SERVICE_UP =
8122523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan            "android.net.sip.SIP_SERVICE_UP";
8222523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan    /**
833adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Action string for the incoming call intent for the Phone app.
843adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Internal use only.
853adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @hide
863adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     */
873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static final String ACTION_SIP_INCOMING_CALL =
8898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            "com.android.phone.SIP_INCOMING_CALL";
893adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    /**
903adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Action string for the add-phone intent.
913adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Internal use only.
923adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @hide
933adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     */
943adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static final String ACTION_SIP_ADD_PHONE =
9598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            "com.android.phone.SIP_ADD_PHONE";
963adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    /**
973adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Action string for the remove-phone intent.
983adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Internal use only.
993adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @hide
1003adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     */
1013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static final String ACTION_SIP_REMOVE_PHONE =
10298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            "com.android.phone.SIP_REMOVE_PHONE";
1033adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    /**
1043adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Part of the ACTION_SIP_ADD_PHONE and ACTION_SIP_REMOVE_PHONE intents.
1053adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Internal use only.
1063adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @hide
1073adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     */
1083adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static final String EXTRA_LOCAL_URI = "android:localSipUri";
10998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
110e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan    private static final String TAG = "SipManager";
111e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan
11298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private ISipService mSipService;
1133adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    private Context mContext;
11498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
11598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
1163adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Creates a manager instance. Returns null if SIP API is not supported.
11798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
1183adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @param context application context for creating the manager object
11969d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan     * @return the manager instance or null if SIP API is not supported
12098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
1213adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static SipManager newInstance(Context context) {
1223adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        return (isApiSupported(context) ? new SipManager(context) : null);
12369d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    }
12469d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan
12569d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    /**
12669d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan     * Returns true if the SIP API is supported by the system.
12769d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan     */
12869d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    public static boolean isApiSupported(Context context) {
1290d889a979d7e2e6f21de72de0c45a9c8ffa930e6Hung-ying Tyan        return true;
1303adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        /* TODO: uncomment this before ship
13169d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan        return context.getPackageManager().hasSystemFeature(
13269d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan                PackageManager.FEATURE_SIP);
1330d889a979d7e2e6f21de72de0c45a9c8ffa930e6Hung-ying Tyan         */
13469d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    }
13569d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan
13669d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    /**
13769d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan     * Returns true if the system supports SIP-based VoIP.
13869d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan     */
13969d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    public static boolean isVoipSupported(Context context) {
1400d889a979d7e2e6f21de72de0c45a9c8ffa930e6Hung-ying Tyan        return true;
1413adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        /* TODO: uncomment this before ship
14269d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan        return context.getPackageManager().hasSystemFeature(
14369d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan                PackageManager.FEATURE_SIP_VOIP) && isApiSupported(context);
1440d889a979d7e2e6f21de72de0c45a9c8ffa930e6Hung-ying Tyan         */
14598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
14698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
147d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan    /**
148d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan     * Returns true if SIP is only available on WIFI.
149d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan     */
150d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan    public static boolean isSipWifiOnly(Context context) {
151d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan        return context.getResources().getBoolean(
152d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan                com.android.internal.R.bool.config_sip_wifi_only);
153d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan    }
154d96284491dfc918c72258f84b47a6554c21db92eHung-ying Tyan
1553adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    private SipManager(Context context) {
1563adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        mContext = context;
15769d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan        createSipService();
15898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
15998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
16069d66b75112e2763bf8bce718c22c7baa1efac7dHung-ying Tyan    private void createSipService() {
16168144a84e3cd43ba4f62c73dbd2ce9c74d50e1a6Chung-yih Wang        IBinder b = ServiceManager.getService(Context.SIP_SERVICE);
16298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        mSipService = ISipService.Stub.asInterface(b);
16398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
16498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
16598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
1663adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Opens the profile for making calls. The caller may make subsequent calls
1673adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * through {@link #makeAudioCall}. If one also wants to receive calls on the
168845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * profile, use
169845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)}
1703adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * instead.
17198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
17298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to make calls from
17398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if the profile contains incorrect settings or
17498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      calling the SIP service results in an error
17598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
17698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void open(SipProfile localProfile) throws SipException {
17798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
17898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mSipService.open(localProfile);
17998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
18098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("open()", e);
18198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
18298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
18398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
18498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
1853adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Opens the profile for making calls and/or receiving calls. The caller may
1863adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * make subsequent calls through {@link #makeAudioCall}. If the
1873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * auto-registration option is enabled in the profile, the SIP service
1883adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * will register the profile to the corresponding SIP provider periodically
1894e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * in order to receive calls from the provider. When the SIP service
1904e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * receives a new call, it will send out an intent with the provided action
1914e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * string. The intent contains a call ID extra and an offer session
1924e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * description string extra. Use {@link #getCallId} and
1934e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * {@link #getOfferSessionDescription} to retrieve those extras.
19498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
19598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to receive incoming calls for
196845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @param incomingCallPendingIntent When an incoming call is received, the
197845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     *      SIP service will call
198845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     *      {@link PendingIntent#send(Context, int, Intent)} to send back the
199845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     *      intent to the caller with {@link #INCOMING_CALL_RESULT_CODE} as the
200845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     *      result code and the intent to fill in the call ID and session
201845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     *      description information. It cannot be null.
20298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to registration events; can be null
203845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @see #getCallId
204845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @see #getOfferSessionDescription
205845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @see #takeAudioCall
206845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * @throws NullPointerException if {@code incomingCallPendingIntent} is null
20798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if the profile contains incorrect settings or
20898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      calling the SIP service results in an error
2094e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @see #isIncomingCallIntent
2104e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @see #getCallId
2114e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @see #getOfferSessionDescription
21298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
21398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void open(SipProfile localProfile,
214845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            PendingIntent incomingCallPendingIntent,
21598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
216845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        if (incomingCallPendingIntent == null) {
217845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            throw new NullPointerException(
218845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    "incomingCallPendingIntent cannot be null");
219845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        }
22098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
221845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            mSipService.open3(localProfile, incomingCallPendingIntent,
222f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan                    createRelay(listener, localProfile.getUriString()));
22398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
22498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("open()", e);
22598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
22698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
22798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
22898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
22998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Sets the listener to listen to registration events. No effect if the
230845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * profile has not been opened to receive calls (see
231845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)}).
23298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
23398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile
23498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to registration events; can be null
23598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
23698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
23798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void setRegistrationListener(String localProfileUri,
23898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
23998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
24098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mSipService.setRegistrationListener(
241f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan                    localProfileUri, createRelay(listener, localProfileUri));
24298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
24398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("setRegistrationListener()", e);
24498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
24598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
24698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
24798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
24898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Closes the specified profile to not make/receive calls. All the resources
24998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * that were allocated to the profile are also released.
25098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
25198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile to close
25298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
25398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
25498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void close(String localProfileUri) throws SipException {
25598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
25698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mSipService.close(localProfileUri);
25798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
25898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("close()", e);
25998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
26098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
26198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
26298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
2633adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Checks if the specified profile is opened in the SIP service for
2643adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * making and/or receiving calls.
26598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
26698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile in question
26798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return true if the profile is enabled to receive calls
26898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
26998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
27098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public boolean isOpened(String localProfileUri) throws SipException {
27198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
27298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return mSipService.isOpened(localProfileUri);
27398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
27498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("isOpened()", e);
27598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
27698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
27798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
27898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
2793adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Checks if the SIP service has successfully registered the profile to the
2803adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * SIP provider (specified in the profile) for receiving calls. Returning
2813adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * true from this method also implies the profile is opened
2823adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * ({@link #isOpened}).
28398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
28498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile in question
2853adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @return true if the profile is registered to the SIP provider; false if
2863adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     *        the profile has not been opened in the SIP service or the SIP
2873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     *        service has not yet successfully registered the profile to the SIP
2883adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     *        provider
28998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
29098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
29198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public boolean isRegistered(String localProfileUri) throws SipException {
29298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
29398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return mSipService.isRegistered(localProfileUri);
29498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
29598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("isRegistered()", e);
29698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
29798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
29898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
29998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
300f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * Creates a {@link SipAudioCall} to make a call. The attempt will be timed
301f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * out if the call is not established within {@code timeout} seconds and
302f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * {@code SipAudioCall.Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
303f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * will be called.
30498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
30598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to make the call from
30698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param peerProfile the SIP profile to make the call to
30798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
30898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      can be null
3094e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @param timeout the timeout value in seconds. Default value (defined by
3104e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     *        SIP protocol) is used if {@code timeout} is zero or negative.
31198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return a {@link SipAudioCall} object
31298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
313f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * @see SipAudioCall.Listener.onError
31498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
3153adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public SipAudioCall makeAudioCall(SipProfile localProfile,
316f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan            SipProfile peerProfile, SipAudioCall.Listener listener, int timeout)
31798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throws SipException {
3183adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        SipAudioCall call = new SipAudioCall(mContext, localProfile);
31998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        call.setListener(listener);
3207a4ec7268fbfb56e22f1cb8497d37ed733d8aa8eHung-ying Tyan        SipSession s = createSipSession(localProfile, null);
3217a4ec7268fbfb56e22f1cb8497d37ed733d8aa8eHung-ying Tyan        if (s == null) {
3227a4ec7268fbfb56e22f1cb8497d37ed733d8aa8eHung-ying Tyan            throw new SipException(
3237a4ec7268fbfb56e22f1cb8497d37ed733d8aa8eHung-ying Tyan                    "Failed to create SipSession; network available?");
3247a4ec7268fbfb56e22f1cb8497d37ed733d8aa8eHung-ying Tyan        }
3257a4ec7268fbfb56e22f1cb8497d37ed733d8aa8eHung-ying Tyan        call.makeCall(peerProfile, s, timeout);
32698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return call;
32798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
32898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
32998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
330845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * Creates a {@link SipAudioCall} to make an audio call. The attempt will be
331845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * timed out if the call is not established within {@code timeout} seconds
332845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * and
333f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * {@code SipAudioCall.Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
334f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * will be called.
33598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
33698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri URI of the SIP profile to make the call from
33798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param peerProfileUri URI of the SIP profile to make the call to
33898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
33998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      can be null
3404e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * @param timeout the timeout value in seconds. Default value (defined by
3414e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     *        SIP protocol) is used if {@code timeout} is zero or negative.
34298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return a {@link SipAudioCall} object
34398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
344f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan     * @see SipAudioCall.Listener.onError
34598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
3463adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public SipAudioCall makeAudioCall(String localProfileUri,
347f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan            String peerProfileUri, SipAudioCall.Listener listener, int timeout)
34898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throws SipException {
34998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
3503adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            return makeAudioCall(
35198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    new SipProfile.Builder(localProfileUri).build(),
352f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan                    new SipProfile.Builder(peerProfileUri).build(), listener,
353f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan                    timeout);
35498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (ParseException e) {
35598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("build SipProfile", e);
35698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
35798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
35898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
35998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
3603adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * The method calls {@code takeAudioCall(incomingCallIntent,
36198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * listener, true}.
36298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
3633adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * @see #takeAudioCall(Intent, SipAudioCall.Listener, boolean)
36498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
3653adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public SipAudioCall takeAudioCall(Intent incomingCallIntent,
3663adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            SipAudioCall.Listener listener) throws SipException {
3673adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        return takeAudioCall(incomingCallIntent, listener, true);
36898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
36998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
37098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
37198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Creates a {@link SipAudioCall} to take an incoming call. Before the call
37298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * is returned, the listener will receive a
373901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan     * {@link SipAudioCall.Listener#onRinging}
37498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * callback.
37598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
37698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
37798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
37898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      can be null
37998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return a {@link SipAudioCall} object
38098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
38198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
3823adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public SipAudioCall takeAudioCall(Intent incomingCallIntent,
3833adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            SipAudioCall.Listener listener, boolean ringtoneEnabled)
3843adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            throws SipException {
38598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (incomingCallIntent == null) return null;
38698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
38798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        String callId = getCallId(incomingCallIntent);
38898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (callId == null) {
38998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("Call ID missing in incoming call intent");
39098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
39198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
3926d0ef774a2492b0996ded3a43c300c7f72a94897Chia-chi Yeh        String offerSd = getOfferSessionDescription(incomingCallIntent);
39398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (offerSd == null) {
39498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("Session description missing in incoming "
39598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    + "call intent");
39698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
39798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
39898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
39998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            ISipSession session = mSipService.getPendingSession(callId);
40098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            if (session == null) return null;
4013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            SipAudioCall call = new SipAudioCall(
4023adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan                    mContext, session.getLocalProfile());
40398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            call.setRingtoneEnabled(ringtoneEnabled);
4043adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            call.attachCall(new SipSession(session), offerSd);
40598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            call.setListener(listener);
40698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return call;
40798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (Throwable t) {
40898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("takeAudioCall()", t);
40998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
41098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
41198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
41298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
41398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Checks if the intent is an incoming call broadcast intent.
41498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
41598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param intent the intent in question
41698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return true if the intent is an incoming call broadcast intent
41798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
41898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static boolean isIncomingCallIntent(Intent intent) {
41998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (intent == null) return false;
42098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        String callId = getCallId(intent);
4216d0ef774a2492b0996ded3a43c300c7f72a94897Chia-chi Yeh        String offerSd = getOfferSessionDescription(intent);
42298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return ((callId != null) && (offerSd != null));
42398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
42498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
42598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
42698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Gets the call ID from the specified incoming call broadcast intent.
42798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
42898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
42998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the call ID or null if the intent does not contain it
43098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
43198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static String getCallId(Intent incomingCallIntent) {
4323adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        return incomingCallIntent.getStringExtra(EXTRA_CALL_ID);
43398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
43498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
43598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
43698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Gets the offer session description from the specified incoming call
43798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * broadcast intent.
43898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
43998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
44098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the offer session description or null if the intent does not
44198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      have it
44298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
4436d0ef774a2492b0996ded3a43c300c7f72a94897Chia-chi Yeh    public static String getOfferSessionDescription(Intent incomingCallIntent) {
4443adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        return incomingCallIntent.getStringExtra(EXTRA_OFFER_SD);
44598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
44698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
44798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
44898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Creates an incoming call broadcast intent.
44998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
45098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param callId the call ID of the incoming call
45198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param sessionDescription the session description of the incoming call
45298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the incoming call intent
45398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @hide
45498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
4553adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public static Intent createIncomingCallBroadcast(String callId,
4563adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            String sessionDescription) {
4573adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        Intent intent = new Intent();
4583adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        intent.putExtra(EXTRA_CALL_ID, callId);
4593adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan        intent.putExtra(EXTRA_OFFER_SD, sessionDescription);
46098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return intent;
46198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
46298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
46398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
4643adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Manually registers the profile to the corresponding SIP provider for
465845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * receiving calls.
466845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)} is
467845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * still needed to be called at least once in order for the SIP service to
468845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * notify the caller with the {@code PendingIntent} when an incoming call is
469845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan     * received.
47098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
47198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to register with
472901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan     * @param expiryTime registration expiration time (in seconds)
47398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the registration events
47498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
47598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
47698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void register(SipProfile localProfile, int expiryTime,
47798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
47898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
479f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan            ISipSession session = mSipService.createSession(localProfile,
480f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan                    createRelay(listener, localProfile.getUriString()));
48198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            session.register(expiryTime);
48298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
48398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("register()", e);
48498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
48598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
48698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
48798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
4883adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * Manually unregisters the profile from the corresponding SIP provider for
4893adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * stop receiving further calls. This may interference with the auto
4903adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * registration process in the SIP service if the auto-registration option
4913adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan     * in the profile is enabled.
49298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
49398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to register with
49498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the registration events
49598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
49698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
49798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void unregister(SipProfile localProfile,
49898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
49998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
500f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan            ISipSession session = mSipService.createSession(localProfile,
501f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan                    createRelay(listener, localProfile.getUriString()));
50298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            session.unregister();
50398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
50498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("unregister()", e);
50598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
50698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
50798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
50898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
5094e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * Gets the {@link SipSession} that handles the incoming call. For audio
51098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * calls, consider to use {@link SipAudioCall} to handle the incoming call.
511901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan     * See {@link #takeAudioCall}. Note that the method may be called only once
512901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan     * for the same intent. For subsequent calls on the same intent, the method
513901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan     * returns null.
51498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
51598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
51698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the session object that handles the incoming call
51798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
5184e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan    public SipSession getSessionFor(Intent incomingCallIntent)
51998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throws SipException {
52098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
52198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            String callId = getCallId(incomingCallIntent);
5224e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan            ISipSession s = mSipService.getPendingSession(callId);
5234e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan            return new SipSession(s);
52498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
52598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("getSessionFor()", e);
52698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
52798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
52898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
52998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private static ISipSessionListener createRelay(
530f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan            SipRegistrationListener listener, String uri) {
531f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan        return ((listener == null) ? null : new ListenerRelay(listener, uri));
53298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
53398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
53498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
5354e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * Creates a {@link SipSession} with the specified profile. Use other
5364e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan     * methods, if applicable, instead of interacting with {@link SipSession}
53798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * directly.
53898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
53998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile the session is associated with
54098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to SIP session events
54198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
5423adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan    public SipSession createSipSession(SipProfile localProfile,
5433adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            SipSession.Listener listener) throws SipException {
54498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
5453adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            ISipSession s = mSipService.createSession(localProfile, null);
5463adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan            return new SipSession(s, listener);
54798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
54898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("createSipSession()", e);
54998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
55098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
55198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
55298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
55398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Gets the list of profiles hosted by the SIP service. The user information
55498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * (username, password and display name) are crossed out.
55598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @hide
55698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
55798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public SipProfile[] getListOfProfiles() {
55898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
55998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return mSipService.getListOfProfiles();
56098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
56198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return null;
56298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
56398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
56498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
56598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private static class ListenerRelay extends SipSessionAdapter {
56698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        private SipRegistrationListener mListener;
567f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan        private String mUri;
56898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
56998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        // listener must not be null
570f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan        public ListenerRelay(SipRegistrationListener listener, String uri) {
57198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener = listener;
572f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan            mUri = uri;
57398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
57498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
57598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        private String getUri(ISipSession session) {
57698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            try {
577d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                return ((session == null)
578f3d1e1fd0f86eb956c82634c075b167dc367757cHung-ying Tyan                        ? mUri
579d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                        : session.getLocalProfile().getUriString());
580e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan            } catch (Throwable e) {
581e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan                // SipService died? SIP stack died?
582e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan                Log.w(TAG, "getUri(): " + e);
583e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan                return null;
58498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            }
58598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
58698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
58798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
58898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        public void onRegistering(ISipSession session) {
58998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener.onRegistering(getUri(session));
59098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
59198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
59298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
59398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        public void onRegistrationDone(ISipSession session, int duration) {
59498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            long expiryTime = duration;
59598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            if (duration > 0) expiryTime += System.currentTimeMillis();
59698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener.onRegistrationDone(getUri(session), expiryTime);
59798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
59898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
59998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
600a0171082cfc4b860a82dcf5ebbd498b253f1032fHung-ying Tyan        public void onRegistrationFailed(ISipSession session, int errorCode,
60198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                String message) {
602a0171082cfc4b860a82dcf5ebbd498b253f1032fHung-ying Tyan            mListener.onRegistrationFailed(getUri(session), errorCode, message);
60398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
60498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
60598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
60698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        public void onRegistrationTimeout(ISipSession session) {
60798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener.onRegistrationFailed(getUri(session),
6081ab079168ccc185408a8691c6b804021d79f7376Hung-ying Tyan                    SipErrorCode.TIME_OUT, "registration timed out");
60998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
61098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
61198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang}
612