1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.sip;
18
19import android.net.sip.ISipSession;
20import android.net.sip.ISipSessionListener;
21import android.net.sip.SipProfile;
22import android.os.DeadObjectException;
23import android.util.Log;
24
25/** Class to help safely run a callback in a different thread. */
26class SipSessionListenerProxy extends ISipSessionListener.Stub {
27    private static final String TAG = "SipSession";
28
29    private ISipSessionListener mListener;
30
31    public void setListener(ISipSessionListener listener) {
32        mListener = listener;
33    }
34
35    public ISipSessionListener getListener() {
36        return mListener;
37    }
38
39    private void proxy(Runnable runnable) {
40        // One thread for each calling back.
41        // Note: Guarantee ordering if the issue becomes important. Currently,
42        // the chance of handling two callback events at a time is none.
43        new Thread(runnable, "SipSessionCallbackThread").start();
44    }
45
46    public void onCalling(final ISipSession session) {
47        if (mListener == null) return;
48        proxy(new Runnable() {
49            public void run() {
50                try {
51                    mListener.onCalling(session);
52                } catch (Throwable t) {
53                    handle(t, "onCalling()");
54                }
55            }
56        });
57    }
58
59    public void onRinging(final ISipSession session, final SipProfile caller,
60            final String sessionDescription) {
61        if (mListener == null) return;
62        proxy(new Runnable() {
63            public void run() {
64                try {
65                    mListener.onRinging(session, caller, sessionDescription);
66                } catch (Throwable t) {
67                    handle(t, "onRinging()");
68                }
69            }
70        });
71    }
72
73    public void onRingingBack(final ISipSession session) {
74        if (mListener == null) return;
75        proxy(new Runnable() {
76            public void run() {
77                try {
78                    mListener.onRingingBack(session);
79                } catch (Throwable t) {
80                    handle(t, "onRingingBack()");
81                }
82            }
83        });
84    }
85
86    public void onCallEstablished(final ISipSession session,
87            final String sessionDescription) {
88        if (mListener == null) return;
89        proxy(new Runnable() {
90            public void run() {
91                try {
92                    mListener.onCallEstablished(session, sessionDescription);
93                } catch (Throwable t) {
94                    handle(t, "onCallEstablished()");
95                }
96            }
97        });
98    }
99
100    public void onCallEnded(final ISipSession session) {
101        if (mListener == null) return;
102        proxy(new Runnable() {
103            public void run() {
104                try {
105                    mListener.onCallEnded(session);
106                } catch (Throwable t) {
107                    handle(t, "onCallEnded()");
108                }
109            }
110        });
111    }
112
113    public void onCallTransferring(final ISipSession newSession,
114            final String sessionDescription) {
115        if (mListener == null) return;
116        proxy(new Runnable() {
117            public void run() {
118                try {
119                    mListener.onCallTransferring(newSession, sessionDescription);
120                } catch (Throwable t) {
121                    handle(t, "onCallTransferring()");
122                }
123            }
124        });
125    }
126
127    public void onCallBusy(final ISipSession session) {
128        if (mListener == null) return;
129        proxy(new Runnable() {
130            public void run() {
131                try {
132                    mListener.onCallBusy(session);
133                } catch (Throwable t) {
134                    handle(t, "onCallBusy()");
135                }
136            }
137        });
138    }
139
140    public void onCallChangeFailed(final ISipSession session,
141            final int errorCode, final String message) {
142        if (mListener == null) return;
143        proxy(new Runnable() {
144            public void run() {
145                try {
146                    mListener.onCallChangeFailed(session, errorCode, message);
147                } catch (Throwable t) {
148                    handle(t, "onCallChangeFailed()");
149                }
150            }
151        });
152    }
153
154    public void onError(final ISipSession session, final int errorCode,
155            final String message) {
156        if (mListener == null) return;
157        proxy(new Runnable() {
158            public void run() {
159                try {
160                    mListener.onError(session, errorCode, message);
161                } catch (Throwable t) {
162                    handle(t, "onError()");
163                }
164            }
165        });
166    }
167
168    public void onRegistering(final ISipSession session) {
169        if (mListener == null) return;
170        proxy(new Runnable() {
171            public void run() {
172                try {
173                    mListener.onRegistering(session);
174                } catch (Throwable t) {
175                    handle(t, "onRegistering()");
176                }
177            }
178        });
179    }
180
181    public void onRegistrationDone(final ISipSession session,
182            final int duration) {
183        if (mListener == null) return;
184        proxy(new Runnable() {
185            public void run() {
186                try {
187                    mListener.onRegistrationDone(session, duration);
188                } catch (Throwable t) {
189                    handle(t, "onRegistrationDone()");
190                }
191            }
192        });
193    }
194
195    public void onRegistrationFailed(final ISipSession session,
196            final int errorCode, final String message) {
197        if (mListener == null) return;
198        proxy(new Runnable() {
199            public void run() {
200                try {
201                    mListener.onRegistrationFailed(session, errorCode, message);
202                } catch (Throwable t) {
203                    handle(t, "onRegistrationFailed()");
204                }
205            }
206        });
207    }
208
209    public void onRegistrationTimeout(final ISipSession session) {
210        if (mListener == null) return;
211        proxy(new Runnable() {
212            public void run() {
213                try {
214                    mListener.onRegistrationTimeout(session);
215                } catch (Throwable t) {
216                    handle(t, "onRegistrationTimeout()");
217                }
218            }
219        });
220    }
221
222    private void handle(Throwable t, String message) {
223        if (t instanceof DeadObjectException) {
224            mListener = null;
225            // This creates race but it's harmless. Just don't log the error
226            // when it happens.
227        } else if (mListener != null) {
228            Log.w(TAG, message, t);
229        }
230    }
231}
232