SipManager.java revision 98cee0ce2354234e72bafb836864ec10a490ea4d
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
1998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.content.Context;
2098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.content.Intent;
2198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.os.IBinder;
2298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.os.Looper;
2398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.os.RemoteException;
2498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.os.ServiceManager;
2598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
2698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport java.text.ParseException;
2798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport javax.sip.SipException;
2898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
2998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang/**
3098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * The class provides API for various SIP related tasks. Specifically, the API
3198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * allows the application to:
3298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * <ul>
3398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * <li>register a {@link SipProfile} to have the background SIP service listen
3498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      to incoming calls and broadcast them with registered command string. See
3598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      {@link #open(SipProfile, String, SipRegistrationListener)},
3698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      {@link #open(SipProfile)}, {@link #close(String)},
3798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      {@link #isOpened(String)} and {@link isRegistered(String)}. It also
3898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      facilitates handling of the incoming call broadcast intent. See
3998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      {@link #isIncomingCallIntent(Intent)}, {@link #getCallId(Intent)},
4098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      {@link #getOfferSessionDescription(Intent)} and
4198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      {@link #takeAudioCall(Context, Intent, SipAudioCall.Listener)}.</li>
4298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * <li>make/take SIP-based audio calls. See
4398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      {@link #makeAudioCall(Context, SipProfile, SipProfile, SipAudioCall.Listener)}
4498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      and {@link #takeAudioCall(Context, Intent, SipAudioCall.Listener}.</li>
4598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * <li>register/unregister with a SIP service provider. See
4698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      {@link #register(SipProfile, int, ISipSessionListener)} and
4798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      {@link #unregister(SipProfile, ISipSessionListener)}.</li>
4898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * <li>process SIP events directly with a {@link ISipSession} created by
4998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      {@link createSipSession(SipProfile, ISipSessionListener)}.</li>
5098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * </ul>
5198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @hide
5298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */
5398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangpublic class SipManager {
5498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /** @hide */
5598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static final String SIP_INCOMING_CALL_ACTION =
5698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            "com.android.phone.SIP_INCOMING_CALL";
5798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /** @hide */
5898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static final String SIP_ADD_PHONE_ACTION =
5998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            "com.android.phone.SIP_ADD_PHONE";
6098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /** @hide */
6198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static final String SIP_REMOVE_PHONE_ACTION =
6298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            "com.android.phone.SIP_REMOVE_PHONE";
6398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /** @hide */
6498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static final String LOCAL_URI_KEY = "LOCAL SIPURI";
6598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
6698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private static final String CALL_ID_KEY = "CallID";
6798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private static final String OFFER_SD_KEY = "OfferSD";
6898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
6998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private ISipService mSipService;
7098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
7198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    // Will be removed once the SIP service is integrated into framework
7298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private BinderHelper<ISipService> mBinderHelper;
7398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
7498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
7598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Creates a manager instance and initializes the background SIP service.
7698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Will be removed once the SIP service is integrated into framework.
7798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
7898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param context context to start the SIP service
7998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the manager instance
8098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
8198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static SipManager getInstance(final Context context) {
8298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        final SipManager manager = new SipManager();
8398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        manager.createSipService(context);
8498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return manager;
8598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
8698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
8798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private SipManager() {
8898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
8998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
9098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private void createSipService(Context context) {
9198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (mSipService != null) return;
9298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        IBinder b = ServiceManager.getService(Context.SIP_SERVICE);
9398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        mSipService = ISipService.Stub.asInterface(b);
9498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
9598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
9698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
9798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Opens the profile for making calls and/or receiving calls. Subsequent
9898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * SIP calls can be made through the default phone UI. The caller may also
9998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * make subsequent calls through
10098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * {@link #makeAudioCall(Context, String, String, SipAudioCall.Listener)}.
10198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * If the receiving-call option is enabled in the profile, the SIP service
10298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * will register the profile to the corresponding server periodically in
10398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * order to receive calls from the server.
10498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
10598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to make calls from
10698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if the profile contains incorrect settings or
10798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      calling the SIP service results in an error
10898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
10998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void open(SipProfile localProfile) throws SipException {
11098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
11198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mSipService.open(localProfile);
11298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
11398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("open()", e);
11498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
11598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
11698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
11798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
11898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Opens the profile for making calls and/or receiving calls. Subsequent
11998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * SIP calls can be made through the default phone UI. The caller may also
12098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * make subsequent calls through
12198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * {@link #makeAudioCall(Context, String, String, SipAudioCall.Listener)}.
12298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * If the receiving-call option is enabled in the profile, the SIP service
12398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * will register the profile to the corresponding server periodically in
12498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * order to receive calls from the server.
12598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
12698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to receive incoming calls for
12798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallBroadcastAction the action to be broadcast when an
12898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      incoming call is received
12998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to registration events; can be null
13098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if the profile contains incorrect settings or
13198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      calling the SIP service results in an error
13298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
13398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void open(SipProfile localProfile,
13498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            String incomingCallBroadcastAction,
13598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
13698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
13798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mSipService.open3(localProfile, incomingCallBroadcastAction,
13898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    createRelay(listener));
13998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
14098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("open()", e);
14198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
14298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
14398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
14498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
14598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Sets the listener to listen to registration events. No effect if the
14698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * profile has not been opened to receive calls
14798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * (see {@link #open(SipProfile, String, SipRegistrationListener)} and
14898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * {@link #open(SipProfile)}).
14998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
15098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile
15198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to registration events; can be null
15298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
15398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
15498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void setRegistrationListener(String localProfileUri,
15598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
15698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
15798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mSipService.setRegistrationListener(
15898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    localProfileUri, createRelay(listener));
15998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
16098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("setRegistrationListener()", e);
16198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
16298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
16398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
16498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
16598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Closes the specified profile to not make/receive calls. All the resources
16698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * that were allocated to the profile are also released.
16798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
16898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile to close
16998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
17098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
17198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void close(String localProfileUri) throws SipException {
17298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
17398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mSipService.close(localProfileUri);
17498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
17598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("close()", e);
17698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
17798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
17898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
17998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
18098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Checks if the specified profile is enabled to receive calls.
18198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
18298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile in question
18398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return true if the profile is enabled to receive calls
18498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
18598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
18698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public boolean isOpened(String localProfileUri) throws SipException {
18798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
18898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return mSipService.isOpened(localProfileUri);
18998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
19098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("isOpened()", e);
19198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
19298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
19398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
19498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
19598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Checks if the specified profile is registered to the server for
19698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * receiving calls.
19798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
19898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri the URI of the profile in question
19998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return true if the profile is registered to the server
20098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
20198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
20298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public boolean isRegistered(String localProfileUri) throws SipException {
20398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
20498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return mSipService.isRegistered(localProfileUri);
20598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
20698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("isRegistered()", e);
20798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
20898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
20998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
21098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
21198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Creates a {@link SipAudioCall} to make a call.
21298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
21398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param context context to create a {@link SipAudioCall} object
21498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to make the call from
21598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param peerProfile the SIP profile to make the call to
21698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
21798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      can be null
21898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return a {@link SipAudioCall} object
21998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
22098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
22198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public SipAudioCall makeAudioCall(Context context, SipProfile localProfile,
22298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipProfile peerProfile, SipAudioCall.Listener listener)
22398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throws SipException {
22498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        SipAudioCall call = new SipAudioCallImpl(context, localProfile);
22598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        call.setListener(listener);
22698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        call.makeCall(peerProfile, this);
22798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return call;
22898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
22998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
23098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
23198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Creates a {@link SipAudioCall} to make a call. To use this method, one
23298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * must call {@link #open(SipProfile)} first.
23398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
23498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param context context to create a {@link SipAudioCall} object
23598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfileUri URI of the SIP profile to make the call from
23698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param peerProfileUri URI of the SIP profile to make the call to
23798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
23898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      can be null
23998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return a {@link SipAudioCall} object
24098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
24198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
24298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public SipAudioCall makeAudioCall(Context context, String localProfileUri,
24398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            String peerProfileUri, SipAudioCall.Listener listener)
24498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throws SipException {
24598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
24698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return makeAudioCall(context,
24798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    new SipProfile.Builder(localProfileUri).build(),
24898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    new SipProfile.Builder(peerProfileUri).build(), listener);
24998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (ParseException e) {
25098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("build SipProfile", e);
25198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
25298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
25398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
25498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
25598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * The method calls {@code takeAudioCall(context, incomingCallIntent,
25698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * listener, true}.
25798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
25898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @see #takeAudioCall(Context, Intent, SipAudioCall.Listener, boolean)
25998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
26098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public SipAudioCall takeAudioCall(Context context,
26198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            Intent incomingCallIntent, SipAudioCall.Listener listener)
26298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throws SipException {
26398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return takeAudioCall(context, incomingCallIntent, listener, true);
26498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
26598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
26698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
26798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Creates a {@link SipAudioCall} to take an incoming call. Before the call
26898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * is returned, the listener will receive a
26998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * {@link SipAudioCall#Listener.onRinging(SipAudioCall, SipProfile)}
27098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * callback.
27198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
27298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param context context to create a {@link SipAudioCall} object
27398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
27498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the call events from {@link SipAudioCall};
27598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      can be null
27698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return a {@link SipAudioCall} object
27798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
27898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
27998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public SipAudioCall takeAudioCall(Context context,
28098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            Intent incomingCallIntent, SipAudioCall.Listener listener,
28198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            boolean ringtoneEnabled) throws SipException {
28298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (incomingCallIntent == null) return null;
28398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
28498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        String callId = getCallId(incomingCallIntent);
28598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (callId == null) {
28698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("Call ID missing in incoming call intent");
28798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
28898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
28998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        byte[] offerSd = getOfferSessionDescription(incomingCallIntent);
29098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (offerSd == null) {
29198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("Session description missing in incoming "
29298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    + "call intent");
29398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
29498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
29598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
29698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SdpSessionDescription sdp = new SdpSessionDescription(offerSd);
29798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
29898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            ISipSession session = mSipService.getPendingSession(callId);
29998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            if (session == null) return null;
30098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipAudioCall call = new SipAudioCallImpl(
30198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    context, session.getLocalProfile());
30298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            call.setRingtoneEnabled(ringtoneEnabled);
30398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            call.attachCall(session, sdp);
30498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            call.setListener(listener);
30598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return call;
30698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (Throwable t) {
30798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("takeAudioCall()", t);
30898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
30998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
31098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
31198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
31298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Checks if the intent is an incoming call broadcast intent.
31398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
31498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param intent the intent in question
31598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return true if the intent is an incoming call broadcast intent
31698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
31798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static boolean isIncomingCallIntent(Intent intent) {
31898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (intent == null) return false;
31998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        String callId = getCallId(intent);
32098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        byte[] offerSd = getOfferSessionDescription(intent);
32198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return ((callId != null) && (offerSd != null));
32298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
32398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
32498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
32598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Gets the call ID from the specified incoming call broadcast intent.
32698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
32798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
32898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the call ID or null if the intent does not contain it
32998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
33098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static String getCallId(Intent incomingCallIntent) {
33198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return incomingCallIntent.getStringExtra(CALL_ID_KEY);
33298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
33398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
33498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
33598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Gets the offer session description from the specified incoming call
33698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * broadcast intent.
33798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
33898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
33998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the offer session description or null if the intent does not
34098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *      have it
34198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
34298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static byte[] getOfferSessionDescription(Intent incomingCallIntent) {
34398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return incomingCallIntent.getByteArrayExtra(OFFER_SD_KEY);
34498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
34598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
34698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
34798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Creates an incoming call broadcast intent.
34898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
34998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param action the action string to broadcast
35098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param callId the call ID of the incoming call
35198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param sessionDescription the session description of the incoming call
35298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the incoming call intent
35398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @hide
35498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
35598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public static Intent createIncomingCallBroadcast(String action,
35698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            String callId, byte[] sessionDescription) {
35798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        Intent intent = new Intent(action);
35898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        intent.putExtra(CALL_ID_KEY, callId);
35998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        intent.putExtra(OFFER_SD_KEY, sessionDescription);
36098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return intent;
36198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
36298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
36398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
36498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Registers the profile to the corresponding server for receiving calls.
36598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * {@link #open(SipProfile, String, SipRegistrationListener)} is still
36698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * needed to be called at least once in order for the SIP service to
36798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * broadcast an intent when an incoming call is received.
36898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
36998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to register with
37098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param expiryTime registration expiration time (in second)
37198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the registration events
37298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
37398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
37498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void register(SipProfile localProfile, int expiryTime,
37598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
37698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
37798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            ISipSession session = mSipService.createSession(
37898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    localProfile, createRelay(listener));
37998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            session.register(expiryTime);
38098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
38198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("register()", e);
38298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
38398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
38498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
38598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
38698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Unregisters the profile from the corresponding server for not receiving
38798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * further calls.
38898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
38998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile to register with
39098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to the registration events
39198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SipException if calling the SIP service results in an error
39298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
39398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void unregister(SipProfile localProfile,
39498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) throws SipException {
39598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
39698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            ISipSession session = mSipService.createSession(
39798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    localProfile, createRelay(listener));
39898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            session.unregister();
39998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
40098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("unregister()", e);
40198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
40298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
40398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
40498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
40598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Gets the {@link ISipSession} that handles the incoming call. For audio
40698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * calls, consider to use {@link SipAudioCall} to handle the incoming call.
40798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * See {@link #takeAudioCall(Context, Intent, SipAudioCall.Listener)}.
40898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Note that the method may be called only once for the same intent. For
40998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * subsequent calls on the same intent, the method returns null.
41098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
41198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param incomingCallIntent the incoming call broadcast intent
41298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @return the session object that handles the incoming call
41398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
41498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public ISipSession getSessionFor(Intent incomingCallIntent)
41598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throws SipException {
41698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
41798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            String callId = getCallId(incomingCallIntent);
41898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return mSipService.getPendingSession(callId);
41998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
42098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("getSessionFor()", e);
42198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
42298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
42398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
42498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private static ISipSessionListener createRelay(
42598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            SipRegistrationListener listener) {
42698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return ((listener == null) ? null : new ListenerRelay(listener));
42798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
42898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
42998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
43098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Creates a {@link ISipSession} with the specified profile. Use other
43198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * methods, if applicable, instead of interacting with {@link ISipSession}
43298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * directly.
43398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
43498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param localProfile the SIP profile the session is associated with
43598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param listener to listen to SIP session events
43698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
43798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public ISipSession createSipSession(SipProfile localProfile,
43898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            ISipSessionListener listener) throws SipException {
43998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
44098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return mSipService.createSession(localProfile, listener);
44198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
44298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new SipException("createSipSession()", e);
44398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
44498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
44598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
44698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
44798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Gets the list of profiles hosted by the SIP service. The user information
44898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * (username, password and display name) are crossed out.
44998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @hide
45098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
45198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public SipProfile[] getListOfProfiles() {
45298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        try {
45398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return mSipService.getListOfProfiles();
45498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        } catch (RemoteException e) {
45598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            return null;
45698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
45798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
45898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
45998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private static class ListenerRelay extends SipSessionAdapter {
46098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        private SipRegistrationListener mListener;
46198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
46298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        // listener must not be null
46398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        public ListenerRelay(SipRegistrationListener listener) {
46498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener = listener;
46598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
46698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
46798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        private String getUri(ISipSession session) {
46898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            try {
46998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                return session.getLocalProfile().getUriString();
47098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            } catch (RemoteException e) {
47198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                throw new RuntimeException(e);
47298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            }
47398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
47498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
47598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
47698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        public void onRegistering(ISipSession session) {
47798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener.onRegistering(getUri(session));
47898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
47998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
48098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
48198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        public void onRegistrationDone(ISipSession session, int duration) {
48298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            long expiryTime = duration;
48398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            if (duration > 0) expiryTime += System.currentTimeMillis();
48498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener.onRegistrationDone(getUri(session), expiryTime);
48598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
48698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
48798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
48898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        public void onRegistrationFailed(ISipSession session, String className,
48998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                String message) {
49098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener.onRegistrationFailed(getUri(session), className, message);
49198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
49298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
49398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        @Override
49498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        public void onRegistrationTimeout(ISipSession session) {
49598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            mListener.onRegistrationFailed(getUri(session),
49698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                    SipException.class.getName(), "registration timed out");
49798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
49898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
49998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang}
500