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  */
16 package com.android.launcher3.allapps.search;
17 
18 import android.text.Editable;
19 import android.text.TextUtils;
20 import android.text.TextWatcher;
21 import android.view.KeyEvent;
22 import android.view.View;
23 import android.view.View.OnFocusChangeListener;
24 import android.view.inputmethod.EditorInfo;
25 import android.widget.TextView;
26 import android.widget.TextView.OnEditorActionListener;
27 
28 import com.android.launcher3.BaseDraggingActivity;
29 import com.android.launcher3.ExtendedEditText;
30 import com.android.launcher3.Utilities;
31 import com.android.launcher3.model.AppLaunchTracker;
32 import com.android.launcher3.util.ComponentKey;
33 import com.android.launcher3.util.PackageManagerHelper;
34 
35 import java.util.ArrayList;
36 
37 /**
38  * An interface to a search box that AllApps can command.
39  */
40 public class AllAppsSearchBarController
41         implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener,
42         OnFocusChangeListener {
43 
44     protected BaseDraggingActivity mLauncher;
45     protected Callbacks mCb;
46     protected ExtendedEditText mInput;
47     protected String mQuery;
48 
49     protected SearchAlgorithm mSearchAlgorithm;
50 
setVisibility(int visibility)51     public void setVisibility(int visibility) {
52         mInput.setVisibility(visibility);
53     }
54     /**
55      * Sets the references to the apps model and the search result callback.
56      */
initialize( SearchAlgorithm searchAlgorithm, ExtendedEditText input, BaseDraggingActivity launcher, Callbacks cb)57     public final void initialize(
58             SearchAlgorithm searchAlgorithm, ExtendedEditText input,
59             BaseDraggingActivity launcher, Callbacks cb) {
60         mCb = cb;
61         mLauncher = launcher;
62 
63         mInput = input;
64         mInput.addTextChangedListener(this);
65         mInput.setOnEditorActionListener(this);
66         mInput.setOnBackKeyListener(this);
67         mInput.setOnFocusChangeListener(this);
68         mSearchAlgorithm = searchAlgorithm;
69     }
70 
71     @Override
beforeTextChanged(CharSequence s, int start, int count, int after)72     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
73         // Do nothing
74     }
75 
76     @Override
onTextChanged(CharSequence s, int start, int before, int count)77     public void onTextChanged(CharSequence s, int start, int before, int count) {
78         // Do nothing
79     }
80 
81     @Override
afterTextChanged(final Editable s)82     public void afterTextChanged(final Editable s) {
83         mQuery = s.toString();
84         if (mQuery.isEmpty()) {
85             mSearchAlgorithm.cancel(true);
86             mCb.clearSearchResult();
87         } else {
88             mSearchAlgorithm.cancel(false);
89             mSearchAlgorithm.doSearch(mQuery, mCb);
90         }
91     }
92 
refreshSearchResult()93     public void refreshSearchResult() {
94         if (TextUtils.isEmpty(mQuery)) {
95             return;
96         }
97         // If play store continues auto updating an app, we want to show partial result.
98         mSearchAlgorithm.cancel(false);
99         mSearchAlgorithm.doSearch(mQuery, mCb);
100     }
101 
102     @Override
onEditorAction(TextView v, int actionId, KeyEvent event)103     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
104         // Skip if it's not the right action
105         if (actionId != EditorInfo.IME_ACTION_SEARCH) {
106             return false;
107         }
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,
115                 PackageManagerHelper.getMarketSearchIntent(mLauncher, query), null,
116                 AppLaunchTracker.CONTAINER_SEARCH);
117     }
118 
119     @Override
onBackKey()120     public boolean onBackKey() {
121         // Only hide the search field if there is no query
122         String query = Utilities.trim(mInput.getEditableText().toString());
123         if (query.isEmpty()) {
124             reset();
125             return true;
126         }
127         return false;
128     }
129 
130     @Override
onFocusChange(View view, boolean hasFocus)131     public void onFocusChange(View view, boolean hasFocus) {
132         if (!hasFocus) {
133             mInput.hideKeyboard();
134         }
135     }
136 
137     /**
138      * Resets the search bar state.
139      */
reset()140     public void reset() {
141         mCb.clearSearchResult();
142         mInput.reset();
143         mQuery = null;
144     }
145 
146     /**
147      * Focuses the search field to handle key events.
148      */
focusSearchField()149     public void focusSearchField() {
150         mInput.showKeyboard();
151     }
152 
153     /**
154      * Returns whether the search field is focused.
155      */
isSearchFieldFocused()156     public boolean isSearchFieldFocused() {
157         return mInput.isFocused();
158     }
159 
160     /**
161      * Callback for getting search results.
162      */
163     public interface Callbacks {
164 
165         /**
166          * Called when the search is complete.
167          *
168          * @param apps sorted list of matching components or null if in case of failure.
169          */
onSearchResult(String query, ArrayList<ComponentKey> apps)170         void onSearchResult(String query, ArrayList<ComponentKey> apps);
171 
172         /**
173          * Called when the search results should be cleared.
174          */
clearSearchResult()175         void clearSearchResult();
176     }
177 
178 }