AllAppsSearchBarController.java revision ce3fffb5fb446e031e52ee0c5f2a4a5cf86a8c81
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
49    protected DefaultAppSearchAlgorithm mSearchAlgorithm;
50    protected InputMethodManager mInputMethodManager;
51
52    public void setVisibility(int visibility) {
53        mInput.setVisibility(visibility);
54    }
55    /**
56     * Sets the references to the apps model and the search result callback.
57     */
58    public final void initialize(
59            AlphabeticalAppsList apps, ExtendedEditText input,
60            Launcher launcher, Callbacks cb) {
61        mApps = apps;
62        mCb = cb;
63        mLauncher = launcher;
64
65        mInput = input;
66        mInput.addTextChangedListener(this);
67        mInput.setOnEditorActionListener(this);
68        mInput.setOnBackKeyListener(this);
69
70        mInputMethodManager = (InputMethodManager)
71                mInput.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
72
73        mSearchAlgorithm = onInitializeSearch();
74    }
75
76    /**
77     * To be implemented by subclasses. This method will get called when the controller is set.
78     */
79    protected abstract DefaultAppSearchAlgorithm onInitializeSearch();
80
81    @Override
82    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
83        // Do nothing
84    }
85
86    @Override
87    public void onTextChanged(CharSequence s, int start, int before, int count) {
88        // Do nothing
89    }
90
91    @Override
92    public void afterTextChanged(final Editable s) {
93        String query = s.toString();
94        if (query.isEmpty()) {
95            mSearchAlgorithm.cancel(true);
96            mCb.clearSearchResult();
97        } else {
98            mSearchAlgorithm.cancel(false);
99            mSearchAlgorithm.doSearch(query, mCb);
100        }
101    }
102
103    @Override
104    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
105        // Skip if it's not the right action
106        if (actionId != EditorInfo.IME_ACTION_SEARCH) {
107            return false;
108        }
109        // Skip if the query is empty
110        String query = v.getText().toString();
111        if (query.isEmpty()) {
112            return false;
113        }
114        return mLauncher.startActivitySafely(v, createMarketSearchIntent(query), null);
115    }
116
117    @Override
118    public boolean onBackKey() {
119        // Only hide the search field if there is no query, or if there
120        // are no filtered results
121        String query = Utilities.trim(mInput.getEditableText().toString());
122        if (query.isEmpty() || mApps.hasNoFilteredResults()) {
123            reset();
124            return true;
125        }
126        return false;
127    }
128
129    /**
130     * Resets the search bar state.
131     */
132    public void reset() {
133        unfocusSearchField();
134        mCb.clearSearchResult();
135        mInput.setText("");
136        mInputMethodManager.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
137    }
138
139    protected void unfocusSearchField() {
140        View nextFocus = mInput.focusSearch(View.FOCUS_DOWN);
141        if (nextFocus != null) {
142            nextFocus.requestFocus();
143        }
144    }
145
146    /**
147     * Focuses the search field to handle key events.
148     */
149    public void focusSearchField() {
150        mInput.requestFocus();
151        mInputMethodManager.showSoftInput(mInput, InputMethodManager.SHOW_IMPLICIT);
152    }
153
154    /**
155     * Returns whether the search field is focused.
156     */
157    public boolean isSearchFieldFocused() {
158        return mInput.isFocused();
159    }
160
161    /**
162     * Creates a new market search intent.
163     */
164    public Intent createMarketSearchIntent(String query) {
165        Uri marketSearchUri = Uri.parse("market://search")
166                .buildUpon()
167                .appendQueryParameter("c", "apps")
168                .appendQueryParameter("q", query)
169                .build();
170        return new Intent(Intent.ACTION_VIEW).setData(marketSearchUri);
171    }
172
173    /**
174     * Callback for getting search results.
175     */
176    public interface Callbacks {
177
178        /**
179         * Called when the bounds of the search bar has changed.
180         */
181        @Deprecated
182        void onBoundsChanged(Rect newBounds);
183
184        /**
185         * Called when the search is complete.
186         *
187         * @param apps sorted list of matching components or null if in case of failure.
188         */
189        void onSearchResult(String query, ArrayList<ComponentKey> apps);
190
191        /**
192         * Called when the search results should be cleared.
193         */
194        void clearSearchResult();
195    }
196}