1 /* 2 * Copyright (C) 2022 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.telecom.voip; 18 19 import android.os.Handler; 20 import android.os.HandlerThread; 21 import android.telecom.Log; 22 23 import com.android.server.telecom.LoggedHandlerExecutor; 24 import com.android.server.telecom.TelecomSystem; 25 26 import java.util.List; 27 import java.util.concurrent.CompletableFuture; 28 import java.util.concurrent.CompletionStage; 29 import java.util.concurrent.atomic.AtomicBoolean; 30 import java.util.function.Function; 31 32 public class VoipCallTransaction { 33 //TODO: add log events 34 protected static final long TIMEOUT_LIMIT = 5000L; 35 protected final AtomicBoolean mCompleted = new AtomicBoolean(false); 36 protected String mTransactionName = this.getClass().getSimpleName(); 37 private HandlerThread mHandlerThread; 38 protected Handler mHandler; 39 protected TransactionManager.TransactionCompleteListener mCompleteListener; 40 protected List<VoipCallTransaction> mSubTransactions; 41 protected TelecomSystem.SyncRoot mLock; 42 VoipCallTransaction( List<VoipCallTransaction> subTransactions, TelecomSystem.SyncRoot lock)43 public VoipCallTransaction( 44 List<VoipCallTransaction> subTransactions, TelecomSystem.SyncRoot lock) { 45 mSubTransactions = subTransactions; 46 mHandlerThread = new HandlerThread(this.toString()); 47 mHandlerThread.start(); 48 mHandler = new Handler(mHandlerThread.getLooper()); 49 mLock = lock; 50 } 51 VoipCallTransaction(TelecomSystem.SyncRoot lock)52 public VoipCallTransaction(TelecomSystem.SyncRoot lock) { 53 this(null /** mSubTransactions */, lock); 54 } 55 start()56 public void start() { 57 // post timeout work 58 CompletableFuture<Void> future = new CompletableFuture<>(); 59 mHandler.postDelayed(() -> future.complete(null), TIMEOUT_LIMIT); 60 future.thenApplyAsync((x) -> { 61 if (mCompleted.getAndSet(true)) { 62 return null; 63 } 64 if (mCompleteListener != null) { 65 mCompleteListener.onTransactionTimeout(mTransactionName); 66 } 67 finish(); 68 return null; 69 }, new LoggedHandlerExecutor(mHandler, mTransactionName + "@" + hashCode() 70 + ".s", mLock)); 71 72 scheduleTransaction(); 73 } 74 scheduleTransaction()75 protected void scheduleTransaction() { 76 LoggedHandlerExecutor executor = new LoggedHandlerExecutor(mHandler, 77 mTransactionName + "@" + hashCode() + ".pT", mLock); 78 CompletableFuture<Void> future = CompletableFuture.completedFuture(null); 79 future.thenComposeAsync(this::processTransaction, executor) 80 .thenApplyAsync((Function<VoipCallTransactionResult, Void>) result -> { 81 mCompleted.set(true); 82 if (mCompleteListener != null) { 83 mCompleteListener.onTransactionCompleted(result, mTransactionName); 84 } 85 finish(); 86 return null; 87 }, executor) 88 .exceptionallyAsync((throwable -> { 89 Log.e(this, throwable, "Error while executing transaction."); 90 return null; 91 }), executor); 92 } 93 processTransaction(Void v)94 public CompletionStage<VoipCallTransactionResult> processTransaction(Void v) { 95 return CompletableFuture.completedFuture( 96 new VoipCallTransactionResult(VoipCallTransactionResult.RESULT_SUCCEED, null)); 97 } 98 setCompleteListener(TransactionManager.TransactionCompleteListener listener)99 public void setCompleteListener(TransactionManager.TransactionCompleteListener listener) { 100 mCompleteListener = listener; 101 } 102 finish()103 public void finish() { 104 // finish all sub transactions 105 if (mSubTransactions != null && mSubTransactions.size() > 0) { 106 mSubTransactions.forEach(VoipCallTransaction::finish); 107 } 108 mHandlerThread.quit(); 109 } 110 } 111