Add permission prompts for contacts and dialpad search

Update the following fragments to handle denied permissions
-Contacts Search (Contacts and Location)
-Dialpad Search (Phone)

Tweak and remove some of the onTouch listener logic as they are
no longer valid with the new UI. Instead of intercepting the touches
when the query is empty and returning to the main dialer activity,
allow the fragments to remain on screen if the permission request
UI is showing.

Modify signature of onEmptyViewActionButtonClicked to remove unused
permissions parameter.

Bug: 22174668
Change-Id: I96d00f2ab45df936dca602ac025f723638ac02c4
diff --git a/res/layout/empty_content_view.xml b/res/layout/empty_content_view.xml
index d8f27aa..97ac4c7 100644
--- a/res/layout/empty_content_view.xml
+++ b/res/layout/empty_content_view.xml
@@ -43,7 +43,6 @@
         android:paddingLeft="16dp"
         android:paddingTop="8dp"
         android:paddingBottom="8dp"
-        android:text="@string/permission_single_turn_on"
         android:background="?android:attr/selectableItemBackground"
         android:clickable="true"
         style="@style/TextActionStyle" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 505e491..f07eb62 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -808,8 +808,8 @@
     <!-- 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 contacts and location permissions to allow contact and nearby places search -->
-    <string name="permission_no_search">To search your contacts and nearby locations, turn on the Contacts and Location permissions.</string>
+    <!-- Shown as a prompt to turn on contacts permissions to allow contact search -->
+    <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>
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index 85197a5..98f34b5 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -103,6 +103,7 @@
         DialpadFragment.OnDialpadQueryChangedListener,
         OnListFragmentScrolledListener,
         CallLogFragment.HostInterface,
+        DialpadFragment.HostInterface,
         ListsFragment.HostInterface,
         SpeedDialFragment.HostInterface,
         SearchFragment.HostInterface,
@@ -486,8 +487,6 @@
                     }
                 });
 
-        setupActivityOverlay();
-
         Trace.endSection();
 
         Trace.beginSection(TAG + " initialize smart dialing");
@@ -497,19 +496,6 @@
         Trace.endSection();
     }
 
-    private void setupActivityOverlay() {
-        final View activityOverlay = findViewById(R.id.activity_overlay);
-        activityOverlay.setOnTouchListener(new OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                if (!mIsDialpadShown) {
-                    maybeExitSearchUi();
-                }
-                return false;
-            }
-        });
-    }
-
     @Override
     protected void onResume() {
         Trace.beginSection(TAG + " onResume");
@@ -1147,7 +1133,16 @@
         } catch (Exception ignored) {
             // Skip any exceptions for this piece of code
         }
+    }
 
+    @Override
+    public boolean onDialpadSpacerTouchWithEmptyQuery() {
+        if (mInDialpadSearch && mSmartDialSearchFragment != null
+                && !mSmartDialSearchFragment.isShowingPermissionRequest()) {
+            hideDialpadFragment(true /* animate */, true /* clearDialpad */);
+            return true;
+        }
+        return false;
     }
 
     @Override
diff --git a/src/com/android/dialer/calllog/CallLogFragment.java b/src/com/android/dialer/calllog/CallLogFragment.java
index d1a9827..59e2c7f 100644
--- a/src/com/android/dialer/calllog/CallLogFragment.java
+++ b/src/com/android/dialer/calllog/CallLogFragment.java
@@ -486,7 +486,7 @@
     }
 
     @Override
-    public void onEmptyViewActionButtonClicked(String[] permissions) {
+    public void onEmptyViewActionButtonClicked() {
         final Activity activity = getActivity();
         if (activity == null) {
             return;
diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java
index b18069f..d35abd7 100644
--- a/src/com/android/dialer/dialpad/DialpadFragment.java
+++ b/src/com/android/dialer/dialpad/DialpadFragment.java
@@ -135,6 +135,15 @@
         void onDialpadQueryChanged(String query);
     }
 
+    public interface HostInterface {
+        /**
+         * Notifies the parent activity that the space above the dialpad has been tapped with
+         * no query in the dialpad present. In most situations this will cause the dialpad to
+         * be dismissed, unless there happens to be content showing.
+         */
+        boolean onDialpadSpacerTouchWithEmptyQuery();
+    }
+
     private static final boolean DEBUG = DialtactsActivity.DEBUG;
 
     // This is the amount of screen the dialpad fragment takes up when fully displayed
@@ -385,7 +394,9 @@
             @Override
             public boolean onTouch(View v, MotionEvent event) {
                 if (isDigitsEmpty()) {
-                    hideAndClearDialpad(true);
+                    if (getActivity() != null) {
+                        return ((HostInterface) getActivity()).onDialpadSpacerTouchWithEmptyQuery();
+                    }
                     return true;
                 }
                 return false;
diff --git a/src/com/android/dialer/list/AllContactsFragment.java b/src/com/android/dialer/list/AllContactsFragment.java
index 19d8a43..0de8434 100644
--- a/src/com/android/dialer/list/AllContactsFragment.java
+++ b/src/com/android/dialer/list/AllContactsFragment.java
@@ -133,7 +133,7 @@
     }
 
     @Override
-    public void onEmptyViewActionButtonClicked(String[] permissions) {
+    public void onEmptyViewActionButtonClicked() {
         final Activity activity = getActivity();
         if (activity == null) {
             return;
diff --git a/src/com/android/dialer/list/RegularSearchFragment.java b/src/com/android/dialer/list/RegularSearchFragment.java
index 19c7321..b7e26d6 100644
--- a/src/com/android/dialer/list/RegularSearchFragment.java
+++ b/src/com/android/dialer/list/RegularSearchFragment.java
@@ -15,16 +15,29 @@
  */
 package com.android.dialer.list;
 
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.READ_CONTACTS;
+
+import android.app.Activity;
+import android.content.pm.PackageManager;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
 
 import com.android.contacts.common.list.ContactEntryListAdapter;
 import com.android.contacts.common.list.PinnedHeaderListView;
+import com.android.contacts.common.util.PermissionsUtil;
 import com.android.contacts.commonbind.analytics.AnalyticsUtil;
 import com.android.dialerbind.ObjectFactory;
-import com.android.dialer.service.CachedNumberLookupService;
 
-public class RegularSearchFragment extends SearchFragment {
+import com.android.dialer.R;
+import com.android.dialer.service.CachedNumberLookupService;
+import com.android.dialer.widget.EmptyContentView;
+import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener;
+
+public class RegularSearchFragment extends SearchFragment
+        implements OnEmptyViewActionButtonClickedListener {
+
+    private static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 1;
 
     private static final int SEARCH_DIRECTORY_RESULT_LIMIT = 5;
 
@@ -68,4 +81,38 @@
                     adapter.getContactInfo(mCachedNumberLookupService, position));
         }
     }
+
+    @Override
+    protected void setupEmptyView() {
+        if (mEmptyView != null && getActivity() != null) {
+            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);
+            } else {
+                mEmptyView.setImage(EmptyContentView.NO_IMAGE);
+                mEmptyView.setActionLabel(EmptyContentView.NO_LABEL);
+                mEmptyView.setDescription(EmptyContentView.NO_LABEL);
+            }
+        }
+    }
+
+    @Override
+    public void onEmptyViewActionButtonClicked() {
+        final Activity activity = getActivity();
+        if (activity == null) {
+            return;
+        }
+
+        requestPermissions(new String[] {READ_CONTACTS}, READ_CONTACTS_PERMISSION_REQUEST_CODE);
+    }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, String[] permissions,
+            int[] grantResults) {
+        if (requestCode == READ_CONTACTS_PERMISSION_REQUEST_CODE) {
+            setupEmptyView();
+        }
+    }
 }
diff --git a/src/com/android/dialer/list/SearchFragment.java b/src/com/android/dialer/list/SearchFragment.java
index 77ab291..315cfb9 100644
--- a/src/com/android/dialer/list/SearchFragment.java
+++ b/src/com/android/dialer/list/SearchFragment.java
@@ -15,6 +15,8 @@
  */
 package com.android.dialer.list;
 
+import static android.Manifest.permission.READ_CONTACTS;
+
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.animation.AnimatorListenerAdapter;
@@ -50,6 +52,7 @@
 import com.android.dialer.R;
 import com.android.dialer.util.DialerUtils;
 import com.android.dialer.util.IntentUtil;
+import com.android.dialer.widget.EmptyContentView;
 import com.android.phone.common.animation.AnimUtils;
 
 public class SearchFragment extends PhoneNumberPickerFragment {
@@ -79,6 +82,8 @@
 
     private HostInterface mActivity;
 
+    protected EmptyContentView mEmptyView;
+
     public interface HostInterface {
         public boolean isActionBarShowing();
         public boolean isDialpadShown();
@@ -125,6 +130,13 @@
 
         final ListView listView = getListView();
 
+        if (mEmptyView == null) {
+            mEmptyView = new EmptyContentView(getActivity());
+            ((ViewGroup) getListView().getParent()).addView(mEmptyView);
+            getListView().setEmptyView(mEmptyView);
+            setupEmptyView();
+        }
+
         listView.setBackgroundColor(res.getColor(R.color.background_dialer_results));
         listView.setClipToPadding(false);
         setVisibleScrollbarEnabled(false);
@@ -341,7 +353,7 @@
 
     @Override
     protected void startLoading() {
-        if (PermissionsUtil.hasContactsPermissions(getActivity())) {
+        if (PermissionsUtil.hasPermission(getActivity(), READ_CONTACTS)) {
             super.startLoading();
         } else if (TextUtils.isEmpty(getQueryString())) {
             // Clear out any existing call shortcuts.
@@ -354,6 +366,8 @@
             // list.
             getAdapter().notifyDataSetChanged();
         }
+
+        setupEmptyView();
     }
 
     public void setOnTouchListener(View.OnTouchListener onTouchListener) {
@@ -371,4 +385,6 @@
         }
         return parent;
     }
+
+    protected void setupEmptyView() {}
 }
diff --git a/src/com/android/dialer/list/SmartDialSearchFragment.java b/src/com/android/dialer/list/SmartDialSearchFragment.java
index 082bc43..72d3abf 100644
--- a/src/com/android/dialer/list/SmartDialSearchFragment.java
+++ b/src/com/android/dialer/list/SmartDialSearchFragment.java
@@ -15,21 +15,33 @@
  */
 package com.android.dialer.list;
 
+import static android.Manifest.permission.CALL_PHONE;
+
+import android.app.Activity;
 import android.content.Loader;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.Log;
+import android.view.View;
 
 import com.android.contacts.common.list.ContactEntryListAdapter;
+import com.android.contacts.common.util.PermissionsUtil;
 import com.android.dialer.dialpad.SmartDialCursorLoader;
+import com.android.dialer.R;
+import com.android.dialer.widget.EmptyContentView;
+
+import java.util.ArrayList;
 
 /**
  * Implements a fragment to load and display SmartDial search results.
  */
-public class SmartDialSearchFragment extends SearchFragment {
+public class SmartDialSearchFragment extends SearchFragment
+        implements EmptyContentView.OnEmptyViewActionButtonClickedListener {
     private static final String TAG = SmartDialSearchFragment.class.getSimpleName();
 
+    private static final int CALL_PHONE_PERMISSION_REQUEST_CODE = 1;
+
     /**
      * Creates a SmartDialListAdapter to display and operate on search results.
      */
@@ -69,4 +81,42 @@
         final SmartDialNumberListAdapter adapter = (SmartDialNumberListAdapter) getAdapter();
         return adapter.getDataUri(position);
     }
+
+    @Override
+    protected void setupEmptyView() {
+        if (mEmptyView != null && getActivity() != null) {
+            if (!PermissionsUtil.hasPermission(getActivity(), CALL_PHONE)) {
+                mEmptyView.setImage(R.drawable.empty_contacts);
+                mEmptyView.setActionLabel(R.string.permission_single_turn_on);
+                mEmptyView.setDescription(R.string.permission_place_call);
+                mEmptyView.setActionClickedListener(this);
+            } else {
+                mEmptyView.setImage(EmptyContentView.NO_IMAGE);
+                mEmptyView.setActionLabel(EmptyContentView.NO_LABEL);
+                mEmptyView.setDescription(EmptyContentView.NO_LABEL);
+            }
+        }
+    }
+
+    @Override
+    public void onEmptyViewActionButtonClicked() {
+        final Activity activity = getActivity();
+        if (activity == null) {
+            return;
+        }
+
+        requestPermissions(new String[] {CALL_PHONE}, CALL_PHONE_PERMISSION_REQUEST_CODE);
+    }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, String[] permissions,
+            int[] grantResults) {
+        if (requestCode == CALL_PHONE_PERMISSION_REQUEST_CODE) {
+            setupEmptyView();
+        }
+    }
+
+    public boolean isShowingPermissionRequest() {
+        return mEmptyView != null && mEmptyView.isShowingContent();
+    }
 }
diff --git a/src/com/android/dialer/list/SpeedDialFragment.java b/src/com/android/dialer/list/SpeedDialFragment.java
index aead1c8..ebfc72d 100644
--- a/src/com/android/dialer/list/SpeedDialFragment.java
+++ b/src/com/android/dialer/list/SpeedDialFragment.java
@@ -463,7 +463,7 @@
     }
 
     @Override
-    public void onEmptyViewActionButtonClicked(String[] permissions) {
+    public void onEmptyViewActionButtonClicked() {
         final Activity activity = getActivity();
         if (activity == null) {
             return;
diff --git a/src/com/android/dialer/widget/EmptyContentView.java b/src/com/android/dialer/widget/EmptyContentView.java
index 67c9ce1..2f5e0d9 100644
--- a/src/com/android/dialer/widget/EmptyContentView.java
+++ b/src/com/android/dialer/widget/EmptyContentView.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
@@ -29,15 +30,15 @@
 public class EmptyContentView extends LinearLayout implements View.OnClickListener {
 
     public static final int NO_LABEL = 0;
+    public static final int NO_IMAGE = 0;
 
     private ImageView mImageView;
     private TextView mDescriptionView;
     private TextView mActionView;
-    private String[] mPermissions = new String[] {};
     private OnEmptyViewActionButtonClickedListener mOnActionButtonClickedListener;
 
     public interface OnEmptyViewActionButtonClickedListener {
-        public void onEmptyViewActionButtonClicked(String[] permissions);
+        public void onEmptyViewActionButtonClicked();
     }
 
     public EmptyContentView(Context context) {
@@ -60,11 +61,6 @@
         final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         inflater.inflate(R.layout.empty_content_view, this);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
         mImageView = (ImageView) findViewById(R.id.emptyListViewImage);
         mDescriptionView = (TextView) findViewById(R.id.emptyListViewMessage);
         mActionView = (TextView) findViewById(R.id.emptyListViewAction);
@@ -72,11 +68,22 @@
     }
 
     public void setDescription(int resourceId) {
-        mDescriptionView.setText(resourceId);
+        if (resourceId == NO_LABEL) {
+            mDescriptionView.setText(null);
+            mDescriptionView.setVisibility(View.GONE);
+        } else {
+            mDescriptionView.setText(resourceId);
+            mDescriptionView.setVisibility(View.VISIBLE);
+        }
     }
 
     public void setImage(int resourceId) {
         mImageView.setImageResource(resourceId);
+        if (resourceId == NO_LABEL) {
+            mImageView.setVisibility(View.GONE);
+        } else {
+            mImageView.setVisibility(View.VISIBLE);
+        }
     }
 
     public void setActionLabel(int resourceId) {
@@ -89,6 +96,12 @@
         }
     }
 
+    public boolean isShowingContent() {
+        return mImageView.getVisibility() == View.VISIBLE
+                || mDescriptionView.getVisibility() == View.VISIBLE
+                || mActionView.getVisibility() == View.VISIBLE;
+    }
+
     public void setActionClickedListener(OnEmptyViewActionButtonClickedListener listener) {
         mOnActionButtonClickedListener = listener;
     }
@@ -96,7 +109,7 @@
     @Override
     public void onClick(View v) {
         if (mOnActionButtonClickedListener != null) {
-            mOnActionButtonClickedListener.onEmptyViewActionButtonClicked(mPermissions);
+            mOnActionButtonClickedListener.onEmptyViewActionButtonClicked();
         }
     }
 }