blob: 11b8891b0b12b71ed5aff24325d0da0cc54cf9e1 [file] [log] [blame]
Aga Wronska8788dad2016-01-15 17:30:15 -08001/*
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
Ben Kwa543a2922016-03-22 11:11:46 -070019import static com.android.documentsui.Shared.DEBUG;
20
Aga Wronskaaf5ace52016-02-17 13:50:42 -080021import android.annotation.Nullable;
22import android.os.Bundle;
Aga Wronska8788dad2016-01-15 17:30:15 -080023import android.provider.DocumentsContract.Root;
24import android.text.TextUtils;
25import android.util.Log;
Aga Wronska8e21daa2016-03-24 18:22:09 -070026import android.view.Menu;
Aga Wronska8788dad2016-01-15 17:30:15 -080027import android.view.MenuItem;
Aga Wronska8e21daa2016-03-24 18:22:09 -070028import android.view.MenuItem.OnActionExpandListener;
Aga Wronska8788dad2016-01-15 17:30:15 -080029import android.view.View;
30import android.view.View.OnClickListener;
31import android.view.View.OnFocusChangeListener;
32import android.widget.SearchView;
33import android.widget.SearchView.OnQueryTextListener;
34
35import com.android.documentsui.model.RootInfo;
36
37/**
38 * Manages searching UI behavior.
39 */
Aga Wronskaaf5ace52016-02-17 13:50:42 -080040final class SearchViewManager implements
Aga Wronska8e21daa2016-03-24 18:22:09 -070041 SearchView.OnCloseListener, OnQueryTextListener, OnClickListener, OnFocusChangeListener,
42 OnActionExpandListener {
Aga Wronska8788dad2016-01-15 17:30:15 -080043
44 public interface SearchManagerListener {
Aga Wronskaaf5ace52016-02-17 13:50:42 -080045 void onSearchChanged(@Nullable String query);
Aga Wronska8e21daa2016-03-24 18:22:09 -070046 void onSearchFinished();
Aga Wronska8788dad2016-01-15 17:30:15 -080047 }
48
49 public static final String TAG = "SearchManger";
50
51 private SearchManagerListener mListener;
Aga Wronska8788dad2016-01-15 17:30:15 -080052 private boolean mSearchExpanded;
Aga Wronskaaf5ace52016-02-17 13:50:42 -080053 private String mCurrentSearch;
Aga Wronska8788dad2016-01-15 17:30:15 -080054 private boolean mIgnoreNextClose;
Aga Wronska8e21daa2016-03-24 18:22:09 -070055 private boolean mFullBar;
Aga Wronska8788dad2016-01-15 17:30:15 -080056
Steve McKay18d01e82016-02-03 11:15:57 -080057 private DocumentsToolbar mActionBar;
Aga Wronska8e21daa2016-03-24 18:22:09 -070058 private MenuItem mMenuItem;
59 private SearchView mSearchView;
Aga Wronska8788dad2016-01-15 17:30:15 -080060
Aga Wronskaaf5ace52016-02-17 13:50:42 -080061 public SearchViewManager(SearchManagerListener listener, @Nullable Bundle savedState) {
Aga Wronska8788dad2016-01-15 17:30:15 -080062 mListener = listener;
Aga Wronskaaf5ace52016-02-17 13:50:42 -080063 mCurrentSearch = savedState != null ? savedState.getString(Shared.EXTRA_QUERY) : null;
Aga Wronska8788dad2016-01-15 17:30:15 -080064 }
65
66 public void setSearchMangerListener(SearchManagerListener listener) {
67 mListener = listener;
68 }
69
Aga Wronska8e21daa2016-03-24 18:22:09 -070070 public void install(DocumentsToolbar actionBar, boolean isFullBarSearch) {
Aga Wronska8788dad2016-01-15 17:30:15 -080071 mActionBar = actionBar;
Aga Wronska8e21daa2016-03-24 18:22:09 -070072 mMenuItem = actionBar.getSearchMenu();
73 mSearchView = (SearchView) mMenuItem.getActionView();
Aga Wronska8788dad2016-01-15 17:30:15 -080074
Aga Wronska8e21daa2016-03-24 18:22:09 -070075 mSearchView.setOnQueryTextListener(this);
76 mSearchView.setOnCloseListener(this);
77 mSearchView.setOnSearchClickListener(this);
78 mSearchView.setOnQueryTextFocusChangeListener(this);
79
80 mFullBar = isFullBarSearch;
81 if (mFullBar) {
82 mMenuItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
83 | MenuItem.SHOW_AS_ACTION_ALWAYS);
84 mMenuItem.setOnActionExpandListener(this);
85 }
Aga Wronskaaf5ace52016-02-17 13:50:42 -080086
87 restoreSearch();
Aga Wronska8788dad2016-01-15 17:30:15 -080088 }
89
90 /**
Aga Wronska8e21daa2016-03-24 18:22:09 -070091 * Used to hide menu icons, when the search is being restored. Needed because search restoration
92 * is done before onPrepareOptionsMenu(Menu menu) that is overriding the icons visibility.
93 */
94 public void updateMenu() {
95 if (isSearching() && mFullBar) {
96 Menu menu = mActionBar.getMenu();
97 menu.setGroupVisible(R.id.group_hide_when_searching, false);
98 }
99 }
100
101 /**
Aga Wronska8788dad2016-01-15 17:30:15 -0800102 * @param root Info about the current directory.
103 */
104 void update(RootInfo root) {
Aga Wronska8e21daa2016-03-24 18:22:09 -0700105 if (mMenuItem == null) {
Ben Kwa543a2922016-03-22 11:11:46 -0700106 if (DEBUG) Log.d(TAG, "update called before Search MenuItem installed.");
Aga Wronska8788dad2016-01-15 17:30:15 -0800107 return;
108 }
109
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800110 if (mCurrentSearch != null) {
Aga Wronska8e21daa2016-03-24 18:22:09 -0700111 mMenuItem.expandActionView();
Aga Wronska8788dad2016-01-15 17:30:15 -0800112
Aga Wronska8e21daa2016-03-24 18:22:09 -0700113 mSearchView.setIconified(false);
114 mSearchView.clearFocus();
115 mSearchView.setQuery(mCurrentSearch, false);
Aga Wronska8788dad2016-01-15 17:30:15 -0800116 } else {
Aga Wronska8e21daa2016-03-24 18:22:09 -0700117 mSearchView.clearFocus();
118 if (!mSearchView.isIconified()) {
Aga Wronska8788dad2016-01-15 17:30:15 -0800119 mIgnoreNextClose = true;
Aga Wronska8e21daa2016-03-24 18:22:09 -0700120 mSearchView.setIconified(true);
Aga Wronska8788dad2016-01-15 17:30:15 -0800121 }
122
Aga Wronska8e21daa2016-03-24 18:22:09 -0700123 if (mMenuItem.isActionViewExpanded()) {
124 mMenuItem.collapseActionView();
Aga Wronska8788dad2016-01-15 17:30:15 -0800125 }
126 }
127
128 showMenu(root != null
129 && ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0));
130 }
131
132 void showMenu(boolean visible) {
Aga Wronska8e21daa2016-03-24 18:22:09 -0700133 if (mMenuItem == null) {
Ben Kwa543a2922016-03-22 11:11:46 -0700134 if (DEBUG) Log.d(TAG, "showMenu called before Search MenuItem installed.");
Aga Wronska8788dad2016-01-15 17:30:15 -0800135 return;
136 }
137
Aga Wronska8788dad2016-01-15 17:30:15 -0800138 if (!visible) {
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800139 mCurrentSearch = null;
Aga Wronska8788dad2016-01-15 17:30:15 -0800140 }
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800141
Aga Wronska8e21daa2016-03-24 18:22:09 -0700142 mMenuItem.setVisible(visible);
Aga Wronska8788dad2016-01-15 17:30:15 -0800143 }
144
145 /**
146 * Cancels current search operation. Triggers clearing and collapsing the SearchView.
147 *
148 * @return True if it cancels search. False if it does not operate search currently.
149 */
150 boolean cancelSearch() {
151 if (isExpanded() || isSearching()) {
152 // If the query string is not empty search view won't get iconified
Aga Wronska8e21daa2016-03-24 18:22:09 -0700153 mSearchView.setQuery("", false);
154
155 if (mFullBar) {
156 onClose();
157 } else {
158 // Causes calling onClose(). onClose() is triggering directory content update.
159 mSearchView.setIconified(true);
160 }
Aga Wronska8788dad2016-01-15 17:30:15 -0800161 return true;
162 }
163 return false;
164 }
165
Aga Wronska8e21daa2016-03-24 18:22:09 -0700166 /**
167 * Sets search view into the searching state. Used to restore state after device orientation
168 * change.
169 */
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800170 private void restoreSearch() {
171 if (isSearching()) {
Aga Wronska8e21daa2016-03-24 18:22:09 -0700172 if(mFullBar) {
173 mMenuItem.expandActionView();
174 } else {
175 mSearchView.setIconified(false);
176 }
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800177 onSearchExpanded();
Aga Wronska8e21daa2016-03-24 18:22:09 -0700178 mSearchView.setQuery(mCurrentSearch, false);
179 mSearchView.clearFocus();
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800180 }
181 }
182
183 private void onSearchExpanded() {
184 mSearchExpanded = true;
Aga Wronska8e21daa2016-03-24 18:22:09 -0700185 if(mFullBar) {
186 Menu menu = mActionBar.getMenu();
187 menu.setGroupVisible(R.id.group_hide_when_searching, false);
188 }
Aga Wronska8788dad2016-01-15 17:30:15 -0800189 }
190
191 /**
Aga Wronska8e21daa2016-03-24 18:22:09 -0700192 * Clears the search. Triggers refreshing of the directory content.
Aga Wronska8788dad2016-01-15 17:30:15 -0800193 * @return True if the default behavior of clearing/dismissing SearchView should be overridden.
194 * False otherwise.
195 */
196 @Override
197 public boolean onClose() {
198 mSearchExpanded = false;
199 if (mIgnoreNextClose) {
200 mIgnoreNextClose = false;
201 return false;
202 }
203
Aga Wronska8788dad2016-01-15 17:30:15 -0800204 // Refresh the directory if a search was done
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800205 if (mCurrentSearch != null) {
206 mCurrentSearch = null;
Aga Wronska8788dad2016-01-15 17:30:15 -0800207 if (mListener != null) {
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800208 mListener.onSearchChanged(mCurrentSearch);
Aga Wronska8788dad2016-01-15 17:30:15 -0800209 }
210 }
Aga Wronska8e21daa2016-03-24 18:22:09 -0700211
212 if(mFullBar) {
213 mMenuItem.collapseActionView();
214 }
215 mListener.onSearchFinished();
216
Aga Wronska8788dad2016-01-15 17:30:15 -0800217 return false;
218 }
219
220 /**
Aga Wronska8e21daa2016-03-24 18:22:09 -0700221 * Called when owning activity is saving state to be used to restore state during creation.
222 * @param state Bundle to save state too
223 */
224 public void onSaveInstanceState(Bundle state) {
225 state.putString(Shared.EXTRA_QUERY, mCurrentSearch);
226 }
227
228 /**
229 * Sets mSearchExpanded. Called when search icon is clicked to start search for both search view
230 * modes.
Aga Wronska8788dad2016-01-15 17:30:15 -0800231 */
232 @Override
233 public void onClick(View v) {
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800234 onSearchExpanded();
Aga Wronska8788dad2016-01-15 17:30:15 -0800235 }
236
237 @Override
238 public boolean onQueryTextSubmit(String query) {
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800239 mCurrentSearch = query;
Aga Wronska8e21daa2016-03-24 18:22:09 -0700240 mSearchView.clearFocus();
Aga Wronska8788dad2016-01-15 17:30:15 -0800241 if (mListener != null) {
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800242 mListener.onSearchChanged(mCurrentSearch);
Aga Wronska8788dad2016-01-15 17:30:15 -0800243 }
244 return true;
245 }
246
Aga Wronska8e21daa2016-03-24 18:22:09 -0700247 /**
248 * Used to detect and handle back button pressed event when search is expanded.
249 */
Aga Wronska8788dad2016-01-15 17:30:15 -0800250 @Override
251 public void onFocusChange(View v, boolean hasFocus) {
252 if (!hasFocus) {
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800253 if (mCurrentSearch == null) {
Aga Wronska8e21daa2016-03-24 18:22:09 -0700254 mSearchView.setIconified(true);
255 } else if (TextUtils.isEmpty(mSearchView.getQuery())) {
Aga Wronska8788dad2016-01-15 17:30:15 -0800256 cancelSearch();
257 }
258 }
259 }
260
261 @Override
262 public boolean onQueryTextChange(String newText) {
263 return false;
264 }
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800265
Aga Wronska8e21daa2016-03-24 18:22:09 -0700266 @Override
267 public boolean onMenuItemActionCollapse(MenuItem item) {
268 Menu menu = mActionBar.getMenu();
269 menu.setGroupVisible(R.id.group_hide_when_searching, true);
270
271 // Handles case when search view is collapsed by using the arrow on the left of the bar
272 if (isExpanded() || isSearching()) {
273 cancelSearch();
274 return false;
275 }
276 return true;
277 }
278
279 @Override
280 public boolean onMenuItemActionExpand(MenuItem item) {
281 return true;
282 }
283
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800284 String getCurrentSearch() {
285 return mCurrentSearch;
286 }
287
Aga Wronska8e21daa2016-03-24 18:22:09 -0700288 boolean isSearching() {
289 return mCurrentSearch != null;
290 }
291
292 boolean isExpanded() {
293 return mSearchExpanded;
294 }
295
Aga Wronska8788dad2016-01-15 17:30:15 -0800296}