AllAppsSearchBarController.java revision a81f580fb71c3e867ccbdef1d034ab17835318fb
1/* 2 * Copyright (C) 2015 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 */ 16package com.android.launcher3.allapps; 17 18import android.content.Context; 19import android.content.Intent; 20import android.graphics.Rect; 21import android.net.Uri; 22import android.text.Editable; 23import android.text.TextWatcher; 24import android.view.KeyEvent; 25import android.view.View; 26import android.view.inputmethod.EditorInfo; 27import android.view.inputmethod.InputMethodManager; 28import android.widget.TextView; 29import android.widget.TextView.OnEditorActionListener; 30 31import com.android.launcher3.ExtendedEditText; 32import com.android.launcher3.Launcher; 33import com.android.launcher3.Utilities; 34import com.android.launcher3.util.ComponentKey; 35 36import java.util.ArrayList; 37 38/** 39 * An interface to a search box that AllApps can command. 40 */ 41public abstract class AllAppsSearchBarController 42 implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener { 43 44 protected Launcher mLauncher; 45 protected AlphabeticalAppsList mApps; 46 protected Callbacks mCb; 47 protected ExtendedEditText mInput; 48 private String mQuery; 49 50 protected DefaultAppSearchAlgorithm mSearchAlgorithm; 51 protected InputMethodManager mInputMethodManager; 52 53 public void setVisibility(int visibility) { 54 mInput.setVisibility(visibility); 55 } 56 /** 57 * Sets the references to the apps model and the search result callback. 58 */ 59 public final void initialize( 60 AlphabeticalAppsList apps, ExtendedEditText input, 61 Launcher launcher, Callbacks cb) { 62 mApps = apps; 63 mCb = cb; 64 mLauncher = launcher; 65 66 mInput = input; 67 mInput.addTextChangedListener(this); 68 mInput.setOnEditorActionListener(this); 69 mInput.setOnBackKeyListener(this); 70 71 mInputMethodManager = (InputMethodManager) 72 mInput.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 73 74 mSearchAlgorithm = onInitializeSearch(); 75 } 76 77 /** 78 * To be implemented by subclasses. This method will get called when the controller is set. 79 */ 80 protected abstract DefaultAppSearchAlgorithm onInitializeSearch(); 81 82 @Override 83 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 84 // Do nothing 85 } 86 87 @Override 88 public void onTextChanged(CharSequence s, int start, int before, int count) { 89 // Do nothing 90 } 91 92 @Override 93 public void afterTextChanged(final Editable s) { 94 mQuery = s.toString(); 95 if (mQuery.isEmpty()) { 96 mSearchAlgorithm.cancel(true); 97 mCb.clearSearchResult(); 98 } else { 99 mSearchAlgorithm.cancel(false); 100 mSearchAlgorithm.doSearch(mQuery, mCb); 101 } 102 } 103 104 protected void refreshSearchResult() { 105 if (mQuery == null) { 106 return; 107 } 108 // If play store continues auto updating an app, we want to show partial result. 109 mSearchAlgorithm.cancel(false); 110 mSearchAlgorithm.doSearch(mQuery, mCb); 111 } 112 113 @Override 114 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 115 // Skip if it's not the right action 116 if (actionId != EditorInfo.IME_ACTION_SEARCH) { 117 return false; 118 } 119 // Skip if the query is empty 120 String query = v.getText().toString(); 121 if (query.isEmpty()) { 122 return false; 123 } 124 return mLauncher.startActivitySafely(v, createMarketSearchIntent(query), null); 125 } 126 127 @Override 128 public boolean onBackKey() { 129 // Only hide the search field if there is no query, or if there 130 // are no filtered results 131 String query = Utilities.trim(mInput.getEditableText().toString()); 132 if (query.isEmpty() || mApps.hasNoFilteredResults()) { 133 reset(); 134 return true; 135 } 136 return false; 137 } 138 139 /** 140 * Resets the search bar state. 141 */ 142 public void reset() { 143 unfocusSearchField(); 144 mCb.clearSearchResult(); 145 mInput.setText(""); 146 // We need to reset this after we clear the input text 147 mQuery = null; 148 hideKeyboard(); 149 } 150 151 protected void hideKeyboard() { 152 mInputMethodManager.hideSoftInputFromWindow(mInput.getWindowToken(), 0); 153 } 154 155 protected void unfocusSearchField() { 156 View nextFocus = mInput.focusSearch(View.FOCUS_DOWN); 157 if (nextFocus != null) { 158 nextFocus.requestFocus(); 159 } 160 } 161 162 /** 163 * Focuses the search field to handle key events. 164 */ 165 public void focusSearchField() { 166 mInput.requestFocus(); 167 mInputMethodManager.showSoftInput(mInput, InputMethodManager.SHOW_IMPLICIT); 168 } 169 170 /** 171 * Returns whether the search field is focused. 172 */ 173 public boolean isSearchFieldFocused() { 174 return mInput.isFocused(); 175 } 176 177 /** 178 * Creates a new market search intent. 179 */ 180 public Intent createMarketSearchIntent(String query) { 181 Uri marketSearchUri = Uri.parse("market://search") 182 .buildUpon() 183 .appendQueryParameter("c", "apps") 184 .appendQueryParameter("q", query) 185 .build(); 186 return new Intent(Intent.ACTION_VIEW).setData(marketSearchUri); 187 } 188 189 /** 190 * Callback for getting search results. 191 */ 192 public interface Callbacks { 193 194 /** 195 * Called when the bounds of the search bar has changed. 196 */ 197 @Deprecated 198 void onBoundsChanged(Rect newBounds); 199 200 /** 201 * Called when the search is complete. 202 * 203 * @param apps sorted list of matching components or null if in case of failure. 204 */ 205 void onSearchResult(String query, ArrayList<ComponentKey> apps); 206 207 /** 208 * Called when the search results should be cleared. 209 */ 210 void clearSearchResult(); 211 } 212}