Add old speed dial fragment to NUI.

Bug: 72618868
Test: existing
PiperOrigin-RevId: 183896896
Change-Id: I9b90aaa02e1c40f38fbbe636f4e51cfd01c570f6
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java
index 23f4d40..293ebed 100644
--- a/java/com/android/dialer/app/DialtactsActivity.java
+++ b/java/com/android/dialer/app/DialtactsActivity.java
@@ -1508,6 +1508,11 @@
   @Override
   public void onDroppedOnRemove() {}
 
+  @Override
+  public ImageView getDragShadowOverlay() {
+    return findViewById(R.id.contact_tile_drag_shadow_overlay);
+  }
+
   /**
    * Allows the SpeedDialFragment to attach the drag controller to mRemoveViewContainer once it has
    * been attached to the activity.
diff --git a/java/com/android/dialer/app/list/OldSpeedDialFragment.java b/java/com/android/dialer/app/list/OldSpeedDialFragment.java
index 1b366c1..caa5e91 100644
--- a/java/com/android/dialer/app/list/OldSpeedDialFragment.java
+++ b/java/com/android/dialer/app/list/OldSpeedDialFragment.java
@@ -20,7 +20,6 @@
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
-import android.app.Activity;
 import android.app.Fragment;
 import android.app.LoaderManager;
 import android.content.CursorLoader;
@@ -50,6 +49,7 @@
 import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
 import com.android.dialer.app.R;
 import com.android.dialer.callintent.CallSpecificAppData;
+import com.android.dialer.common.FragmentUtils;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.contactphoto.ContactPhotoManager;
 import com.android.dialer.util.PermissionsUtil;
@@ -77,22 +77,17 @@
   private static final long KEY_REMOVED_ITEM_HEIGHT = Long.MAX_VALUE;
 
   private static final String TAG = "OldSpeedDialFragment";
-  private static final boolean DEBUG = false;
   /** Used with LoaderManager. */
   private static final int LOADER_ID_CONTACT_TILE = 1;
 
   private final LongSparseArray<Integer> itemIdTopMap = new LongSparseArray<>();
   private final LongSparseArray<Integer> itemIdLeftMap = new LongSparseArray<>();
   private final ContactTileView.Listener contactTileAdapterListener =
-      new ContactTileAdapterListener();
-  private final LoaderManager.LoaderCallbacks<Cursor> contactTileLoaderListener =
-      new ContactTileLoaderListener();
-  private final ScrollListener scrollListener = new ScrollListener();
+      new ContactTileAdapterListener(this);
+  private final ScrollListener scrollListener = new ScrollListener(this);
+  private LoaderManager.LoaderCallbacks<Cursor> contactTileLoaderListener;
   private int animationDuration;
-  private OnPhoneNumberPickerActionListener phoneNumberPickerActionListener;
-  private OnListFragmentScrolledListener activityScrollListener;
   private PhoneFavoritesTileAdapter contactTileAdapter;
-  private View parentView;
   private PhoneFavoriteListView listView;
   private View contactTileFrame;
   /** Layout used when there are no favorites. */
@@ -100,9 +95,6 @@
 
   @Override
   public void onCreate(Bundle savedState) {
-    if (DEBUG) {
-      LogUtil.d("OldSpeedDialFragment.onCreate", null);
-    }
     Trace.beginSection(TAG + " onCreate");
     super.onCreate(savedState);
 
@@ -110,8 +102,9 @@
     // We don't construct the resultant adapter at this moment since it requires LayoutInflater
     // that will be available on onCreateView().
     contactTileAdapter =
-        new PhoneFavoritesTileAdapter(getActivity(), contactTileAdapterListener, this);
-    contactTileAdapter.setPhotoLoader(ContactPhotoManager.getInstance(getActivity()));
+        new PhoneFavoritesTileAdapter(getContext(), contactTileAdapterListener, this);
+    contactTileAdapter.setPhotoLoader(ContactPhotoManager.getInstance(getContext()));
+    contactTileLoaderListener = new ContactTileLoaderListener(this, contactTileAdapter);
     animationDuration = getResources().getInteger(R.integer.fade_duration);
     Trace.endSection();
   }
@@ -123,7 +116,7 @@
     if (contactTileAdapter != null) {
       contactTileAdapter.refreshContactsPreferences();
     }
-    if (PermissionsUtil.hasContactsReadPermissions(getActivity())) {
+    if (PermissionsUtil.hasContactsReadPermissions(getContext())) {
       if (getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE) == null) {
         getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, contactTileLoaderListener);
 
@@ -144,7 +137,7 @@
   public View onCreateView(
       LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     Trace.beginSection(TAG + " onCreateView");
-    parentView = inflater.inflate(R.layout.speed_dial_fragment, container, false);
+    View parentView = inflater.inflate(R.layout.speed_dial_fragment, container, false);
 
     listView = (PhoneFavoriteListView) parentView.findViewById(R.id.contact_tile_list);
     listView.setOnItemClickListener(this);
@@ -152,10 +145,8 @@
     listView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
     listView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
     listView.getDragDropController().addOnDragDropListener(contactTileAdapter);
-
-    final ImageView dragShadowOverlay =
-        (ImageView) getActivity().findViewById(R.id.contact_tile_drag_shadow_overlay);
-    listView.setDragShadowOverlay(dragShadowOverlay);
+    listView.setDragShadowOverlay(
+        FragmentUtils.getParentUnsafe(this, HostInterface.class).getDragShadowOverlay());
 
     emptyView = (EmptyContentView) parentView.findViewById(R.id.empty_list_view);
     emptyView.setImage(R.drawable.empty_speed_dial);
@@ -165,7 +156,7 @@
 
     final LayoutAnimationController controller =
         new LayoutAnimationController(
-            AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in));
+            AnimationUtils.loadAnimation(getContext(), android.R.anim.fade_in));
     controller.setDelay(0);
     listView.setLayoutAnimation(controller);
     listView.setAdapter(contactTileAdapter);
@@ -206,36 +197,16 @@
   @Override
   public void onStart() {
     super.onStart();
-
-    final Activity activity = getActivity();
-
-    try {
-      activityScrollListener = (OnListFragmentScrolledListener) activity;
-    } catch (ClassCastException e) {
-      throw new ClassCastException(
-          activity.toString() + " must implement OnListFragmentScrolledListener");
-    }
-
-    try {
-      OnDragDropListener listener = (OnDragDropListener) activity;
-      listView.getDragDropController().addOnDragDropListener(listener);
-      ((HostInterface) activity).setDragDropController(listView.getDragDropController());
-    } catch (ClassCastException e) {
-      throw new ClassCastException(
-          activity.toString() + " must implement OnDragDropListener and HostInterface");
-    }
-
-    try {
-      phoneNumberPickerActionListener = (OnPhoneNumberPickerActionListener) activity;
-    } catch (ClassCastException e) {
-      throw new ClassCastException(
-          activity.toString() + " must implement PhoneFavoritesFragment.listener");
-    }
+    listView
+        .getDragDropController()
+        .addOnDragDropListener(FragmentUtils.getParentUnsafe(this, OnDragDropListener.class));
+    FragmentUtils.getParentUnsafe(this, HostInterface.class)
+        .setDragDropController(listView.getDragDropController());
 
     // Use initLoader() instead of restartLoader() to refraining unnecessary reload.
     // This method call implicitly assures ContactTileLoaderListener's onLoadFinished() will
     // be called, on which we'll check if "all" contacts should be reloaded again or not.
-    if (PermissionsUtil.hasContactsReadPermissions(activity)) {
+    if (PermissionsUtil.hasContactsReadPermissions(getContext())) {
       getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, contactTileLoaderListener);
     } else {
       setEmptyViewVisibility(true);
@@ -268,9 +239,6 @@
    */
   private void saveOffsets(int removedItemHeight) {
     final int firstVisiblePosition = listView.getFirstVisiblePosition();
-    if (DEBUG) {
-      LogUtil.d("OldSpeedDialFragment.saveOffsets", "Child count : " + listView.getChildCount());
-    }
     for (int i = 0; i < listView.getChildCount(); i++) {
       final View child = listView.getChildAt(i);
       final int position = firstVisiblePosition + i;
@@ -281,11 +249,6 @@
         continue;
       }
       final long itemId = contactTileAdapter.getItemId(position);
-      if (DEBUG) {
-        LogUtil.d(
-            "OldSpeedDialFragment.saveOffsets",
-            "Saving itemId: " + itemId + " for listview child " + i + " Top: " + child.getTop());
-      }
       itemIdTopMap.put(itemId, child.getTop());
       itemIdLeftMap.put(itemId, child.getLeft());
     }
@@ -350,19 +313,6 @@
                     animators.add(ObjectAnimator.ofFloat(child, "translationY", deltaY, 0.0f));
                   }
                 }
-
-                if (DEBUG) {
-                  LogUtil.d(
-                      "OldSpeedDialFragment.onPreDraw",
-                      "Found itemId: "
-                          + itemId
-                          + " for listview child "
-                          + i
-                          + " Top: "
-                          + top
-                          + " Delta: "
-                          + deltaY);
-                }
               }
             }
 
@@ -399,11 +349,6 @@
 
   @Override
   public void onEmptyViewActionButtonClicked() {
-    final Activity activity = getActivity();
-    if (activity == null) {
-      return;
-    }
-
     String[] deniedPermissions =
         PermissionsUtil.getPermissionsCurrentlyDenied(
             getContext(), PermissionsUtil.allContactsGroupPermissionsUsedInDialer);
@@ -415,7 +360,7 @@
           this, deniedPermissions, READ_CONTACTS_PERMISSION_REQUEST_CODE);
     } else {
       // Switch tabs
-      ((HostInterface) activity).showAllContactsTab();
+      FragmentUtils.getParentUnsafe(this, HostInterface.class).showAllContactsTab();
     }
   }
 
@@ -424,79 +369,88 @@
       int requestCode, String[] permissions, int[] grantResults) {
     if (requestCode == READ_CONTACTS_PERMISSION_REQUEST_CODE) {
       if (grantResults.length == 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) {
-        PermissionsUtil.notifyPermissionGranted(getActivity(), READ_CONTACTS);
+        PermissionsUtil.notifyPermissionGranted(getContext(), READ_CONTACTS);
       }
     }
   }
 
+  private static final class ContactTileLoaderListener
+      implements LoaderManager.LoaderCallbacks<Cursor> {
+
+    private final OldSpeedDialFragment fragment;
+    private final PhoneFavoritesTileAdapter adapter;
+
+    ContactTileLoaderListener(OldSpeedDialFragment fragment, PhoneFavoritesTileAdapter adapter) {
+      this.fragment = fragment;
+      this.adapter = adapter;
+    }
+
+    @Override
+    public CursorLoader onCreateLoader(int id, Bundle args) {
+      return ContactTileLoaderFactory.createStrequentPhoneOnlyLoader(fragment.getContext());
+    }
+
+    @Override
+    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+      adapter.setContactCursor(data);
+      fragment.setEmptyViewVisibility(adapter.getCount() == 0);
+    }
+
+    @Override
+    public void onLoaderReset(Loader<Cursor> loader) {}
+  }
+
+  private static final class ContactTileAdapterListener implements ContactTileView.Listener {
+
+    private final OldSpeedDialFragment fragment;
+
+    ContactTileAdapterListener(OldSpeedDialFragment fragment) {
+      this.fragment = fragment;
+    }
+
+    @Override
+    public void onContactSelected(
+        Uri contactUri, Rect targetRect, CallSpecificAppData callSpecificAppData) {
+      FragmentUtils.getParentUnsafe(fragment, OnPhoneNumberPickerActionListener.class)
+          .onPickDataUri(contactUri, false /* isVideoCall */, callSpecificAppData);
+    }
+
+    @Override
+    public void onCallNumberDirectly(String phoneNumber, CallSpecificAppData callSpecificAppData) {
+      FragmentUtils.getParentUnsafe(fragment, OnPhoneNumberPickerActionListener.class)
+          .onPickPhoneNumber(phoneNumber, false /* isVideoCall */, callSpecificAppData);
+    }
+  }
+
+  private static class ScrollListener implements ListView.OnScrollListener {
+
+    private final OldSpeedDialFragment fragment;
+
+    ScrollListener(OldSpeedDialFragment fragment) {
+      this.fragment = fragment;
+    }
+
+    @Override
+    public void onScroll(
+        AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+      FragmentUtils.getParentUnsafe(fragment, OnListFragmentScrolledListener.class)
+          .onListFragmentScroll(firstVisibleItem, visibleItemCount, totalItemCount);
+    }
+
+    @Override
+    public void onScrollStateChanged(AbsListView view, int scrollState) {
+      FragmentUtils.getParentUnsafe(fragment, OnListFragmentScrolledListener.class)
+          .onListFragmentScrollStateChange(scrollState);
+    }
+  }
+
+  /** Interface for parents of OldSpeedDialFragment to implement. */
   public interface HostInterface {
 
     void setDragDropController(DragDropController controller);
 
     void showAllContactsTab();
-  }
 
-  class ContactTileLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
-
-    @Override
-    public CursorLoader onCreateLoader(int id, Bundle args) {
-      if (DEBUG) {
-        LogUtil.d("ContactTileLoaderListener.onCreateLoader", null);
-      }
-      return ContactTileLoaderFactory.createStrequentPhoneOnlyLoader(getActivity());
-    }
-
-    @Override
-    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
-      if (DEBUG) {
-        LogUtil.d("ContactTileLoaderListener.onLoadFinished", null);
-      }
-      contactTileAdapter.setContactCursor(data);
-      setEmptyViewVisibility(contactTileAdapter.getCount() == 0);
-    }
-
-    @Override
-    public void onLoaderReset(Loader<Cursor> loader) {
-      if (DEBUG) {
-        LogUtil.d("ContactTileLoaderListener.onLoaderReset", null);
-      }
-    }
-  }
-
-  private class ContactTileAdapterListener implements ContactTileView.Listener {
-
-    @Override
-    public void onContactSelected(
-        Uri contactUri, Rect targetRect, CallSpecificAppData callSpecificAppData) {
-      if (phoneNumberPickerActionListener != null) {
-        phoneNumberPickerActionListener.onPickDataUri(
-            contactUri, false /* isVideoCall */, callSpecificAppData);
-      }
-    }
-
-    @Override
-    public void onCallNumberDirectly(String phoneNumber, CallSpecificAppData callSpecificAppData) {
-      if (phoneNumberPickerActionListener != null) {
-        phoneNumberPickerActionListener.onPickPhoneNumber(
-            phoneNumber, false /* isVideoCall */, callSpecificAppData);
-      }
-    }
-  }
-
-  private class ScrollListener implements ListView.OnScrollListener {
-
-    @Override
-    public void onScroll(
-        AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
-      if (activityScrollListener != null) {
-        activityScrollListener.onListFragmentScroll(
-            firstVisibleItem, visibleItemCount, totalItemCount);
-      }
-    }
-
-    @Override
-    public void onScrollStateChanged(AbsListView view, int scrollState) {
-      activityScrollListener.onListFragmentScrollStateChange(scrollState);
-    }
+    ImageView getDragShadowOverlay();
   }
 }
diff --git a/java/com/android/dialer/main/impl/MainActivity.java b/java/com/android/dialer/main/impl/MainActivity.java
index 0308b89..4bc15da 100644
--- a/java/com/android/dialer/main/impl/MainActivity.java
+++ b/java/com/android/dialer/main/impl/MainActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.dialer.main.impl;
 
+import android.app.Fragment;
+import android.app.FragmentManager;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
@@ -25,15 +27,24 @@
 import android.support.annotation.Nullable;
 import android.support.design.widget.FloatingActionButton;
 import android.support.v4.app.FragmentTransaction;
-import android.support.v7.app.AppCompatActivity;
 import android.view.View;
 import android.widget.ImageView;
+import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
+import com.android.dialer.app.list.DragDropController;
+import com.android.dialer.app.list.OldSpeedDialFragment;
+import com.android.dialer.app.list.OnDragDropListener;
+import com.android.dialer.app.list.OnListFragmentScrolledListener;
+import com.android.dialer.app.list.PhoneFavoriteSquareTileView;
+import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.callintent.CallSpecificAppData;
 import com.android.dialer.calllog.ui.NewCallLogFragment;
+import com.android.dialer.common.Assert;
 import com.android.dialer.common.FragmentUtils.FragmentUtilListener;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.common.concurrent.DialerExecutorComponent;
 import com.android.dialer.common.concurrent.UiListener;
 import com.android.dialer.compat.CompatUtils;
+import com.android.dialer.configprovider.ConfigProviderComponent;
 import com.android.dialer.constants.ActivityRequestCodes;
 import com.android.dialer.contactsfragment.ContactsFragment;
 import com.android.dialer.contactsfragment.ContactsFragment.Header;
@@ -43,18 +54,30 @@
 import com.android.dialer.dialpadview.DialpadFragment.DialpadListener;
 import com.android.dialer.dialpadview.DialpadFragment.LastOutgoingCallCallback;
 import com.android.dialer.dialpadview.DialpadFragment.OnDialpadQueryChangedListener;
+import com.android.dialer.interactions.PhoneNumberInteraction;
+import com.android.dialer.interactions.PhoneNumberInteraction.DisambigDialogDismissedListener;
+import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorCode;
+import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorListener;
 import com.android.dialer.main.impl.BottomNavBar.OnBottomNavTabSelectedListener;
 import com.android.dialer.main.impl.toolbar.MainToolbar;
 import com.android.dialer.postcall.PostCall;
+import com.android.dialer.precall.PreCall;
 import com.android.dialer.searchfragment.list.NewSearchFragment.SearchFragmentListener;
 import com.android.dialer.smartdial.util.SmartDialPrefix;
 import com.android.dialer.speeddial.SpeedDialFragment;
 import com.android.dialer.telecom.TelecomUtil;
+import com.android.dialer.util.DialerUtils;
+import com.android.dialer.util.TransactionSafeActivity;
 import com.android.dialer.voicemail.listui.NewVoicemailFragment;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /** This is the main activity for dialer. It hosts favorites, call log, search, dialpad, etc... */
-public final class MainActivity extends AppCompatActivity implements FragmentUtilListener {
+// TODO(calderwoodra): Do not extend TransactionSafeActivity after new SpeedDial is launched
+public final class MainActivity extends TransactionSafeActivity
+    implements FragmentUtilListener,
+        // TODO(calderwoodra): remove these 2 interfaces when we migrate to new speed dial fragment
+        InteractionErrorListener,
+        DisambigDialogDismissedListener {
 
   private static final String KEY_SAVED_LANGUAGE_CODE = "saved_language_code";
 
@@ -67,6 +90,10 @@
   private MainOnDialpadQueryChangedListener onDialpadQueryChangedListener;
   private MainDialpadListener dialpadListener;
   private MainSearchFragmentListener searchFragmentListener;
+  private MainOnListFragmentScrolledListener onListFragmentScrolledListener;
+  private MainOnPhoneNumberPickerActionListener onPhoneNumberPickerActionListener;
+  private MainOldSpeedDialFragmentHostInterface oldSpeedDialFragmentHostInterface;
+  private MainOnDragDropListener onDragDropListener;
 
   /** Language the device was in last time {@link #onSaveInstanceState(Bundle)} was called. */
   private String savedLanguageCode;
@@ -110,7 +137,10 @@
     setSupportActionBar(findViewById(R.id.toolbar));
 
     BottomNavBar bottomNav = findViewById(R.id.bottom_nav_bar);
-    bottomNav.setOnTabSelectedListener(new MainBottomNavBarBottomNavTabListener());
+    MainBottomNavBarBottomNavTabListener bottomNavTabListener =
+        new MainBottomNavBarBottomNavTabListener(
+            this, getFragmentManager(), getSupportFragmentManager());
+    bottomNav.setOnTabSelectedListener(bottomNavTabListener);
 
     searchController = new MainSearchController(this, bottomNav, fab, toolbar);
     toolbar.setSearchBarListener(searchController);
@@ -118,6 +148,12 @@
     onDialpadQueryChangedListener = new MainOnDialpadQueryChangedListener(searchController);
     dialpadListener = new MainDialpadListener(this, searchController, getLastOutgoingCallListener);
     searchFragmentListener = new MainSearchFragmentListener(searchController);
+    onListFragmentScrolledListener = new MainOnListFragmentScrolledListener(snackbarContainer);
+    onPhoneNumberPickerActionListener = new MainOnPhoneNumberPickerActionListener(this);
+    oldSpeedDialFragmentHostInterface =
+        new MainOldSpeedDialFragmentHostInterface(
+            bottomNavTabListener, findViewById(R.id.contact_tile_drag_shadow_overlay));
+    onDragDropListener = new MainOnDragDropListener();
 
     // Restore our view state if needed, else initialize as if the app opened for the first time
     if (savedInstanceState != null) {
@@ -192,11 +228,41 @@
       return (T) dialpadFragmentHostInterface;
     } else if (callbackInterface.isInstance(searchFragmentListener)) {
       return (T) searchFragmentListener;
+    } else if (callbackInterface.isInstance(onListFragmentScrolledListener)) {
+      return (T) onListFragmentScrolledListener;
+    } else if (callbackInterface.isInstance(onPhoneNumberPickerActionListener)) {
+      return (T) onPhoneNumberPickerActionListener;
+    } else if (callbackInterface.isInstance(oldSpeedDialFragmentHostInterface)) {
+      return (T) oldSpeedDialFragmentHostInterface;
+    } else if (callbackInterface.isInstance(onDragDropListener)) {
+      return (T) onDragDropListener;
     } else {
       return null;
     }
   }
 
+  @Override
+  public void interactionError(@InteractionErrorCode int interactionErrorCode) {
+    switch (interactionErrorCode) {
+      case InteractionErrorCode.USER_LEAVING_ACTIVITY:
+        // This is expected to happen if the user exits the activity before the interaction occurs.
+        return;
+      case InteractionErrorCode.CONTACT_NOT_FOUND:
+      case InteractionErrorCode.CONTACT_HAS_NO_NUMBER:
+      case InteractionErrorCode.OTHER_ERROR:
+      default:
+        // All other error codes are unexpected. For example, it should be impossible to start an
+        // interaction with an invalid contact from this activity.
+        throw Assert.createIllegalStateFailException(
+            "PhoneNumberInteraction error: " + interactionErrorCode);
+    }
+  }
+
+  @Override
+  public void onDisambigDialogDismissed() {
+    // Don't do anything; the app will remain open with favorites tiles displayed.
+  }
+
   /** @see OnContactSelectedListener */
   private static final class MainOnContactSelectedListener implements OnContactSelectedListener {
 
@@ -294,11 +360,123 @@
     }
   }
 
+  /** @see OnListFragmentScrolledListener */
+  private static final class MainOnListFragmentScrolledListener
+      implements OnListFragmentScrolledListener {
+
+    private final View parentLayout;
+
+    MainOnListFragmentScrolledListener(View parentLayout) {
+      this.parentLayout = parentLayout;
+    }
+
+    @Override
+    public void onListFragmentScrollStateChange(int scrollState) {
+      DialerUtils.hideInputMethod(parentLayout);
+    }
+
+    @Override
+    public void onListFragmentScroll(
+        int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+      // TODO: No-op for now. This should eventually show/hide the actionBar based on
+      // interactions with the ListsFragments.
+    }
+  }
+
+  /** @see OnPhoneNumberPickerActionListener */
+  private static final class MainOnPhoneNumberPickerActionListener
+      implements OnPhoneNumberPickerActionListener {
+
+    private final TransactionSafeActivity activity;
+
+    MainOnPhoneNumberPickerActionListener(TransactionSafeActivity activity) {
+      this.activity = activity;
+    }
+
+    @Override
+    public void onPickDataUri(
+        Uri dataUri, boolean isVideoCall, CallSpecificAppData callSpecificAppData) {
+      PhoneNumberInteraction.startInteractionForPhoneCall(
+          activity, dataUri, isVideoCall, callSpecificAppData);
+    }
+
+    @Override
+    public void onPickPhoneNumber(
+        String phoneNumber, boolean isVideoCall, CallSpecificAppData callSpecificAppData) {
+      if (phoneNumber == null) {
+        // Invalid phone number, but let the call go through so that InCallUI can show
+        // an error message.
+        phoneNumber = "";
+      }
+      PreCall.start(
+          activity,
+          new CallIntentBuilder(phoneNumber, callSpecificAppData)
+              .setIsVideoCall(isVideoCall)
+              .setAllowAssistedDial(callSpecificAppData.getAllowAssistedDialing()));
+    }
+
+    @Override
+    public void onHomeInActionBarSelected() {
+      // TODO(calderwoodra): investigate if we need to exit search here
+      // PhoneNumberPickerFragment#onOptionsItemSelected
+    }
+  }
+
+  /** @see OldSpeedDialFragment.HostInterface */
+  private static final class MainOldSpeedDialFragmentHostInterface
+      implements OldSpeedDialFragment.HostInterface {
+
+    private final MainBottomNavBarBottomNavTabListener listener;
+    private final ImageView dragShadowOverlay;
+
+    // TODO(calderwoodra): Use this for drag and drop
+    @SuppressWarnings("unused")
+    private DragDropController dragDropController;
+
+    MainOldSpeedDialFragmentHostInterface(
+        MainBottomNavBarBottomNavTabListener listener, ImageView dragShadowOverlay) {
+      this.listener = listener;
+      this.dragShadowOverlay = dragShadowOverlay;
+    }
+
+    @Override
+    public void setDragDropController(DragDropController dragDropController) {
+      this.dragDropController = dragDropController;
+    }
+
+    @Override
+    public void showAllContactsTab() {
+      listener.onContactsSelected();
+    }
+
+    @Override
+    public ImageView getDragShadowOverlay() {
+      return dragShadowOverlay;
+    }
+  }
+
+  /** @see com.android.dialer.app.list.OnDragDropListener */
+  // TODO(calderwoodra): implement drag and drop
+  private static final class MainOnDragDropListener implements OnDragDropListener {
+
+    @Override
+    public void onDragStarted(int x, int y, PhoneFavoriteSquareTileView view) {}
+
+    @Override
+    public void onDragHovered(int x, int y, PhoneFavoriteSquareTileView view) {}
+
+    @Override
+    public void onDragFinished(int x, int y) {}
+
+    @Override
+    public void onDroppedOnRemove() {}
+  }
+
   /**
    * Implementation of {@link OnBottomNavTabSelectedListener} that handles logic for showing each of
    * the main tabs.
    */
-  private final class MainBottomNavBarBottomNavTabListener
+  private static final class MainBottomNavBarBottomNavTabListener
       implements OnBottomNavTabSelectedListener {
 
     private static final String SPEED_DIAL_TAG = "speed_dial";
@@ -306,18 +484,37 @@
     private static final String CONTACTS_TAG = "contacts";
     private static final String VOICEMAIL_TAG = "voicemail";
 
+    private final Context context;
+    private final FragmentManager fragmentManager;
+    private final android.support.v4.app.FragmentManager supportFragmentManager;
+
+    private MainBottomNavBarBottomNavTabListener(
+        Context context,
+        FragmentManager fragmentManager,
+        android.support.v4.app.FragmentManager supportFragmentManager) {
+      this.context = context;
+      this.fragmentManager = fragmentManager;
+      this.supportFragmentManager = supportFragmentManager;
+    }
+
     @Override
     public void onSpeedDialSelected() {
       hideAllFragments();
-      SpeedDialFragment fragment =
-          (SpeedDialFragment) getFragmentManager().findFragmentByTag(SPEED_DIAL_TAG);
+      Fragment fragment = fragmentManager.findFragmentByTag(SPEED_DIAL_TAG);
       if (fragment == null) {
-        getFragmentManager()
+        if (ConfigProviderComponent.get(context)
+            .getConfigProvider()
+            .getBoolean("enable_new_favorites_tab", false)) {
+          fragment = SpeedDialFragment.newInstance();
+        } else {
+          fragment = new OldSpeedDialFragment();
+        }
+        fragmentManager
             .beginTransaction()
-            .add(R.id.fragment_container, SpeedDialFragment.newInstance(), SPEED_DIAL_TAG)
+            .add(R.id.fragment_container, fragment, SPEED_DIAL_TAG)
             .commit();
       } else {
-        getFragmentManager().beginTransaction().show(fragment).commit();
+        fragmentManager.beginTransaction().show(fragment).commit();
       }
     }
 
@@ -325,14 +522,14 @@
     public void onCallLogSelected() {
       hideAllFragments();
       NewCallLogFragment fragment =
-          (NewCallLogFragment) getSupportFragmentManager().findFragmentByTag(CALL_LOG_TAG);
+          (NewCallLogFragment) supportFragmentManager.findFragmentByTag(CALL_LOG_TAG);
       if (fragment == null) {
-        getSupportFragmentManager()
+        supportFragmentManager
             .beginTransaction()
             .add(R.id.fragment_container, new NewCallLogFragment(), CALL_LOG_TAG)
             .commit();
       } else {
-        getSupportFragmentManager().beginTransaction().show(fragment).commit();
+        supportFragmentManager.beginTransaction().show(fragment).commit();
       }
     }
 
@@ -340,9 +537,9 @@
     public void onContactsSelected() {
       hideAllFragments();
       ContactsFragment fragment =
-          (ContactsFragment) getFragmentManager().findFragmentByTag(CONTACTS_TAG);
+          (ContactsFragment) fragmentManager.findFragmentByTag(CONTACTS_TAG);
       if (fragment == null) {
-        getFragmentManager()
+        fragmentManager
             .beginTransaction()
             .add(
                 R.id.fragment_container,
@@ -350,7 +547,7 @@
                 CONTACTS_TAG)
             .commit();
       } else {
-        getFragmentManager().beginTransaction().show(fragment).commit();
+        fragmentManager.beginTransaction().show(fragment).commit();
       }
     }
 
@@ -358,33 +555,33 @@
     public void onVoicemailSelected() {
       hideAllFragments();
       NewVoicemailFragment fragment =
-          (NewVoicemailFragment) getSupportFragmentManager().findFragmentByTag(VOICEMAIL_TAG);
+          (NewVoicemailFragment) supportFragmentManager.findFragmentByTag(VOICEMAIL_TAG);
       if (fragment == null) {
-        getSupportFragmentManager()
+        supportFragmentManager
             .beginTransaction()
             .add(R.id.fragment_container, new NewVoicemailFragment(), VOICEMAIL_TAG)
             .commit();
       } else {
-        getSupportFragmentManager().beginTransaction().show(fragment).commit();
+        supportFragmentManager.beginTransaction().show(fragment).commit();
       }
     }
 
     private void hideAllFragments() {
-      FragmentTransaction supportTransaction = getSupportFragmentManager().beginTransaction();
-      if (getSupportFragmentManager().findFragmentByTag(CALL_LOG_TAG) != null) {
-        supportTransaction.hide(getSupportFragmentManager().findFragmentByTag(CALL_LOG_TAG));
+      FragmentTransaction supportTransaction = supportFragmentManager.beginTransaction();
+      if (supportFragmentManager.findFragmentByTag(CALL_LOG_TAG) != null) {
+        supportTransaction.hide(supportFragmentManager.findFragmentByTag(CALL_LOG_TAG));
       }
-      if (getSupportFragmentManager().findFragmentByTag(VOICEMAIL_TAG) != null) {
-        supportTransaction.hide(getSupportFragmentManager().findFragmentByTag(VOICEMAIL_TAG));
+      if (supportFragmentManager.findFragmentByTag(VOICEMAIL_TAG) != null) {
+        supportTransaction.hide(supportFragmentManager.findFragmentByTag(VOICEMAIL_TAG));
       }
       supportTransaction.commit();
 
-      android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
-      if (getFragmentManager().findFragmentByTag(SPEED_DIAL_TAG) != null) {
-        transaction.hide(getFragmentManager().findFragmentByTag(SPEED_DIAL_TAG));
+      android.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
+      if (fragmentManager.findFragmentByTag(SPEED_DIAL_TAG) != null) {
+        transaction.hide(fragmentManager.findFragmentByTag(SPEED_DIAL_TAG));
       }
-      if (getFragmentManager().findFragmentByTag(CONTACTS_TAG) != null) {
-        transaction.hide(getFragmentManager().findFragmentByTag(CONTACTS_TAG));
+      if (fragmentManager.findFragmentByTag(CONTACTS_TAG) != null) {
+        transaction.hide(fragmentManager.findFragmentByTag(CONTACTS_TAG));
       }
       transaction.commit();
     }
diff --git a/java/com/android/dialer/main/impl/res/layout/main_activity.xml b/java/com/android/dialer/main/impl/res/layout/main_activity.xml
index aaba8da..2094a73 100644
--- a/java/com/android/dialer/main/impl/res/layout/main_activity.xml
+++ b/java/com/android/dialer/main/impl/res/layout/main_activity.xml
@@ -66,4 +66,18 @@
   <include
       android:id="@+id/toolbar"
       layout="@layout/toolbar_layout"/>
+
+  <!-- TODO(calderwoodra): investigate what this is for and why we want it. -->
+  <!-- Host container for the contact tile drag shadow -->
+  <FrameLayout
+      android:id="@+id/activity_overlay"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent">
+    <ImageView
+        android:id="@+id/contact_tile_drag_shadow_overlay"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:importantForAccessibility="no"
+        android:visibility="gone"/>
+  </FrameLayout>
 </RelativeLayout>
\ No newline at end of file