SearchViewManager.java revision f6a31d319f3e08d26ca4c0fbfb5803056bafb243
1/*
2 * Copyright (C) 2013 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
17package com.android.documentsui;
18
19import android.provider.DocumentsContract.Root;
20import android.text.TextUtils;
21import android.util.Log;
22import android.view.MenuItem;
23import android.view.View;
24import android.view.View.OnClickListener;
25import android.view.View.OnFocusChangeListener;
26import android.widget.SearchView;
27import android.widget.SearchView.OnQueryTextListener;
28
29import com.android.documentsui.model.RootInfo;
30
31/**
32 * Manages searching UI behavior.
33 */
34final class SearchManager implements
35        SearchView.OnCloseListener, OnQueryTextListener, OnClickListener, OnFocusChangeListener {
36
37    public interface SearchManagerListener {
38        void onSearchChanged();
39
40        void onSearchQueryChanged(String query);
41    }
42
43    public static final String TAG = "SearchManger";
44
45    private SearchManagerListener mListener;
46    private String currentSearch;
47    private boolean mSearchExpanded;
48    private boolean mIgnoreNextClose;
49
50    private DocumentsToolBar mActionBar;
51    private MenuItem mMenu;
52    private SearchView mView;
53
54    public SearchManager(SearchManagerListener listener) {
55        mListener = listener;
56    }
57
58    public void setSearchMangerListener(SearchManagerListener listener) {
59        mListener = listener;
60    }
61
62    public void install(DocumentsToolBar actionBar) {
63        assert (mActionBar == null);
64        mActionBar = actionBar;
65        mMenu = actionBar.getSearchMenu();
66        mView = (SearchView) mMenu.getActionView();
67
68        mView.setOnQueryTextListener(this);
69        mView.setOnCloseListener(this);
70        mView.setOnSearchClickListener(this);
71        mView.setOnQueryTextFocusChangeListener(this);
72    }
73
74    /**
75     * @param root Info about the current directory.
76     */
77    void update(RootInfo root) {
78        if (mMenu == null) {
79            Log.d(TAG, "update called before Search MenuItem installed.");
80            return;
81        }
82
83        if (currentSearch != null) {
84            mMenu.expandActionView();
85
86            mView.setIconified(false);
87            mView.clearFocus();
88            mView.setQuery(currentSearch, false);
89        } else {
90            mView.clearFocus();
91            if (!mView.isIconified()) {
92                mIgnoreNextClose = true;
93                mView.setIconified(true);
94            }
95
96            if (mMenu.isActionViewExpanded()) {
97                mMenu.collapseActionView();
98            }
99        }
100
101        showMenu(root != null
102                && ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0));
103    }
104
105    void showMenu(boolean visible) {
106        if (mMenu == null) {
107            Log.d(TAG, "showMenu called before Search MenuItem installed.");
108            return;
109        }
110
111        mMenu.setVisible(visible);
112        if (!visible) {
113            currentSearch = null;
114            if (mListener != null) {
115                mListener.onSearchQueryChanged(currentSearch);
116            }
117        }
118    }
119
120    /**
121     * Cancels current search operation. Triggers clearing and collapsing the SearchView.
122     *
123     * @return True if it cancels search. False if it does not operate search currently.
124     */
125    boolean cancelSearch() {
126        if (isExpanded() || isSearching()) {
127            // If the query string is not empty search view won't get iconified
128            mView.setQuery("", false);
129            // Causes calling onClose(). onClose() is triggering directory content update.
130            mView.setIconified(true);
131            return true;
132        }
133        return false;
134    }
135
136    boolean isSearching() {
137        return currentSearch != null;
138    }
139
140    boolean isExpanded() {
141        return mSearchExpanded;
142    }
143
144    /**
145     * Clears the search. Clears the SearchView background color. Triggers refreshing of the
146     * directory content.
147     * @return True if the default behavior of clearing/dismissing SearchView should be overridden.
148     *         False otherwise.
149     */
150    @Override
151    public boolean onClose() {
152        mSearchExpanded = false;
153        if (mIgnoreNextClose) {
154            mIgnoreNextClose = false;
155            return false;
156        }
157
158        mView.setBackgroundColor(
159                mView.getResources().getColor(android.R.color.transparent, null));
160
161        // Refresh the directory if a search was done
162        if (currentSearch != null) {
163            currentSearch = null;
164            if (mListener != null) {
165                mListener.onSearchQueryChanged(currentSearch);
166                mListener.onSearchChanged();
167            }
168        }
169        return false;
170    }
171
172    /**
173     * Sets mSearchExpanded. Called when search icon is clicked to start search. Used to detect when
174     * the view expanded instead of onMenuItemActionExpand, because SearchView has showAsAction set
175     * to always and onMenuItemAction* methods are not called.
176     */
177    @Override
178    public void onClick(View v) {
179        mSearchExpanded = true;
180        mView.setBackgroundColor(
181                mView.getResources().getColor(R.color.menu_search_background, null));
182    }
183
184    @Override
185    public boolean onQueryTextSubmit(String query) {
186        currentSearch = query;
187        mView.clearFocus();
188        if (mListener != null) {
189            mListener.onSearchQueryChanged(currentSearch);
190            mListener.onSearchChanged();
191        }
192        return true;
193    }
194
195    @Override
196    public void onFocusChange(View v, boolean hasFocus) {
197        if (!hasFocus) {
198            if (currentSearch == null) {
199                mView.setIconified(true);
200            } else if (TextUtils.isEmpty(mView.getQuery())) {
201                cancelSearch();
202            }
203        }
204    }
205
206    @Override
207    public boolean onQueryTextChange(String newText) {
208        return false;
209    }
210}
211