summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/searchfragment
diff options
context:
space:
mode:
authorcalderwoodra <calderwoodra@google.com>2017-09-20 14:03:33 -0700
committerEric Erfanian <erfanian@google.com>2017-09-22 15:55:15 +0000
commitf7d8f63913c8d1e83ee379cbf60077f02c978cad (patch)
tree8ef43661758ddd74f6e0ec563bc3801006fcdeb5 /java/com/android/dialer/searchfragment
parent81643679f629176a6e79e6b3f08ad0a78f426935 (diff)
Added location permission request inline the search fragment.
This change adds a prompt inline the search fragment list view to request the location permission (if they haven't already granted it). screenshot: http://screen/upu9t55mghq Bug: 65858857 Test: NSFT, SAT, SCMT PiperOrigin-RevId: 169447095 Change-Id: I6c312057ff3c4e2362ce21b0c57e1e5de7b25ce0
Diffstat (limited to 'java/com/android/dialer/searchfragment')
-rw-r--r--java/com/android/dialer/searchfragment/list/NewSearchFragment.java25
-rw-r--r--java/com/android/dialer/searchfragment/list/SearchAdapter.java44
-rw-r--r--java/com/android/dialer/searchfragment/list/SearchCursorManager.java66
-rw-r--r--java/com/android/dialer/searchfragment/nearbyplaces/res/layout/location_permission_row.xml51
4 files changed, 180 insertions, 6 deletions
diff --git a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
index 3cf8fb5b9..1dbd953dd 100644
--- a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
+++ b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
@@ -16,6 +16,8 @@
package com.android.dialer.searchfragment.list;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+
import android.app.Fragment;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Loader;
@@ -76,6 +78,7 @@ public final class NewSearchFragment extends Fragment
private static final String KEY_SHOW_ZERO_SUGGEST = "use_zero_suggest";
@VisibleForTesting public static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 1;
+ @VisibleForTesting private static final int LOCATION_PERMISSION_REQUEST_CODE = 2;
private static final int CONTACTS_LOADER_ID = 0;
private static final int NEARBY_PLACES_LOADER_ID = 1;
@@ -279,6 +282,12 @@ public final class NewSearchFragment extends Fragment
emptyContentView.setVisibility(View.GONE);
initLoaders();
}
+ } else if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
+ if (grantResults.length >= 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) {
+ // Force a refresh of the data since we were missing the permission before this.
+ loadNearbyPlacesCursor();
+ adapter.hideLocationPermissionRequest();
+ }
}
}
@@ -317,6 +326,12 @@ public final class NewSearchFragment extends Fragment
// Should not be called before remote directories (not contacts) have finished loading.
private void loadNearbyPlacesCursor() {
+ if (!PermissionsUtil.hasLocationPermissions(getContext())) {
+ if (adapter != null) {
+ adapter.showLocationPermissionRequest(v -> requestLocationPermission());
+ }
+ return;
+ }
// Cancel existing load if one exists.
ThreadUtil.getUiThreadHandler().removeCallbacks(loadNearbyPlacesRunnable);
@@ -328,6 +343,16 @@ public final class NewSearchFragment extends Fragment
.postDelayed(loadNearbyPlacesRunnable, NETWORK_SEARCH_DELAY_MILLIS);
}
+ private void requestLocationPermission() {
+ Assert.checkArgument(
+ !PermissionsUtil.hasPermission(getContext(), ACCESS_FINE_LOCATION),
+ "attempted to request already granted location permission");
+ String[] deniedPermissions =
+ PermissionsUtil.getPermissionsCurrentlyDenied(
+ getContext(), PermissionsUtil.allLocationGroupPermissionsUsedInDialer);
+ requestPermissions(deniedPermissions, LOCATION_PERMISSION_REQUEST_CODE);
+ }
+
@Override
public void onResume() {
super.onResume();
diff --git a/java/com/android/dialer/searchfragment/list/SearchAdapter.java b/java/com/android/dialer/searchfragment/list/SearchAdapter.java
index d4b5cf29d..358a59a41 100644
--- a/java/com/android/dialer/searchfragment/list/SearchAdapter.java
+++ b/java/com/android/dialer/searchfragment/list/SearchAdapter.java
@@ -23,6 +23,8 @@ import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.TextUtils;
import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import com.android.dialer.callcomposer.CallComposerActivity;
import com.android.dialer.callintent.CallInitiationType;
@@ -54,6 +56,7 @@ public final class SearchAdapter extends RecyclerView.Adapter<ViewHolder>
private boolean showZeroSuggest;
private String query;
private CallInitiationType.Type callInitiationType = CallInitiationType.Type.UNKNOWN_INITIATION;
+ private OnClickListener locationRequestClickListener;
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public SearchAdapter(Activity activity, SearchCursorManager searchCursorManager) {
@@ -81,6 +84,10 @@ public final class SearchAdapter extends RecyclerView.Adapter<ViewHolder>
case RowType.SEARCH_ACTION:
return new SearchActionViewHolder(
LayoutInflater.from(activity).inflate(R.layout.search_action_layout, root, false));
+ case RowType.LOCATION_REQUEST:
+ return new LocationPermissionViewHolder(
+ LayoutInflater.from(activity).inflate(R.layout.location_permission_row, root, false),
+ locationRequestClickListener);
case RowType.INVALID:
default:
throw Assert.createIllegalStateFailException("Invalid RowType: " + rowType);
@@ -107,6 +114,8 @@ public final class SearchAdapter extends RecyclerView.Adapter<ViewHolder>
} else if (holder instanceof SearchActionViewHolder) {
((SearchActionViewHolder) holder)
.setAction(searchCursorManager.getSearchAction(position), position, query);
+ } else if (holder instanceof LocationPermissionViewHolder) {
+ // No-op
} else {
throw Assert.createIllegalStateFailException("Invalid ViewHolder: " + holder);
}
@@ -165,6 +174,28 @@ public final class SearchAdapter extends RecyclerView.Adapter<ViewHolder>
}
}
+ /**
+ * Updates the adapter to show the location request row element. If the element was previously
+ * hidden, the adapter will call {@link #notifyDataSetChanged()}.
+ */
+ public void showLocationPermissionRequest(OnClickListener clickListener) {
+ Assert.isNotNull(locationRequestClickListener = clickListener);
+ if (searchCursorManager.showLocationPermissionRequest(true)) {
+ notifyDataSetChanged();
+ }
+ }
+
+ /**
+ * Updates the adapter to hide the location request row element. If the element was previously
+ * visible, the adapter will call {@link #notifyDataSetChanged()}.
+ */
+ void hideLocationPermissionRequest() {
+ locationRequestClickListener = null;
+ if (searchCursorManager.showLocationPermissionRequest(false)) {
+ notifyDataSetChanged();
+ }
+ }
+
public void setRemoteContactsCursor(SearchCursor remoteContactsCursor) {
if (searchCursorManager.setCorpDirectoryCursor(remoteContactsCursor)) {
notifyDataSetChanged();
@@ -207,4 +238,17 @@ public final class SearchAdapter extends RecyclerView.Adapter<ViewHolder>
Intent intent = CallComposerActivity.newIntent(activity, contact);
DialerUtils.startActivityWithErrorToast(activity, intent);
}
+
+ /** Viewholder for R.layout.location_permission_row that requests the location permission. */
+ private static class LocationPermissionViewHolder extends RecyclerView.ViewHolder {
+
+ LocationPermissionViewHolder(View itemView, OnClickListener locationRequestClickListener) {
+ super(itemView);
+ Assert.isNotNull(locationRequestClickListener);
+ itemView
+ .findViewById(
+ com.android.dialer.searchfragment.nearbyplaces.R.id.location_permission_allow)
+ .setOnClickListener(locationRequestClickListener);
+ }
+ }
}
diff --git a/java/com/android/dialer/searchfragment/list/SearchCursorManager.java b/java/com/android/dialer/searchfragment/list/SearchCursorManager.java
index 3704e817d..f8d1e1be5 100644
--- a/java/com/android/dialer/searchfragment/list/SearchCursorManager.java
+++ b/java/com/android/dialer/searchfragment/list/SearchCursorManager.java
@@ -16,6 +16,7 @@
package com.android.dialer.searchfragment.list;
+import android.database.MatrixCursor;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
@@ -60,7 +61,8 @@ public final class SearchCursorManager {
SearchCursorManager.RowType.NEARBY_PLACES_ROW,
SearchCursorManager.RowType.DIRECTORY_HEADER,
SearchCursorManager.RowType.DIRECTORY_ROW,
- SearchCursorManager.RowType.SEARCH_ACTION
+ SearchCursorManager.RowType.SEARCH_ACTION,
+ SearchCursorManager.RowType.LOCATION_REQUEST
})
@interface RowType {
int INVALID = 0;
@@ -79,13 +81,20 @@ public final class SearchCursorManager {
int DIRECTORY_ROW = 6;
/** A row containing a search action */
int SEARCH_ACTION = 7;
+ /** A row which requests location permission */
+ int LOCATION_REQUEST = 8;
}
+ private static final LocationPermissionCursor LOCATION_PERMISSION_CURSOR =
+ new LocationPermissionCursor(new String[0]);
+
private SearchCursor contactsCursor = null;
private SearchCursor nearbyPlacesCursor = null;
private SearchCursor corpDirectoryCursor = null;
private List<Integer> searchActions = new ArrayList<>();
+ private boolean showLocationPermissionRequest;
+
/** Returns true if the cursor changed. */
boolean setContactsCursor(@Nullable SearchCursor cursor) {
if (cursor == contactsCursor) {
@@ -122,6 +131,15 @@ public final class SearchCursorManager {
return true;
}
+ /** Returns true if the value changed. */
+ boolean showLocationPermissionRequest(boolean enabled) {
+ if (showLocationPermissionRequest == enabled) {
+ return false;
+ }
+ showLocationPermissionRequest = enabled;
+ return true;
+ }
+
/** Returns true if a cursor changed. */
boolean setCorpDirectoryCursor(@Nullable SearchCursor cursor) {
if (cursor == corpDirectoryCursor) {
@@ -177,7 +195,9 @@ public final class SearchCursorManager {
count += contactsCursor.getCount();
}
- if (nearbyPlacesCursor != null) {
+ if (showLocationPermissionRequest) {
+ count++;
+ } else if (nearbyPlacesCursor != null) {
count += nearbyPlacesCursor.getCount();
}
@@ -203,6 +223,10 @@ public final class SearchCursorManager {
return cursor.isHeader() ? RowType.CONTACT_HEADER : RowType.CONTACT_ROW;
}
+ if (cursor == LOCATION_PERMISSION_CURSOR) {
+ return RowType.LOCATION_REQUEST;
+ }
+
if (cursor == nearbyPlacesCursor) {
return cursor.isHeader() ? RowType.NEARBY_PLACES_HEADER : RowType.NEARBY_PLACES_ROW;
}
@@ -214,9 +238,7 @@ public final class SearchCursorManager {
}
/**
- * Gets cursor corresponding to position in coalesced list of search cursors. Callers should
- * ensure that {@link #getRowType(int)} doesn't correspond to header position, otherwise an
- * exception will be thrown.
+ * Gets cursor corresponding to position in coalesced list of search cursors.
*
* @param position in coalesced list of search cursors
* @return Cursor moved to position specific to passed in position.
@@ -232,7 +254,13 @@ public final class SearchCursorManager {
position -= count;
}
- if (nearbyPlacesCursor != null) {
+ if (showLocationPermissionRequest) {
+ if (position == 0) {
+ return LOCATION_PERMISSION_CURSOR;
+ }
+ position--;
+
+ } else if (nearbyPlacesCursor != null) {
int count = nearbyPlacesCursor.getCount();
if (position - count < 0) {
@@ -272,4 +300,30 @@ public final class SearchCursorManager {
corpDirectoryCursor = null;
}
}
+
+ /**
+ * No-op implementation of {@link android.database.Cursor} and {@link SearchCursor} for
+ * representing location permission request row elements.
+ */
+ private static class LocationPermissionCursor extends MatrixCursor implements SearchCursor {
+
+ LocationPermissionCursor(String[] columnNames) {
+ super(columnNames);
+ }
+
+ @Override
+ public boolean isHeader() {
+ return false;
+ }
+
+ @Override
+ public boolean updateQuery(String query) {
+ return false;
+ }
+
+ @Override
+ public long getDirectoryId() {
+ return 0;
+ }
+ }
}
diff --git a/java/com/android/dialer/searchfragment/nearbyplaces/res/layout/location_permission_row.xml b/java/com/android/dialer/searchfragment/nearbyplaces/res/layout/location_permission_row.xml
new file mode 100644
index 000000000..800bf62a8
--- /dev/null
+++ b/java/com/android/dialer/searchfragment/nearbyplaces/res/layout/location_permission_row.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:paddingTop="16dp">
+
+ <ImageView
+ android:id="@+id/permission_image"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
+ android:layout_marginEnd="16dp"
+ android:src="@drawable/quantum_ic_my_location_vd_theme_24"
+ android:tint="@color/dialer_secondary_text_color"/>
+
+ <TextView
+ android:id="@+id/permission_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toEndOf="@id/permission_image"
+ android:minHeight="56dp"
+ android:text="@string/permission_no_location_for_search"
+ android:textSize="16sp"
+ android:textColor="@color/dialer_secondary_text_color"/>
+
+ <Button
+ android:id="@+id/location_permission_allow"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_below="@id/permission_text"
+ android:text="@string/nearby_places_allow"
+ android:textColor="@color/dialer_theme_color"
+ style="@style/Widget.AppCompat.Button.Borderless"/>
+</RelativeLayout> \ No newline at end of file