Home | History | Annotate | Download | only in list
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.dialer.searchfragment.list;
     18 
     19 import android.content.Context;
     20 import android.support.annotation.Nullable;
     21 import android.support.annotation.VisibleForTesting;
     22 import android.support.v7.widget.RecyclerView;
     23 import android.support.v7.widget.RecyclerView.ViewHolder;
     24 import android.text.TextUtils;
     25 import android.view.LayoutInflater;
     26 import android.view.View;
     27 import android.view.View.OnClickListener;
     28 import android.view.ViewGroup;
     29 import com.android.dialer.callintent.CallInitiationType;
     30 import com.android.dialer.common.Assert;
     31 import com.android.dialer.searchfragment.common.RowClickListener;
     32 import com.android.dialer.searchfragment.common.SearchCursor;
     33 import com.android.dialer.searchfragment.cp2.SearchContactViewHolder;
     34 import com.android.dialer.searchfragment.directories.DirectoryContactViewHolder;
     35 import com.android.dialer.searchfragment.list.SearchCursorManager.RowType;
     36 import com.android.dialer.searchfragment.nearbyplaces.NearbyPlaceViewHolder;
     37 import java.util.List;
     38 
     39 /** RecyclerView adapter for {@link NewSearchFragment}. */
     40 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
     41 public final class SearchAdapter extends RecyclerView.Adapter<ViewHolder> {
     42 
     43   private final SearchCursorManager searchCursorManager;
     44   private final Context context;
     45 
     46   private boolean showZeroSuggest;
     47   private String query;
     48   // Raw query number from dialpad, which may contain special character such as "+". This is used
     49   // for actions to add contact or send sms.
     50   private String rawNumber;
     51   private CallInitiationType.Type callInitiationType;
     52   private OnClickListener allowClickListener;
     53   private OnClickListener dismissClickListener;
     54   private RowClickListener rowClickListener;
     55 
     56   @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
     57   public SearchAdapter(
     58       Context context, SearchCursorManager searchCursorManager, RowClickListener rowClickListener) {
     59     this.context = context;
     60     this.searchCursorManager = searchCursorManager;
     61     this.rowClickListener = rowClickListener;
     62   }
     63 
     64   @Override
     65   public ViewHolder onCreateViewHolder(ViewGroup root, @RowType int rowType) {
     66     switch (rowType) {
     67       case RowType.CONTACT_ROW:
     68         return new SearchContactViewHolder(
     69             LayoutInflater.from(context).inflate(R.layout.search_contact_row, root, false),
     70             rowClickListener);
     71       case RowType.NEARBY_PLACES_ROW:
     72         return new NearbyPlaceViewHolder(
     73             LayoutInflater.from(context).inflate(R.layout.search_contact_row, root, false));
     74       case RowType.CONTACT_HEADER:
     75       case RowType.DIRECTORY_HEADER:
     76       case RowType.NEARBY_PLACES_HEADER:
     77         return new HeaderViewHolder(
     78             LayoutInflater.from(context).inflate(R.layout.header_layout, root, false));
     79       case RowType.DIRECTORY_ROW:
     80         return new DirectoryContactViewHolder(
     81             LayoutInflater.from(context).inflate(R.layout.search_contact_row, root, false));
     82       case RowType.SEARCH_ACTION:
     83         return new SearchActionViewHolder(
     84             LayoutInflater.from(context).inflate(R.layout.search_action_layout, root, false));
     85       case RowType.LOCATION_REQUEST:
     86         return new LocationPermissionViewHolder(
     87             LayoutInflater.from(context).inflate(R.layout.location_permission_row, root, false),
     88             allowClickListener,
     89             dismissClickListener);
     90       case RowType.INVALID:
     91       default:
     92         throw Assert.createIllegalStateFailException("Invalid RowType: " + rowType);
     93     }
     94   }
     95 
     96   @Override
     97   public @RowType int getItemViewType(int position) {
     98     return searchCursorManager.getRowType(position);
     99   }
    100 
    101   @Override
    102   public void onBindViewHolder(ViewHolder holder, int position) {
    103     if (holder instanceof SearchContactViewHolder) {
    104       ((SearchContactViewHolder) holder).bind(searchCursorManager.getCursor(position), query);
    105     } else if (holder instanceof NearbyPlaceViewHolder) {
    106       ((NearbyPlaceViewHolder) holder).bind(searchCursorManager.getCursor(position), query);
    107     } else if (holder instanceof DirectoryContactViewHolder) {
    108       ((DirectoryContactViewHolder) holder).bind(searchCursorManager.getCursor(position), query);
    109     } else if (holder instanceof HeaderViewHolder) {
    110       String header =
    111           searchCursorManager.getCursor(position).getString(SearchCursor.HEADER_TEXT_POSITION);
    112       ((HeaderViewHolder) holder).setHeader(header);
    113     } else if (holder instanceof SearchActionViewHolder) {
    114       ((SearchActionViewHolder) holder)
    115           .setAction(
    116               searchCursorManager.getSearchAction(position),
    117               position,
    118               TextUtils.isEmpty(rawNumber) ? query : rawNumber,
    119               callInitiationType);
    120     } else if (holder instanceof LocationPermissionViewHolder) {
    121       // No-op
    122     } else {
    123       throw Assert.createIllegalStateFailException("Invalid ViewHolder: " + holder);
    124     }
    125   }
    126 
    127   public void setContactsCursor(SearchCursor cursor) {
    128     if (searchCursorManager.setContactsCursor(cursor)) {
    129       // Since this is a new contacts cursor, we need to reapply the filter.
    130       searchCursorManager.setQuery(query);
    131       notifyDataSetChanged();
    132     }
    133   }
    134 
    135   void clear() {
    136     searchCursorManager.clear();
    137   }
    138 
    139   @Override
    140   public int getItemCount() {
    141     if (TextUtils.isEmpty(query) && !showZeroSuggest) {
    142       return 0;
    143     }
    144     return searchCursorManager.getCount();
    145   }
    146 
    147   /**
    148    * @param visible If true and query is empty, the adapter won't show any list elements.
    149    * @see #setQuery(String, String, CallInitiationType.Type)
    150    * @see #getItemCount()
    151    */
    152   public void setZeroSuggestVisible(boolean visible) {
    153     showZeroSuggest = visible;
    154   }
    155 
    156   public void setQuery(String query, @Nullable String rawNumber, CallInitiationType.Type type) {
    157     this.query = query;
    158     this.rawNumber = rawNumber;
    159     this.callInitiationType = type;
    160     if (searchCursorManager.setQuery(query)) {
    161       notifyDataSetChanged();
    162     }
    163   }
    164 
    165   /** Sets the actions to be shown at the bottom of the search results. */
    166   void setSearchActions(List<Integer> actions) {
    167     if (searchCursorManager.setSearchActions(actions)) {
    168       notifyDataSetChanged();
    169     }
    170   }
    171 
    172   public void setNearbyPlacesCursor(SearchCursor nearbyPlacesCursor) {
    173     if (searchCursorManager.setNearbyPlacesCursor(nearbyPlacesCursor)) {
    174       notifyDataSetChanged();
    175     }
    176   }
    177 
    178   /**
    179    * Updates the adapter to show the location request row element. If the element was previously
    180    * hidden, the adapter will call {@link #notifyDataSetChanged()}.
    181    */
    182   public void showLocationPermissionRequest(
    183       OnClickListener allowClickListener, OnClickListener dismissClickListener) {
    184     this.allowClickListener = Assert.isNotNull(allowClickListener);
    185     this.dismissClickListener = Assert.isNotNull(dismissClickListener);
    186     if (searchCursorManager.showLocationPermissionRequest(true)) {
    187       notifyItemInserted(0);
    188     }
    189   }
    190 
    191   /**
    192    * Updates the adapter to hide the location request row element. If the element was previously
    193    * visible, the adapter will call {@link #notifyDataSetChanged()}.
    194    */
    195   void hideLocationPermissionRequest() {
    196     allowClickListener = null;
    197     dismissClickListener = null;
    198     if (searchCursorManager.showLocationPermissionRequest(false)) {
    199       notifyItemRemoved(0);
    200     }
    201   }
    202 
    203   void setDirectoryContactsCursor(SearchCursor directoryContactsCursor) {
    204     if (searchCursorManager.setCorpDirectoryCursor(directoryContactsCursor)) {
    205       notifyDataSetChanged();
    206     }
    207   }
    208 
    209   /** Viewholder for R.layout.location_permission_row that requests the location permission. */
    210   private static class LocationPermissionViewHolder extends RecyclerView.ViewHolder {
    211 
    212     LocationPermissionViewHolder(
    213         View itemView, OnClickListener allowClickListener, OnClickListener dismissClickListener) {
    214       super(itemView);
    215       Assert.isNotNull(allowClickListener);
    216       Assert.isNotNull(dismissClickListener);
    217       itemView
    218           .findViewById(
    219               com.android.dialer.searchfragment.nearbyplaces.R.id.location_permission_allow)
    220           .setOnClickListener(allowClickListener);
    221       itemView
    222           .findViewById(
    223               com.android.dialer.searchfragment.nearbyplaces.R.id.location_permission_dismiss)
    224           .setOnClickListener(dismissClickListener);
    225     }
    226   }
    227 }
    228