Merge "Settings UI elements for importing VM to block list." into ub-contactsdialer-a-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4db1213..3f4b9e2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -891,48 +891,51 @@
     <!-- DO NOT TRANSLATE. Internal key for DTMF tone length preference. -->
     <string name="dtmf_tone_length_preference_key" translatable="false">button_dtmf_settings</string>
 
-    <!-- The label of the button used to turn on a single permission -->
+    <!-- The label of the button used to turn on a single permission [CHAR LIMIT=30]-->
     <string name="permission_single_turn_on">Turn on</string>
 
-    <!--  The label of the button used to turn on multiple permissions -->
+    <!--  The label of the button used to turn on multiple permissions [CHAR LIMIT=30]-->
     <string name="permission_multiple_turn_on">Set permissions</string>
 
-    <!-- Shown as a prompt to turn on the contacts permission to enable speed dial -->
-    <string name="permission_no_speeddial">To enable speed dial,\n turn on the Contacts permission.</string>
+    <!-- Shown as a prompt to turn on the contacts permission to enable speed dial [CHAR LIMIT=NONE]-->
+    <string name="permission_no_speeddial">To enable speed dial, turn on the Contacts permission.</string>
 
-    <!-- Shown as a prompt to turn on the phone permission to enable the call log -->
-    <string name="permission_no_calllog">To see your call log,\n turn on the Phone permission.</string>
+    <!-- Shown as a prompt to turn on the phone permission to enable the call log [CHAR LIMIT=NONE]-->
+    <string name="permission_no_calllog">To see your call log, turn on the Phone permission.</string>
 
-    <!-- Shown as a prompt to turn on the contacts permission to show all contacts -->
-    <string name="permission_no_contacts">To see your contacts,\n turn on the Contacts permission.</string>
+    <!-- Shown as a prompt to turn on the contacts permission to show all contacts [CHAR LIMIT=NONE]-->
+    <string name="permission_no_contacts">To see your contacts, turn on the Contacts permission.</string>
 
-    <!-- Shown as a prompt to turn on the phone permission to show voicemails -->
-    <string name="permission_no_voicemail">To access your voicemail,\n turn on the Phone permission.</string>
+    <!-- Shown as a prompt to turn on the phone permission to show voicemails [CHAR LIMIT=NONE]-->
+    <string name="permission_no_voicemail">To access your voicemail, turn on the Phone permission.</string>
 
-    <!-- Shown as a prompt to turn on contacts permissions to allow contact search -->
+    <!-- Shown as a prompt to turn on contacts permissions to allow contact search [CHAR LIMIT=NONE]-->
     <string name="permission_no_search">To search your contacts, turn on the Contacts permissions.</string>
 
-    <!-- Shown as a prompt to turn on the phone permission to allow a call to be placed -->
-    <string name="permission_place_call">To place a call,\n turn on the Phone permission.</string>
+    <!-- Shown as a prompt to turn on location permissions and/or enable location to allow nearby places search [CHAR LIMIT=NONE]-->
+    <string name="permission_no_location_for_search">To search nearby locations, allow Phone to access your location.</string>
 
-    <!-- Shown as a message that notifies the user that the Phone app cannot write to system settings, which is why the system settings app is being launched directly instead.-->
+    <!-- Shown as a prompt to turn on the phone permission to allow a call to be placed [CHAR LIMIT=NONE]-->
+    <string name="permission_place_call">To place a call, turn on the Phone permission.</string>
+
+    <!-- Shown as a message that notifies the user that the Phone app cannot write to system settings, which is why the system settings app is being launched directly instead. [CHAR LIMIT=NONE]-->
     <string name="toast_cannot_write_system_settings">Phone app does not have permission to write to system settings.</string>
 
-    <!-- Title of the onboarding screen that asks the user to make Phone the default Phone app -->
+    <!-- Title of the onboarding screen that asks the user to make Phone the default Phone app [CHAR LIMIT=NONE]-->
     <string name="request_default_dialer_screen_title">A better way of calling is calling</string>
 
-    <!-- Content of the onboarding screen that asks the user to make Phone the default Phone app -->
+    <!-- Content of the onboarding screen that asks the user to make Phone the default Phone app [CHAR LIMIT=NONE]-->
     <string name="request_default_dialer_screen_content">Make Phone your default phone app to be able to do things like see who\'s calling you, even when they\'re not in your contacts.</string>
 
-    <!-- Title of the onboarding screen that asks the user to grant us the Contacts and Phone permissions -->
+    <!-- Title of the onboarding screen that asks the user to grant us the Contacts and Phone permissions [CHAR LIMIT=NONE]-->
     <string name="request_permissions_screen_title">Get talking to your friends and family</string>
 
-    <!-- Content of the onboarding screen that asks the user to grant us the Contacts and Phone permissions -->
+    <!-- Content of the onboarding screen that asks the user to grant us the Contacts and Phone permissions [CHAR LIMIT=NONE]-->
     <string name="request_permissions_screen_content">Phone will need to access your phone and contacts to make calls to people in your contacts.</string>
 
-    <!-- The label of the button used to skip a screen in the onboarding flow -->
+    <!-- The label of the button used to skip a screen in the onboarding flow [CHAR LIMIT=30]-->
     <string name="onboarding_skip_button">Skip</string>
 
-    <!-- The label of the button used to go to the next screen in the onboarding flow -->
+    <!-- The label of the button used to go to the next screen in the onboarding flow [CHAR LIMIT=30]-->
     <string name="onboarding_next_button">Next</string>
 </resources>
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index 455b097..4bfd565 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -110,6 +110,7 @@
         ListsFragment.HostInterface,
         SpeedDialFragment.HostInterface,
         SearchFragment.HostInterface,
+        RegularSearchFragment.HostInterface,
         OnDragDropListener,
         OnPhoneNumberPickerActionListener,
         PopupMenu.OnMenuItemClickListener,
@@ -870,6 +871,11 @@
         }
     }
 
+    @Override
+    public boolean isNearbyPlacesSearchEnabled() {
+        return false;
+    }
+
     protected int getSearchBoxHint () {
         return R.string.dialer_hint_find_contact;
     }
diff --git a/src/com/android/dialer/calllog/CallLogGroupBuilder.java b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
index 4cf2d07..5eea096 100644
--- a/src/com/android/dialer/calllog/CallLogGroupBuilder.java
+++ b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
@@ -24,6 +24,7 @@
 
 import com.android.contacts.common.util.DateUtils;
 import com.android.contacts.common.util.PhoneNumberHelper;
+import com.android.dialer.util.AppCompatConstants;
 
 import com.google.common.annotations.VisibleForTesting;
 
@@ -145,10 +146,11 @@
             final boolean isSameAccount = isSameAccount(
                     groupAccountComponentName, accountComponentName, groupAccountId, accountId);
 
-            // Group with the same number and account which are not voicemail.
-            if (isSameNumber && isSameAccount
-                    && (callType != Calls.VOICEMAIL_TYPE)
-                    && (groupCallType != Calls.VOICEMAIL_TYPE)) {
+            // Group with the same number and account. Never group voicemails. Only group blocked
+            // calls with other blocked calls.
+            if (isSameNumber && isSameAccount && areBothNotVoicemail(callType, groupCallType)
+                    && (areBothNotBlocked(callType, groupCallType)
+                            || areBothBlocked(callType, groupCallType))) {
                 // Increment the size of the group to include the current call, but do not create
                 // the group until finding a call that does not match.
                 groupSize++;
@@ -240,4 +242,19 @@
             return DAY_GROUP_OTHER;
         }
     }
+
+    private boolean areBothNotVoicemail(int callType, int groupCallType) {
+        return callType != AppCompatConstants.CALLS_VOICEMAIL_TYPE
+                && groupCallType != AppCompatConstants.CALLS_VOICEMAIL_TYPE;
+    }
+
+    private boolean areBothNotBlocked(int callType, int groupCallType) {
+        return callType != AppCompatConstants.CALLS_BLOCKED_TYPE
+                && groupCallType != AppCompatConstants.CALLS_BLOCKED_TYPE;
+    }
+
+    private boolean areBothBlocked(int callType, int groupCallType) {
+        return callType == AppCompatConstants.CALLS_BLOCKED_TYPE
+                && groupCallType == AppCompatConstants.CALLS_BLOCKED_TYPE;
+    }
 }
diff --git a/src/com/android/dialer/list/RegularSearchFragment.java b/src/com/android/dialer/list/RegularSearchFragment.java
index ec771e8..0b87033 100644
--- a/src/com/android/dialer/list/RegularSearchFragment.java
+++ b/src/com/android/dialer/list/RegularSearchFragment.java
@@ -16,6 +16,7 @@
 package com.android.dialer.list;
 
 import static android.Manifest.permission.READ_CONTACTS;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
 
 import android.app.Activity;
 import android.content.pm.PackageManager;
@@ -36,13 +37,19 @@
 public class RegularSearchFragment extends SearchFragment
         implements OnEmptyViewActionButtonClickedListener {
 
-    private static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 1;
+    private static final int PERMISSION_REQUEST_CODE = 1;
 
     private static final int SEARCH_DIRECTORY_RESULT_LIMIT = 5;
 
     private static final CachedNumberLookupService mCachedNumberLookupService =
         ObjectFactory.newCachedNumberLookupService();
 
+    public interface HostInterface {
+        public boolean isNearbyPlacesSearchEnabled();
+    }
+
+    private String mPermissionToRequest;
+
     public RegularSearchFragment() {
         configureDirectorySearch();
     }
@@ -64,6 +71,7 @@
         ((PinnedHeaderListView) getListView()).setScrollToSectionOnHeaderTouch(true);
     }
 
+    @Override
     protected ContactEntryListAdapter createListAdapter() {
         RegularSearchListAdapter adapter = new RegularSearchListAdapter(getActivity());
         adapter.setDisplayPhotos(true);
@@ -84,15 +92,36 @@
     @Override
     protected void setupEmptyView() {
         if (mEmptyView != null && getActivity() != null) {
+            final int imageResource;
+            final int actionLabelResource;
+            final int descriptionResource;
+            final OnEmptyViewActionButtonClickedListener listener;
             if (!PermissionsUtil.hasPermission(getActivity(), READ_CONTACTS)) {
-                mEmptyView.setImage(R.drawable.empty_contacts);
-                mEmptyView.setActionLabel(R.string.permission_single_turn_on);
-                mEmptyView.setDescription(R.string.permission_no_search);
-                mEmptyView.setActionClickedListener(this);
+                imageResource = R.drawable.empty_contacts;
+                actionLabelResource = R.string.permission_single_turn_on;
+                descriptionResource = R.string.permission_no_search;
+                listener = this;
+                mPermissionToRequest = READ_CONTACTS;
+            } else if (((HostInterface) getActivity()).isNearbyPlacesSearchEnabled()
+                    && !PermissionsUtil.hasPermission(getActivity(), ACCESS_FINE_LOCATION)) {
+                imageResource = R.drawable.empty_contacts;
+                actionLabelResource = R.string.permission_single_turn_on;
+                descriptionResource = R.string.permission_no_location_for_search;
+                listener = this;
+                mPermissionToRequest = ACCESS_FINE_LOCATION;
             } else {
-                mEmptyView.setImage(EmptyContentView.NO_IMAGE);
-                mEmptyView.setActionLabel(EmptyContentView.NO_LABEL);
-                mEmptyView.setDescription(EmptyContentView.NO_LABEL);
+                imageResource = EmptyContentView.NO_IMAGE;
+                actionLabelResource = EmptyContentView.NO_LABEL;
+                descriptionResource = EmptyContentView.NO_LABEL;
+                listener = null;
+                mPermissionToRequest = null;
+            }
+
+            mEmptyView.setImage(imageResource);
+            mEmptyView.setActionLabel(actionLabelResource);
+            mEmptyView.setDescription(descriptionResource);
+            if (listener != null) {
+                mEmptyView.setActionClickedListener(listener);
             }
         }
     }
@@ -104,17 +133,20 @@
             return;
         }
 
-        requestPermissions(new String[] {READ_CONTACTS}, READ_CONTACTS_PERMISSION_REQUEST_CODE);
+        if (READ_CONTACTS.equals(mPermissionToRequest)
+                || ACCESS_FINE_LOCATION.equals(mPermissionToRequest)) {
+            requestPermissions(new String[] {mPermissionToRequest}, PERMISSION_REQUEST_CODE);
+        }
     }
 
     @Override
     public void onRequestPermissionsResult(int requestCode, String[] permissions,
             int[] grantResults) {
-        if (requestCode == READ_CONTACTS_PERMISSION_REQUEST_CODE) {
+        if (requestCode == PERMISSION_REQUEST_CODE) {
             setupEmptyView();
             if (grantResults != null && grantResults.length == 1
                     && PackageManager.PERMISSION_GRANTED == grantResults[0]) {
-                PermissionsUtil.notifyPermissionGranted(getActivity(), READ_CONTACTS);
+                PermissionsUtil.notifyPermissionGranted(getActivity(), mPermissionToRequest);
             }
         }
     }
diff --git a/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java b/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
index f5a9fe6..5d0b6be 100644
--- a/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
@@ -95,7 +95,7 @@
         assertGroupIs(0, 3, mFakeGroupCreator.groups.get(0));
     }
 
-    public void testAddGroups_Voicemail() {
+    public void testGrouping_Voicemail() {
         // Does not group with other types of calls, include voicemail themselves.
         assertCallsAreNotGrouped(
                 AppCompatConstants.CALLS_VOICEMAIL_TYPE, AppCompatConstants.CALLS_MISSED_TYPE);
@@ -107,7 +107,7 @@
                 AppCompatConstants.CALLS_VOICEMAIL_TYPE, AppCompatConstants.CALLS_OUTGOING_TYPE);
     }
 
-    public void testAddGroups_Missed() {
+    public void testGrouping_Missed() {
         // Groups with one or more missed calls.
         assertCallsAreGrouped(
                 AppCompatConstants.CALLS_MISSED_TYPE, AppCompatConstants.CALLS_MISSED_TYPE);
@@ -124,7 +124,7 @@
                 AppCompatConstants.CALLS_MISSED_TYPE, AppCompatConstants.CALLS_OUTGOING_TYPE);
     }
 
-    public void testAddGroups_Incoming() {
+    public void testGrouping_Incoming() {
         // Groups with one or more incoming or outgoing.
         assertCallsAreGrouped(
                 AppCompatConstants.CALLS_INCOMING_TYPE, AppCompatConstants.CALLS_INCOMING_TYPE);
@@ -145,7 +145,7 @@
                 AppCompatConstants.CALLS_INCOMING_TYPE, AppCompatConstants.CALLS_VOICEMAIL_TYPE);
     }
 
-    public void testAddGroups_Outgoing() {
+    public void testGrouping_Outgoing() {
         // Groups with one or more incoming or outgoing.
         assertCallsAreGrouped(
                 AppCompatConstants.CALLS_OUTGOING_TYPE, AppCompatConstants.CALLS_INCOMING_TYPE);
@@ -166,20 +166,31 @@
                 AppCompatConstants.CALLS_INCOMING_TYPE, AppCompatConstants.CALLS_VOICEMAIL_TYPE);
     }
 
+    public void testGrouping_Blocked() {
+        assertCallsAreNotGrouped(
+                AppCompatConstants.CALLS_BLOCKED_TYPE, AppCompatConstants.CALLS_INCOMING_TYPE);
+        assertCallsAreNotGrouped(
+                AppCompatConstants.CALLS_BLOCKED_TYPE, AppCompatConstants.CALLS_OUTGOING_TYPE);
+        assertCallsAreNotGrouped(
+                AppCompatConstants.CALLS_BLOCKED_TYPE, AppCompatConstants.CALLS_MISSED_TYPE);
+
+    }
+
     public void testAddGroups_Mixed() {
         addMultipleCallLogEntries(TEST_NUMBER1,
-                AppCompatConstants.CALLS_VOICEMAIL_TYPE,   // Group 1:Stand-alone
+                AppCompatConstants.CALLS_VOICEMAIL_TYPE,   // Group 1: 0
                 AppCompatConstants.CALLS_INCOMING_TYPE,    // Group 2: 1-4
                 AppCompatConstants.CALLS_OUTGOING_TYPE,
                 AppCompatConstants.CALLS_MISSED_TYPE,
                 AppCompatConstants.CALLS_MISSED_TYPE,
-                AppCompatConstants.CALLS_VOICEMAIL_TYPE,   // Group 3: Stand-alone
-                AppCompatConstants.CALLS_INCOMING_TYPE,    // Group 4: Stand-alone
-                AppCompatConstants.CALLS_VOICEMAIL_TYPE,   // Group 5: Stand-alone
+                AppCompatConstants.CALLS_VOICEMAIL_TYPE,   // Group 3: 5
+                AppCompatConstants.CALLS_INCOMING_TYPE,    // Group 4: 6
+                AppCompatConstants.CALLS_VOICEMAIL_TYPE,   // Group 5: 7
                 AppCompatConstants.CALLS_MISSED_TYPE,      // Group 6: 8-10
                 AppCompatConstants.CALLS_MISSED_TYPE,
                 AppCompatConstants.CALLS_OUTGOING_TYPE);
         mBuilder.addGroups(mCursor);
+
         assertEquals(6, mFakeGroupCreator.groups.size());
         assertGroupIs(0, 1, mFakeGroupCreator.groups.get(0));
         assertGroupIs(1, 4, mFakeGroupCreator.groups.get(1));
@@ -189,6 +200,23 @@
         assertGroupIs(8, 3, mFakeGroupCreator.groups.get(5));
     }
 
+    public void testAddGroups_Blocked() {
+        addMultipleCallLogEntries(TEST_NUMBER1,
+                AppCompatConstants.CALLS_INCOMING_TYPE,     // Group 1: 0-1
+                AppCompatConstants.CALLS_OUTGOING_TYPE,
+                AppCompatConstants.CALLS_BLOCKED_TYPE,      // Group 2: 2
+                AppCompatConstants.CALLS_MISSED_TYPE,       // Group 3: 3
+                AppCompatConstants.CALLS_BLOCKED_TYPE,      // Group 4: 4-5
+                AppCompatConstants.CALLS_BLOCKED_TYPE);
+        mBuilder.addGroups(mCursor);
+
+        assertEquals(4, mFakeGroupCreator.groups.size());
+        assertGroupIs(0, 2, mFakeGroupCreator.groups.get(0));
+        assertGroupIs(2, 1, mFakeGroupCreator.groups.get(1));
+        assertGroupIs(3, 1, mFakeGroupCreator.groups.get(2));
+        assertGroupIs(4, 2, mFakeGroupCreator.groups.get(3));
+    }
+
     public void testEqualPhoneNumbers() {
         // Identical.
         assertTrue(mBuilder.equalNumbers("6505555555", "6505555555"));