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.telephony.Rlog;
24
25/** Class to help safely run a callback in a different thread. */
26class SipSessionListenerProxy extends ISipSessionListener.Stub {
27    private static final String TAG = "SipSessionListnerProxy";
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    @Override
47    public void onCalling(final ISipSession session) {
48        if (mListener == null) return;
49        proxy(new Runnable() {
50            @Override
51            public void run() {
52                try {
53                    mListener.onCalling(session);
54                } catch (Throwable t) {
55                    handle(t, "onCalling()");
56                }
57            }
58        });
59    }
60
61    @Override
62    public void onRinging(final ISipSession session, final SipProfile caller,
63            final String sessionDescription) {
64        if (mListener == null) return;
65        proxy(new Runnable() {
66            @Override
67            public void run() {
68                try {
69                    mListener.onRinging(session, caller, sessionDescription);
70                } catch (Throwable t) {
71                    handle(t, "onRinging()");
72                }
73            }
74        });
75    }
76
77    @Override
78    public void onRingingBack(final ISipSession session) {
79        if (mListener == null) return;
80        proxy(new Runnable() {
81            @Override
82            public void run() {
83                try {
84                    mListener.onRingingBack(session);
85                } catch (Throwable t) {
86                    handle(t, "onRingingBack()");
87                }
88            }
89        });
90    }
91
92    @Override
93    public void onCallEstablished(final ISipSession session,
94            final String sessionDescription) {
95        if (mListener == null) return;
96        proxy(new Runnable() {
97            @Override
98            public void run() {
99                try {
100                    mListener.onCallEstablished(session, sessionDescription);
101                } catch (Throwable t) {
102                    handle(t, "onCallEstablished()");
103                }
104            }
105        });
106    }
107
108    @Override
109    public void onCallEnded(final ISipSession session) {
110        if (mListener == null) return;
111        proxy(new Runnable() {
112            @Override
113            public void run() {
114                try {
115                    mListener.onCallEnded(session);
116                } catch (Throwable t) {
117                    handle(t, "onCallEnded()");
118                }
119            }
120        });
121    }
122
123    @Override
124    public void onCallTransferring(final ISipSession newSession,
125            final String sessionDescription) {
126        if (mListener == null) return;
127        proxy(new Runnable() {
128            @Override
129            public void run() {
130                try {
131                    mListener.onCallTransferring(newSession, sessionDescription);
132                } catch (Throwable t) {
133                    handle(t, "onCallTransferring()");
134                }
135            }
136        });
137    }
138
139    @Override
140    public void onCallBusy(final ISipSession session) {
141        if (mListener == null) return;
142        proxy(new Runnable() {
143            @Override
144            public void run() {
145                try {
146                    mListener.onCallBusy(session);
147                } catch (Throwable t) {
148                    handle(t, "onCallBusy()");
149                }
150            }
151        });
152    }
153
154    @Override
155    public void onCallChangeFailed(final ISipSession session,
156            final int errorCode, final String message) {
157        if (mListener == null) return;
158        proxy(new Runnable() {
159            @Override
160            public void run() {
161                try {
162                    mListener.onCallChangeFailed(session, errorCode, message);
163                } catch (Throwable t) {
164                    handle(t, "onCallChangeFailed()");
165                }
166            }
167        });
168    }
169
170    @Override
171    public void onError(final ISipSession session, final int errorCode,
172            final String message) {
173        if (mListener == null) return;
174        proxy(new Runnable() {
175            @Override
176            public void run() {
177                try {
178                    mListener.onError(session, errorCode, message);
179                } catch (Throwable t) {
180                    handle(t, "onError()");
181                }
182            }
183        });
184    }
185
186    @Override
187    public void onRegistering(final ISipSession session) {
188        if (mListener == null) return;
189        proxy(new Runnable() {
190            @Override
191            public void run() {
192                try {
193                    mListener.onRegistering(session);
194                } catch (Throwable t) {
195                    handle(t, "onRegistering()");
196                }
197            }
198        });
199    }
200
201    @Override
202    public void onRegistrationDone(final ISipSession session,
203            final int duration) {
204        if (mListener == null) return;
205        proxy(new Runnable() {
206            @Override
207            public void run() {
208                try {
209                    mListener.onRegistrationDone(session, duration);
210                } catch (Throwable t) {
211                    handle(t, "onRegistrationDone()");
212                }
213            }
214        });
215    }
216
217    @Override
218    public void onRegistrationFailed(final ISipSession session,
219            final int errorCode, final String message) {
220        if (mListener == null) return;
221        proxy(new Runnable() {
222            @Override
223            public void run() {
224                try {
225                    mListener.onRegistrationFailed(session, errorCode, message);
226                } catch (Throwable t) {
227                    handle(t, "onRegistrationFailed()");
228                }
229            }
230        });
231    }
232
233    @Override
234    public void onRegistrationTimeout(final ISipSession session) {
235        if (mListener == null) return;
236        proxy(new Runnable() {
237            @Override
238            public void run() {
239                try {
240                    mListener.onRegistrationTimeout(session);
241                } catch (Throwable t) {
242                    handle(t, "onRegistrationTimeout()");
243                }
244            }
245        });
246    }
247
248    private void handle(Throwable t, String message) {
249        if (t instanceof DeadObjectException) {
250            mListener = null;
251            // This creates race but it's harmless. Just don't log the error
252            // when it happens.
253        } else if (mListener != null) {
254            loge(message, t);
255        }
256    }
257
258    private void log(String s) {
259        Rlog.d(TAG, s);
260    }
261
262    private void loge(String s, Throwable t) {
263        Rlog.e(TAG, s, t);
264    }
265}
266