Merge changes Ia72bdfab,I72df9feb

* changes:
  Update dynamic shortcuts to match speed dial pinned positions.
  Add empty content view for when the user has no contacts in favorites.
diff --git a/java/com/android/dialer/shortcuts/ShortcutRefresher.java b/java/com/android/dialer/shortcuts/ShortcutRefresher.java
index 3201d59..7776aa9 100644
--- a/java/com/android/dialer/shortcuts/ShortcutRefresher.java
+++ b/java/com/android/dialer/shortcuts/ShortcutRefresher.java
@@ -25,6 +25,7 @@
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.common.concurrent.DialerExecutor.Worker;
 import com.android.dialer.common.concurrent.DialerExecutorComponent;
+import com.android.dialer.speeddial.loader.SpeedDialUiItem;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -52,6 +53,20 @@
         .executeSerial(new ArrayList<>(contacts));
   }
 
+  public static List<ContactEntry> speedDialUiItemsToContactEntries(List<SpeedDialUiItem> items) {
+    List<ContactEntry> contactEntries = new ArrayList<>();
+    for (SpeedDialUiItem item : items) {
+      ContactEntry entry = new ContactEntry();
+      entry.id = item.contactId();
+      entry.lookupKey = item.lookupKey();
+      // SpeedDialUiItem name's are already configured for alternative display orders, so we don't
+      // need to account for them in these entries.
+      entry.namePrimary = item.name();
+      contactEntries.add(entry);
+    }
+    return contactEntries;
+  }
+
   private static final class RefreshWorker implements Worker<List<ContactEntry>, Void> {
     private final Context context;
 
diff --git a/java/com/android/dialer/speeddial/SpeedDialFragment.java b/java/com/android/dialer/speeddial/SpeedDialFragment.java
index c118f96..c48eb8d 100644
--- a/java/com/android/dialer/speeddial/SpeedDialFragment.java
+++ b/java/com/android/dialer/speeddial/SpeedDialFragment.java
@@ -56,6 +56,7 @@
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
 import com.android.dialer.precall.PreCall;
+import com.android.dialer.shortcuts.ShortcutRefresher;
 import com.android.dialer.speeddial.ContextMenu.ContextMenuItemListener;
 import com.android.dialer.speeddial.FavoritesViewHolder.FavoriteContactsListener;
 import com.android.dialer.speeddial.HeaderViewHolder.SpeedDialHeaderListener;
@@ -137,11 +138,7 @@
     LogUtil.enterBlock("SpeedDialFragment.onCreateView");
     View rootLayout = inflater.inflate(R.layout.fragment_speed_dial, container, false);
     emptyContentView = rootLayout.findViewById(R.id.speed_dial_empty_content_view);
-    emptyContentView.setActionLabel(R.string.speed_dial_turn_on_contacts_permission);
-    emptyContentView.setDescription(R.string.speed_dial_contacts_permission_description);
     emptyContentView.setImage(R.drawable.empty_speed_dial);
-    emptyContentView.setActionClickedListener(
-        new SpeedDialEmptyContentViewClickedListener(getContext(), this));
 
     speedDialLoaderListener =
         DialerExecutorComponent.get(getContext())
@@ -213,6 +210,9 @@
                 }),
         new DefaultFutureCallback<>(),
         DialerExecutorComponent.get(getContext()).backgroundExecutor());
+    ShortcutRefresher.refresh(
+        getContext(),
+        ShortcutRefresher.speedDialUiItemsToContactEntries(adapter.getSpeedDialUiItems()));
   }
 
   @Override
@@ -232,11 +232,8 @@
       return;
     }
 
-    if (!PermissionsUtil.hasContactsReadPermissions(getContext())) {
-      emptyContentView.setVisibility(View.VISIBLE);
+    if (showContactsPermissionEmptyContentView()) {
       return;
-    } else {
-      emptyContentView.setVisibility(View.GONE);
     }
 
     speedDialLoaderListener.listen(
@@ -274,20 +271,51 @@
             .speedDialUiItemMutator()
             .insertDuoChannels(getContext(), speedDialUiItems));
     adapter.notifyDataSetChanged();
+    maybeShowNoContactsEmptyContentView();
+
     if (getActivity() != null) {
       FragmentUtils.getParentUnsafe(this, HostInterface.class)
           .setHasFrequents(adapter.hasFrequents());
     }
   }
 
+  /** Returns true if the empty content view was shown. */
+  private boolean showContactsPermissionEmptyContentView() {
+    if (PermissionsUtil.hasContactsReadPermissions(getContext())) {
+      emptyContentView.setVisibility(View.GONE);
+      return false;
+    }
+
+    emptyContentView.setVisibility(View.VISIBLE);
+    emptyContentView.setActionLabel(R.string.speed_dial_turn_on_contacts_permission);
+    emptyContentView.setDescription(R.string.speed_dial_contacts_permission_description);
+    emptyContentView.setActionClickedListener(
+        new SpeedDialContactPermissionEmptyViewListener(getContext(), this));
+    return true;
+  }
+
+  private void maybeShowNoContactsEmptyContentView() {
+    if (adapter.getItemCount() != 0) {
+      emptyContentView.setVisibility(View.GONE);
+      return;
+    }
+
+    emptyContentView.setVisibility(View.VISIBLE);
+    emptyContentView.setActionLabel(R.string.speed_dial_no_contacts_action_text);
+    emptyContentView.setDescription(R.string.speed_dial_no_contacts_description);
+    emptyContentView.setActionClickedListener(new SpeedDialNoContactsEmptyViewListener(this));
+  }
+
   @Override
   public void onStart() {
     super.onStart();
     PermissionsUtil.registerPermissionReceiver(
         getActivity(), readContactsPermissionGrantedReceiver, Manifest.permission.READ_CONTACTS);
-    getContext()
-        .getContentResolver()
-        .registerContentObserver(Contacts.CONTENT_STREQUENT_URI, true, strequentsContentObserver);
+    if (PermissionsUtil.hasContactsReadPermissions(getContext())) {
+      getContext()
+          .getContentResolver()
+          .registerContentObserver(Contacts.CONTENT_STREQUENT_URI, true, strequentsContentObserver);
+    }
   }
 
   @Override
@@ -559,13 +587,13 @@
     }
   }
 
-  private static final class SpeedDialEmptyContentViewClickedListener
+  private static final class SpeedDialContactPermissionEmptyViewListener
       implements OnEmptyViewActionButtonClickedListener {
 
     private final Context context;
     private final Fragment fragment;
 
-    private SpeedDialEmptyContentViewClickedListener(Context context, Fragment fragment) {
+    private SpeedDialContactPermissionEmptyViewListener(Context context, Fragment fragment) {
       this.context = context;
       this.fragment = fragment;
     }
@@ -583,6 +611,22 @@
     }
   }
 
+  private static final class SpeedDialNoContactsEmptyViewListener
+      implements OnEmptyViewActionButtonClickedListener {
+
+    private final Fragment fragment;
+
+    SpeedDialNoContactsEmptyViewListener(Fragment fragment) {
+      this.fragment = fragment;
+    }
+
+    @Override
+    public void onEmptyViewActionButtonClicked() {
+      Intent intent = new Intent(Intent.ACTION_PICK, Phone.CONTENT_URI);
+      fragment.startActivityForResult(intent, ActivityRequestCodes.SPEED_DIAL_ADD_FAVORITE);
+    }
+  }
+
   /** Listener for when a SpeedDialUiItem is updated. */
   private class UpdateSpeedDialAdapterListener {
 
diff --git a/java/com/android/dialer/speeddial/res/values/strings.xml b/java/com/android/dialer/speeddial/res/values/strings.xml
index 7f11119..7f8fed5 100644
--- a/java/com/android/dialer/speeddial/res/values/strings.xml
+++ b/java/com/android/dialer/speeddial/res/values/strings.xml
@@ -65,4 +65,10 @@
 
   <!-- The label of the button used to turn on a single permission [CHAR LIMIT=30]-->
   <string name="speed_dial_turn_on_contacts_permission">Turn on</string>
+
+  <!-- [CHAR LIMIT=NONE] Shown when there are no contacts in the all contacts list. -->
+  <string name="speed_dial_no_contacts_description">You haven\'t added any favorites yet</string>
+
+  <!-- [CHAR LIMIT=NONE] Shown as an action when the all contacts list is empty -->
+  <string name="speed_dial_no_contacts_action_text">Add favorite</string>
 </resources>
\ No newline at end of file