Update answer button logic.

Bug: 73774884
Test: unit
PiperOrigin-RevId: 196021103
Change-Id: Id2176e6ef4259dc6e1136564051dae14e30175d4
diff --git a/java/com/android/incallui/AnswerScreenPresenter.java b/java/com/android/incallui/AnswerScreenPresenter.java
index 0b79e4b..e41bac6 100644
--- a/java/com/android/incallui/AnswerScreenPresenter.java
+++ b/java/com/android/incallui/AnswerScreenPresenter.java
@@ -24,6 +24,7 @@
 import android.telecom.VideoProfile;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
 import com.android.dialer.common.concurrent.ThreadUtil;
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
@@ -35,6 +36,9 @@
 import com.android.incallui.call.DialerCall;
 import com.android.incallui.call.DialerCallListener;
 import com.android.incallui.incalluilock.InCallUiLock;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 
 /** Manages changes for an incoming call screen. */
 public class AnswerScreenPresenter
@@ -90,6 +94,39 @@
 
   @Override
   public void onAnswer(boolean answerVideoAsAudio) {
+
+    DialerCall incomingCall = CallList.getInstance().getIncomingCall();
+    InCallActivity inCallActivity =
+        (InCallActivity) answerScreen.getAnswerScreenFragment().getActivity();
+    ListenableFuture<Void> answerPrecondition;
+
+    if (incomingCall != null && inCallActivity != null) {
+      answerPrecondition = inCallActivity.getSpeakEasyCallManager().onNewIncomingCall(incomingCall);
+    } else {
+      answerPrecondition = Futures.immediateFuture(null);
+    }
+
+    Futures.addCallback(
+        answerPrecondition,
+        new FutureCallback<Void>() {
+          @Override
+          public void onSuccess(Void result) {
+            onAnswerCallback(answerVideoAsAudio);
+          }
+
+          @Override
+          public void onFailure(Throwable t) {
+            onAnswerCallback(answerVideoAsAudio);
+            // TODO(erfanian): Enumerate all error states and specify recovery strategies.
+            throw new RuntimeException("Failed to successfully complete pre call tasks.", t);
+          }
+        },
+        DialerExecutorComponent.get(context).uiExecutor());
+    addTimeoutCheck();
+  }
+
+  private void onAnswerCallback(boolean answerVideoAsAudio) {
+
     if (answerScreen.isVideoUpgradeRequest()) {
       if (answerVideoAsAudio) {
         Logger.get(context)
@@ -113,7 +150,6 @@
         call.answer();
       }
     }
-    addTimeoutCheck();
   }
 
   @Override
diff --git a/java/com/android/incallui/NotificationBroadcastReceiver.java b/java/com/android/incallui/NotificationBroadcastReceiver.java
index 52d01f5..602eb5c 100644
--- a/java/com/android/incallui/NotificationBroadcastReceiver.java
+++ b/java/com/android/incallui/NotificationBroadcastReceiver.java
@@ -20,15 +20,21 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build.VERSION_CODES;
+import android.support.annotation.NonNull;
 import android.support.annotation.RequiresApi;
 import android.telecom.CallAudioState;
 import android.telecom.VideoProfile;
 import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
 import com.android.incallui.call.CallList;
 import com.android.incallui.call.DialerCall;
 import com.android.incallui.call.TelecomAdapter;
+import com.android.incallui.speakeasy.SpeakEasyCallManager;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 
 /**
  * Accepts broadcast Intents which will be prepared by {@link StatusBarNotifier} and thus sent from
@@ -72,9 +78,9 @@
 
     // TODO: Commands of this nature should exist in the CallList.
     if (action.equals(ACTION_ANSWER_VIDEO_INCOMING_CALL)) {
-      answerIncomingCall(VideoProfile.STATE_BIDIRECTIONAL);
+      answerIncomingCall(VideoProfile.STATE_BIDIRECTIONAL, context);
     } else if (action.equals(ACTION_ANSWER_VOICE_INCOMING_CALL)) {
-      answerIncomingCall(VideoProfile.STATE_AUDIO_ONLY);
+      answerIncomingCall(VideoProfile.STATE_AUDIO_ONLY, context);
     } else if (action.equals(ACTION_DECLINE_INCOMING_CALL)) {
       Logger.get(context)
           .logImpression(DialerImpression.Type.REJECT_INCOMING_CALL_FROM_NOTIFICATION);
@@ -140,7 +146,7 @@
     }
   }
 
-  private void answerIncomingCall(int videoState) {
+  private void answerIncomingCall(int videoState, @NonNull Context context) {
     CallList callList = InCallPresenter.getInstance().getCallList();
     if (callList == null) {
       StatusBarNotifier.clearAllCallNotifications();
@@ -148,13 +154,42 @@
     } else {
       DialerCall call = callList.getIncomingCall();
       if (call != null) {
-        call.answer(videoState);
-        InCallPresenter.getInstance()
-            .showInCall(false /* showDialpad */, false /* newOutgoingCall */);
+
+        SpeakEasyCallManager speakEasyCallManager =
+            InCallPresenter.getInstance().getSpeakEasyCallManager();
+        ListenableFuture<Void> answerPrecondition;
+
+        if (speakEasyCallManager != null) {
+          answerPrecondition = speakEasyCallManager.onNewIncomingCall(call);
+        } else {
+          answerPrecondition = Futures.immediateFuture(null);
+        }
+
+        Futures.addCallback(
+            answerPrecondition,
+            new FutureCallback<Void>() {
+              @Override
+              public void onSuccess(Void result) {
+                answerIncomingCallCallback(call, videoState);
+              }
+
+              @Override
+              public void onFailure(Throwable t) {
+                answerIncomingCallCallback(call, videoState);
+                // TODO(erfanian): Enumerate all error states and specify recovery strategies.
+                throw new RuntimeException("Failed to successfully complete pre call tasks.", t);
+              }
+            },
+            DialerExecutorComponent.get(context).uiExecutor());
       }
     }
   }
 
+  private void answerIncomingCallCallback(@NonNull DialerCall call, int videoState) {
+    call.answer(videoState);
+    InCallPresenter.getInstance().showInCall(false /* showDialpad */, false /* newOutgoingCall */);
+  }
+
   private void declineIncomingCall() {
     CallList callList = InCallPresenter.getInstance().getCallList();
     if (callList == null) {
diff --git a/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java b/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java
index 8a815d3..b060f64 100644
--- a/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java
+++ b/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java
@@ -21,6 +21,7 @@
 import android.support.v4.app.Fragment;
 import com.android.incallui.call.DialerCall;
 import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
 
 /** Provides operations necessary to SpeakEasy. */
 public interface SpeakEasyCallManager {
@@ -40,6 +41,13 @@
   void onCallRemoved(@NonNull DialerCall call);
 
   /**
+   * Indicates there is a new incoming call that is about to be answered.
+   *
+   * @param call The call which is about to become active.
+   */
+  ListenableFuture<Void> onNewIncomingCall(@NonNull DialerCall call);
+
+  /**
    * Indicates the feature is available.
    *
    * @param context The application context.
diff --git a/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java b/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java
index a040973..da5e88a 100644
--- a/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java
+++ b/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java
@@ -22,6 +22,8 @@
 import android.support.v4.app.Fragment;
 import com.android.incallui.call.DialerCall;
 import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import javax.inject.Inject;
 
 /** Default implementation of SpeakEasyCallManager. */
@@ -41,6 +43,11 @@
   @Override
   public void onCallRemoved(DialerCall call) {}
 
+  @Override
+  public ListenableFuture<Void> onNewIncomingCall(@NonNull DialerCall call) {
+    return Futures.immediateFuture(null);
+  }
+
   /** Always returns false. */
   @Override
   public boolean isAvailable(@NonNull Context unused) {