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