Merge changes Iae86dabb,I1db81304
am: a109ed80be

Change-Id: Idaac7535bce9af699df26c9c81575db491c69ad4
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java
index b8fd571..37b241b 100644
--- a/java/com/android/dialer/app/DialtactsActivity.java
+++ b/java/com/android/dialer/app/DialtactsActivity.java
@@ -1454,6 +1454,12 @@
   }
 
   @Override
+  public boolean shouldShowDialpadChooser() {
+    // Show the dialpad chooser if we're in a call
+    return true;
+  }
+
+  @Override
   public void onSearchListTouch() {
     if (isDialpadShown) {
       PerformanceReport.recordClick(UiAction.Type.CLOSE_DIALPAD);
diff --git a/java/com/android/dialer/app/calllog/CallLogFragment.java b/java/com/android/dialer/app/calllog/CallLogFragment.java
index 11c2499..7e49cc9 100644
--- a/java/com/android/dialer/app/calllog/CallLogFragment.java
+++ b/java/com/android/dialer/app/calllog/CallLogFragment.java
@@ -222,18 +222,6 @@
     final Activity activity = getActivity();
     final ContentResolver resolver = activity.getContentResolver();
     callLogQueryHandler = new CallLogQueryHandler(activity, resolver, this, logLimit);
-
-    if (PermissionsUtil.hasCallLogReadPermissions(getContext())) {
-      resolver.registerContentObserver(CallLog.CONTENT_URI, true, callLogObserver);
-    } else {
-      LogUtil.w("CallLogFragment.onCreate", "call log permission not available");
-    }
-    if (PermissionsUtil.hasContactsReadPermissions(getContext())) {
-      resolver.registerContentObserver(
-          ContactsContract.Contacts.CONTENT_URI, true, contactsObserver);
-    } else {
-      LogUtil.w("CallLogFragment.onCreate", "contacts permission not available.");
-    }
     setHasOptionsMenu(true);
   }
 
@@ -412,6 +400,19 @@
       updateEmptyMessage(callTypeFilter);
     }
 
+    ContentResolver resolver = getActivity().getContentResolver();
+    if (PermissionsUtil.hasCallLogReadPermissions(getContext())) {
+      resolver.registerContentObserver(CallLog.CONTENT_URI, true, callLogObserver);
+    } else {
+      LogUtil.w("CallLogFragment.onCreate", "call log permission not available");
+    }
+    if (PermissionsUtil.hasContactsReadPermissions(getContext())) {
+      resolver.registerContentObserver(
+          ContactsContract.Contacts.CONTENT_URI, true, contactsObserver);
+    } else {
+      LogUtil.w("CallLogFragment.onCreate", "contacts permission not available.");
+    }
+
     this.hasReadCallLogPermission = hasReadCallLogPermission;
 
     /*
@@ -432,6 +433,8 @@
   @Override
   public void onPause() {
     LogUtil.enterBlock("CallLogFragment.onPause");
+    getActivity().getContentResolver().unregisterContentObserver(callLogObserver);
+    getActivity().getContentResolver().unregisterContentObserver(contactsObserver);
     if (getUserVisibleHint()) {
       onNotVisible();
     }
@@ -465,9 +468,6 @@
     if (adapter != null) {
       adapter.changeCursor(null);
     }
-
-    getActivity().getContentResolver().unregisterContentObserver(callLogObserver);
-    getActivity().getContentResolver().unregisterContentObserver(contactsObserver);
     super.onDestroy();
   }
 
diff --git a/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java b/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java
index 364736e..f24bb1c 100644
--- a/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java
+++ b/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java
@@ -26,7 +26,6 @@
 import com.android.dialer.blockreportspam.BlockReportSpamDialogs.OnSpamDialogClickListener;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.logging.ContactSource;
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
 import com.android.dialer.protos.ProtoParsers;
@@ -109,7 +108,7 @@
                 dialogInfo.getCountryIso(),
                 dialogInfo.getCallType(),
                 dialogInfo.getReportingLocation(),
-                ContactSource.Type.UNKNOWN_SOURCE_TYPE /* TODO(a bug): Fix. */);
+                dialogInfo.getContactSource());
           }
 
           // TODO(a bug): Block the number.
@@ -154,7 +153,7 @@
                 dialogInfo.getCountryIso(),
                 dialogInfo.getCallType(),
                 dialogInfo.getReportingLocation(),
-                ContactSource.Type.UNKNOWN_SOURCE_TYPE /* TODO(a bug): Fix. */);
+                dialogInfo.getContactSource());
           }
         };
 
diff --git a/java/com/android/dialer/blockreportspam/block_report_spam_dialog_info.proto b/java/com/android/dialer/blockreportspam/block_report_spam_dialog_info.proto
index 3c5a616..70872c7 100644
--- a/java/com/android/dialer/blockreportspam/block_report_spam_dialog_info.proto
+++ b/java/com/android/dialer/blockreportspam/block_report_spam_dialog_info.proto
@@ -7,11 +7,12 @@
 
 package com.android.dialer.blockreportspam;
 
+import "java/com/android/dialer/logging/contact_source.proto";
 import "java/com/android/dialer/logging/reporting_location.proto";
 
 // Contains information needed in dialogs that allow a user to block a number
 // and/or report it as spam/not spam.
-// Next ID: 5
+// Next ID: 6
 message BlockReportSpamDialogInfo {
   // A dialer-normalized version of the number used in the dialogs.
   // See DialerPhoneNumber#normalized_number.
@@ -27,4 +28,7 @@
   // The location where the number is reported.
   optional com.android.dialer.logging.ReportingLocation.Type
       reporting_location = 4;
+
+  // The source where contact info is associated with the number.
+  optional com.android.dialer.logging.ContactSource.Type contact_source = 5;
 }
\ No newline at end of file
diff --git a/java/com/android/dialer/calllog/database/contract/number_attributes.proto b/java/com/android/dialer/calllog/database/contract/number_attributes.proto
index 594e676..e24f393 100644
--- a/java/com/android/dialer/calllog/database/contract/number_attributes.proto
+++ b/java/com/android/dialer/calllog/database/contract/number_attributes.proto
@@ -21,8 +21,10 @@
 
 package com.android.dialer;
 
+import "java/com/android/dialer/logging/contact_source.proto";
+
 // Information related to the phone number of the call.
-// Next ID: 12
+// Next ID: 13
 message NumberAttributes {
   // The name (which may be a person's name or business name, but not a number)
   // formatted exactly as it should appear to the user. If the user's locale or
@@ -65,4 +67,7 @@
 
   // Whether the number is spam.
   optional bool is_spam = 11;
+
+  // Source of the contact associated with the number.
+  optional com.android.dialer.logging.ContactSource.Type contact_source = 12;
 }
\ No newline at end of file
diff --git a/java/com/android/dialer/calllog/ui/menu/Modules.java b/java/com/android/dialer/calllog/ui/menu/Modules.java
index 9df1223..184f7ab 100644
--- a/java/com/android/dialer/calllog/ui/menu/Modules.java
+++ b/java/com/android/dialer/calllog/ui/menu/Modules.java
@@ -90,6 +90,7 @@
               .setCountryIso(row.number().getCountryIso())
               .setCallType(row.callType())
               .setReportingLocation(ReportingLocation.Type.CALL_LOG_HISTORY)
+              .setContactSource(row.numberAttributes().getContactSource())
               .build();
       modules.addAll(
           SharedModules.createModulesHandlingBlockedOrSpamNumber(
diff --git a/java/com/android/dialer/calllogutils/NumberAttributesConverter.java b/java/com/android/dialer/calllogutils/NumberAttributesConverter.java
index ceb8d57..a9376bb 100644
--- a/java/com/android/dialer/calllogutils/NumberAttributesConverter.java
+++ b/java/com/android/dialer/calllogutils/NumberAttributesConverter.java
@@ -56,6 +56,7 @@
         .setIsBlocked(phoneLookupInfoConsolidator.isBlocked())
         .setIsSpam(phoneLookupInfoConsolidator.isSpam())
         .setCanReportAsInvalidNumber(phoneLookupInfoConsolidator.canReportAsInvalidNumber())
-        .setIsCp2InfoIncomplete(phoneLookupInfoConsolidator.isDefaultCp2InfoIncomplete());
+        .setIsCp2InfoIncomplete(phoneLookupInfoConsolidator.isDefaultCp2InfoIncomplete())
+        .setContactSource(phoneLookupInfoConsolidator.getContactSource());
   }
 }
diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java
index 6801590..f093332 100644
--- a/java/com/android/dialer/dialpadview/DialpadFragment.java
+++ b/java/com/android/dialer/dialpadview/DialpadFragment.java
@@ -1312,7 +1312,9 @@
    *     or ringing or dialing, or on hold).
    */
   private boolean isPhoneInUse() {
-    return getContext() != null && TelecomUtil.isInManagedCall(getContext());
+    return getContext() != null
+        && TelecomUtil.isInManagedCall(getContext())
+        && FragmentUtils.getParentUnsafe(this, HostInterface.class).shouldShowDialpadChooser();
   }
 
   /** @return true if the phone is a CDMA phone type */
@@ -1584,6 +1586,9 @@
      * unless there happens to be content showing.
      */
     boolean onDialpadSpacerTouchWithEmptyQuery();
+
+    /** Returns true if this fragment's parent want the dialpad to show the dialpad chooser. */
+    boolean shouldShowDialpadChooser();
   }
 
   /**
diff --git a/java/com/android/dialer/main/impl/OldMainActivityPeer.java b/java/com/android/dialer/main/impl/OldMainActivityPeer.java
index 2999c6b..ee0dad5 100644
--- a/java/com/android/dialer/main/impl/OldMainActivityPeer.java
+++ b/java/com/android/dialer/main/impl/OldMainActivityPeer.java
@@ -651,6 +651,12 @@
       // No-op, just let the clicks fall through to the search list
       return false;
     }
+
+    @Override
+    public boolean shouldShowDialpadChooser() {
+      // Never show the dialpad chooser. Ever.
+      return false;
+    }
   }
 
   /** @see CallLogAdapter.OnActionModeStateChangedListener */
diff --git a/java/com/android/dialer/main/impl/toolbar/MainToolbar.java b/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
index fc4bd03..2f36717 100644
--- a/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
+++ b/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
@@ -19,6 +19,7 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
+import android.support.annotation.NonNull;
 import android.support.annotation.StringRes;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
@@ -66,9 +67,9 @@
     return listener.onMenuItemClicked(menuItem);
   }
 
-  public void setSearchBarListener(SearchBarListener listener) {
-    this.listener = listener;
-    ((SearchBarView) findViewById(R.id.search_view_container)).setSearchBarListener(listener);
+  public void setSearchBarListener(@NonNull SearchBarListener listener) {
+    this.listener = Assert.isNotNull(listener);
+    searchBar.setSearchBarListener(listener);
   }
 
   /** Slides the toolbar up and off the screen. */
diff --git a/java/com/android/dialer/main/impl/toolbar/SearchBarView.java b/java/com/android/dialer/main/impl/toolbar/SearchBarView.java
index 78cabf7..2999850 100644
--- a/java/com/android/dialer/main/impl/toolbar/SearchBarView.java
+++ b/java/com/android/dialer/main/impl/toolbar/SearchBarView.java
@@ -32,6 +32,7 @@
 import android.widget.FrameLayout;
 import android.widget.TextView;
 import com.android.dialer.animation.AnimUtils;
+import com.android.dialer.common.Assert;
 import com.android.dialer.common.UiUtil;
 import com.android.dialer.util.DialerUtils;
 import com.google.common.base.Optional;
@@ -188,8 +189,8 @@
     requestLayout();
   }
 
-  /* package-private */ void setSearchBarListener(SearchBarListener listener) {
-    this.listener = listener;
+  /* package-private */ void setSearchBarListener(@NonNull SearchBarListener listener) {
+    this.listener = Assert.isNotNull(listener);
   }
 
   public String getQuery() {
@@ -236,7 +237,15 @@
         return;
       }
 
-      listener.onSearchQueryUpdated(s.toString());
+      // afterTextChanged is called each time the device is rotated (or the activity is recreated).
+      // That means that this method could potentially be called before the listener is set and
+      // we should check if it's null. In the case that it is null, assert that the query is empty
+      // because the listener must be notified of non-empty queries.
+      if (listener != null) {
+        listener.onSearchQueryUpdated(s.toString());
+      } else {
+        Assert.checkArgument(TextUtils.isEmpty(s.toString()));
+      }
     }
   }
 }
diff --git a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java
index 3a48fd5..6e86756 100644
--- a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java
+++ b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java
@@ -18,6 +18,7 @@
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
 import com.android.dialer.common.Assert;
+import com.android.dialer.logging.ContactSource;
 import com.android.dialer.phonelookup.PhoneLookup;
 import com.android.dialer.phonelookup.PhoneLookupInfo;
 import com.android.dialer.phonelookup.PhoneLookupInfo.BlockedState;
@@ -91,6 +92,39 @@
   }
 
   /**
+   * Returns a {@link com.android.dialer.logging.ContactSource.Type} representing the source from
+   * which info is used to display contact info in the UI.
+   */
+  public ContactSource.Type getContactSource() {
+    switch (nameSource) {
+      case NameSource.CP2_DEFAULT_DIRECTORY:
+        return ContactSource.Type.SOURCE_TYPE_DIRECTORY;
+      case NameSource.CP2_EXTENDED_DIRECTORY:
+        return ContactSource.Type.SOURCE_TYPE_EXTENDED;
+      case NameSource.PEOPLE_API:
+        return getRefinedPeopleApiSource();
+      case NameSource.NONE:
+        return ContactSource.Type.UNKNOWN_SOURCE_TYPE;
+      default:
+        throw Assert.createUnsupportedOperationFailException(
+            String.format("Unsupported name source: %s", nameSource));
+    }
+  }
+
+  private ContactSource.Type getRefinedPeopleApiSource() {
+    Assert.checkState(nameSource == NameSource.PEOPLE_API);
+
+    switch (phoneLookupInfo.getPeopleApiInfo().getInfoType()) {
+      case CONTACT:
+        return ContactSource.Type.SOURCE_TYPE_PROFILE;
+      case NEARBY_BUSINESS:
+        return ContactSource.Type.SOURCE_TYPE_PLACES;
+      default:
+        return ContactSource.Type.SOURCE_TYPE_REMOTE_OTHER;
+    }
+  }
+
+  /**
    * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method
    * returns the name associated with that number.
    *
diff --git a/java/com/android/dialer/voicemail/listui/menu/Modules.java b/java/com/android/dialer/voicemail/listui/menu/Modules.java
index cc7bcbe..c3c883c 100644
--- a/java/com/android/dialer/voicemail/listui/menu/Modules.java
+++ b/java/com/android/dialer/voicemail/listui/menu/Modules.java
@@ -71,6 +71,7 @@
             .setCountryIso(voicemailEntry.number().getCountryIso())
             .setCallType(voicemailEntry.callType())
             .setReportingLocation(ReportingLocation.Type.VOICEMAIL_HISTORY)
+            .setContactSource(voicemailEntry.numberAttributes().getContactSource())
             .build();
     modules.addAll(
         SharedModules.createModulesHandlingBlockedOrSpamNumber(