Merge changes Ide5ec431,Icf2f8fae

* changes:
  Implement PreCallCoordinator
  Make CallIntentBuilder parcelable
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java
index 12c191e..089ffd3 100644
--- a/java/com/android/dialer/app/DialtactsActivity.java
+++ b/java/com/android/dialer/app/DialtactsActivity.java
@@ -44,7 +44,6 @@
 import android.support.v4.view.ViewPager;
 import android.support.v7.app.ActionBar;
 import android.telecom.PhoneAccount;
-import android.telephony.TelephonyManager;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
@@ -90,7 +89,6 @@
 import com.android.dialer.app.settings.DialerSettingsActivity;
 import com.android.dialer.app.widget.ActionBarController;
 import com.android.dialer.app.widget.SearchEditTextLayout;
-import com.android.dialer.assisteddialing.ConcreteCreator;
 import com.android.dialer.callcomposer.CallComposerActivity;
 import com.android.dialer.calldetails.CallDetailsActivity;
 import com.android.dialer.callintent.CallInitiationType;
@@ -1521,11 +1519,7 @@
     Intent intent =
         new CallIntentBuilder(phoneNumber, callSpecificAppData)
             .setIsVideoCall(isVideoCall)
-            .setAllowAssistedDial(
-                callSpecificAppData.getAllowAssistedDialing(),
-                ConcreteCreator.createNewAssistedDialingMediator(
-                    getApplication().getSystemService(TelephonyManager.class),
-                    getApplicationContext()))
+            .setAllowAssistedDial(callSpecificAppData.getAllowAssistedDialing())
             .build();
 
     DialerUtils.startActivityWithErrorToast(this, intent);
diff --git a/java/com/android/dialer/app/calllog/IntentProvider.java b/java/com/android/dialer/app/calllog/IntentProvider.java
index 36e62c3..5180651 100644
--- a/java/com/android/dialer/app/calllog/IntentProvider.java
+++ b/java/com/android/dialer/app/calllog/IntentProvider.java
@@ -26,7 +26,6 @@
 import android.telephony.TelephonyManager;
 import com.android.contacts.common.model.Contact;
 import com.android.contacts.common.model.ContactLoader;
-import com.android.dialer.assisteddialing.ConcreteCreator;
 import com.android.dialer.calldetails.CallDetailsActivity;
 import com.android.dialer.calldetails.CallDetailsEntries;
 import com.android.dialer.callintent.CallInitiationType;
@@ -67,8 +66,7 @@
       @Override
       public Intent getIntent(Context context) {
         return new CallIntentBuilder(number, CallInitiationType.Type.CALL_LOG)
-            .setAllowAssistedDial(
-                true, ConcreteCreator.createNewAssistedDialingMediator(telephonyManager, context))
+            .setAllowAssistedDial(true)
             .build();
       }
     };
diff --git a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java
index bd275df..a02727e 100644
--- a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java
+++ b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java
@@ -25,6 +25,7 @@
 import com.android.dialer.inject.ContextModule;
 import com.android.dialer.phonelookup.PhoneLookupModule;
 import com.android.dialer.phonenumbergeoutil.impl.PhoneNumberGeoUtilModule;
+import com.android.dialer.precall.impl.PreCallModule;
 import com.android.dialer.simulator.impl.SimulatorModule;
 import com.android.dialer.storage.StorageModule;
 import com.android.dialer.strictmode.impl.SystemStrictModeModule;
@@ -43,6 +44,7 @@
     DialerExecutorModule.class,
     PhoneLookupModule.class,
     PhoneNumberGeoUtilModule.class,
+    PreCallModule.class,
     SharedPrefConfigProviderModule.class,
     SimulatorModule.class,
     StorageModule.class,
diff --git a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java
index bc5036f..387fca5 100644
--- a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java
+++ b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java
@@ -25,6 +25,7 @@
 import com.android.dialer.main.MainComponent;
 import com.android.dialer.phonelookup.PhoneLookupComponent;
 import com.android.dialer.phonenumbergeoutil.PhoneNumberGeoUtilComponent;
+import com.android.dialer.precall.PreCallComponent;
 import com.android.dialer.simulator.SimulatorComponent;
 import com.android.dialer.storage.StorageComponent;
 import com.android.dialer.strictmode.StrictModeComponent;
@@ -48,6 +49,7 @@
         MapsComponent.HasComponent,
         PhoneLookupComponent.HasComponent,
         PhoneNumberGeoUtilComponent.HasComponent,
+        PreCallComponent.HasComponent,
         SimulatorComponent.HasComponent,
         StorageComponent.HasComponent,
         StrictModeComponent.HasComponent,
diff --git a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java
index c47a69b..273d1e4 100644
--- a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java
+++ b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java
@@ -25,6 +25,7 @@
 import com.android.dialer.inject.ContextModule;
 import com.android.dialer.phonelookup.PhoneLookupModule;
 import com.android.dialer.phonenumbergeoutil.impl.PhoneNumberGeoUtilModule;
+import com.android.dialer.precall.impl.PreCallModule;
 import com.android.dialer.simulator.impl.SimulatorModule;
 import com.android.dialer.storage.StorageModule;
 import com.android.dialer.strictmode.impl.SystemStrictModeModule;
@@ -47,6 +48,7 @@
     DialerExecutorModule.class,
     PhoneLookupModule.class, // TODO(zachh): Module which uses APDL?
     PhoneNumberGeoUtilModule.class,
+    PreCallModule.class,
     SharedPrefConfigProviderModule.class,
     SimulatorModule.class,
     StorageModule.class,
diff --git a/java/com/android/dialer/calldetails/CallDetailsActivity.java b/java/com/android/dialer/calldetails/CallDetailsActivity.java
index 3a3c911..6ba31e6 100644
--- a/java/com/android/dialer/calldetails/CallDetailsActivity.java
+++ b/java/com/android/dialer/calldetails/CallDetailsActivity.java
@@ -30,10 +30,8 @@
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.Toolbar;
 import android.support.v7.widget.Toolbar.OnMenuItemClickListener;
-import android.telephony.TelephonyManager;
 import android.view.MenuItem;
 import android.widget.Toast;
-import com.android.dialer.assisteddialing.ConcreteCreator;
 import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry;
 import com.android.dialer.callintent.CallInitiationType;
 import com.android.dialer.callintent.CallIntentBuilder;
@@ -243,10 +241,7 @@
     CallIntentBuilder callIntentBuilder =
         new CallIntentBuilder(phoneNumber + postDialDigits, CallInitiationType.Type.CALL_DETAILS);
     if (canSupportedAssistedDialing) {
-      callIntentBuilder.setAllowAssistedDial(
-          true,
-          ConcreteCreator.createNewAssistedDialingMediator(
-              getSystemService(TelephonyManager.class), this));
+      callIntentBuilder.setAllowAssistedDial(true);
     }
 
     DialerUtils.startActivityWithErrorToast(this, callIntentBuilder.build());
diff --git a/java/com/android/dialer/callintent/CallIntentBuilder.java b/java/com/android/dialer/callintent/CallIntentBuilder.java
index 25a5803..aabeabd 100644
--- a/java/com/android/dialer/callintent/CallIntentBuilder.java
+++ b/java/com/android/dialer/callintent/CallIntentBuilder.java
@@ -16,11 +16,11 @@
 
 package com.android.dialer.callintent;
 
-import android.annotation.TargetApi;
 import android.content.Intent;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.SystemClock;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
@@ -30,23 +30,22 @@
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 import android.text.TextUtils;
-import com.android.dialer.assisteddialing.AssistedDialingMediator;
-import com.android.dialer.assisteddialing.TransformationInfo;
+import com.android.dialer.callintent.CallInitiationType.Type;
 import com.android.dialer.common.Assert;
-import com.android.dialer.compat.telephony.TelephonyManagerCompat;
 import com.android.dialer.performancereport.PerformanceReport;
 import com.android.dialer.util.CallUtil;
-import java.util.Optional;
+import com.google.protobuf.InvalidProtocolBufferException;
 
 /** Creates an intent to start a new outgoing call. */
-public class CallIntentBuilder {
-  private final Uri uri;
+public class CallIntentBuilder implements Parcelable {
+  private Uri uri;
   private final CallSpecificAppData callSpecificAppData;
   @Nullable private PhoneAccountHandle phoneAccountHandle;
   private boolean isVideoCall;
   private String callSubject;
   private boolean allowAssistedDial;
-  private AssistedDialingMediator assistedDialingMediator;
+
+  private final Bundle outgoingCallExtras = new Bundle();
 
   private static int lightbringerButtonAppearInExpandedCallLogItemCount = 0;
   private static int lightbringerButtonAppearInCollapsedCallLogItemCount = 0;
@@ -96,6 +95,23 @@
     this(CallUtil.getCallUri(Assert.isNotNull(number)), callInitiationType);
   }
 
+  public CallIntentBuilder(@NonNull Parcel parcel) {
+    ClassLoader classLoader = CallIntentBuilder.class.getClassLoader();
+    uri = parcel.readParcelable(classLoader);
+    CallSpecificAppData data;
+    try {
+      data = CallSpecificAppData.parseFrom(parcel.createByteArray());
+    } catch (InvalidProtocolBufferException e) {
+      data = createCallSpecificAppData(Type.UNKNOWN_INITIATION);
+    }
+    callSpecificAppData = data;
+    phoneAccountHandle = parcel.readParcelable(classLoader);
+    isVideoCall = parcel.readInt() != 0;
+    callSubject = parcel.readString();
+    allowAssistedDial = parcel.readInt() != 0;
+    outgoingCallExtras.putAll(parcel.readBundle(classLoader));
+  }
+
   public static CallIntentBuilder forVoicemail(
       @Nullable PhoneAccountHandle phoneAccountHandle, CallInitiationType.Type callInitiationType) {
     return new CallIntentBuilder(
@@ -103,6 +119,14 @@
         .setPhoneAccountHandle(phoneAccountHandle);
   }
 
+  public void setUri(@NonNull Uri uri) {
+    this.uri = Assert.isNotNull(uri);
+  }
+
+  public Uri getUri() {
+    return uri;
+  }
+
   public CallSpecificAppData getCallSpecificAppData() {
     return callSpecificAppData;
   }
@@ -112,40 +136,54 @@
     return this;
   }
 
+  @Nullable
+  public PhoneAccountHandle getPhoneAccountHandle() {
+    return phoneAccountHandle;
+  }
+
   public CallIntentBuilder setIsVideoCall(boolean isVideoCall) {
     this.isVideoCall = isVideoCall;
     return this;
   }
 
-  public CallIntentBuilder setAllowAssistedDial(
-      boolean allowAssistedDial, @NonNull AssistedDialingMediator assistedDialingMediator) {
-    this.assistedDialingMediator = Assert.isNotNull(assistedDialingMediator);
+  public boolean isVideoCall() {
+    return isVideoCall;
+  }
+
+  public CallIntentBuilder setAllowAssistedDial(boolean allowAssistedDial) {
     this.allowAssistedDial = allowAssistedDial;
     return this;
   }
 
+  public boolean isAssistedDialAllowed() {
+    return allowAssistedDial;
+  }
+
   public CallIntentBuilder setCallSubject(String callSubject) {
     this.callSubject = callSubject;
     return this;
   }
 
+  public String getCallSubject() {
+    return callSubject;
+  }
+
+  public Bundle getOutgoingCallExtras() {
+    return outgoingCallExtras;
+  }
+
   public Intent build() {
     Intent intent = new Intent(Intent.ACTION_CALL, uri);
-    Bundle extras = new Bundle();
 
-    if (allowAssistedDial
-        && this.assistedDialingMediator != null
-        && this.assistedDialingMediator.isPlatformEligible()) {
-      intent = buildAssistedDialingParameters(intent, extras);
-    }
     intent.putExtra(
         TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
         isVideoCall ? VideoProfile.STATE_BIDIRECTIONAL : VideoProfile.STATE_AUDIO_ONLY);
 
-    extras.putLong(Constants.EXTRA_CALL_CREATED_TIME_MILLIS, SystemClock.elapsedRealtime());
-    CallIntentParser.putCallSpecificAppData(extras, callSpecificAppData);
+    outgoingCallExtras.putLong(
+        Constants.EXTRA_CALL_CREATED_TIME_MILLIS, SystemClock.elapsedRealtime());
+    CallIntentParser.putCallSpecificAppData(outgoingCallExtras, callSpecificAppData);
 
-    intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
+    intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, outgoingCallExtras);
 
     if (phoneAccountHandle != null) {
       intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
@@ -158,26 +196,6 @@
     return intent;
   }
 
-  @SuppressWarnings("AndroidApiChecker") // Use of optional
-  @TargetApi(Build.VERSION_CODES.N)
-  private Intent buildAssistedDialingParameters(Intent intent, Bundle extras) {
-    extras.putBoolean(TelephonyManagerCompat.ALLOW_ASSISTED_DIAL, true);
-    String phoneNumber =
-        uri.getScheme().equals(PhoneAccount.SCHEME_TEL) ? uri.getSchemeSpecificPart() : "";
-    Optional<TransformationInfo> transformedNumber =
-        assistedDialingMediator.attemptAssistedDial(phoneNumber);
-    if (transformedNumber.isPresent()) {
-      Bundle assistedDialingExtras = transformedNumber.get().toBundle();
-      extras.putBoolean(TelephonyManagerCompat.IS_ASSISTED_DIALED, true);
-      extras.putBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS, assistedDialingExtras);
-      intent =
-          new Intent(
-              Intent.ACTION_CALL,
-              CallUtil.getCallUri(Assert.isNotNull(transformedNumber.get().transformedNumber())));
-    }
-    return intent;
-  }
-
   private static @NonNull CallSpecificAppData createCallSpecificAppData(
       CallInitiationType.Type callInitiationType) {
     CallSpecificAppData callSpecificAppData =
@@ -218,4 +236,33 @@
     lightbringerButtonAppearInExpandedCallLogItemCount = 0;
     lightbringerButtonAppearInSearchCount = 0;
   }
+
+  @Override
+  public int describeContents() {
+    return 0;
+  }
+
+  @Override
+  public void writeToParcel(Parcel dest, int flags) {
+    dest.writeParcelable(uri, flags);
+    dest.writeByteArray(callSpecificAppData.toByteArray());
+    dest.writeParcelable(phoneAccountHandle, flags);
+    dest.writeInt(isVideoCall ? 1 : 0);
+    dest.writeString(callSubject);
+    dest.writeInt(allowAssistedDial ? 1 : 0);
+    dest.writeBundle(outgoingCallExtras);
+  }
+
+  public static final Creator<CallIntentBuilder> CREATOR =
+      new Creator<CallIntentBuilder>() {
+        @Override
+        public CallIntentBuilder createFromParcel(Parcel source) {
+          return new CallIntentBuilder(source);
+        }
+
+        @Override
+        public CallIntentBuilder[] newArray(int size) {
+          return new CallIntentBuilder[0];
+        }
+      };
 }
diff --git a/java/com/android/dialer/interactions/PhoneNumberInteraction.java b/java/com/android/dialer/interactions/PhoneNumberInteraction.java
index ac744cc..255f6c3 100644
--- a/java/com/android/dialer/interactions/PhoneNumberInteraction.java
+++ b/java/com/android/dialer/interactions/PhoneNumberInteraction.java
@@ -41,7 +41,6 @@
 import android.support.annotation.IntDef;
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.app.ActivityCompat;
-import android.telephony.TelephonyManager;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -53,7 +52,6 @@
 import com.android.contacts.common.Collapser.Collapsible;
 import com.android.contacts.common.MoreContactUtils;
 import com.android.contacts.common.util.ContactDisplayUtils;
-import com.android.dialer.assisteddialing.ConcreteCreator;
 import com.android.dialer.callintent.CallInitiationType;
 import com.android.dialer.callintent.CallIntentBuilder;
 import com.android.dialer.callintent.CallIntentParser;
@@ -187,10 +185,7 @@
         intent =
             new CallIntentBuilder(phoneNumber, callSpecificAppData)
                 .setIsVideoCall(isVideoCall)
-                .setAllowAssistedDial(
-                    callSpecificAppData.getAllowAssistedDialing(),
-                    ConcreteCreator.createNewAssistedDialingMediator(
-                        context.getSystemService(TelephonyManager.class), context))
+                .setAllowAssistedDial(callSpecificAppData.getAllowAssistedDialing())
                 .build();
         break;
     }
diff --git a/java/com/android/dialer/precall/PreCall.java b/java/com/android/dialer/precall/PreCall.java
new file mode 100644
index 0000000..93fd8e9
--- /dev/null
+++ b/java/com/android/dialer/precall/PreCall.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.precall;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
+import com.android.dialer.callintent.CallIntentBuilder;
+import com.google.common.collect.ImmutableList;
+
+/** Interface to prepare a {@link CallIntentBuilder} before placing the call with telecom. */
+public interface PreCall {
+
+  /**
+   * @return a list of {@link PreCallAction} in execution order for the {@link PreCallCoordinator}
+   *     to run.
+   */
+  @NonNull
+  ImmutableList<PreCallAction> getActions();
+
+  /**
+   * @return a intent when started as activity, will perform the pre-call actions and then place a
+   *     call. TODO(twyen): if all actions do not require an UI, return a intent that will place the
+   *     call directly instead.
+   */
+  @NonNull
+  @MainThread
+  Intent buildIntent(Context context, CallIntentBuilder builder);
+}
diff --git a/java/com/android/dialer/precall/PreCallAction.java b/java/com/android/dialer/precall/PreCallAction.java
new file mode 100644
index 0000000..9434694
--- /dev/null
+++ b/java/com/android/dialer/precall/PreCallAction.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.precall;
+
+import android.support.annotation.MainThread;
+import com.android.dialer.callintent.CallIntentBuilder;
+
+/**
+ * An action to perform before the call is made. The action should inspect and modify the {@link
+ * CallIntentBuilder} to generate full information for the call. For example, showing a dialog to
+ * select the phone account on a multi-SIM device, ask if RTT should be enabled, or rewrite the
+ * number for roaming calls.
+ */
+public interface PreCallAction {
+
+  /**
+   * Runs the action. Should block on the main thread until the action is finished. If the action is
+   * not instantaneous, {@link PreCallCoordinator#startPendingAction()} should be called to release
+   * the thread and continue later.
+   */
+  @MainThread
+  void run(PreCallCoordinator coordinator);
+
+  /**
+   * Called when the UI is being paused when a {@link PreCallCoordinator.PendingAction} is started,
+   * and the action is going to be discarded. If the action is showing a dialog the dialog should be
+   * dismissed. The action should not retain state, a new instance of the action will be re-run when
+   * the UI is resumed.
+   */
+  @MainThread
+  void onDiscard();
+}
diff --git a/java/com/android/dialer/precall/PreCallComponent.java b/java/com/android/dialer/precall/PreCallComponent.java
new file mode 100644
index 0000000..00adde5
--- /dev/null
+++ b/java/com/android/dialer/precall/PreCallComponent.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.precall;
+
+import android.content.Context;
+import com.android.dialer.inject.HasRootComponent;
+import dagger.Subcomponent;
+
+/** Daggaer component for {@link PreCall} */
+@Subcomponent
+public abstract class PreCallComponent {
+  public abstract PreCall getPreCall();
+
+  public static PreCallComponent get(Context context) {
+    return ((HasComponent) ((HasRootComponent) context.getApplicationContext()).component())
+        .preCallActionsComponent();
+  }
+
+  /** Used to refer to the root application component. */
+  public interface HasComponent {
+    PreCallComponent preCallActionsComponent();
+  }
+}
diff --git a/java/com/android/dialer/precall/PreCallCoordinator.java b/java/com/android/dialer/precall/PreCallCoordinator.java
new file mode 100644
index 0000000..b5e9e85
--- /dev/null
+++ b/java/com/android/dialer/precall/PreCallCoordinator.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.precall;
+
+import android.app.Activity;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
+import com.android.dialer.callintent.CallIntentBuilder;
+
+/**
+ * Runs {@link PreCallAction} one by one to prepare a {@link
+ * com.android.dialer.callintent.CallIntentBuilder} for a call.
+ */
+public interface PreCallCoordinator {
+
+  @NonNull
+  CallIntentBuilder getBuilder();
+
+  /**
+   * @return the activity to attach the UI to. Returns {@link null} if the coordinator is running on
+   *     headless mode. TODO(twyen): implement headless mode.
+   */
+  @NonNull
+  Activity getActivity();
+
+  /**
+   * Called by a {@link PreCallAction} to abort the call. For example, the user has dismissed the
+   * dialog and must start over.
+   */
+  void abortCall();
+
+  /**
+   * Callback from a {@link PreCallAction} to signal the action started by {@link
+   * PreCallCoordinator#startPendingAction()} has finished.
+   */
+  interface PendingAction {
+
+    @MainThread
+    void finish();
+  }
+
+  /**
+   * Called by the current running {@link PreCallAction} to release the main thread and resume
+   * pre-call later.
+   *
+   * @return a {@link PendingAction} which {@link PendingAction#finish(boolean)} should be called to
+   *     resume pre-call. For example the action shows a dialog to the user, startPendingAction()
+   *     should be called as the action will not be finished immediately. When the dialog is
+   *     completed, {@code finish()} is then called to continue the next step.
+   */
+  @MainThread
+  @NonNull
+  PendingAction startPendingAction();
+}
diff --git a/java/com/android/dialer/precall/impl/AndroidManifest.xml b/java/com/android/dialer/precall/impl/AndroidManifest.xml
new file mode 100644
index 0000000..d3d0f53
--- /dev/null
+++ b/java/com/android/dialer/precall/impl/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~      http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.dialer.precall.impl">
+
+  <application>
+    <activity
+        android:exported="false"
+        android:name="com.android.dialer.precall.impl.PreCallActivity"
+        android:excludeFromRecents="true"
+        android:noHistory="true"
+        android:theme="@style/Theme.PreCall.DialogHolder">
+    </activity>
+  </application>
+</manifest>
diff --git a/java/com/android/dialer/precall/impl/PreCallActivity.java b/java/com/android/dialer/precall/impl/PreCallActivity.java
new file mode 100644
index 0000000..938d31d
--- /dev/null
+++ b/java/com/android/dialer/precall/impl/PreCallActivity.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.precall.impl;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+/** A transparent activity to host dialogs for {@link PreCallCoordinatorImpl} */
+public class PreCallActivity extends Activity {
+
+  private PreCallCoordinatorImpl preCallCoordinator;
+
+  @Override
+  public void onCreate(@Nullable Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    preCallCoordinator = new PreCallCoordinatorImpl(this);
+    preCallCoordinator.onCreate(getIntent(), savedInstanceState);
+  }
+
+  @Override
+  protected void onRestoreInstanceState(Bundle savedInstanceState) {
+    super.onRestoreInstanceState(savedInstanceState);
+    preCallCoordinator.onRestoreInstanceState(savedInstanceState);
+  }
+
+  @Override
+  public void onResume() {
+    super.onResume();
+    preCallCoordinator.onResume();
+  }
+
+  @Override
+  public void onPause() {
+    super.onPause();
+    preCallCoordinator.onPause();
+  }
+
+  @Override
+  public void onSaveInstanceState(Bundle outState) {
+    super.onSaveInstanceState(outState);
+    preCallCoordinator.onSaveInstanceState(outState);
+  }
+}
diff --git a/java/com/android/dialer/precall/impl/PreCallCoordinatorImpl.java b/java/com/android/dialer/precall/impl/PreCallCoordinatorImpl.java
new file mode 100644
index 0000000..25083ef
--- /dev/null
+++ b/java/com/android/dialer/precall/impl/PreCallCoordinatorImpl.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.precall.impl;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.precall.PreCallAction;
+import com.android.dialer.precall.PreCallComponent;
+import com.android.dialer.precall.PreCallCoordinator;
+import com.android.dialer.telecom.TelecomUtil;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Implements {@link PreCallCoordinator}. Listens to the life cycle of {@link PreCallActivity} to
+ * save/restore states.
+ */
+public class PreCallCoordinatorImpl implements PreCallCoordinator {
+
+  private static final String SAVED_STATE_CURRENT_ACTION = "current_action";
+
+  static final String EXTRA_CALL_INTENT_BUILDER = "extra_call_intent_builder";
+
+  @NonNull private final Activity activity;
+
+  private CallIntentBuilder builder;
+  private ImmutableList<PreCallAction> actions;
+  private int currentActionIndex = 0;
+  private PreCallAction currentAction;
+  private PendingAction pendingAction;
+  private boolean aborted = false;
+
+  PreCallCoordinatorImpl(@NonNull Activity activity) {
+    this.activity = Assert.isNotNull(activity);
+  }
+
+  void onCreate(Intent intent, @Nullable Bundle savedInstanceState) {
+    LogUtil.enterBlock("PreCallCoordinatorImpl.onCreate");
+    if (savedInstanceState != null) {
+      currentActionIndex = savedInstanceState.getInt(SAVED_STATE_CURRENT_ACTION);
+      builder = Assert.isNotNull(savedInstanceState.getParcelable(EXTRA_CALL_INTENT_BUILDER));
+    } else {
+      builder = Assert.isNotNull(intent.getParcelableExtra(EXTRA_CALL_INTENT_BUILDER));
+    }
+    actions = PreCallComponent.get(activity).getPreCall().getActions();
+  }
+
+  void onRestoreInstanceState(Bundle savedInstanceState) {
+    currentActionIndex = savedInstanceState.getInt(SAVED_STATE_CURRENT_ACTION);
+    builder = savedInstanceState.getParcelable(EXTRA_CALL_INTENT_BUILDER);
+  }
+
+  void onResume() {
+    runNextAction();
+  }
+
+  void onPause() {
+    if (currentAction != null) {
+      currentAction.onDiscard();
+    }
+    currentAction = null;
+  }
+
+  void onSaveInstanceState(Bundle outState) {
+    outState.putInt(SAVED_STATE_CURRENT_ACTION, currentActionIndex);
+    outState.putParcelable(EXTRA_CALL_INTENT_BUILDER, builder);
+  }
+
+  private void runNextAction() {
+    LogUtil.enterBlock("PreCallCoordinatorImpl.runNextAction");
+    Assert.checkArgument(currentAction == null);
+    if (currentActionIndex >= actions.size()) {
+      TelecomUtil.placeCall(activity, builder.build());
+      activity.finish();
+      return;
+    }
+    LogUtil.i("PreCallCoordinatorImpl.runNextAction", "running " + actions.get(currentActionIndex));
+    currentAction = actions.get(currentActionIndex);
+    actions.get(currentActionIndex).run(this);
+    if (pendingAction == null) {
+      onActionFinished();
+    }
+  }
+
+  private void onActionFinished() {
+    LogUtil.enterBlock("PreCallCoordinatorImpl.onActionFinished");
+    Assert.isNotNull(currentAction);
+    currentAction = null;
+    currentActionIndex++;
+    if (!aborted) {
+      runNextAction();
+    } else {
+      activity.finish();
+    }
+  }
+
+  @Override
+  public void abortCall() {
+    Assert.checkState(currentAction != null);
+    aborted = true;
+  }
+
+  @NonNull
+  @Override
+  public CallIntentBuilder getBuilder() {
+    return builder;
+  }
+
+  @NonNull
+  @Override
+  public Activity getActivity() {
+    return activity;
+  }
+
+  @Override
+  @NonNull
+  public PendingAction startPendingAction() {
+    Assert.isMainThread();
+    Assert.isNotNull(currentAction);
+    Assert.checkArgument(pendingAction == null);
+    pendingAction = new PendingActionImpl();
+    return pendingAction;
+  }
+
+  private class PendingActionImpl implements PendingAction {
+
+    @Override
+    public void finish() {
+      Assert.checkArgument(pendingAction == this);
+      pendingAction = null;
+      onActionFinished();
+    }
+  }
+}
diff --git a/java/com/android/dialer/precall/impl/PreCallImpl.java b/java/com/android/dialer/precall/impl/PreCallImpl.java
new file mode 100644
index 0000000..ac9750e
--- /dev/null
+++ b/java/com/android/dialer/precall/impl/PreCallImpl.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.precall.impl;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.annotation.NonNull;
+import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.precall.PreCall;
+import com.android.dialer.precall.PreCallAction;
+import com.google.common.collect.ImmutableList;
+import javax.inject.Inject;
+
+/** Implementation of {@link PreCall} */
+public class PreCallImpl implements PreCall {
+
+  @Inject
+  PreCallImpl() {}
+
+  @Override
+  public ImmutableList<PreCallAction> getActions() {
+    return ImmutableList.of();
+  }
+
+  @NonNull
+  @Override
+  public Intent buildIntent(Context context, CallIntentBuilder builder) {
+    Intent intent = new Intent(context, PreCallActivity.class);
+    intent.putExtra(PreCallCoordinatorImpl.EXTRA_CALL_INTENT_BUILDER, builder);
+    return intent;
+  }
+}
diff --git a/java/com/android/dialer/precall/impl/PreCallModule.java b/java/com/android/dialer/precall/impl/PreCallModule.java
new file mode 100644
index 0000000..608cd5a
--- /dev/null
+++ b/java/com/android/dialer/precall/impl/PreCallModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.precall.impl;
+
+import com.android.dialer.precall.PreCall;
+import dagger.Binds;
+import dagger.Module;
+import javax.inject.Singleton;
+
+/** Dagger module for {@link PreCall}. */
+@Module
+public abstract class PreCallModule {
+
+  @Binds
+  @Singleton
+  public abstract PreCall bindPreCall(PreCallImpl simulator);
+}
diff --git a/java/com/android/dialer/precall/impl/res/values/styles.xml b/java/com/android/dialer/precall/impl/res/values/styles.xml
new file mode 100644
index 0000000..dd41265
--- /dev/null
+++ b/java/com/android/dialer/precall/impl/res/values/styles.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+  <style name="Theme.PreCall.DialogHolder" parent="DialerThemeBase.NoActionBar">
+    <item name="android:windowBackground">@android:color/transparent</item>
+    <item name="android:windowActivityTransitions">false</item>
+    <item name="android:windowIsTranslucent">true</item>
+
+    <item name="android:statusBarColor">@android:color/transparent</item>
+    <item name="android:navigationBarColor">@android:color/transparent</item>
+    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+  </style>
+
+</resources>
diff --git a/java/com/android/dialer/precall/testing/TestPreCallModule.java b/java/com/android/dialer/precall/testing/TestPreCallModule.java
new file mode 100644
index 0000000..b777de8
--- /dev/null
+++ b/java/com/android/dialer/precall/testing/TestPreCallModule.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.precall.testing;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.annotation.NonNull;
+import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.precall.PreCall;
+import com.android.dialer.precall.PreCallAction;
+import com.google.common.collect.ImmutableList;
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Singleton;
+
+/** Provides test implementation of {@link PreCall} */
+@Module
+public class TestPreCallModule {
+  private static PreCall preCall = new StubPreCall();
+
+  public static void setPreCall(PreCall preCall) {
+    TestPreCallModule.preCall = preCall;
+  }
+
+  @Provides
+  @Singleton
+  public static PreCall providePreCall() {
+    return preCall;
+  }
+
+  private static class StubPreCall implements PreCall {
+
+    @NonNull
+    @Override
+    public ImmutableList<PreCallAction> getActions() {
+      return ImmutableList.of();
+    }
+
+    @NonNull
+    @Override
+    public Intent buildIntent(Context context, CallIntentBuilder builder) {
+      return builder.build();
+    }
+  }
+}
diff --git a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
index cd42a74..c0a6700 100644
--- a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
+++ b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
@@ -32,7 +32,6 @@
 import android.support.v13.app.FragmentCompat;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
-import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -44,7 +43,6 @@
 import android.widget.FrameLayout.LayoutParams;
 import com.android.contacts.common.extensions.PhoneDirectoryExtenderAccessor;
 import com.android.dialer.animation.AnimUtils;
-import com.android.dialer.assisteddialing.ConcreteCreator;
 import com.android.dialer.callcomposer.CallComposerActivity;
 import com.android.dialer.callintent.CallInitiationType;
 import com.android.dialer.callintent.CallIntentBuilder;
@@ -488,11 +486,7 @@
     Intent intent =
         new CallIntentBuilder(phoneNumber, callSpecificAppData)
             .setIsVideoCall(isVideoCall)
-            .setAllowAssistedDial(
-                allowAssistedDial,
-                ConcreteCreator.createNewAssistedDialingMediator(
-                    getContext().getSystemService(TelephonyManager.class),
-                    getContext().getApplicationContext()))
+            .setAllowAssistedDial(allowAssistedDial)
             .build();
     DialerUtils.startActivityWithErrorToast(getActivity(), intent);
     FragmentUtils.getParentUnsafe(this, SearchFragmentListener.class).onCallPlaced();
diff --git a/packages.mk b/packages.mk
index 3b9c2e2..06f8dae 100644
--- a/packages.mk
+++ b/packages.mk
@@ -39,6 +39,7 @@
 	com.android.dialer.oem \
 	com.android.dialer.phonenumberutil \
 	com.android.dialer.postcall \
+	com.android.dialer.precall.impl \
 	com.android.dialer.searchfragment.common \
 	com.android.dialer.searchfragment.cp2 \
 	com.android.dialer.searchfragment.list \