Merge changes Id8170206,I4e63ef1d,I05e176ef am: 21de509b13 am: 9d22414b82
am: a300c01b2b

Change-Id: Ib2352c91fd346a0f605d94f8ecf22726066070d4
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java
index 04f1431..5f3620b 100644
--- a/java/com/android/dialer/app/DialtactsActivity.java
+++ b/java/com/android/dialer/app/DialtactsActivity.java
@@ -43,7 +43,7 @@
 import android.support.v4.view.ViewPager;
 import android.support.v7.app.ActionBar;
 import android.telecom.PhoneAccount;
-import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
@@ -90,6 +90,7 @@
 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;
@@ -97,7 +98,6 @@
 import com.android.dialer.callintent.CallSpecificAppData;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.compat.telephony.TelephonyManagerCompat;
 import com.android.dialer.configprovider.ConfigProviderBindings;
 import com.android.dialer.constants.ActivityRequestCodes;
 import com.android.dialer.contactsfragment.ContactsFragment;
@@ -1488,13 +1488,14 @@
     }
 
     Intent intent =
-        new CallIntentBuilder(phoneNumber, callSpecificAppData).setIsVideoCall(isVideoCall).build();
-
-    if (callSpecificAppData.getAllowAssistedDialing()) {
-      Bundle extras = new Bundle();
-      extras.putBoolean(TelephonyManagerCompat.ALLOW_ASSISTED_DIAL, true);
-      intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
-    }
+        new CallIntentBuilder(phoneNumber, callSpecificAppData)
+            .setIsVideoCall(isVideoCall)
+            .setAllowAssistedDial(
+                callSpecificAppData.getAllowAssistedDialing(),
+                ConcreteCreator.createNewAssistedDialingMediator(
+                    getApplication().getSystemService(TelephonyManager.class),
+                    getApplicationContext()))
+            .build();
 
     DialerUtils.startActivityWithErrorToast(this, intent);
     mClearSearchOnPause = true;
diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java
index e79c89c..2283215 100644
--- a/java/com/android/dialer/app/calllog/CallLogAdapter.java
+++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java
@@ -64,6 +64,7 @@
 import com.android.dialer.calldetails.CallDetailsEntries;
 import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry;
 import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.calllogutils.CallbackActionHelper.CallbackAction;
 import com.android.dialer.calllogutils.PhoneAccountUtils;
 import com.android.dialer.calllogutils.PhoneCallDetails;
 import com.android.dialer.common.Assert;
@@ -479,8 +480,17 @@
   @NonNull private final Set<Uri> mHiddenItemUris = new ArraySet<>();
 
   private CallLogListItemViewHolder.OnClickListener mBlockReportSpamListener;
+
   /**
-   * Map, keyed by call Id, used to track the day group for a call. As call log entries are put into
+   * Map, keyed by call ID, used to track the callback action for a call. Calls associated with the
+   * same callback action will be put into the same primary call group in {@link
+   * com.android.dialer.app.calllog.CallLogGroupBuilder}. This information is used to set the
+   * callback icon and trigger the corresponding action.
+   */
+  private final Map<Long, Integer> mCallbackActions = new ArrayMap<>();
+
+  /**
+   * Map, keyed by call ID, used to track the day group for a call. As call log entries are put into
    * the primary call groups in {@link com.android.dialer.app.calllog.CallLogGroupBuilder}, they are
    * also assigned a secondary "day group". This map tracks the day group assigned to all calls in
    * the call log. This information is used to trigger the display of a day group header above the
@@ -491,7 +501,7 @@
    * previous day group without having to reverse the cursor to the start of the previous day call
    * log entry.
    */
-  private Map<Long, Integer> mDayGroups = new ArrayMap<>();
+  private final Map<Long, Integer> mDayGroups = new ArrayMap<>();
 
   private boolean mLoading = true;
   private ContactsPreferences mContactsPreferences;
@@ -688,7 +698,7 @@
 
   @Override
   protected void addGroups(Cursor cursor) {
-    mCallLogGroupBuilder.addGroups(cursor);
+    mCallLogGroupBuilder.addGroups(cursor, mActivity);
   }
 
   @Override
@@ -865,10 +875,11 @@
           protected void onPostExecute(Boolean success) {
             views.isLoaded = true;
             if (success) {
-              int currentGroup = getDayGroupForCall(views.rowId);
-              if (currentGroup != details.previousGroup) {
+              views.callbackAction = getCallbackAction(views.rowId);
+              int currentDayGroup = getDayGroup(views.rowId);
+              if (currentDayGroup != details.previousGroup) {
                 views.dayGroupHeaderVisibility = View.VISIBLE;
-                views.dayGroupHeaderText = getGroupDescription(currentGroup);
+                views.dayGroupHeaderText = getGroupDescription(currentDayGroup);
               } else {
                 views.dayGroupHeaderVisibility = View.GONE;
               }
@@ -1226,7 +1237,7 @@
       cursor.moveToPosition(startingPosition);
       return CallLogGroupBuilder.DAY_GROUP_NONE;
     }
-    int result = getDayGroupForCall(cursor.getLong(CallLogQuery.ID));
+    int result = getDayGroup(cursor.getLong(CallLogQuery.ID));
     cursor.moveToPosition(startingPosition);
     return result;
   }
@@ -1236,14 +1247,30 @@
   }
 
   /**
-   * Given a call Id, look up the day group that the call belongs to. The day group data is
-   * populated in {@link com.android.dialer.app.calllog.CallLogGroupBuilder}.
+   * Given a call ID, look up its callback action. Callback action data are populated in {@link
+   * com.android.dialer.app.calllog.CallLogGroupBuilder}.
    *
-   * @param callId The call to retrieve the day group for.
+   * @param callId The call ID to retrieve the callback action.
+   * @return The callback action for the call.
+   */
+  @MainThread
+  private int getCallbackAction(long callId) {
+    Integer result = mCallbackActions.get(callId);
+    if (result != null) {
+      return result;
+    }
+    return CallbackAction.NONE;
+  }
+
+  /**
+   * Given a call ID, look up the day group the call belongs to. Day group data are populated in
+   * {@link com.android.dialer.app.calllog.CallLogGroupBuilder}.
+   *
+   * @param callId The call ID to retrieve the day group.
    * @return The day group for the call.
    */
   @MainThread
-  private int getDayGroupForCall(long callId) {
+  private int getDayGroup(long callId) {
     Integer result = mDayGroups.get(callId);
     if (result != null) {
       return result;
@@ -1306,17 +1333,27 @@
   }
 
   /**
+   * Stores the callback action associated with a call in the call log.
+   *
+   * @param rowId The row ID of the current call.
+   * @param callbackAction The current call's callback action.
+   */
+  @Override
+  @MainThread
+  public void setCallbackAction(long rowId, @CallbackAction int callbackAction) {
+    mCallbackActions.put(rowId, callbackAction);
+  }
+
+  /**
    * Stores the day group associated with a call in the call log.
    *
-   * @param rowId The row Id of the current call.
+   * @param rowId The row ID of the current call.
    * @param dayGroup The day group the call belongs in.
    */
   @Override
   @MainThread
   public void setDayGroup(long rowId, int dayGroup) {
-    if (!mDayGroups.containsKey(rowId)) {
-      mDayGroups.put(rowId, dayGroup);
-    }
+    mDayGroups.put(rowId, dayGroup);
   }
 
   /** Clears the day group associations on re-bind of the call log. */
diff --git a/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java b/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java
index 45ff378..57a8be7 100644
--- a/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java
+++ b/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java
@@ -16,6 +16,7 @@
 
 package com.android.dialer.app.calllog;
 
+import android.content.Context;
 import android.database.Cursor;
 import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
@@ -25,6 +26,8 @@
 import android.text.TextUtils;
 import android.text.format.Time;
 import com.android.contacts.common.util.DateUtils;
+import com.android.dialer.calllogutils.CallbackActionHelper;
+import com.android.dialer.calllogutils.CallbackActionHelper.CallbackAction;
 import com.android.dialer.compat.AppCompatConstants;
 import com.android.dialer.phonenumbercache.CallLogQuery;
 import com.android.dialer.phonenumberutil.PhoneNumberHelper;
@@ -71,7 +74,7 @@
    *
    * @see GroupingListAdapter#addGroups(Cursor)
    */
-  public void addGroups(Cursor cursor) {
+  public void addGroups(Cursor cursor, Context context) {
     final int count = cursor.getCount();
     if (count == 0) {
       return;
@@ -90,23 +93,32 @@
     int groupDayGroup = getDayGroup(firstDate, currentTime);
     mGroupCreator.setDayGroup(firstRowId, groupDayGroup);
 
-    // Instantiate the group values to those of the first call in the cursor.
+    // Determine the callback action for the first call in the cursor.
     String groupNumber = cursor.getString(CallLogQuery.NUMBER);
+    String groupAccountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
+    int groupFeatures = cursor.getInt(CallLogQuery.FEATURES);
+    int groupCallbackAction =
+        CallbackActionHelper.getCallbackAction(
+            groupNumber, groupFeatures, groupAccountComponentName, context);
+    mGroupCreator.setCallbackAction(firstRowId, groupCallbackAction);
+
+    // Instantiate other group values to those of the first call in the cursor.
+    String groupAccountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
     String groupPostDialDigits =
         (VERSION.SDK_INT >= VERSION_CODES.N) ? cursor.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
     String groupViaNumbers =
         (VERSION.SDK_INT >= VERSION_CODES.N) ? cursor.getString(CallLogQuery.VIA_NUMBER) : "";
     int groupCallType = cursor.getInt(CallLogQuery.CALL_TYPE);
-    String groupAccountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
-    String groupAccountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
     int groupSize = 1;
 
     String number;
     String numberPostDialDigits;
     String numberViaNumbers;
     int callType;
+    int features;
     String accountComponentName;
     String accountId;
+    int callbackAction;
 
     while (cursor.moveToNext()) {
       // Obtain the values for the current call to group.
@@ -118,21 +130,28 @@
       numberViaNumbers =
           (VERSION.SDK_INT >= VERSION_CODES.N) ? cursor.getString(CallLogQuery.VIA_NUMBER) : "";
       callType = cursor.getInt(CallLogQuery.CALL_TYPE);
+      features = cursor.getInt(CallLogQuery.FEATURES);
       accountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
       accountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
+      callbackAction =
+          CallbackActionHelper.getCallbackAction(number, features, accountComponentName, context);
 
       final boolean isSameNumber = equalNumbers(groupNumber, number);
       final boolean isSamePostDialDigits = groupPostDialDigits.equals(numberPostDialDigits);
       final boolean isSameViaNumbers = groupViaNumbers.equals(numberViaNumbers);
       final boolean isSameAccount =
           isSameAccount(groupAccountComponentName, accountComponentName, groupAccountId, accountId);
+      final boolean isSameCallbackAction = (groupCallbackAction == callbackAction);
 
-      // Group with the same number and account. Never group voicemails. Only group blocked
-      // calls with other blocked calls.
+      // Group calls with the following criteria:
+      // (1) Calls with the same number, account, and callback action should be in the same group;
+      // (2) Never group voice mails; and
+      // (3) Only group blocked calls with other blocked calls.
       if (isSameNumber
           && isSameAccount
           && isSamePostDialDigits
           && isSameViaNumbers
+          && isSameCallbackAction
           && areBothNotVoicemail(callType, groupCallType)
           && (areBothNotBlocked(callType, groupCallType)
               || areBothBlocked(callType, groupCallType))) {
@@ -158,10 +177,12 @@
         groupCallType = callType;
         groupAccountComponentName = accountComponentName;
         groupAccountId = accountId;
+        groupCallbackAction = callbackAction;
       }
 
-      // Save the day group associated with the current call.
+      // Save the callback action and the day group associated with the current call.
       final long currentCallId = cursor.getLong(CallLogQuery.ID);
+      mGroupCreator.setCallbackAction(currentCallId, groupCallbackAction);
       mGroupCreator.setDayGroup(currentCallId, groupDayGroup);
     }
 
@@ -259,12 +280,22 @@
     void addGroup(int cursorPosition, int size);
 
     /**
+     * Defines the interface for tracking each call's callback action. Calls in a call group are
+     * associated with the same callback action as the first call in the group. The value of a
+     * callback action should be one of the categories in {@link CallbackAction}.
+     *
+     * @param rowId The row ID of the current call.
+     * @param callbackAction The current call's callback action.
+     */
+    void setCallbackAction(long rowId, @CallbackAction int callbackAction);
+
+    /**
      * Defines the interface for tracking the day group each call belongs to. Calls in a call group
      * are assigned the same day group as the first call in the group. The day group assigns calls
      * to the buckets: Today, Yesterday, Last week, and Other
      *
-     * @param rowId The row Id of the current call.
-     * @param dayGroup The day group the call belongs in.
+     * @param rowId The row ID of the current call.
+     * @param dayGroup The day group the call belongs to.
      */
     void setDayGroup(long rowId, int dayGroup);
 
diff --git a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
index 60acb55..225b652 100644
--- a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
+++ b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
@@ -23,7 +23,6 @@
 import android.content.res.Resources;
 import android.net.Uri;
 import android.os.AsyncTask;
-import android.os.Bundle;
 import android.provider.CallLog;
 import android.provider.CallLog.Calls;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
@@ -38,6 +37,7 @@
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
 import android.text.BidiFormatter;
 import android.text.TextDirectionHeuristics;
 import android.text.TextUtils;
@@ -66,10 +66,10 @@
 import com.android.dialer.calldetails.CallDetailsActivity;
 import com.android.dialer.calldetails.CallDetailsEntries;
 import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.calllogutils.CallbackActionHelper.CallbackAction;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.compat.CompatUtils;
-import com.android.dialer.compat.telephony.TelephonyManagerCompat;
 import com.android.dialer.configprovider.ConfigProviderBindings;
 import com.android.dialer.constants.ActivityRequestCodes;
 import com.android.dialer.contactphoto.ContactPhotoManager;
@@ -229,6 +229,7 @@
   private final View.OnLongClickListener longPressListener;
   private boolean mVoicemailPrimaryActionButtonClicked;
 
+  public int callbackAction;
   public int dayGroupHeaderVisibility;
   public CharSequence dayGroupHeaderText;
   public boolean isAttachedToWindow;
@@ -512,25 +513,50 @@
       } else {
         primaryActionButtonView.setVisibility(View.GONE);
       }
-    } else {
-      // Treat as normal list item; show call button, if possible.
-      if (PhoneNumberHelper.canPlaceCallsTo(number, numberPresentation)) {
-        boolean isVoicemailNumber = mCallLogCache.isVoicemailNumber(accountHandle, number);
+      return;
+    }
 
-        if (!isVoicemailNumber && showLightbringerPrimaryButton()) {
+    // Treat as normal list item; show call button, if possible.
+    if (!PhoneNumberHelper.canPlaceCallsTo(number, numberPresentation)) {
+      primaryActionButtonView.setTag(null);
+      primaryActionButtonView.setVisibility(View.GONE);
+      return;
+    }
+
+    switch (callbackAction) {
+      case CallbackAction.IMS_VIDEO:
+        primaryActionButtonView.setTag(
+            IntentProvider.getReturnVideoCallIntentProvider(number, accountHandle));
+        primaryActionButtonView.setContentDescription(
+            TextUtils.expandTemplate(
+                mContext.getString(R.string.description_video_call_action), validNameOrNumber));
+        primaryActionButtonView.setImageResource(R.drawable.quantum_ic_videocam_vd_theme_24);
+        primaryActionButtonView.setVisibility(View.VISIBLE);
+        break;
+      case CallbackAction.LIGHTBRINGER:
+        if (showLightbringerPrimaryButton()) {
           CallIntentBuilder.increaseLightbringerCallButtonAppearInCollapsedCallLogItemCount();
           primaryActionButtonView.setTag(IntentProvider.getLightbringerIntentProvider(number));
-          primaryActionButtonView.setContentDescription(
-              TextUtils.expandTemplate(
-                  mContext.getString(R.string.description_video_call_action), validNameOrNumber));
-          primaryActionButtonView.setImageResource(R.drawable.quantum_ic_videocam_vd_theme_24);
-          primaryActionButtonView.setVisibility(View.VISIBLE);
-          return;
+        } else {
+          primaryActionButtonView.setTag(
+              IntentProvider.getReturnVideoCallIntentProvider(number, accountHandle));
         }
-
-        if (isVoicemailNumber) {
-          // Call to generic voicemail number, in case there are multiple accounts.
+        primaryActionButtonView.setContentDescription(
+            TextUtils.expandTemplate(
+                mContext.getString(R.string.description_video_call_action), validNameOrNumber));
+        primaryActionButtonView.setImageResource(R.drawable.quantum_ic_videocam_vd_theme_24);
+        primaryActionButtonView.setVisibility(View.VISIBLE);
+        break;
+      case CallbackAction.VOICE:
+        if (mCallLogCache.isVoicemailNumber(accountHandle, number)) {
+          // Call to generic voicemail number, in case there are multiple accounts
           primaryActionButtonView.setTag(IntentProvider.getReturnVoicemailCallIntentProvider());
+        } else if (this.info != null && this.info.lookupKey != null) {
+          primaryActionButtonView.setTag(
+              IntentProvider.getAssistedDialIntentProvider(
+                  number + postDialDigits,
+                  mContext,
+                  mContext.getSystemService(TelephonyManager.class)));
         } else {
           primaryActionButtonView.setTag(
               IntentProvider.getReturnCallIntentProvider(number + postDialDigits));
@@ -541,10 +567,10 @@
                 mContext.getString(R.string.description_call_action), validNameOrNumber));
         primaryActionButtonView.setImageResource(R.drawable.quantum_ic_call_vd_theme_24);
         primaryActionButtonView.setVisibility(View.VISIBLE);
-      } else {
+        break;
+      default:
         primaryActionButtonView.setTag(null);
         primaryActionButtonView.setVisibility(View.GONE);
-      }
     }
   }
 
@@ -592,8 +618,14 @@
         ((TextView) callButtonView.findViewById(R.id.call_type_or_location_text));
 
     if (canPlaceCallToNumber) {
-      callButtonView.setTag(IntentProvider.getReturnCallIntentProvider(number));
-      callTypeOrLocationView.setVisibility(View.GONE);
+      if (this.info != null && this.info.lookupKey != null) {
+        callButtonView.setTag(
+            IntentProvider.getAssistedDialIntentProvider(
+                number, mContext, mContext.getSystemService(TelephonyManager.class)));
+      } else {
+        callButtonView.setTag(IntentProvider.getReturnCallIntentProvider(number));
+        callTypeOrLocationView.setVisibility(View.GONE);
+      }
     }
 
     if (!TextUtils.isEmpty(voicemailUri) && canPlaceCallToNumber) {
@@ -911,15 +943,6 @@
         return;
       }
 
-      if (info != null && info.lookupKey != null) {
-        Bundle extras = new Bundle();
-        if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) {
-          extras = intent.getParcelableExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS);
-        }
-        extras.putBoolean(TelephonyManagerCompat.ALLOW_ASSISTED_DIAL, true);
-        intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
-      }
-
       // We check to see if we are starting a Lightbringer intent. The reason is Lightbringer
       // intents need to be started using startActivityForResult instead of the usual startActivity
       String packageName = intent.getPackage();
diff --git a/java/com/android/dialer/app/calllog/IntentProvider.java b/java/com/android/dialer/app/calllog/IntentProvider.java
index 55fdbba..52a7b0f 100644
--- a/java/com/android/dialer/app/calllog/IntentProvider.java
+++ b/java/com/android/dialer/app/calllog/IntentProvider.java
@@ -22,8 +22,10 @@
 import android.net.Uri;
 import android.provider.ContactsContract;
 import android.telecom.PhoneAccountHandle;
+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;
@@ -59,6 +61,19 @@
     };
   }
 
+  public static IntentProvider getAssistedDialIntentProvider(
+      final String number, final Context context, final TelephonyManager telephonyManager) {
+    return new IntentProvider() {
+      @Override
+      public Intent getIntent(Context context) {
+        return new CallIntentBuilder(number, CallInitiationType.Type.CALL_LOG)
+            .setAllowAssistedDial(
+                true, ConcreteCreator.createNewAssistedDialingMediator(telephonyManager, context))
+            .build();
+      }
+    };
+  }
+
   public static IntentProvider getReturnVideoCallIntentProvider(final String number) {
     return getReturnVideoCallIntentProvider(number, null);
   }
diff --git a/java/com/android/dialer/assisteddialing/AssistedDialingMediator.java b/java/com/android/dialer/assisteddialing/AssistedDialingMediator.java
index 3d02729..4dc87a7 100644
--- a/java/com/android/dialer/assisteddialing/AssistedDialingMediator.java
+++ b/java/com/android/dialer/assisteddialing/AssistedDialingMediator.java
@@ -19,63 +19,12 @@
 import android.annotation.TargetApi;
 import android.os.Build.VERSION_CODES;
 import android.support.annotation.NonNull;
-import com.android.dialer.common.LogUtil;
 import java.util.Optional;
 
-/**
- * The Mediator for Assisted Dialing.
- *
- * <p>This class is responsible for mediating location discovery of the user, determining if the
- * call is eligible for assisted dialing, and performing the transformation of numbers eligible for
- * assisted dialing.
- */
-public final class AssistedDialingMediator {
+/** The core interface for the AssistedDialingMediator. */
+public interface AssistedDialingMediator {
 
-  private final LocationDetector locationDetector;
-  private final NumberTransformer numberTransformer;
-
-  protected AssistedDialingMediator(
-      @NonNull LocationDetector locationDetector, @NonNull NumberTransformer numberTransformer) {
-    if (locationDetector == null) {
-      throw new NullPointerException("locationDetector was null");
-    }
-
-    if (numberTransformer == null) {
-      throw new NullPointerException("numberTransformer was null");
-    }
-    this.locationDetector = locationDetector;
-    this.numberTransformer = numberTransformer;
-  }
-
-  /**
-   * Returns a boolean for callers to quickly determine whether or not the AssistedDialingMediator
-   * thinks an attempt at assisted dialing is likely to succeed.
-   */
-  public boolean conditionsEligibleForAssistedDialing(
-      @NonNull String numberToCheck,
-      @NonNull String userHomeCountryCode,
-      @NonNull String userRoamingCountryCode) {
-    return numberTransformer.canDoAssistedDialingTransformation(
-        numberToCheck, userHomeCountryCode, userRoamingCountryCode);
-  }
-
-  /**
-   * Returns an Optional of type String containing the transformed number that was provided. The
-   * transformed number should be capable of dialing out of the User's current country and
-   * successfully connecting with a contact in the User's home country.
-   */
   @SuppressWarnings("AndroidApiChecker") // Use of optional
   @TargetApi(VERSION_CODES.N)
-  public Optional<TransformationInfo> attemptAssistedDial(@NonNull String numberToTransform) {
-    Optional<String> userHomeCountryCode = locationDetector.getUpperCaseUserHomeCountry();
-    Optional<String> userRoamingCountryCode = locationDetector.getUpperCaseUserRoamingCountry();
-
-    if (!userHomeCountryCode.isPresent() || !userRoamingCountryCode.isPresent()) {
-      LogUtil.i("AssistedDialingMediator.attemptAssistedDial", "Unable to determine country codes");
-      return Optional.empty();
-    }
-
-    return numberTransformer.doAssistedDialingTransformation(
-        numberToTransform, userHomeCountryCode.get(), userRoamingCountryCode.get());
-  }
+  public Optional<TransformationInfo> attemptAssistedDial(@NonNull String numberToTransform);
 }
diff --git a/java/com/android/dialer/assisteddialing/AssistedDialingMediatorImpl.java b/java/com/android/dialer/assisteddialing/AssistedDialingMediatorImpl.java
new file mode 100644
index 0000000..1692614
--- /dev/null
+++ b/java/com/android/dialer/assisteddialing/AssistedDialingMediatorImpl.java
@@ -0,0 +1,70 @@
+/*
+ * 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.assisteddialing;
+
+import android.annotation.TargetApi;
+import android.os.Build.VERSION_CODES;
+import android.support.annotation.NonNull;
+import com.android.dialer.common.LogUtil;
+import java.util.Optional;
+
+/**
+ * The Mediator for Assisted Dialing.
+ *
+ * <p>This class is responsible for mediating location discovery of the user, determining if the
+ * call is eligible for assisted dialing, and performing the transformation of numbers eligible for
+ * assisted dialing.
+ */
+final class AssistedDialingMediatorImpl implements AssistedDialingMediator {
+
+  private final LocationDetector locationDetector;
+  private final NumberTransformer numberTransformer;
+
+  AssistedDialingMediatorImpl(
+      @NonNull LocationDetector locationDetector, @NonNull NumberTransformer numberTransformer) {
+    if (locationDetector == null) {
+      throw new NullPointerException("locationDetector was null");
+    }
+
+    if (numberTransformer == null) {
+      throw new NullPointerException("numberTransformer was null");
+    }
+    this.locationDetector = locationDetector;
+    this.numberTransformer = numberTransformer;
+  }
+
+  /**
+   * Returns an Optional of type String containing the transformed number that was provided. The
+   * transformed number should be capable of dialing out of the User's current country and
+   * successfully connecting with a contact in the User's home country.
+   */
+  @SuppressWarnings("AndroidApiChecker") // Use of optional
+  @TargetApi(VERSION_CODES.N)
+  @Override
+  public Optional<TransformationInfo> attemptAssistedDial(@NonNull String numberToTransform) {
+    Optional<String> userHomeCountryCode = locationDetector.getUpperCaseUserHomeCountry();
+    Optional<String> userRoamingCountryCode = locationDetector.getUpperCaseUserRoamingCountry();
+
+    if (!userHomeCountryCode.isPresent() || !userRoamingCountryCode.isPresent()) {
+      LogUtil.i("AssistedDialingMediator.attemptAssistedDial", "Unable to determine country codes");
+      return Optional.empty();
+    }
+
+    return numberTransformer.doAssistedDialingTransformation(
+        numberToTransform, userHomeCountryCode.get(), userRoamingCountryCode.get());
+  }
+}
diff --git a/java/com/android/dialer/assisteddialing/AssistedDialingMediatorStub.java b/java/com/android/dialer/assisteddialing/AssistedDialingMediatorStub.java
new file mode 100644
index 0000000..c7a8212
--- /dev/null
+++ b/java/com/android/dialer/assisteddialing/AssistedDialingMediatorStub.java
@@ -0,0 +1,34 @@
+/*
+ * 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.assisteddialing;
+
+import android.annotation.TargetApi;
+import android.os.Build.VERSION_CODES;
+import android.support.annotation.NonNull;
+import java.util.Optional;
+
+/** A stub assisted dialing implementation. */
+public final class AssistedDialingMediatorStub implements AssistedDialingMediator {
+
+  /** Always returns an empty Optional. */
+  @Override
+  @SuppressWarnings("AndroidApiChecker") // Use of optional
+  @TargetApi(VERSION_CODES.N)
+  public Optional<TransformationInfo> attemptAssistedDial(@NonNull String numberToTransform) {
+    return Optional.empty();
+  }
+}
diff --git a/java/com/android/dialer/assisteddialing/ConcreteCreator.java b/java/com/android/dialer/assisteddialing/ConcreteCreator.java
index f51216a..49d3b1f 100644
--- a/java/com/android/dialer/assisteddialing/ConcreteCreator.java
+++ b/java/com/android/dialer/assisteddialing/ConcreteCreator.java
@@ -18,10 +18,12 @@
 
 import android.annotation.TargetApi;
 import android.content.Context;
+import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.support.annotation.NonNull;
 import android.telephony.TelephonyManager;
 import com.android.dialer.common.LogUtil;
+import com.android.dialer.configprovider.ConfigProviderBindings;
 
 /**
  * A Creator for AssistedDialingMediators.
@@ -32,6 +34,11 @@
 @TargetApi(VERSION_CODES.N)
 public final class ConcreteCreator {
 
+  // Floor set at N due to use of Optional.
+  protected static final int BUILD_CODE_FLOOR = Build.VERSION_CODES.N;
+  // Ceiling set at O because this feature will ship as part of the framework in P.
+  protected static final int BUILD_CODE_CEILING = Build.VERSION_CODES.O;
+
   /**
    * Creates a new AssistedDialingMediator
    *
@@ -42,6 +49,7 @@
    */
   public static AssistedDialingMediator createNewAssistedDialingMediator(
       @NonNull TelephonyManager telephonyManager, @NonNull Context context) {
+
     if (telephonyManager == null) {
       LogUtil.i(
           "ConcreteCreator.createNewAssistedDialingMediator", "provided TelephonyManager was null");
@@ -51,8 +59,14 @@
       LogUtil.i("ConcreteCreator.createNewAssistedDialingMediator", "provided context was null");
       throw new NullPointerException("Provided context was null");
     }
+
+    if ((Build.VERSION.SDK_INT < BUILD_CODE_FLOOR || Build.VERSION.SDK_INT > BUILD_CODE_CEILING)
+        || !ConfigProviderBindings.get(context).getBoolean("assisted_dialing_enabled", false)) {
+      return new AssistedDialingMediatorStub();
+    }
+
     Constraints constraints = new Constraints(context);
-    return new AssistedDialingMediator(
+    return new AssistedDialingMediatorImpl(
         new LocationDetector(telephonyManager), new NumberTransformer(constraints));
   }
 }
diff --git a/java/com/android/dialer/assisteddialing/Constraints.java b/java/com/android/dialer/assisteddialing/Constraints.java
index 6bcab99..023be1c 100644
--- a/java/com/android/dialer/assisteddialing/Constraints.java
+++ b/java/com/android/dialer/assisteddialing/Constraints.java
@@ -62,7 +62,7 @@
         "GB" /* United Kingdom */,
         "JP" /* Japan */,
         "MX" /* Mexico */,
-        "US" /* United States*/,
+        "US" /* United States */,
       };
 
   private final Set<String> supportedCountryCodes =
@@ -115,7 +115,8 @@
         && isUserRoaming(userHomeCountryCode, userRoamingCountryCode)
         && isNotInternationalNumber(parsedPhoneNumber)
         && isNotEmergencyNumber(numberToCheck, context)
-        && isValidNumber(parsedPhoneNumber);
+        && isValidNumber(parsedPhoneNumber)
+        && doesNotHaveExtension(parsedPhoneNumber);
   }
 
   /** Returns a boolean indicating the value equivalence of the provided country codes. */
@@ -165,10 +166,7 @@
     }
   }
 
-  /**
-   * Returns a boolean indicating if the provided number and home country code are already
-   * internationally formatted.
-   */
+  /** Returns a boolean indicating if the provided number is already internationally formatted. */
   private boolean isNotInternationalNumber(@NonNull Optional<PhoneNumber> parsedPhoneNumber) {
 
     if (parsedPhoneNumber.get().hasCountryCode()
@@ -181,6 +179,22 @@
     return true;
   }
 
+  /**
+   * Returns a boolean indicating if the provided number has an extension.
+   *
+   * <p>Extensions are currently stripped when formatting a number for mobile dialing, so we don't
+   * want to purposefully truncate a number.
+   */
+  private boolean doesNotHaveExtension(@NonNull Optional<PhoneNumber> parsedPhoneNumber) {
+
+    if (parsedPhoneNumber.get().hasExtension()
+        && !TextUtils.isEmpty(parsedPhoneNumber.get().getExtension())) {
+      LogUtil.i("Constraints.doesNotHaveExtension", "phone number has an extension");
+      return false;
+    }
+    return true;
+  }
+
   /** Returns a boolean indicating if the provided number is considered to be a valid number. */
   private boolean isValidNumber(@NonNull Optional<PhoneNumber> parsedPhoneNumber) {
     boolean result = PhoneNumberUtil.getInstance().isValidNumber(parsedPhoneNumber.get());
diff --git a/java/com/android/dialer/assisteddialing/TransformationInfo.java b/java/com/android/dialer/assisteddialing/TransformationInfo.java
index 7149d71..03e565c 100644
--- a/java/com/android/dialer/assisteddialing/TransformationInfo.java
+++ b/java/com/android/dialer/assisteddialing/TransformationInfo.java
@@ -43,15 +43,15 @@
   private static final String TRANSFORMED_NUMBER_COUNTRY_CALLING_CODE_KEY =
       "TRANSFORMED_NUMBER_COUNTRY_CALLING_CODE";
 
-  abstract String originalNumber();
+  public abstract String originalNumber();
 
-  abstract String transformedNumber();
+  public abstract String transformedNumber();
 
-  abstract String userHomeCountryCode();
+  public abstract String userHomeCountryCode();
 
-  abstract String userRoamingCountryCode();
+  public abstract String userRoamingCountryCode();
 
-  abstract int transformedNumberCountryCallingCode();
+  public abstract int transformedNumberCountryCallingCode();
 
   public static Builder builder() {
     return new AutoValue_TransformationInfo.Builder();
diff --git a/java/com/android/dialer/callintent/CallIntentBuilder.java b/java/com/android/dialer/callintent/CallIntentBuilder.java
index b5b680e..dc239dc 100644
--- a/java/com/android/dialer/callintent/CallIntentBuilder.java
+++ b/java/com/android/dialer/callintent/CallIntentBuilder.java
@@ -16,21 +16,27 @@
 
 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.SystemClock;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
+import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 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.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;
 
 /** Creates an intent to start a new outgoing call. */
 public class CallIntentBuilder {
@@ -40,6 +46,7 @@
   private boolean isVideoCall;
   private String callSubject;
   private boolean allowAssistedDial;
+  private AssistedDialingMediator assistedDialingMediator;
 
   private static int lightbringerButtonAppearInExpandedCallLogItemCount = 0;
   private static int lightbringerButtonAppearInCollapsedCallLogItemCount = 0;
@@ -103,7 +110,9 @@
     return this;
   }
 
-  public CallIntentBuilder setAllowAssistedDial(boolean allowAssistedDial) {
+  public CallIntentBuilder setAllowAssistedDial(
+      boolean allowAssistedDial, @NonNull AssistedDialingMediator assistedDialingMediator) {
+    this.assistedDialingMediator = Assert.isNotNull(assistedDialingMediator);
     this.allowAssistedDial = allowAssistedDial;
     return this;
   }
@@ -115,18 +124,18 @@
 
   public Intent build() {
     Intent intent = new Intent(Intent.ACTION_CALL, uri);
+    Bundle extras = new Bundle();
+
+    if (allowAssistedDial && this.assistedDialingMediator != null) {
+      intent = buildAssistedDialingParameters(intent, extras);
+    }
     intent.putExtra(
         TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
         isVideoCall ? VideoProfile.STATE_BIDIRECTIONAL : VideoProfile.STATE_AUDIO_ONLY);
 
-    Bundle extras = new Bundle();
     extras.putLong(Constants.EXTRA_CALL_CREATED_TIME_MILLIS, SystemClock.elapsedRealtime());
     CallIntentParser.putCallSpecificAppData(extras, callSpecificAppData);
 
-    if (allowAssistedDial) {
-      extras.putBoolean(TelephonyManagerCompat.ALLOW_ASSISTED_DIAL, true);
-    }
-
     intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
 
     if (phoneAccountHandle != null) {
@@ -140,6 +149,26 @@
     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 =
diff --git a/java/com/android/dialer/calllogutils/CallbackActionHelper.java b/java/com/android/dialer/calllogutils/CallbackActionHelper.java
new file mode 100644
index 0000000..297d5e6
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/CallbackActionHelper.java
@@ -0,0 +1,95 @@
+/*
+ * 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.calllogutils;
+
+import android.content.Context;
+import android.provider.CallLog.Calls;
+import android.support.annotation.IntDef;
+import android.text.TextUtils;
+import com.android.dialer.lightbringer.Lightbringer;
+import com.android.dialer.lightbringer.LightbringerComponent;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Helper class to determine the callback action associated with a call in the call log. */
+public class CallbackActionHelper {
+
+  /** Specifies the action a user can take to make a callback. */
+  @Retention(RetentionPolicy.SOURCE)
+  @IntDef({
+    CallbackAction.NONE,
+    CallbackAction.IMS_VIDEO,
+    CallbackAction.LIGHTBRINGER,
+    CallbackAction.VOICE
+  })
+  public @interface CallbackAction {
+    int NONE = 0;
+    int IMS_VIDEO = 1;
+    int LIGHTBRINGER = 2;
+    int VOICE = 3;
+  }
+
+  /**
+   * Returns the {@link CallbackAction} that can be associated with a call.
+   *
+   * @param number The phone number in column {@link android.provider.CallLog.Calls#NUMBER}.
+   * @param features Value of features in column {@link android.provider.CallLog.Calls#FEATURES}.
+   * @param phoneAccountComponentName Account name in column {@link
+   *     android.provider.CallLog.Calls#PHONE_ACCOUNT_COMPONENT_NAME}.
+   * @param context The context in which the method is called.
+   * @return One of the values in {@link CallbackAction}
+   */
+  public static @CallbackAction int getCallbackAction(
+      String number, int features, String phoneAccountComponentName, Context context) {
+    return getCallbackAction(
+        number, features, isLightbringerCall(phoneAccountComponentName, context));
+  }
+
+  /**
+   * Returns the {@link CallbackAction} that can be associated with a call.
+   *
+   * @param number The phone number in column {@link android.provider.CallLog.Calls#NUMBER}.
+   * @param features Value of features in column {@link android.provider.CallLog.Calls#FEATURES}.
+   * @param isLightbringerCall Whether the call is a Lightbringer call.
+   * @return One of the values in {@link CallbackAction}
+   */
+  public static @CallbackAction int getCallbackAction(
+      String number, int features, boolean isLightbringerCall) {
+    if (TextUtils.isEmpty(number)) {
+      return CallbackAction.NONE;
+    }
+    if (isLightbringerCall) {
+      return CallbackAction.LIGHTBRINGER;
+    }
+
+    boolean isVideoCall = (features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO;
+    if (isVideoCall) {
+      return CallbackAction.IMS_VIDEO;
+    }
+
+    return CallbackAction.VOICE;
+  }
+
+  private static boolean isLightbringerCall(String phoneAccountComponentName, Context context) {
+    Lightbringer lightBringer = LightbringerComponent.get(context).getLightbringer();
+    return lightBringer.getPhoneAccountComponentName() != null
+        && lightBringer
+            .getPhoneAccountComponentName()
+            .flattenToString()
+            .equals(phoneAccountComponentName);
+  }
+}
diff --git a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
index ecd36d3..61c44b9 100644
--- a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
+++ b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
@@ -68,6 +68,11 @@
    */
   public static final String IS_ASSISTED_DIALED = "android.telecom.extra.IS_ASSISTED_DIALED";
 
+  // TODO(erfanian): b/63995261 Replace with the platform/telecom API when available.
+  /** Additional information relating to the assisted dialing transformation. */
+  public static final String ASSISTED_DIALING_EXTRAS =
+      "android.telecom.extra.ASSISTED_DIALING_EXTRAS";
+
   /**
    * Returns the number of phones available. Returns 1 for Single standby mode (Single SIM
    * functionality) Returns 2 for Dual standby mode.(Dual SIM functionality)
diff --git a/java/com/android/dialer/interactions/PhoneNumberInteraction.java b/java/com/android/dialer/interactions/PhoneNumberInteraction.java
index c42be42..9692dae 100644
--- a/java/com/android/dialer/interactions/PhoneNumberInteraction.java
+++ b/java/com/android/dialer/interactions/PhoneNumberInteraction.java
@@ -40,6 +40,7 @@
 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;
@@ -51,6 +52,7 @@
 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;
@@ -83,6 +85,7 @@
   private static final String TAG = PhoneNumberInteraction.class.getSimpleName();
   /** The identifier for a permissions request if one is generated. */
   public static final int REQUEST_READ_CONTACTS = 1;
+
   public static final int REQUEST_CALL_PHONE = 2;
 
   @VisibleForTesting
@@ -183,7 +186,10 @@
         intent =
             new CallIntentBuilder(phoneNumber, callSpecificAppData)
                 .setIsVideoCall(isVideoCall)
-                .setAllowAssistedDial(callSpecificAppData.getAllowAssistedDialing())
+                .setAllowAssistedDial(
+                    callSpecificAppData.getAllowAssistedDialing(),
+                    ConcreteCreator.createNewAssistedDialingMediator(
+                        context.getSystemService(TelephonyManager.class), context))
                 .build();
         break;
     }
diff --git a/java/com/android/dialer/searchfragment/list/SearchAdapter.java b/java/com/android/dialer/searchfragment/list/SearchAdapter.java
index 22bfa6d..1ca29e0 100644
--- a/java/com/android/dialer/searchfragment/list/SearchAdapter.java
+++ b/java/com/android/dialer/searchfragment/list/SearchAdapter.java
@@ -21,11 +21,13 @@
 import android.support.annotation.VisibleForTesting;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import com.android.dialer.assisteddialing.ConcreteCreator;
 import com.android.dialer.callcomposer.CallComposerActivity;
 import com.android.dialer.callintent.CallInitiationType;
 import com.android.dialer.callintent.CallIntentBuilder;
@@ -209,23 +211,32 @@
 
   @Override
   public void placeVoiceCall(String phoneNumber, int ranking) {
-    placeCall(phoneNumber, ranking, false);
+    placeCall(phoneNumber, ranking, false, true);
   }
 
   @Override
   public void placeVideoCall(String phoneNumber, int ranking) {
-    placeCall(phoneNumber, ranking, true);
+    placeCall(phoneNumber, ranking, true, false);
   }
 
-  private void placeCall(String phoneNumber, int position, boolean isVideoCall) {
+  private void placeCall(
+      String phoneNumber, int position, boolean isVideoCall, boolean allowAssistedDial) {
     CallSpecificAppData callSpecificAppData =
         CallSpecificAppData.newBuilder()
             .setCallInitiationType(callInitiationType)
             .setPositionOfSelectedSearchResult(position)
             .setCharactersInSearchString(query == null ? 0 : query.length())
+            .setAllowAssistedDialing(allowAssistedDial)
             .build();
     Intent intent =
-        new CallIntentBuilder(phoneNumber, callSpecificAppData).setIsVideoCall(isVideoCall).build();
+        new CallIntentBuilder(phoneNumber, callSpecificAppData)
+            .setIsVideoCall(isVideoCall)
+            .setAllowAssistedDial(
+                allowAssistedDial,
+                ConcreteCreator.createNewAssistedDialingMediator(
+                    activity.getSystemService(TelephonyManager.class),
+                    activity.getApplicationContext()))
+            .build();
     DialerUtils.startActivityWithErrorToast(activity, intent);
   }
 
diff --git a/java/com/android/incallui/StatusBarNotifier.java b/java/com/android/incallui/StatusBarNotifier.java
index 6ddba16..7146c72 100644
--- a/java/com/android/incallui/StatusBarNotifier.java
+++ b/java/com/android/incallui/StatusBarNotifier.java
@@ -711,6 +711,8 @@
         resId = R.string.notification_incoming_call_wifi_template;
       } else if (call.getAccountHandle() != null && hasMultiplePhoneAccounts()) {
         return getMultiSimIncomingText(call);
+      } else if (call.isVideoCall()) {
+        resId = R.string.notification_incoming_video_call;
       } else {
         resId = R.string.notification_incoming_call;
       }
diff --git a/java/com/android/incallui/res/values/strings.xml b/java/com/android/incallui/res/values/strings.xml
index afadbf8..2f1542a 100644
--- a/java/com/android/incallui/res/values/strings.xml
+++ b/java/com/android/incallui/res/values/strings.xml
@@ -65,6 +65,8 @@
   <string name="notification_on_hold">On hold</string>
   <!-- The "label" of the in-call Notification for an incoming ringing call. [CHAR LIMIT=60] -->
   <string name="notification_incoming_call">Incoming call</string>
+  <!-- The "label" of the in-call Notification for an incoming ringing call. [CHAR LIMIT=60] -->
+  <string name="notification_incoming_video_call">Incoming video call</string>
   <!-- The "label" of the in-call Notification for an incoming ringing call on a device with multiple SIMs. [CHAR LIMIT=60] -->
   <string name="notification_incoming_call_mutli_sim">Incoming call via <xliff:g id="sim_label" example="SIM 1">%1$s</xliff:g></string>
   <!-- The "label" of the in-call Notification for an incoming ringing call. [CHAR LIMIT=50] -->