Moves VerifyCallStateChangeTransaction to use existing timeout
Adds the ability for a VoipCallTransaction to specify a different
timeout from the default and brings VerifyCallStateChangeTransaction
impl to use that timeout instead of redefining a new timeout
again in the subclass.
Bug: 327038818
Test: atest TelecomUnitTests
Change-Id: Ic7ae1ca2892f071a5ab5d38fee46a95f060bbbd8
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index ed72a3f..cdf7cd9 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -3053,16 +3053,24 @@
public void awaitCallStateChangeAndMaybeDisconnectCall(int targetCallState,
boolean shouldDisconnectUponTimeout, String callingMethod) {
TransactionManager tm = TransactionManager.getInstance();
- tm.addTransaction(new VerifyCallStateChangeTransaction(mCallsManager,
- this, targetCallState, shouldDisconnectUponTimeout), new OutcomeReceiver<>() {
+ tm.addTransaction(new VerifyCallStateChangeTransaction(mCallsManager.getLock(),
+ this, targetCallState), new OutcomeReceiver<>() {
@Override
public void onResult(VoipCallTransactionResult result) {
+ Log.i(this, "awaitCallStateChangeAndMaybeDisconnectCall: %s: onResult:"
+ + " due to CallException=[%s]", callingMethod, result);
}
@Override
public void onError(CallException e) {
Log.i(this, "awaitCallStateChangeAndMaybeDisconnectCall: %s: onError"
+ " due to CallException=[%s]", callingMethod, e);
+ if (shouldDisconnectUponTimeout) {
+ mCallsManager.markCallAsDisconnected(Call.this,
+ new DisconnectCause(DisconnectCause.ERROR,
+ "did not hold in timeout window"));
+ mCallsManager.markCallAsRemoved(Call.this);
+ }
}
});
}
diff --git a/src/com/android/server/telecom/voip/CallEventCallbackAckTransaction.java b/src/com/android/server/telecom/voip/CallEventCallbackAckTransaction.java
index 93d9836..9e140a7 100644
--- a/src/com/android/server/telecom/voip/CallEventCallbackAckTransaction.java
+++ b/src/com/android/server/telecom/voip/CallEventCallbackAckTransaction.java
@@ -125,7 +125,7 @@
try {
// wait for the client to ack that CallEventCallback
- boolean success = latch.await(VoipCallTransaction.TIMEOUT_LIMIT, TimeUnit.MILLISECONDS);
+ boolean success = latch.await(mTransactionTimeoutMs, TimeUnit.MILLISECONDS);
if (!success) {
// client send onError and failed to complete transaction
Log.i(TAG, String.format("CallEventCallbackAckTransaction:"
diff --git a/src/com/android/server/telecom/voip/ParallelTransaction.java b/src/com/android/server/telecom/voip/ParallelTransaction.java
index 621892a..79a940b 100644
--- a/src/com/android/server/telecom/voip/ParallelTransaction.java
+++ b/src/com/android/server/telecom/voip/ParallelTransaction.java
@@ -33,78 +33,62 @@
}
@Override
- public void start() {
- if (mStats != null) mStats.markStarted();
- // post timeout work
- CompletableFuture<Void> future = new CompletableFuture<>();
- mHandler.postDelayed(() -> future.complete(null), TIMEOUT_LIMIT);
- future.thenApplyAsync((x) -> {
- if (mCompleted.getAndSet(true)) {
- return null;
- }
- if (mCompleteListener != null) {
- mCompleteListener.onTransactionTimeout(mTransactionName);
- }
- timeout();
- return null;
- }, new LoggedHandlerExecutor(mHandler, mTransactionName + "@" + hashCode()
- + ".s", mLock));
+ public void processTransactions() {
+ if (mSubTransactions == null || mSubTransactions.isEmpty()) {
+ scheduleTransaction();
+ return;
+ }
+ TransactionManager.TransactionCompleteListener subTransactionListener =
+ new TransactionManager.TransactionCompleteListener() {
+ private final AtomicInteger mCount = new AtomicInteger(mSubTransactions.size());
- if (mSubTransactions != null && mSubTransactions.size() > 0) {
- TransactionManager.TransactionCompleteListener subTransactionListener =
- new TransactionManager.TransactionCompleteListener() {
- private final AtomicInteger mCount = new AtomicInteger(mSubTransactions.size());
-
- @Override
- public void onTransactionCompleted(VoipCallTransactionResult result,
- String transactionName) {
- if (result.getResult() != VoipCallTransactionResult.RESULT_SUCCEED) {
- CompletableFuture.completedFuture(null).thenApplyAsync(
- (x) -> {
- VoipCallTransactionResult mainResult =
- new VoipCallTransactionResult(
- VoipCallTransactionResult.RESULT_FAILED,
- String.format(
- "sub transaction %s failed",
- transactionName));
- mCompleteListener.onTransactionCompleted(mainResult,
- mTransactionName);
- finish(mainResult);
- return null;
- }, new LoggedHandlerExecutor(mHandler,
- mTransactionName + "@" + hashCode()
- + ".oTC", mLock));
- } else {
- if (mCount.decrementAndGet() == 0) {
- scheduleTransaction();
- }
- }
- }
-
- @Override
- public void onTransactionTimeout(String transactionName) {
+ @Override
+ public void onTransactionCompleted(VoipCallTransactionResult result,
+ String transactionName) {
+ if (result.getResult() != VoipCallTransactionResult.RESULT_SUCCEED) {
CompletableFuture.completedFuture(null).thenApplyAsync(
(x) -> {
VoipCallTransactionResult mainResult =
new VoipCallTransactionResult(
- VoipCallTransactionResult.RESULT_FAILED,
- String.format("sub transaction %s timed out",
- transactionName));
+ VoipCallTransactionResult.RESULT_FAILED,
+ String.format(
+ "sub transaction %s failed",
+ transactionName));
+ finish(mainResult);
mCompleteListener.onTransactionCompleted(mainResult,
mTransactionName);
- finish(mainResult);
return null;
}, new LoggedHandlerExecutor(mHandler,
mTransactionName + "@" + hashCode()
- + ".oTT", mLock));
+ + ".oTC", mLock));
+ } else {
+ if (mCount.decrementAndGet() == 0) {
+ scheduleTransaction();
+ }
}
- };
- for (VoipCallTransaction transaction : mSubTransactions) {
- transaction.setCompleteListener(subTransactionListener);
- transaction.start();
- }
- } else {
- scheduleTransaction();
+ }
+
+ @Override
+ public void onTransactionTimeout(String transactionName) {
+ CompletableFuture.completedFuture(null).thenApplyAsync(
+ (x) -> {
+ VoipCallTransactionResult mainResult =
+ new VoipCallTransactionResult(
+ VoipCallTransactionResult.RESULT_FAILED,
+ String.format("sub transaction %s timed out",
+ transactionName));
+ finish(mainResult);
+ mCompleteListener.onTransactionCompleted(mainResult,
+ mTransactionName);
+ return null;
+ }, new LoggedHandlerExecutor(mHandler,
+ mTransactionName + "@" + hashCode()
+ + ".oTT", mLock));
+ }
+ };
+ for (VoipCallTransaction transaction : mSubTransactions) {
+ transaction.setCompleteListener(subTransactionListener);
+ transaction.start();
}
}
}
diff --git a/src/com/android/server/telecom/voip/SerialTransaction.java b/src/com/android/server/telecom/voip/SerialTransaction.java
index 7d5a178..55d2065 100644
--- a/src/com/android/server/telecom/voip/SerialTransaction.java
+++ b/src/com/android/server/telecom/voip/SerialTransaction.java
@@ -37,86 +37,71 @@
}
@Override
- public void start() {
- if (mStats != null) mStats.markStarted();
- // post timeout work
- CompletableFuture<Void> future = new CompletableFuture<>();
- mHandler.postDelayed(() -> future.complete(null), TIMEOUT_LIMIT);
- future.thenApplyAsync((x) -> {
- if (mCompleted.getAndSet(true)) {
- return null;
- }
- if (mCompleteListener != null) {
- mCompleteListener.onTransactionTimeout(mTransactionName);
- }
- timeout();
- return null;
- }, new LoggedHandlerExecutor(mHandler, mTransactionName + "@" + hashCode()
- + ".s", mLock));
+ public void processTransactions() {
+ if (mSubTransactions == null || mSubTransactions.isEmpty()) {
+ scheduleTransaction();
+ return;
+ }
+ TransactionManager.TransactionCompleteListener subTransactionListener =
+ new TransactionManager.TransactionCompleteListener() {
+ private final AtomicInteger mTransactionIndex = new AtomicInteger(0);
- if (mSubTransactions != null && mSubTransactions.size() > 0) {
- TransactionManager.TransactionCompleteListener subTransactionListener =
- new TransactionManager.TransactionCompleteListener() {
- private final AtomicInteger mTransactionIndex = new AtomicInteger(0);
-
- @Override
- public void onTransactionCompleted(VoipCallTransactionResult result,
- String transactionName) {
- if (result.getResult() != VoipCallTransactionResult.RESULT_SUCCEED) {
- handleTransactionFailure();
- CompletableFuture.completedFuture(null).thenApplyAsync(
- (x) -> {
- VoipCallTransactionResult mainResult =
- new VoipCallTransactionResult(
- VoipCallTransactionResult.RESULT_FAILED,
- String.format(
- "sub transaction %s failed",
- transactionName));
- mCompleteListener.onTransactionCompleted(mainResult,
- mTransactionName);
- finish(mainResult);
- return null;
- }, new LoggedHandlerExecutor(mHandler,
- mTransactionName + "@" + hashCode()
- + ".oTC", mLock));
- } else {
- int currTransactionIndex = mTransactionIndex.incrementAndGet();
- if (currTransactionIndex < mSubTransactions.size()) {
- VoipCallTransaction transaction = mSubTransactions.get(
- currTransactionIndex);
- transaction.setCompleteListener(this);
- transaction.start();
- } else {
- scheduleTransaction();
- }
- }
- }
-
- @Override
- public void onTransactionTimeout(String transactionName) {
+ @Override
+ public void onTransactionCompleted(VoipCallTransactionResult result,
+ String transactionName) {
+ if (result.getResult() != VoipCallTransactionResult.RESULT_SUCCEED) {
handleTransactionFailure();
CompletableFuture.completedFuture(null).thenApplyAsync(
(x) -> {
VoipCallTransactionResult mainResult =
new VoipCallTransactionResult(
- VoipCallTransactionResult.RESULT_FAILED,
- String.format("sub transaction %s timed out",
- transactionName));
+ VoipCallTransactionResult.RESULT_FAILED,
+ String.format(
+ "sub transaction %s failed",
+ transactionName));
+ finish(mainResult);
mCompleteListener.onTransactionCompleted(mainResult,
mTransactionName);
- finish(mainResult);
return null;
}, new LoggedHandlerExecutor(mHandler,
mTransactionName + "@" + hashCode()
- + ".oTT", mLock));
+ + ".oTC", mLock));
+ } else {
+ int currTransactionIndex = mTransactionIndex.incrementAndGet();
+ if (currTransactionIndex < mSubTransactions.size()) {
+ VoipCallTransaction transaction = mSubTransactions.get(
+ currTransactionIndex);
+ transaction.setCompleteListener(this);
+ transaction.start();
+ } else {
+ scheduleTransaction();
+ }
}
- };
- VoipCallTransaction transaction = mSubTransactions.get(0);
- transaction.setCompleteListener(subTransactionListener);
- transaction.start();
- } else {
- scheduleTransaction();
- }
+ }
+
+ @Override
+ public void onTransactionTimeout(String transactionName) {
+ handleTransactionFailure();
+ CompletableFuture.completedFuture(null).thenApplyAsync(
+ (x) -> {
+ VoipCallTransactionResult mainResult =
+ new VoipCallTransactionResult(
+ VoipCallTransactionResult.RESULT_FAILED,
+ String.format("sub transaction %s timed out",
+ transactionName));
+ finish(mainResult);
+ mCompleteListener.onTransactionCompleted(mainResult,
+ mTransactionName);
+ return null;
+ }, new LoggedHandlerExecutor(mHandler,
+ mTransactionName + "@" + hashCode()
+ + ".oTT", mLock));
+ }
+ };
+ VoipCallTransaction transaction = mSubTransactions.get(0);
+ transaction.setCompleteListener(subTransactionListener);
+ transaction.start();
+
}
public void handleTransactionFailure() {}
diff --git a/src/com/android/server/telecom/voip/VerifyCallStateChangeTransaction.java b/src/com/android/server/telecom/voip/VerifyCallStateChangeTransaction.java
index b17dedd..5de4b1d 100644
--- a/src/com/android/server/telecom/voip/VerifyCallStateChangeTransaction.java
+++ b/src/com/android/server/telecom/voip/VerifyCallStateChangeTransaction.java
@@ -18,14 +18,12 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.telecom.Call;
-import com.android.server.telecom.CallsManager;
+import com.android.server.telecom.TelecomSystem;
-import android.telecom.DisconnectCause;
import android.telecom.Log;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
-import java.util.concurrent.TimeUnit;
/**
* VerifyCallStateChangeTransaction is a transaction that verifies a CallState change and has
@@ -35,37 +33,30 @@
*/
public class VerifyCallStateChangeTransaction extends VoipCallTransaction {
private static final String TAG = VerifyCallStateChangeTransaction.class.getSimpleName();
- public static final int FAILURE_CODE = 0;
- public static final int SUCCESS_CODE = 1;
- public static final int TIMEOUT_SECONDS = 2;
+ private static final long CALL_STATE_TIMEOUT_MILLISECONDS = 2000L;
private final Call mCall;
- private final CallsManager mCallsManager;
private final int mTargetCallState;
- private final boolean mShouldDisconnectUponFailure;
- private final CompletableFuture<Integer> mCallStateOrTimeoutResult = new CompletableFuture<>();
private final CompletableFuture<VoipCallTransactionResult> mTransactionResult =
new CompletableFuture<>();
- @VisibleForTesting
- public Call.CallStateListener mCallStateListenerImpl = new Call.CallStateListener() {
+ private final Call.CallStateListener mCallStateListenerImpl = new Call.CallStateListener() {
@Override
public void onCallStateChanged(int newCallState) {
Log.d(TAG, "newState=[%d], expectedState=[%d]", newCallState, mTargetCallState);
if (newCallState == mTargetCallState) {
- mCallStateOrTimeoutResult.complete(SUCCESS_CODE);
+ mTransactionResult.complete(new VoipCallTransactionResult(
+ VoipCallTransactionResult.RESULT_SUCCEED, TAG));
}
// NOTE:: keep listening to the call state until the timeout is reached. It's possible
// another call state is reached in between...
}
};
- public VerifyCallStateChangeTransaction(CallsManager callsManager, Call call,
- int targetCallState, boolean shouldDisconnectUponFailure) {
- super(callsManager.getLock());
- mCallsManager = callsManager;
+ public VerifyCallStateChangeTransaction(TelecomSystem.SyncRoot lock, Call call,
+ int targetCallState) {
+ super(lock, CALL_STATE_TIMEOUT_MILLISECONDS);
mCall = call;
mTargetCallState = targetCallState;
- mShouldDisconnectUponFailure = shouldDisconnectUponFailure;
}
@Override
@@ -73,68 +64,23 @@
Log.d(TAG, "processTransaction:");
// It's possible the Call is already in the expected call state
if (isNewCallStateTargetCallState()) {
- mTransactionResult.complete(
- new VoipCallTransactionResult(VoipCallTransactionResult.RESULT_SUCCEED,
- TAG));
+ mTransactionResult.complete(new VoipCallTransactionResult(
+ VoipCallTransactionResult.RESULT_SUCCEED, TAG));
return mTransactionResult;
}
- initCallStateListenerOnTimeout();
- // At this point, the mCallStateOrTimeoutResult has been completed. There are 2 scenarios:
- // (1) newCallState == targetCallState --> the transaction is successful
- // (2) timeout is reached --> evaluate the current call state and complete the t accordingly
- // also need to do cleanup for the transaction
- evaluateCallStateUponChangeOrTimeout();
-
+ mCall.addCallStateListener(mCallStateListenerImpl);
return mTransactionResult;
}
+ @Override
+ public void finishTransaction() {
+ mCall.removeCallStateListener(mCallStateListenerImpl);
+ }
+
private boolean isNewCallStateTargetCallState() {
return mCall.getState() == mTargetCallState;
}
- private void initCallStateListenerOnTimeout() {
- mCall.addCallStateListener(mCallStateListenerImpl);
- mCallStateOrTimeoutResult.completeOnTimeout(FAILURE_CODE, TIMEOUT_SECONDS,
- TimeUnit.SECONDS);
- }
-
- private void evaluateCallStateUponChangeOrTimeout() {
- mCallStateOrTimeoutResult.thenAcceptAsync((result) -> {
- Log.i(TAG, "processTransaction: thenAcceptAsync: result=[%s]", result);
- mCall.removeCallStateListener(mCallStateListenerImpl);
- if (isNewCallStateTargetCallState()) {
- mTransactionResult.complete(
- new VoipCallTransactionResult(VoipCallTransactionResult.RESULT_SUCCEED,
- TAG));
- } else {
- maybeDisconnectCall();
- mTransactionResult.complete(
- new VoipCallTransactionResult(VoipCallTransactionResult.RESULT_FAILED,
- TAG));
- }
- }).exceptionally(exception -> {
- Log.i(TAG, "hit exception=[%s] while completing future", exception);
- mTransactionResult.complete(
- new VoipCallTransactionResult(VoipCallTransactionResult.RESULT_FAILED,
- TAG));
- return null;
- });
- }
-
- private void maybeDisconnectCall() {
- if (mShouldDisconnectUponFailure) {
- mCallsManager.markCallAsDisconnected(mCall,
- new DisconnectCause(DisconnectCause.ERROR,
- "did not hold in timeout window"));
- mCallsManager.markCallAsRemoved(mCall);
- }
- }
-
- @VisibleForTesting
- public CompletableFuture<Integer> getCallStateOrTimeoutResult() {
- return mCallStateOrTimeoutResult;
- }
-
@VisibleForTesting
public CompletableFuture<VoipCallTransactionResult> getTransactionResult() {
return mTransactionResult;
diff --git a/src/com/android/server/telecom/voip/VoipCallTransaction.java b/src/com/android/server/telecom/voip/VoipCallTransaction.java
index 3c91158..ceb8d55 100644
--- a/src/com/android/server/telecom/voip/VoipCallTransaction.java
+++ b/src/com/android/server/telecom/voip/VoipCallTransaction.java
@@ -20,6 +20,7 @@
import android.os.HandlerThread;
import android.telecom.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.telecom.LoggedHandlerExecutor;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.flags.Flags;
@@ -34,7 +35,7 @@
public class VoipCallTransaction {
//TODO: add log events
- protected static final long TIMEOUT_LIMIT = 5000L;
+ private static final long DEFAULT_TRANSACTION_TIMEOUT_MS = 5000L;
/**
* Tracks stats about a transaction for logging purposes.
@@ -129,58 +130,80 @@
protected final AtomicBoolean mCompleted = new AtomicBoolean(false);
protected final String mTransactionName = this.getClass().getSimpleName();
- private HandlerThread mHandlerThread;
- protected Handler mHandler;
+ private final HandlerThread mHandlerThread;
+ protected final Handler mHandler;
protected TransactionManager.TransactionCompleteListener mCompleteListener;
- protected List<VoipCallTransaction> mSubTransactions;
- protected TelecomSystem.SyncRoot mLock;
+ protected final List<VoipCallTransaction> mSubTransactions;
+ protected final TelecomSystem.SyncRoot mLock;
+ protected final long mTransactionTimeoutMs;
protected final Stats mStats;
public VoipCallTransaction(
- List<VoipCallTransaction> subTransactions, TelecomSystem.SyncRoot lock) {
+ List<VoipCallTransaction> subTransactions, TelecomSystem.SyncRoot lock,
+ long timeoutMs) {
mSubTransactions = subTransactions;
mHandlerThread = new HandlerThread(this.toString());
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mLock = lock;
+ mTransactionTimeoutMs = timeoutMs;
mStats = Flags.enableCallSequencing() ? new Stats() : null;
}
- public VoipCallTransaction(TelecomSystem.SyncRoot lock) {
- this(null /** mSubTransactions */, lock);
+ public VoipCallTransaction(List<VoipCallTransaction> subTransactions,
+ TelecomSystem.SyncRoot lock) {
+ this(subTransactions, lock, DEFAULT_TRANSACTION_TIMEOUT_MS);
+ }
+ public VoipCallTransaction(TelecomSystem.SyncRoot lock, long timeoutMs) {
+ this(null /* mSubTransactions */, lock, timeoutMs);
}
- public void start() {
+ public VoipCallTransaction(TelecomSystem.SyncRoot lock) {
+ this(null /* mSubTransactions */, lock);
+ }
+
+ public final void start() {
if (mStats != null) mStats.markStarted();
// post timeout work
CompletableFuture<Void> future = new CompletableFuture<>();
- mHandler.postDelayed(() -> future.complete(null), TIMEOUT_LIMIT);
+ mHandler.postDelayed(() -> future.complete(null), mTransactionTimeoutMs);
future.thenApplyAsync((x) -> {
- if (mCompleted.getAndSet(true)) {
- return null;
- }
- if (mCompleteListener != null) {
- mCompleteListener.onTransactionTimeout(mTransactionName);
- }
timeout();
return null;
}, new LoggedHandlerExecutor(mHandler, mTransactionName + "@" + hashCode()
+ ".s", mLock));
+ processTransactions();
+ }
+
+ /**
+ * By default, this processes this transaction. For VoipCallTransactions with sub-transactions,
+ * this implementation should be overwritten to handle also processing sub-transactions.
+ */
+ protected void processTransactions() {
scheduleTransaction();
}
- protected void scheduleTransaction() {
+ /**
+ * This method is called when the transaction has finished either successfully or exceptionally.
+ * VoipCallTransactions that are extending this class should override this method to clean up
+ * any leftover state.
+ */
+ protected void finishTransaction() {
+
+ }
+
+ protected final void scheduleTransaction() {
LoggedHandlerExecutor executor = new LoggedHandlerExecutor(mHandler,
mTransactionName + "@" + hashCode() + ".pT", mLock);
CompletableFuture<Void> future = CompletableFuture.completedFuture(null);
future.thenComposeAsync(this::processTransaction, executor)
.thenApplyAsync((Function<VoipCallTransactionResult, Void>) result -> {
mCompleted.set(true);
+ finish(result);
if (mCompleteListener != null) {
mCompleteListener.onTransactionCompleted(result, mTransactionName);
}
- finish(result);
return null;
}, executor)
.exceptionallyAsync((throwable -> {
@@ -189,25 +212,38 @@
}), executor);
}
- public CompletionStage<VoipCallTransactionResult> processTransaction(Void v) {
+ protected CompletionStage<VoipCallTransactionResult> processTransaction(Void v) {
return CompletableFuture.completedFuture(
new VoipCallTransactionResult(VoipCallTransactionResult.RESULT_SUCCEED, null));
}
- public void setCompleteListener(TransactionManager.TransactionCompleteListener listener) {
+ public final void setCompleteListener(TransactionManager.TransactionCompleteListener listener) {
mCompleteListener = listener;
}
- public void timeout() {
+ @VisibleForTesting
+ public final void timeout() {
+ if (mCompleted.getAndSet(true)) {
+ return;
+ }
finish(true, null);
+ if (mCompleteListener != null) {
+ mCompleteListener.onTransactionTimeout(mTransactionName);
+ }
}
- public void finish(VoipCallTransactionResult result) {
+ @VisibleForTesting
+ public final Handler getHandler() {
+ return mHandler;
+ }
+
+ public final void finish(VoipCallTransactionResult result) {
finish(false, result);
}
- public void finish(boolean isTimedOut, VoipCallTransactionResult result) {
+ private void finish(boolean isTimedOut, VoipCallTransactionResult result) {
if (mStats != null) mStats.markComplete(isTimedOut, result);
+ finishTransaction();
// finish all sub transactions
if (mSubTransactions != null && !mSubTransactions.isEmpty()) {
mSubTransactions.forEach( t -> t.finish(isTimedOut, result));
@@ -218,7 +254,7 @@
/**
* @return Stats related to this transaction if stats are enabled, null otherwise.
*/
- public Stats getStats() {
+ public final Stats getStats() {
return mStats;
}
}
diff --git a/tests/src/com/android/server/telecom/tests/TransactionTests.java b/tests/src/com/android/server/telecom/tests/TransactionTests.java
index e58c6c4..b5a0c26 100644
--- a/tests/src/com/android/server/telecom/tests/TransactionTests.java
+++ b/tests/src/com/android/server/telecom/tests/TransactionTests.java
@@ -17,11 +17,13 @@
package com.android.server.telecom.tests;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.isA;
@@ -61,6 +63,7 @@
import com.android.server.telecom.voip.OutgoingCallTransaction;
import com.android.server.telecom.voip.MaybeHoldCallForNewCallTransaction;
import com.android.server.telecom.voip.RequestNewActiveCallTransaction;
+import com.android.server.telecom.voip.TransactionManager;
import com.android.server.telecom.voip.VerifyCallStateChangeTransaction;
import com.android.server.telecom.voip.VoipCallTransactionResult;
@@ -271,27 +274,24 @@
*/
@SmallTest
@Test
- public void testCallStateChangeTimesOut()
- throws ExecutionException, InterruptedException, TimeoutException {
+ public void testCallStateChangeTimesOut() {
when(mFeatureFlags.transactionalCsVerifier()).thenReturn(true);
- VerifyCallStateChangeTransaction t = new VerifyCallStateChangeTransaction(mCallsManager,
- mMockCall1, CallState.ON_HOLD, true);
+ VerifyCallStateChangeTransaction t = new VerifyCallStateChangeTransaction(
+ mLock, mMockCall1, CallState.ON_HOLD);
+ TransactionManager.TransactionCompleteListener listener =
+ mock(TransactionManager.TransactionCompleteListener.class);
+ t.setCompleteListener(listener);
// WHEN
setupHoldableCall();
// simulate the transaction being processed and the CompletableFuture timing out
t.processTransaction(null);
- CompletableFuture<Integer> timeoutFuture = t.getCallStateOrTimeoutResult();
- timeoutFuture.complete(VerifyCallStateChangeTransaction.FAILURE_CODE);
+ t.timeout();
// THEN
verify(mMockCall1, times(1)).addCallStateListener(t.getCallStateListenerImpl());
- assertEquals(timeoutFuture.get().intValue(), VerifyCallStateChangeTransaction.FAILURE_CODE);
- assertEquals(VoipCallTransactionResult.RESULT_FAILED,
- t.getTransactionResult().get(2, TimeUnit.SECONDS).getResult());
+ verify(listener).onTransactionTimeout(anyString());
verify(mMockCall1, atLeastOnce()).removeCallStateListener(any());
- verify(mCallsManager, times(1)).markCallAsDisconnected(eq(mMockCall1), any());
- verify(mCallsManager, times(1)).markCallAsRemoved(eq(mMockCall1));
}
/**
@@ -303,25 +303,23 @@
public void testCallStateIsSuccessfullyChanged()
throws ExecutionException, InterruptedException, TimeoutException {
when(mFeatureFlags.transactionalCsVerifier()).thenReturn(true);
- VerifyCallStateChangeTransaction t = new VerifyCallStateChangeTransaction(mCallsManager,
- mMockCall1, CallState.ON_HOLD, true);
+ VerifyCallStateChangeTransaction t = new VerifyCallStateChangeTransaction(
+ mLock, mMockCall1, CallState.ON_HOLD);
// WHEN
setupHoldableCall();
// simulate the transaction being processed and the setOnHold() being called / state change
t.processTransaction(null);
+ doReturn(CallState.ON_HOLD).when(mMockCall1).getState();
t.getCallStateListenerImpl().onCallStateChanged(CallState.ON_HOLD);
- when(mMockCall1.getState()).thenReturn(CallState.ON_HOLD);
+ t.finish(null);
+
// THEN
verify(mMockCall1, times(1)).addCallStateListener(t.getCallStateListenerImpl());
- assertEquals(t.getCallStateOrTimeoutResult().get().intValue(),
- VerifyCallStateChangeTransaction.SUCCESS_CODE);
assertEquals(VoipCallTransactionResult.RESULT_SUCCEED,
t.getTransactionResult().get(2, TimeUnit.SECONDS).getResult());
verify(mMockCall1, atLeastOnce()).removeCallStateListener(any());
- verify(mCallsManager, never()).markCallAsDisconnected(eq(mMockCall1), any());
- verify(mCallsManager, never()).markCallAsRemoved(eq(mMockCall1));
}
private Call createSpyCall(PhoneAccountHandle targetPhoneAccount, int initialState, String id) {
diff --git a/tests/src/com/android/server/telecom/tests/VoipCallTransactionTest.java b/tests/src/com/android/server/telecom/tests/VoipCallTransactionTest.java
index b7848a2..30cfc2e 100644
--- a/tests/src/com/android/server/telecom/tests/VoipCallTransactionTest.java
+++ b/tests/src/com/android/server/telecom/tests/VoipCallTransactionTest.java
@@ -61,6 +61,7 @@
private long mSleepTime;
private String mName;
private int mType;
+ public boolean isFinished = false;
public TestVoipCallTransaction(String name, long sleepTime, int type) {
super(VoipCallTransactionTest.this.mLock);
@@ -96,6 +97,11 @@
}, mSleepTime);
return resultFuture;
}
+
+ @Override
+ public void finishTransaction() {
+ isFinished = true;
+ }
}
@Override
@@ -109,7 +115,6 @@
@Override
@After
public void tearDown() throws Exception {
- Log.i("Grace", mLog.toString());
mTransactionManager.clear();
super.tearDown();
}
@@ -119,11 +124,11 @@
public void testSerialTransactionSuccess()
throws ExecutionException, InterruptedException, TimeoutException {
List<VoipCallTransaction> subTransactions = new ArrayList<>();
- VoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
+ TestVoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
TestVoipCallTransaction.SUCCESS);
- VoipCallTransaction t2 = new TestVoipCallTransaction("t2", 1000L,
+ TestVoipCallTransaction t2 = new TestVoipCallTransaction("t2", 1000L,
TestVoipCallTransaction.SUCCESS);
- VoipCallTransaction t3 = new TestVoipCallTransaction("t3", 1000L,
+ TestVoipCallTransaction t3 = new TestVoipCallTransaction("t3", 1000L,
TestVoipCallTransaction.SUCCESS);
subTransactions.add(t1);
subTransactions.add(t2);
@@ -137,6 +142,7 @@
assertEquals(VoipCallTransactionResult.RESULT_SUCCEED,
resultFuture.get(5000L, TimeUnit.MILLISECONDS).getResult());
assertEquals(expectedLog, mLog.toString());
+ verifyTransactionsFinished(t1, t2, t3);
}
@SmallTest
@@ -144,11 +150,11 @@
public void testSerialTransactionFailed()
throws ExecutionException, InterruptedException, TimeoutException {
List<VoipCallTransaction> subTransactions = new ArrayList<>();
- VoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
+ TestVoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
TestVoipCallTransaction.SUCCESS);
- VoipCallTransaction t2 = new TestVoipCallTransaction("t2", 1000L,
+ TestVoipCallTransaction t2 = new TestVoipCallTransaction("t2", 1000L,
TestVoipCallTransaction.FAILED);
- VoipCallTransaction t3 = new TestVoipCallTransaction("t3", 1000L,
+ TestVoipCallTransaction t3 = new TestVoipCallTransaction("t3", 1000L,
TestVoipCallTransaction.SUCCESS);
subTransactions.add(t1);
subTransactions.add(t2);
@@ -171,6 +177,7 @@
exceptionFuture.get(5000L, TimeUnit.MILLISECONDS);
String expectedLog = "t1 success;\nt2 failed;\n";
assertEquals(expectedLog, mLog.toString());
+ verifyTransactionsFinished(t1, t2, t3);
}
@SmallTest
@@ -178,11 +185,11 @@
public void testParallelTransactionSuccess()
throws ExecutionException, InterruptedException, TimeoutException {
List<VoipCallTransaction> subTransactions = new ArrayList<>();
- VoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
+ TestVoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
TestVoipCallTransaction.SUCCESS);
- VoipCallTransaction t2 = new TestVoipCallTransaction("t2", 500L,
+ TestVoipCallTransaction t2 = new TestVoipCallTransaction("t2", 500L,
TestVoipCallTransaction.SUCCESS);
- VoipCallTransaction t3 = new TestVoipCallTransaction("t3", 200L,
+ TestVoipCallTransaction t3 = new TestVoipCallTransaction("t3", 200L,
TestVoipCallTransaction.SUCCESS);
subTransactions.add(t1);
subTransactions.add(t2);
@@ -198,6 +205,7 @@
assertTrue(log.contains("t1 success;\n"));
assertTrue(log.contains("t2 success;\n"));
assertTrue(log.contains("t3 success;\n"));
+ verifyTransactionsFinished(t1, t2, t3);
}
@SmallTest
@@ -205,11 +213,11 @@
public void testParallelTransactionFailed()
throws ExecutionException, InterruptedException, TimeoutException {
List<VoipCallTransaction> subTransactions = new ArrayList<>();
- VoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
+ TestVoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
TestVoipCallTransaction.SUCCESS);
- VoipCallTransaction t2 = new TestVoipCallTransaction("t2", 500L,
+ TestVoipCallTransaction t2 = new TestVoipCallTransaction("t2", 500L,
TestVoipCallTransaction.FAILED);
- VoipCallTransaction t3 = new TestVoipCallTransaction("t3", 200L,
+ TestVoipCallTransaction t3 = new TestVoipCallTransaction("t3", 200L,
TestVoipCallTransaction.SUCCESS);
subTransactions.add(t1);
subTransactions.add(t2);
@@ -231,13 +239,14 @@
outcomeReceiver);
exceptionFuture.get(5000L, TimeUnit.MILLISECONDS);
assertTrue(mLog.toString().contains("t2 failed;\n"));
+ verifyTransactionsFinished(t1, t2, t3);
}
@SmallTest
@Test
public void testTransactionTimeout()
throws ExecutionException, InterruptedException, TimeoutException {
- VoipCallTransaction t = new TestVoipCallTransaction("t", 10000L,
+ TestVoipCallTransaction t = new TestVoipCallTransaction("t", 10000L,
TestVoipCallTransaction.SUCCESS);
CompletableFuture<String> exceptionFuture = new CompletableFuture<>();
OutcomeReceiver<VoipCallTransactionResult, CallException> outcomeReceiver =
@@ -255,15 +264,16 @@
mTransactionManager.addTransaction(t, outcomeReceiver);
String message = exceptionFuture.get(7000L, TimeUnit.MILLISECONDS);
assertTrue(message.contains("timeout"));
+ verifyTransactionsFinished(t);
}
@SmallTest
@Test
public void testTransactionException()
throws ExecutionException, InterruptedException, TimeoutException {
- VoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
+ TestVoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
TestVoipCallTransaction.EXCEPTION);
- VoipCallTransaction t2 = new TestVoipCallTransaction("t2", 1000L,
+ TestVoipCallTransaction t2 = new TestVoipCallTransaction("t2", 1000L,
TestVoipCallTransaction.SUCCESS);
CompletableFuture<String> exceptionFuture = new CompletableFuture<>();
OutcomeReceiver<VoipCallTransactionResult, CallException> outcomeExceptionReceiver =
@@ -290,17 +300,18 @@
assertEquals(VoipCallTransactionResult.RESULT_SUCCEED,
resultFuture.get(5000L, TimeUnit.MILLISECONDS).getResult());
assertEquals(expectedLog, mLog.toString());
+ verifyTransactionsFinished(t1, t2);
}
@SmallTest
@Test
public void testTransactionResultException()
throws ExecutionException, InterruptedException, TimeoutException {
- VoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
+ TestVoipCallTransaction t1 = new TestVoipCallTransaction("t1", 1000L,
TestVoipCallTransaction.SUCCESS);
- VoipCallTransaction t2 = new TestVoipCallTransaction("t2", 1000L,
+ TestVoipCallTransaction t2 = new TestVoipCallTransaction("t2", 1000L,
TestVoipCallTransaction.SUCCESS);
- VoipCallTransaction t3 = new TestVoipCallTransaction("t3", 1000L,
+ TestVoipCallTransaction t3 = new TestVoipCallTransaction("t3", 1000L,
TestVoipCallTransaction.SUCCESS);
OutcomeReceiver<VoipCallTransactionResult, CallException> outcomeExceptionReceiver =
new OutcomeReceiver<>() {
@@ -335,5 +346,13 @@
assertEquals(VoipCallTransactionResult.RESULT_SUCCEED,
resultFuture.get(5000L, TimeUnit.MILLISECONDS).getResult());
assertEquals(expectedLog, mLog.toString());
+ verifyTransactionsFinished(t1, t2, t3);
+ }
+
+ public void verifyTransactionsFinished(TestVoipCallTransaction... transactions) {
+ for (TestVoipCallTransaction t : transactions) {
+ assertTrue("TestVoipCallTransaction[" + t.mName + "] never called finishTransaction",
+ t.isFinished);
+ }
}
}