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