• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.SpannableStringBuilder;
20 import android.text.TextUtils;
21 import android.text.TextWatcher;
22 import android.text.style.SuggestionSpan;
23 import android.view.KeyEvent;
24 import android.view.View;
25 import android.view.View.OnFocusChangeListener;
26 import android.view.inputmethod.EditorInfo;
27 import android.widget.TextView;
28 import android.widget.TextView.OnEditorActionListener;
29 
30 import com.android.launcher3.ExtendedEditText;
31 import com.android.launcher3.Utilities;
32 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
33 import com.android.launcher3.config.FeatureFlags;
34 import com.android.launcher3.search.SearchAlgorithm;
35 import com.android.launcher3.search.SearchCallback;
36 import com.android.launcher3.views.ActivityContext;
37 
38 /**
39  * An interface to a search box that AllApps can command.
40  */
41 public class AllAppsSearchBarController
42         implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener,
43         OnFocusChangeListener {
44 
45     protected ActivityContext mLauncher;
46     protected SearchCallback<AdapterItem> mCallback;
47     protected ExtendedEditText mInput;
48     protected String mQuery;
49     private String[] mTextConversions;
50 
51     protected SearchAlgorithm<AdapterItem> mSearchAlgorithm;
52 
setVisibility(int visibility)53     public void setVisibility(int visibility) {
54         mInput.setVisibility(visibility);
55     }
56 
57     /**
58      * Sets the references to the apps model and the search result callback.
59      */
initialize( SearchAlgorithm<AdapterItem> searchAlgorithm, ExtendedEditText input, ActivityContext launcher, SearchCallback<AdapterItem> callback)60     public final void initialize(
61             SearchAlgorithm<AdapterItem> searchAlgorithm, ExtendedEditText input,
62             ActivityContext launcher, SearchCallback<AdapterItem> callback) {
63         mCallback = callback;
64         mLauncher = launcher;
65 
66         mInput = input;
67         mInput.addTextChangedListener(this);
68         mInput.setOnEditorActionListener(this);
69         mInput.setOnBackKeyListener(this);
70         mInput.addOnFocusChangeListener(this);
71         mSearchAlgorithm = searchAlgorithm;
72     }
73 
74     @Override
beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)75     public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
76         // Do nothing
77     }
78 
79     @Override
onTextChanged(CharSequence s, int start, int before, int count)80     public void onTextChanged(CharSequence s, int start, int before, int count) {
81         mTextConversions = extractTextConversions(s);
82     }
83 
84     /**
85      * Extract text conversions from composing text and send them for search.
86      */
extractTextConversions(CharSequence text)87     public static String[] extractTextConversions(CharSequence text) {
88         if (text instanceof SpannableStringBuilder) {
89             SpannableStringBuilder spanned = (SpannableStringBuilder) text;
90             SuggestionSpan[] suggestionSpans =
91                 spanned.getSpans(0, text.length(), SuggestionSpan.class);
92             if (suggestionSpans != null && suggestionSpans.length > 0) {
93                 spanned.removeSpan(suggestionSpans[0]);
94                 return suggestionSpans[0].getSuggestions();
95             }
96         }
97         return null;
98     }
99 
100     @Override
afterTextChanged(final Editable s)101     public void afterTextChanged(final Editable s) {
102         mQuery = s.toString();
103         if (mQuery.isEmpty()) {
104             mSearchAlgorithm.cancel(true);
105             mCallback.clearSearchResult();
106         } else {
107             mSearchAlgorithm.cancel(false);
108             mSearchAlgorithm.doSearch(mQuery, mTextConversions, mCallback);
109         }
110     }
111 
refreshSearchResult()112     public void refreshSearchResult() {
113         if (TextUtils.isEmpty(mQuery)) {
114             return;
115         }
116         // If play store continues auto updating an app, we want to show partial result.
117         mSearchAlgorithm.cancel(false);
118         mSearchAlgorithm.doSearch(mQuery, mCallback);
119     }
120 
121     @Override
onEditorAction(TextView v, int actionId, KeyEvent event)122     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
123 
124         if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_GO) {
125             // selectFocusedView should return SearchTargetEvent that is passed onto onClick
126             return mLauncher.getAppsView().getMainAdapterProvider().launchHighlightedItem();
127         }
128         return false;
129     }
130 
131     @Override
onBackKey()132     public boolean onBackKey() {
133         // Only hide the search field if there is no query
134         String query = Utilities.trim(mInput.getEditableText().toString());
135         if (query.isEmpty()) {
136             reset();
137             return true;
138         }
139         return false;
140     }
141 
142     @Override
onFocusChange(View view, boolean hasFocus)143     public void onFocusChange(View view, boolean hasFocus) {
144         if (!hasFocus && !FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
145             mInput.hideKeyboard();
146         }
147     }
148 
149     /**
150      * Resets the search bar state.
151      */
reset()152     public void reset() {
153         mCallback.clearSearchResult();
154         mInput.reset();
155         mQuery = null;
156         mInput.removeOnFocusChangeListener(this);
157     }
158 
159     /**
160      * Focuses the search field to handle key events.
161      */
focusSearchField()162     public void focusSearchField() {
163         mInput.showKeyboard(true /* shouldFocus */);
164     }
165 
166     /**
167      * Returns whether the search field is focused.
168      */
isSearchFieldFocused()169     public boolean isSearchFieldFocused() {
170         return mInput.isFocused();
171     }
172 }
173