1363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang/*
2363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * Copyright (C) 2010 The Android Open Source Project
3363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang *
4363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * Licensed under the Apache License, Version 2.0 (the "License");
5363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * you may not use this file except in compliance with the License.
6363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * You may obtain a copy of the License at
7363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang *
8363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang *      http://www.apache.org/licenses/LICENSE-2.0
9363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang *
10363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * Unless required by applicable law or agreed to in writing, software
11363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * distributed under the License is distributed on an "AS IS" BASIS,
12363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * See the License for the specific language governing permissions and
14363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * limitations under the License.
15363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang */
16363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
17363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangpackage android.net.sip;
18363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
19323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyanimport android.app.PendingIntent;
20363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangimport android.content.Context;
21363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangimport android.content.Intent;
223424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyanimport android.content.pm.PackageManager;
23363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangimport android.os.IBinder;
24363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangimport android.os.Looper;
25363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangimport android.os.RemoteException;
26363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangimport android.os.ServiceManager;
279ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyanimport android.util.Log;
28363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
29363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangimport java.text.ParseException;
30363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
31363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang/**
3202b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * Provides APIs for SIP tasks, such as initiating SIP connections, and provides access to related
3302b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * SIP services. This class is the starting point for any SIP actions. You can acquire an instance
3402b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * of it with {@link #newInstance newInstance()}.</p>
3502b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * <p>The APIs in this class allows you to:</p>
36363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * <ul>
3702b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * <li>Create a {@link SipSession} to get ready for making calls or listen for incoming calls. See
3802b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * {@link #createSipSession createSipSession()} and {@link #getSessionFor getSessionFor()}.</li>
3902b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * <li>Initiate and receive generic SIP calls or audio-only SIP calls. Generic SIP calls may
4002b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * be video, audio, or other, and are initiated with {@link #open open()}. Audio-only SIP calls
4102b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * should be handled with a {@link SipAudioCall}, which you can acquire with {@link
4202b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * #makeAudioCall makeAudioCall()} and {@link #takeAudioCall takeAudioCall()}.</li>
4302b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * <li>Register and unregister with a SIP service provider, with
4402b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main *      {@link #register register()} and {@link #unregister unregister()}.</li>
4502b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * <li>Verify session connectivity, with {@link #isOpened isOpened()} and
4602b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main *      {@link #isRegistered isRegistered()}.</li>
47363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * </ul>
4802b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * <p class="note"><strong>Note:</strong> Not all Android-powered devices support VOIP calls using
4902b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * SIP. You should always call {@link android.net.sip.SipManager#isVoipSupported
5002b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * isVoipSupported()} to verify that the device supports VOIP calling and {@link
5102b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * android.net.sip.SipManager#isApiSupported isApiSupported()} to verify that the device supports
523aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * the SIP APIs. Your application must also request the {@link
5302b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * android.Manifest.permission#INTERNET} and {@link android.Manifest.permission#USE_SIP}
5402b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main * permissions.</p>
553aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez *
563aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <div class="special reference">
573aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <h3>Developer Guides</h3>
583aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <p>For more information about using SIP, read the
593aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <a href="{@docRoot}guide/topics/network/sip.html">Session Initiation Protocol</a>
603aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * developer guide.</p>
613aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * </div>
62363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang */
63363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangpublic class SipManager {
6484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    /**
65323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * The result code to be sent back with the incoming call
66323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * {@link PendingIntent}.
67323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * @see #open(SipProfile, PendingIntent, SipRegistrationListener)
68323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     */
69323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan    public static final int INCOMING_CALL_RESULT_CODE = 101;
70323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan
7108faac3c26e12863858e1534985dd950193f755fHung-ying Tyan    /**
7208faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * Key to retrieve the call ID from an incoming call intent.
7308faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * @see #open(SipProfile, PendingIntent, SipRegistrationListener)
7408faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     */
75323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan    public static final String EXTRA_CALL_ID = "android:sipCallID";
76323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan
7708faac3c26e12863858e1534985dd950193f755fHung-ying Tyan    /**
7808faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * Key to retrieve the offered session description from an incoming call
7908faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * intent.
8008faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * @see #open(SipProfile, PendingIntent, SipRegistrationListener)
8108faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     */
82323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan    public static final String EXTRA_OFFER_SD = "android:sipOfferSD";
83323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan
84323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan    /**
859db99a4dc10ac0d5d3751f03ea51c0fed217d2f8Hung-ying Tyan     * Action to broadcast when SipService is up.
869db99a4dc10ac0d5d3751f03ea51c0fed217d2f8Hung-ying Tyan     * Internal use only.
879db99a4dc10ac0d5d3751f03ea51c0fed217d2f8Hung-ying Tyan     * @hide
889db99a4dc10ac0d5d3751f03ea51c0fed217d2f8Hung-ying Tyan     */
899db99a4dc10ac0d5d3751f03ea51c0fed217d2f8Hung-ying Tyan    public static final String ACTION_SIP_SERVICE_UP =
909db99a4dc10ac0d5d3751f03ea51c0fed217d2f8Hung-ying Tyan            "android.net.sip.SIP_SERVICE_UP";
919db99a4dc10ac0d5d3751f03ea51c0fed217d2f8Hung-ying Tyan    /**
9284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Action string for the incoming call intent for the Phone app.
9384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Internal use only.
9484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * @hide
9584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     */
9684a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    public static final String ACTION_SIP_INCOMING_CALL =
97363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            "com.android.phone.SIP_INCOMING_CALL";
9884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    /**
9984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Action string for the add-phone intent.
10084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Internal use only.
10184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * @hide
10284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     */
10384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    public static final String ACTION_SIP_ADD_PHONE =
104363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            "com.android.phone.SIP_ADD_PHONE";
10584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    /**
10684a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Action string for the remove-phone intent.
10784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Internal use only.
10884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * @hide
10984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     */
11084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    public static final String ACTION_SIP_REMOVE_PHONE =
111363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            "com.android.phone.SIP_REMOVE_PHONE";
11284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    /**
11384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Part of the ACTION_SIP_ADD_PHONE and ACTION_SIP_REMOVE_PHONE intents.
11484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Internal use only.
11584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * @hide
11684a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     */
11784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    public static final String EXTRA_LOCAL_URI = "android:localSipUri";
118363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
1199ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan    private static final String TAG = "SipManager";
1209ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan
121363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    private ISipService mSipService;
12284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    private Context mContext;
123363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
124363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
12584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Creates a manager instance. Returns null if SIP API is not supported.
126363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
12784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * @param context application context for creating the manager object
1283424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan     * @return the manager instance or null if SIP API is not supported
129363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
13084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    public static SipManager newInstance(Context context) {
13184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan        return (isApiSupported(context) ? new SipManager(context) : null);
1323424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan    }
1333424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan
1343424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan    /**
1353424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan     * Returns true if the SIP API is supported by the system.
1363424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan     */
1373424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan    public static boolean isApiSupported(Context context) {
1383424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan        return context.getPackageManager().hasSystemFeature(
1393424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan                PackageManager.FEATURE_SIP);
1403424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan    }
1413424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan
1423424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan    /**
1435bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan     * Returns true if the system supports SIP-based VOIP API.
1443424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan     */
1453424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan    public static boolean isVoipSupported(Context context) {
1463424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan        return context.getPackageManager().hasSystemFeature(
1473424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan                PackageManager.FEATURE_SIP_VOIP) && isApiSupported(context);
148363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
149363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
150c4b87477c076d61062950becc132b7483e3fb198Hung-ying Tyan    /**
151c4b87477c076d61062950becc132b7483e3fb198Hung-ying Tyan     * Returns true if SIP is only available on WIFI.
152c4b87477c076d61062950becc132b7483e3fb198Hung-ying Tyan     */
153c4b87477c076d61062950becc132b7483e3fb198Hung-ying Tyan    public static boolean isSipWifiOnly(Context context) {
154c4b87477c076d61062950becc132b7483e3fb198Hung-ying Tyan        return context.getResources().getBoolean(
155c4b87477c076d61062950becc132b7483e3fb198Hung-ying Tyan                com.android.internal.R.bool.config_sip_wifi_only);
156c4b87477c076d61062950becc132b7483e3fb198Hung-ying Tyan    }
157c4b87477c076d61062950becc132b7483e3fb198Hung-ying Tyan
15884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    private SipManager(Context context) {
15984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan        mContext = context;
1603424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan        createSipService();
161363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
162363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
1633424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan    private void createSipService() {
164cde66df44240cfe5a7bec12ac52464c3bf26c14fChung-yih Wang        IBinder b = ServiceManager.getService(Context.SIP_SERVICE);
165363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        mSipService = ISipService.Stub.asInterface(b);
166363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
167363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
168363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
16902b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main     * Opens the profile for making generic SIP calls. The caller may make subsequent calls
17084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * through {@link #makeAudioCall}. If one also wants to receive calls on the
171323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * profile, use
172323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)}
17384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * instead.
174363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
175363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param localProfile the SIP profile to make calls from
176363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws SipException if the profile contains incorrect settings or
177363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *      calling the SIP service results in an error
178363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
179363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public void open(SipProfile localProfile) throws SipException {
180363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
181363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            mSipService.open(localProfile);
182363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (RemoteException e) {
183363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("open()", e);
184363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
185363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
186363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
187363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
18802b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main     * Opens the profile for making calls and/or receiving generic SIP calls. The caller may
18984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * make subsequent calls through {@link #makeAudioCall}. If the
19084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * auto-registration option is enabled in the profile, the SIP service
19184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * will register the profile to the corresponding SIP provider periodically
19208faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * in order to receive calls from the provider. When the SIP service
19308faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * receives a new call, it will send out an intent with the provided action
19408faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * string. The intent contains a call ID extra and an offer session
19508faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * description string extra. Use {@link #getCallId} and
19608faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * {@link #getOfferSessionDescription} to retrieve those extras.
197363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
198363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param localProfile the SIP profile to receive incoming calls for
199323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * @param incomingCallPendingIntent When an incoming call is received, the
200323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     *      SIP service will call
201323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     *      {@link PendingIntent#send(Context, int, Intent)} to send back the
202323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     *      intent to the caller with {@link #INCOMING_CALL_RESULT_CODE} as the
203323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     *      result code and the intent to fill in the call ID and session
204323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     *      description information. It cannot be null.
205363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param listener to listen to registration events; can be null
206323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * @see #getCallId
207323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * @see #getOfferSessionDescription
208323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * @see #takeAudioCall
209323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * @throws NullPointerException if {@code incomingCallPendingIntent} is null
210363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws SipException if the profile contains incorrect settings or
211363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *      calling the SIP service results in an error
21208faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * @see #isIncomingCallIntent
21308faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * @see #getCallId
21408faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * @see #getOfferSessionDescription
215363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
216363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public void open(SipProfile localProfile,
217323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan            PendingIntent incomingCallPendingIntent,
218363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            SipRegistrationListener listener) throws SipException {
219323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan        if (incomingCallPendingIntent == null) {
220323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan            throw new NullPointerException(
221323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan                    "incomingCallPendingIntent cannot be null");
222323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan        }
223363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
224323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan            mSipService.open3(localProfile, incomingCallPendingIntent,
2259e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan                    createRelay(listener, localProfile.getUriString()));
226363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (RemoteException e) {
227363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("open()", e);
228363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
229363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
230363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
231363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
232363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Sets the listener to listen to registration events. No effect if the
233323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * profile has not been opened to receive calls (see
234323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)}).
235363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
236363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param localProfileUri the URI of the profile
237363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param listener to listen to registration events; can be null
238363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws SipException if calling the SIP service results in an error
239363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
240363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public void setRegistrationListener(String localProfileUri,
241363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            SipRegistrationListener listener) throws SipException {
242363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
243363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            mSipService.setRegistrationListener(
2449e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan                    localProfileUri, createRelay(listener, localProfileUri));
245363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (RemoteException e) {
246363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("setRegistrationListener()", e);
247363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
248363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
249363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
250363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
251363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Closes the specified profile to not make/receive calls. All the resources
252363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * that were allocated to the profile are also released.
253363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
254363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param localProfileUri the URI of the profile to close
255363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws SipException if calling the SIP service results in an error
256363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
257363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public void close(String localProfileUri) throws SipException {
258363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
259363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            mSipService.close(localProfileUri);
260363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (RemoteException e) {
261363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("close()", e);
262363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
263363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
264363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
265363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
26684a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Checks if the specified profile is opened in the SIP service for
26784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * making and/or receiving calls.
268363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
269363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param localProfileUri the URI of the profile in question
270363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @return true if the profile is enabled to receive calls
271363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws SipException if calling the SIP service results in an error
272363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
273363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public boolean isOpened(String localProfileUri) throws SipException {
274363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
275363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            return mSipService.isOpened(localProfileUri);
276363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (RemoteException e) {
277363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("isOpened()", e);
278363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
279363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
280363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
281363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
28284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Checks if the SIP service has successfully registered the profile to the
28384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * SIP provider (specified in the profile) for receiving calls. Returning
28484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * true from this method also implies the profile is opened
28584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * ({@link #isOpened}).
286363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
287363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param localProfileUri the URI of the profile in question
28884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * @return true if the profile is registered to the SIP provider; false if
28984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     *        the profile has not been opened in the SIP service or the SIP
29084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     *        service has not yet successfully registered the profile to the SIP
29184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     *        provider
292363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws SipException if calling the SIP service results in an error
293363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
294363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public boolean isRegistered(String localProfileUri) throws SipException {
295363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
296363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            return mSipService.isRegistered(localProfileUri);
297363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (RemoteException e) {
298363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("isRegistered()", e);
299363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
300363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
301363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
302363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
3039352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan     * Creates a {@link SipAudioCall} to make a call. The attempt will be timed
3049352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan     * out if the call is not established within {@code timeout} seconds and
30502b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main     * {@link SipAudioCall.Listener#onError onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
3069352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan     * will be called.
307363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
308363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param localProfile the SIP profile to make the call from
309363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param peerProfile the SIP profile to make the call to
310363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
311363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *      can be null
31208faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * @param timeout the timeout value in seconds. Default value (defined by
31308faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     *        SIP protocol) is used if {@code timeout} is zero or negative.
314363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @return a {@link SipAudioCall} object
3155bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan     * @throws SipException if calling the SIP service results in an error or
3165bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan     *      VOIP API is not supported by the device
31702b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main     * @see SipAudioCall.Listener#onError
3185bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan     * @see #isVoipSupported
319363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
32084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    public SipAudioCall makeAudioCall(SipProfile localProfile,
3219352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan            SipProfile peerProfile, SipAudioCall.Listener listener, int timeout)
322363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throws SipException {
3235bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan        if (!isVoipSupported(mContext)) {
3245bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan            throw new SipException("VOIP API is not supported");
3255bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan        }
32684a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan        SipAudioCall call = new SipAudioCall(mContext, localProfile);
327363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        call.setListener(listener);
3283a4197e642e9c70f1fe00c2cba30f0f957d36bfcHung-ying Tyan        SipSession s = createSipSession(localProfile, null);
3293a4197e642e9c70f1fe00c2cba30f0f957d36bfcHung-ying Tyan        call.makeCall(peerProfile, s, timeout);
330363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        return call;
331363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
332363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
333363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
334323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * Creates a {@link SipAudioCall} to make an audio call. The attempt will be
335323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * timed out if the call is not established within {@code timeout} seconds
336323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * and
33702b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main     * {@link SipAudioCall.Listener#onError onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
3389352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan     * will be called.
339363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
340363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param localProfileUri URI of the SIP profile to make the call from
341363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param peerProfileUri URI of the SIP profile to make the call to
342363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
343363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *      can be null
34408faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * @param timeout the timeout value in seconds. Default value (defined by
34508faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     *        SIP protocol) is used if {@code timeout} is zero or negative.
346363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @return a {@link SipAudioCall} object
3475bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan     * @throws SipException if calling the SIP service results in an error or
3485bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan     *      VOIP API is not supported by the device
34902b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main     * @see SipAudioCall.Listener#onError
3505bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan     * @see #isVoipSupported
351363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
35284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    public SipAudioCall makeAudioCall(String localProfileUri,
3539352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan            String peerProfileUri, SipAudioCall.Listener listener, int timeout)
354363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throws SipException {
3555bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan        if (!isVoipSupported(mContext)) {
3565bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan            throw new SipException("VOIP API is not supported");
3575bd3782f244212cd8ef51bf9f3578869b08b4e18Hung-ying Tyan        }
358363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
35984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan            return makeAudioCall(
360363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang                    new SipProfile.Builder(localProfileUri).build(),
3619352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan                    new SipProfile.Builder(peerProfileUri).build(), listener,
3629352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan                    timeout);
363363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (ParseException e) {
364363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("build SipProfile", e);
365363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
366363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
367363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
368363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
369363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Creates a {@link SipAudioCall} to take an incoming call. Before the call
370363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * is returned, the listener will receive a
371286bb5a00bdb9f0cb0815aef441ec72f231c84eaHung-ying Tyan     * {@link SipAudioCall.Listener#onRinging}
372363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * callback.
373363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
374363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
375363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
376363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *      can be null
377363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @return a {@link SipAudioCall} object
378363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws SipException if calling the SIP service results in an error
379363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
38084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    public SipAudioCall takeAudioCall(Intent incomingCallIntent,
3819b449e5606786f7c197679f8f9d25985308bfb72Hung-ying Tyan            SipAudioCall.Listener listener) throws SipException {
3828d1b2a17d9935819ec96f1b5fca0e9945f564eaaHung-ying Tyan        if (incomingCallIntent == null) {
3838d1b2a17d9935819ec96f1b5fca0e9945f564eaaHung-ying Tyan            throw new SipException("Cannot retrieve session with null intent");
3848d1b2a17d9935819ec96f1b5fca0e9945f564eaaHung-ying Tyan        }
385363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
386363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        String callId = getCallId(incomingCallIntent);
387363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        if (callId == null) {
388363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("Call ID missing in incoming call intent");
389363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
390363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
39195b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh        String offerSd = getOfferSessionDescription(incomingCallIntent);
392363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        if (offerSd == null) {
393363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("Session description missing in incoming "
394363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang                    + "call intent");
395363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
396363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
397363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
398363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            ISipSession session = mSipService.getPendingSession(callId);
3998d1b2a17d9935819ec96f1b5fca0e9945f564eaaHung-ying Tyan            if (session == null) {
4008d1b2a17d9935819ec96f1b5fca0e9945f564eaaHung-ying Tyan                throw new SipException("No pending session for the call");
4018d1b2a17d9935819ec96f1b5fca0e9945f564eaaHung-ying Tyan            }
40284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan            SipAudioCall call = new SipAudioCall(
40384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan                    mContext, session.getLocalProfile());
40484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan            call.attachCall(new SipSession(session), offerSd);
405363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            call.setListener(listener);
406363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            return call;
407363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (Throwable t) {
408363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("takeAudioCall()", t);
409363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
410363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
411363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
412363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
413363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Checks if the intent is an incoming call broadcast intent.
414363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
415363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param intent the intent in question
416363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @return true if the intent is an incoming call broadcast intent
417363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
418363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public static boolean isIncomingCallIntent(Intent intent) {
419363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        if (intent == null) return false;
420363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        String callId = getCallId(intent);
42195b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh        String offerSd = getOfferSessionDescription(intent);
422363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        return ((callId != null) && (offerSd != null));
423363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
424363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
425363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
426363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Gets the call ID from the specified incoming call broadcast intent.
427363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
428363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
429363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @return the call ID or null if the intent does not contain it
430363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
431363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public static String getCallId(Intent incomingCallIntent) {
43284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan        return incomingCallIntent.getStringExtra(EXTRA_CALL_ID);
433363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
434363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
435363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
436363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Gets the offer session description from the specified incoming call
437363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * broadcast intent.
438363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
439363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
440363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @return the offer session description or null if the intent does not
441363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *      have it
442363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
44395b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh    public static String getOfferSessionDescription(Intent incomingCallIntent) {
44484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan        return incomingCallIntent.getStringExtra(EXTRA_OFFER_SD);
445363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
446363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
447363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
448363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Creates an incoming call broadcast intent.
449363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
450363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param callId the call ID of the incoming call
451363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param sessionDescription the session description of the incoming call
452363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @return the incoming call intent
453363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @hide
454363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
45584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    public static Intent createIncomingCallBroadcast(String callId,
45684a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan            String sessionDescription) {
45784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan        Intent intent = new Intent();
45884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan        intent.putExtra(EXTRA_CALL_ID, callId);
45984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan        intent.putExtra(EXTRA_OFFER_SD, sessionDescription);
460363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        return intent;
461363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
462363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
463363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
46484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Manually registers the profile to the corresponding SIP provider for
465323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * receiving calls.
466323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)} is
467323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * still needed to be called at least once in order for the SIP service to
46802b1d685cc287d7c53141872b3d80be4ee5dd59eScott Main     * notify the caller with the {@link android.app.PendingIntent} when an incoming call is
469323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan     * received.
470363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
471363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param localProfile the SIP profile to register with
472286bb5a00bdb9f0cb0815aef441ec72f231c84eaHung-ying Tyan     * @param expiryTime registration expiration time (in seconds)
473363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param listener to listen to the registration events
474363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws SipException if calling the SIP service results in an error
475363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
476363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public void register(SipProfile localProfile, int expiryTime,
477363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            SipRegistrationListener listener) throws SipException {
478363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
4799e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan            ISipSession session = mSipService.createSession(localProfile,
4809e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan                    createRelay(listener, localProfile.getUriString()));
48125ccbb97ffd3298caede635f29445073e845cfc3Masahiko Endo            if (session == null) {
48225ccbb97ffd3298caede635f29445073e845cfc3Masahiko Endo                throw new SipException(
48325ccbb97ffd3298caede635f29445073e845cfc3Masahiko Endo                        "SipService.createSession() returns null");
48425ccbb97ffd3298caede635f29445073e845cfc3Masahiko Endo            }
485363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            session.register(expiryTime);
486363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (RemoteException e) {
487363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("register()", e);
488363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
489363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
490363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
491363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
49284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * Manually unregisters the profile from the corresponding SIP provider for
49384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * stop receiving further calls. This may interference with the auto
49484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * registration process in the SIP service if the auto-registration option
49584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan     * in the profile is enabled.
496363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
497363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param localProfile the SIP profile to register with
498363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param listener to listen to the registration events
499363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws SipException if calling the SIP service results in an error
500363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
501363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public void unregister(SipProfile localProfile,
502363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            SipRegistrationListener listener) throws SipException {
503363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
5049e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan            ISipSession session = mSipService.createSession(localProfile,
5059e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan                    createRelay(listener, localProfile.getUriString()));
50625ccbb97ffd3298caede635f29445073e845cfc3Masahiko Endo            if (session == null) {
50725ccbb97ffd3298caede635f29445073e845cfc3Masahiko Endo                throw new SipException(
50825ccbb97ffd3298caede635f29445073e845cfc3Masahiko Endo                        "SipService.createSession() returns null");
50925ccbb97ffd3298caede635f29445073e845cfc3Masahiko Endo            }
510363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            session.unregister();
511363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (RemoteException e) {
512363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("unregister()", e);
513363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
514363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
515363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
516363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
51708faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * Gets the {@link SipSession} that handles the incoming call. For audio
518363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * calls, consider to use {@link SipAudioCall} to handle the incoming call.
519286bb5a00bdb9f0cb0815aef441ec72f231c84eaHung-ying Tyan     * See {@link #takeAudioCall}. Note that the method may be called only once
520286bb5a00bdb9f0cb0815aef441ec72f231c84eaHung-ying Tyan     * for the same intent. For subsequent calls on the same intent, the method
521286bb5a00bdb9f0cb0815aef441ec72f231c84eaHung-ying Tyan     * returns null.
522363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
523363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
524363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @return the session object that handles the incoming call
525363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
52608faac3c26e12863858e1534985dd950193f755fHung-ying Tyan    public SipSession getSessionFor(Intent incomingCallIntent)
527363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throws SipException {
528363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
529363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            String callId = getCallId(incomingCallIntent);
53008faac3c26e12863858e1534985dd950193f755fHung-ying Tyan            ISipSession s = mSipService.getPendingSession(callId);
53125ccbb97ffd3298caede635f29445073e845cfc3Masahiko Endo            return ((s == null) ? null : new SipSession(s));
532363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (RemoteException e) {
533363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("getSessionFor()", e);
534363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
535363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
536363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
537363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    private static ISipSessionListener createRelay(
5389e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan            SipRegistrationListener listener, String uri) {
5399e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan        return ((listener == null) ? null : new ListenerRelay(listener, uri));
540363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
541363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
542363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
54308faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * Creates a {@link SipSession} with the specified profile. Use other
54408faac3c26e12863858e1534985dd950193f755fHung-ying Tyan     * methods, if applicable, instead of interacting with {@link SipSession}
545363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * directly.
546363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
547363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param localProfile the SIP profile the session is associated with
548363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param listener to listen to SIP session events
549363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
55084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan    public SipSession createSipSession(SipProfile localProfile,
55184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan            SipSession.Listener listener) throws SipException {
552363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
55384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan            ISipSession s = mSipService.createSession(localProfile, null);
5548d1b2a17d9935819ec96f1b5fca0e9945f564eaaHung-ying Tyan            if (s == null) {
5558d1b2a17d9935819ec96f1b5fca0e9945f564eaaHung-ying Tyan                throw new SipException(
5568d1b2a17d9935819ec96f1b5fca0e9945f564eaaHung-ying Tyan                        "Failed to create SipSession; network unavailable?");
5578d1b2a17d9935819ec96f1b5fca0e9945f564eaaHung-ying Tyan            }
55884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan            return new SipSession(s, listener);
559363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (RemoteException e) {
560363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new SipException("createSipSession()", e);
561363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
562363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
563363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
564363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
565363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Gets the list of profiles hosted by the SIP service. The user information
566363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * (username, password and display name) are crossed out.
567363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @hide
568363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
569363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public SipProfile[] getListOfProfiles() {
570363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        try {
571363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            return mSipService.getListOfProfiles();
572363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        } catch (RemoteException e) {
5738d1b2a17d9935819ec96f1b5fca0e9945f564eaaHung-ying Tyan            return new SipProfile[0];
574363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
575363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
576363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
577363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    private static class ListenerRelay extends SipSessionAdapter {
578363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        private SipRegistrationListener mListener;
5799e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan        private String mUri;
580363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
581363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        // listener must not be null
5829e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan        public ListenerRelay(SipRegistrationListener listener, String uri) {
583363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            mListener = listener;
5849e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan            mUri = uri;
585363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
586363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
587363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        private String getUri(ISipSession session) {
588363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            try {
589fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan                return ((session == null)
5909e1d308e993d451882456e44cfaacae63df7a496Hung-ying Tyan                        ? mUri
591fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan                        : session.getLocalProfile().getUriString());
5929ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan            } catch (Throwable e) {
5939ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan                // SipService died? SIP stack died?
5949ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan                Log.w(TAG, "getUri(): " + e);
5959ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan                return null;
596363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            }
597363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
598363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
599363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        @Override
600363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        public void onRegistering(ISipSession session) {
601363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            mListener.onRegistering(getUri(session));
602363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
603363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
604363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        @Override
605363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        public void onRegistrationDone(ISipSession session, int duration) {
606363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            long expiryTime = duration;
607363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            if (duration > 0) expiryTime += System.currentTimeMillis();
608363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            mListener.onRegistrationDone(getUri(session), expiryTime);
609363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
610363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
611363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        @Override
61297963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan        public void onRegistrationFailed(ISipSession session, int errorCode,
613363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang                String message) {
61497963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan            mListener.onRegistrationFailed(getUri(session), errorCode, message);
615363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
616363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
617363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        @Override
618363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        public void onRegistrationTimeout(ISipSession session) {
619363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            mListener.onRegistrationFailed(getUri(session),
62099bf4e45c4566172189735b34b368b76660ca57aHung-ying Tyan                    SipErrorCode.TIME_OUT, "registration timed out");
621363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
622363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
623363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang}
624