From 1ca6207a1ec5bf9c12027c4f09a4fe18bd3f825c Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Tue, 7 Jul 2015 17:34:51 -0700 Subject: Change sequence of call removal from Phone's db. Since the Call API's callbacks are now fired from handlers, they end up changing the order in which the callbacks from the Phone and Call API's are fired. To preserve the below ordering, we move the call removal from Phone's db to after all the onCallDestoryedcallbacks have executed. 1. Call->onStateChanged 2. Call->onDetailsChanged 3. Call->onCallDestroyed 4. Phone->onCallRemoved BUG: 22127504 Change-Id: Ice17f727decb516baabbe69adae598ebdf370094 --- telecomm/java/android/telecom/Call.java | 43 +++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) (limited to 'telecomm/java/android') diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index e756a57..4569549 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -921,7 +921,8 @@ public final class Call { */ public void registerCallback(Callback callback, Handler handler) { unregisterCallback(callback); - if (callback != null && handler != null) { + // Don't allow new callback registration if the call is already being destroyed. + if (callback != null && handler != null && mState != STATE_DISCONNECTED) { mCallbackRecords.add(new CallbackRecord(callback, handler)); } } @@ -932,7 +933,8 @@ public final class Call { * @param callback A {@code Callback}. */ public void unregisterCallback(Callback callback) { - if (callback != null) { + // Don't allow callback deregistration if the call is already being destroyed. + if (callback != null && mState != STATE_DISCONNECTED) { for (CallbackRecord record : mCallbackRecords) { if (record.getCallback() == callback) { mCallbackRecords.remove(record); @@ -1080,7 +1082,6 @@ public final class Call { // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list. if (mState == STATE_DISCONNECTED) { fireCallDestroyed(); - mPhone.internalRemoveCall(this); } } @@ -1096,7 +1097,6 @@ public final class Call { mState = Call.STATE_DISCONNECTED; fireStateChanged(mState); fireCallDestroyed(); - mPhone.internalRemoveCall(this); } } @@ -1192,13 +1192,42 @@ public final class Call { } private void fireCallDestroyed() { - for (CallbackRecord record: mCallbackRecords) { - final Call call = this; + /** + * To preserve the ordering of the Call's onCallDestroyed callback and Phone's + * onCallRemoved callback, we remove this call from the Phone's record + * only once all of the registered onCallDestroyed callbacks are executed. + * All the callbacks get removed from our records as a part of this operation + * since onCallDestroyed is the final callback. + */ + final Call call = this; + if (mCallbackRecords.isEmpty()) { + // No callbacks registered, remove the call from Phone's record. + mPhone.internalRemoveCall(call); + } + for (final CallbackRecord record : mCallbackRecords) { final Callback callback = record.getCallback(); record.getHandler().post(new Runnable() { @Override public void run() { - callback.onCallDestroyed(call); + boolean isFinalRemoval = false; + RuntimeException toThrow = null; + try { + callback.onCallDestroyed(call); + } catch (RuntimeException e) { + toThrow = e; + } + synchronized(Call.this) { + mCallbackRecords.remove(record); + if (mCallbackRecords.isEmpty()) { + isFinalRemoval = true; + } + } + if (isFinalRemoval) { + mPhone.internalRemoveCall(call); + } + if (toThrow != null) { + throw toThrow; + } } }); } -- cgit v1.1