1ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung/* 2ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * Copyright (C) 2015 The Android Open Source Project 3ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * 4ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * Licensed under the Apache License, Version 2.0 (the "License"); 5ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * you may not use this file except in compliance with the License. 6ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * You may obtain a copy of the License at 7ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * 8ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * http://www.apache.org/licenses/LICENSE-2.0 9ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * 10ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * Unless required by applicable law or agreed to in writing, software 11ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * distributed under the License is distributed on an "AS IS" BASIS, 12ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * See the License for the specific language governing permissions and 14ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * limitations under the License. 15ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung */ 16ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chungpackage com.android.launcher3.allapps; 17ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 180ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyalimport android.content.Context; 192494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyalimport android.content.Intent; 20ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chungimport android.graphics.Rect; 212494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyalimport android.net.Uri; 220ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyalimport android.text.Editable; 2345a11dd9ee5c9cdaa65527ae0ef1c8b004417f28Winsonimport android.text.TextUtils; 240ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyalimport android.text.TextWatcher; 250ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyalimport android.view.KeyEvent; 26ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chungimport android.view.View; 270ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyalimport android.view.inputmethod.EditorInfo; 280ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyalimport android.view.inputmethod.InputMethodManager; 290ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyalimport android.widget.TextView; 300ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyalimport android.widget.TextView.OnEditorActionListener; 31ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 320ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyalimport com.android.launcher3.ExtendedEditText; 339e3fee1427c0baa38564e20a9f351d1a87c25761Sunny Goyalimport com.android.launcher3.Launcher; 340ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyalimport com.android.launcher3.Utilities; 355183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyalimport com.android.launcher3.util.ComponentKey; 365183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal 37ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chungimport java.util.ArrayList; 38ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 39ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung/** 40ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * An interface to a search box that AllApps can command. 41ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung */ 420ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyalpublic abstract class AllAppsSearchBarController 43ce3fffb5fb446e031e52ee0c5f2a4a5cf86a8c81Sunny Goyal implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener { 44ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 459e3fee1427c0baa38564e20a9f351d1a87c25761Sunny Goyal protected Launcher mLauncher; 46ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung protected AlphabeticalAppsList mApps; 47ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung protected Callbacks mCb; 480ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal protected ExtendedEditText mInput; 49f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song private String mQuery; 500ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal 510ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal protected DefaultAppSearchAlgorithm mSearchAlgorithm; 520ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal protected InputMethodManager mInputMethodManager; 53ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 54645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song public void setVisibility(int visibility) { 55645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song mInput.setVisibility(visibility); 56645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song } 57ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung /** 58ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * Sets the references to the apps model and the search result callback. 59ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung */ 600ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal public final void initialize( 610ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal AlphabeticalAppsList apps, ExtendedEditText input, 629e3fee1427c0baa38564e20a9f351d1a87c25761Sunny Goyal Launcher launcher, Callbacks cb) { 63ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung mApps = apps; 64ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung mCb = cb; 659e3fee1427c0baa38564e20a9f351d1a87c25761Sunny Goyal mLauncher = launcher; 660ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal 670ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mInput = input; 680ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mInput.addTextChangedListener(this); 690ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mInput.setOnEditorActionListener(this); 700ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mInput.setOnBackKeyListener(this); 710ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal 720ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mInputMethodManager = (InputMethodManager) 730ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mInput.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 740ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal 750ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mSearchAlgorithm = onInitializeSearch(); 76ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung } 77ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 784919827990b16ae22595d0b7cb123a875961d9beSunny Goyal /** 792494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyal * To be implemented by subclasses. This method will get called when the controller is set. 804919827990b16ae22595d0b7cb123a875961d9beSunny Goyal */ 812494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyal protected abstract DefaultAppSearchAlgorithm onInitializeSearch(); 820ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal 830ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal @Override 840ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal public void beforeTextChanged(CharSequence s, int start, int count, int after) { 850ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal // Do nothing 860ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 870ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal 880ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal @Override 890ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal public void onTextChanged(CharSequence s, int start, int before, int count) { 900ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal // Do nothing 910ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 920ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal 930ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal @Override 940ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal public void afterTextChanged(final Editable s) { 95f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song mQuery = s.toString(); 96f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song if (mQuery.isEmpty()) { 970ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mSearchAlgorithm.cancel(true); 980ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mCb.clearSearchResult(); 990ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } else { 1000ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mSearchAlgorithm.cancel(false); 101f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song mSearchAlgorithm.doSearch(mQuery, mCb); 102f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song } 103f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song } 104f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song 105f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song protected void refreshSearchResult() { 10645a11dd9ee5c9cdaa65527ae0ef1c8b004417f28Winson if (TextUtils.isEmpty(mQuery)) { 107f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song return; 1080ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 109f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song // If play store continues auto updating an app, we want to show partial result. 110f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song mSearchAlgorithm.cancel(false); 111f66b6802392bc473d7e1f86a58cf65b25ed2148cHyunyoung Song mSearchAlgorithm.doSearch(mQuery, mCb); 1120ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 1130ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal 1140ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal @Override 1150ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 1160ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal // Skip if it's not the right action 1170ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal if (actionId != EditorInfo.IME_ACTION_SEARCH) { 1180ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal return false; 1190ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 1209e3fee1427c0baa38564e20a9f351d1a87c25761Sunny Goyal // Skip if the query is empty 1219e3fee1427c0baa38564e20a9f351d1a87c25761Sunny Goyal String query = v.getText().toString(); 1229e3fee1427c0baa38564e20a9f351d1a87c25761Sunny Goyal if (query.isEmpty()) { 1230ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal return false; 1240ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 1252494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyal return mLauncher.startActivitySafely(v, createMarketSearchIntent(query), null); 1260ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 1270ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal 1280ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal @Override 1290ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal public boolean onBackKey() { 130bb918b3532f0f88177a9f38f55440121305c79ceJon Miranda // Only hide the search field if there is no query 1310ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal String query = Utilities.trim(mInput.getEditableText().toString()); 132bb918b3532f0f88177a9f38f55440121305c79ceJon Miranda if (query.isEmpty()) { 1330ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal reset(); 1340ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal return true; 1350ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 1360ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal return false; 1370ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 1380ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal 1390ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal /** 1400ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal * Resets the search bar state. 1410ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal */ 1420ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal public void reset() { 1430ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal unfocusSearchField(); 1440ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mCb.clearSearchResult(); 1450ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mInput.setText(""); 146a81f580fb71c3e867ccbdef1d034ab17835318fbWinson mQuery = null; 14735d96306ad6d8c404cfaa90e1d68fb194a27a2faPeter Schiller hideKeyboard(); 14835d96306ad6d8c404cfaa90e1d68fb194a27a2faPeter Schiller } 14935d96306ad6d8c404cfaa90e1d68fb194a27a2faPeter Schiller 15035d96306ad6d8c404cfaa90e1d68fb194a27a2faPeter Schiller protected void hideKeyboard() { 1510ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal mInputMethodManager.hideSoftInputFromWindow(mInput.getWindowToken(), 0); 1520ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 1530ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal 1540ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal protected void unfocusSearchField() { 1550ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal View nextFocus = mInput.focusSearch(View.FOCUS_DOWN); 1560ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal if (nextFocus != null) { 1570ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal nextFocus.requestFocus(); 1580ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 1590ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 160ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 161ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung /** 162ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * Focuses the search field to handle key events. 163ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung */ 1640ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal public void focusSearchField() { 165c2fe1147f9802d581d1e0c1da4dcaaf8ebdfa939Hyunyoung Song mInput.showKeyboard(); 1660ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 167ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 168ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung /** 169ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * Returns whether the search field is focused. 170ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung */ 1710ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal public boolean isSearchFieldFocused() { 1720ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal return mInput.isFocused(); 1730ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 174ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 175ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung /** 1762494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyal * Creates a new market search intent. 177ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung */ 1782494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyal public Intent createMarketSearchIntent(String query) { 1792494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyal Uri marketSearchUri = Uri.parse("market://search") 1802494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyal .buildUpon() 1812494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyal .appendQueryParameter("c", "apps") 1822494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyal .appendQueryParameter("q", query) 1832494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyal .build(); 1842494c3f1681e71af06556ef47de16f018811f7e3Sunny Goyal return new Intent(Intent.ACTION_VIEW).setData(marketSearchUri); 1850ac7ede56afebe4401c0636196f5844be573ad68Sunny Goyal } 186ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 187ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung /** 188ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * Callback for getting search results. 189ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung */ 190ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung public interface Callbacks { 191ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 192ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung /** 193ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * Called when the bounds of the search bar has changed. 194ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung */ 19505c8c57fa72a81f34058036f6dc30c084ca6742bSunny Goyal @Deprecated 196ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung void onBoundsChanged(Rect newBounds); 197ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 198ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung /** 199ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * Called when the search is complete. 200ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * 201ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * @param apps sorted list of matching components or null if in case of failure. 202ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung */ 2035183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal void onSearchResult(String query, ArrayList<ComponentKey> apps); 204ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung 205ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung /** 206ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * Called when the search results should be cleared. 207ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung */ 208ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung void clearSearchResult(); 209ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung } 210ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung}