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 17 package com.android.server.sip; 18 19 import android.net.sip.ISipSession; 20 import android.net.sip.ISipSessionListener; 21 import android.net.sip.SipProfile; 22 import android.os.DeadObjectException; 23 import android.util.Log; 24 25 /** Class to help safely run a callback in a different thread. */ 26 class 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 onCallBusy(final ISipSession session) { 114 if (mListener == null) return; 115 proxy(new Runnable() { 116 public void run() { 117 try { 118 mListener.onCallBusy(session); 119 } catch (Throwable t) { 120 handle(t, "onCallBusy()"); 121 } 122 } 123 }); 124 } 125 126 public void onCallChangeFailed(final ISipSession session, 127 final int errorCode, final String message) { 128 if (mListener == null) return; 129 proxy(new Runnable() { 130 public void run() { 131 try { 132 mListener.onCallChangeFailed(session, errorCode, message); 133 } catch (Throwable t) { 134 handle(t, "onCallChangeFailed()"); 135 } 136 } 137 }); 138 } 139 140 public void onError(final ISipSession session, final int errorCode, 141 final String message) { 142 if (mListener == null) return; 143 proxy(new Runnable() { 144 public void run() { 145 try { 146 mListener.onError(session, errorCode, message); 147 } catch (Throwable t) { 148 handle(t, "onError()"); 149 } 150 } 151 }); 152 } 153 154 public void onRegistering(final ISipSession session) { 155 if (mListener == null) return; 156 proxy(new Runnable() { 157 public void run() { 158 try { 159 mListener.onRegistering(session); 160 } catch (Throwable t) { 161 handle(t, "onRegistering()"); 162 } 163 } 164 }); 165 } 166 167 public void onRegistrationDone(final ISipSession session, 168 final int duration) { 169 if (mListener == null) return; 170 proxy(new Runnable() { 171 public void run() { 172 try { 173 mListener.onRegistrationDone(session, duration); 174 } catch (Throwable t) { 175 handle(t, "onRegistrationDone()"); 176 } 177 } 178 }); 179 } 180 181 public void onRegistrationFailed(final ISipSession session, 182 final int errorCode, final String message) { 183 if (mListener == null) return; 184 proxy(new Runnable() { 185 public void run() { 186 try { 187 mListener.onRegistrationFailed(session, errorCode, message); 188 } catch (Throwable t) { 189 handle(t, "onRegistrationFailed()"); 190 } 191 } 192 }); 193 } 194 195 public void onRegistrationTimeout(final ISipSession session) { 196 if (mListener == null) return; 197 proxy(new Runnable() { 198 public void run() { 199 try { 200 mListener.onRegistrationTimeout(session); 201 } catch (Throwable t) { 202 handle(t, "onRegistrationTimeout()"); 203 } 204 } 205 }); 206 } 207 208 private void handle(Throwable t, String message) { 209 if (t instanceof DeadObjectException) { 210 mListener = null; 211 // This creates race but it's harmless. Just don't log the error 212 // when it happens. 213 } else if (mListener != null) { 214 Log.w(TAG, message, t); 215 } 216 } 217 } 218