MaterialSearchSuggestionsList.java revision 37d8ca1eec6c9e3b03eb9036427121ece11fbf5a
1/* 2 * Copyright (C) 2014 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.mail.ui; 19 20import android.app.SearchManager; 21import android.content.Context; 22import android.database.Cursor; 23import android.net.Uri; 24import android.os.AsyncTask; 25import android.util.AttributeSet; 26import android.view.LayoutInflater; 27import android.view.View; 28import android.view.ViewGroup; 29import android.widget.AdapterView; 30import android.widget.BaseAdapter; 31import android.widget.ImageView; 32import android.widget.LinearLayout; 33import android.widget.ListView; 34import android.widget.TextView; 35 36import com.android.mail.R; 37import com.android.mail.providers.SearchRecentSuggestionsProvider; 38import com.google.common.collect.Lists; 39 40import java.util.List; 41 42/** 43 * Custom quantum-styled search view that overlays the main activity. 44 */ 45public class MaterialSearchSuggestionsList extends LinearLayout 46 implements AdapterView.OnItemClickListener, View.OnClickListener { 47 private MaterialSearchViewController mController; 48 private SearchRecentSuggestionsProvider mSuggestionsProvider; 49 private List<SuggestionItem> mSuggestions = Lists.newArrayList(); 50 private String mQuery; 51 52 private View mDummyHolder; 53 private ListView mListView; 54 private MaterialSearchViewListAdapter mAdapter; 55 private QuerySuggestionsTask mQueryTask; 56 57 public MaterialSearchSuggestionsList(Context context) { 58 super(context); 59 } 60 61 public MaterialSearchSuggestionsList(Context context, AttributeSet attrs) { 62 super(context, attrs); 63 } 64 65 // PUBLIC API 66 public void setController(MaterialSearchViewController controller, 67 SearchRecentSuggestionsProvider suggestionsProvider) { 68 mController = controller; 69 mSuggestionsProvider = suggestionsProvider; 70 } 71 72 public void setQuery(String query) { 73 mQuery = query; 74 if (mQueryTask != null) { 75 mQueryTask.cancel(true); 76 } 77 mQueryTask = new QuerySuggestionsTask(); 78 mQueryTask.execute(query); 79 } 80 81 // PRIVATE API 82 @Override 83 protected void onFinishInflate() { 84 super.onFinishInflate(); 85 86 mListView = (ListView) findViewById(R.id.search_overlay_suggestion_list); 87 mListView.setOnItemClickListener(this); 88 mDummyHolder = findViewById(R.id.search_overlay_scrim); 89 mDummyHolder.setOnClickListener(this); 90 91 // set up the adapter 92 mAdapter = new MaterialSearchViewListAdapter(getContext(), R.layout.search_suggestion_item); 93 mListView.setAdapter(mAdapter); 94 } 95 96 @Override 97 public void setVisibility(int visibility) { 98 if (!isShown() && visibility == VISIBLE) { 99 // When we go from gone to visible, re-query for suggestions in case they changed. 100 setQuery(mQuery); 101 } 102 super.setVisibility(visibility); 103 } 104 105 @Override 106 public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { 107 mController.onSearchPerformed(mSuggestions.get(position).suggestion); 108 } 109 110 @Override 111 public void onClick(View view) { 112 mController.showSearchActionBar( 113 MaterialSearchViewController.SEARCH_VIEW_STATE_ONLY_ACTIONBAR); 114 } 115 116 // Background task for querying the suggestions list 117 private class QuerySuggestionsTask extends AsyncTask<String, Void, List<SuggestionItem>> { 118 @Override 119 protected List<SuggestionItem> doInBackground(String... strings) { 120 String query = strings[0]; 121 if (query == null) { 122 query = ""; 123 } 124 125 Cursor c = null; 126 final List<SuggestionItem> result = Lists.newArrayList(); 127 try { 128 c = mSuggestionsProvider.query(null, "query LIKE ?", 129 new String[] { query }, null); 130 131 if (c != null && c.moveToFirst()) { 132 final int textIndex = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY); 133 final int iconIndex = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1); 134 do { 135 final String suggestion = c.getString(textIndex); 136 final Uri iconUri = Uri.parse(c.getString(iconIndex)); 137 result.add(new SuggestionItem(suggestion, iconUri)); 138 } while (c.moveToNext()); 139 } 140 } finally { 141 if (c != null) { 142 c.close(); 143 } 144 } 145 146 return result; 147 } 148 149 @Override 150 protected void onPostExecute(List<SuggestionItem> strings) { 151 if (!isCancelled()) { 152 // Should not have any race conditions here since we cancel the previous asynctask 153 // before starting the new one. It's unlikely that the new task finishes fast enough 154 // to get to onPostExecute when this one is in addAll. 155 mSuggestions.clear(); 156 mSuggestions.addAll(strings); 157 mAdapter.notifyDataSetChanged(); 158 } 159 } 160 } 161 162 private static class SuggestionItem { 163 final String suggestion; 164 final Uri icon; 165 166 public SuggestionItem(String s, Uri i) { 167 suggestion = s; 168 icon = i; 169 } 170 } 171 172 // Custom adapter to populate our list 173 private class MaterialSearchViewListAdapter extends BaseAdapter { 174 private final Context mContext; 175 private final int mResId; 176 private LayoutInflater mInflater; 177 178 public MaterialSearchViewListAdapter(Context context, int resource) { 179 super(); 180 mContext = context; 181 mResId = resource; 182 } 183 184 private LayoutInflater getInflater() { 185 if (mInflater == null) { 186 mInflater = LayoutInflater.from(mContext); 187 } 188 return mInflater; 189 } 190 191 @Override 192 public int getCount() { 193 return mSuggestions.size(); 194 } 195 196 @Override 197 public Object getItem(int i) { 198 return mSuggestions.get(i); 199 } 200 201 @Override 202 public long getItemId(int i) { 203 return 0; 204 } 205 206 @Override 207 public View getView(int position, View convertView, ViewGroup parent) { 208 if (convertView == null) { 209 convertView = getInflater().inflate(mResId, parent, false); 210 } 211 212 final SuggestionItem item = mSuggestions.get(position); 213 ((TextView) convertView.findViewById(R.id.search_overlay_item_text)) 214 .setText(item.suggestion); 215 ((ImageView) convertView.findViewById(R.id.search_overlay_item_icon)) 216 .setImageURI(item.icon); 217 218 return convertView; 219 } 220 } 221} 222