Merge "Add full bar mode for search view on small devices" into nyc-dev

This commit is contained in:
Aga Wronska
2016-03-28 16:18:56 +00:00
committed by Android (Google) Code Review
8 changed files with 227 additions and 113 deletions

View File

@@ -31,61 +31,64 @@
android:actionViewClass="android.widget.SearchView" android:actionViewClass="android.widget.SearchView"
android:imeOptions="actionSearch" android:imeOptions="actionSearch"
android:visible="false" /> android:visible="false" />
<item <!-- This group is being hidden when searching is in full bar mode-->
android:id="@+id/menu_grid" <group android:id="@+id/group_hide_when_searching">
android:title="@string/menu_grid" <item
android:icon="@drawable/ic_menu_view_grid" android:id="@+id/menu_grid"
android:showAsAction="always" /> android:title="@string/menu_grid"
<item android:icon="@drawable/ic_menu_view_grid"
android:id="@+id/menu_list" android:showAsAction="always" />
android:title="@string/menu_list" <item
android:icon="@drawable/ic_menu_view_list" android:id="@+id/menu_list"
android:showAsAction="always" /> android:title="@string/menu_list"
android:icon="@drawable/ic_menu_view_list"
android:showAsAction="always" />
<item <item
android:id="@+id/menu_new_window" android:id="@+id/menu_new_window"
android:title="@string/menu_new_window" android:title="@string/menu_new_window"
android:alphabeticShortcut="n" android:alphabeticShortcut="n"
android:showAsAction="never" android:showAsAction="never"
android:visible="false" /> android:visible="false" />
<item <item
android:id="@+id/menu_create_dir" android:id="@+id/menu_create_dir"
android:title="@string/menu_create_dir" android:title="@string/menu_create_dir"
android:icon="@drawable/ic_menu_new_folder" android:icon="@drawable/ic_menu_new_folder"
android:alphabeticShortcut="e" android:alphabeticShortcut="e"
android:showAsAction="never" android:showAsAction="never"
android:visible="false" /> android:visible="false" />
<item <item
android:id="@+id/menu_paste_from_clipboard" android:id="@+id/menu_paste_from_clipboard"
android:title="@string/menu_paste_from_clipboard" android:title="@string/menu_paste_from_clipboard"
android:alphabeticShortcut="v" android:alphabeticShortcut="v"
android:showAsAction="never" android:showAsAction="never"
android:visible="false" /> android:visible="false" />
<!-- Copy action is defined in mode_directory.xml --> <!-- Copy action is defined in mode_directory.xml -->
<item <item
android:id="@+id/menu_sort" android:id="@+id/menu_sort"
android:title="@string/menu_sort" android:title="@string/menu_sort"
android:icon="@drawable/ic_menu_sortby" android:icon="@drawable/ic_menu_sortby"
android:showAsAction="ifRoom"> android:showAsAction="ifRoom">
<menu> <menu>
<item <item
android:id="@+id/menu_sort_name" android:id="@+id/menu_sort_name"
android:title="@string/sort_name" /> android:title="@string/sort_name" />
<item <item
android:id="@+id/menu_sort_date" android:id="@+id/menu_sort_date"
android:title="@string/sort_date" /> android:title="@string/sort_date" />
<item <item
android:id="@+id/menu_sort_size" android:id="@+id/menu_sort_size"
android:title="@string/sort_size" /> android:title="@string/sort_size" />
</menu> </menu>
</item> </item>
<item <item
android:id="@+id/menu_file_size" android:id="@+id/menu_file_size"
android:showAsAction="never" android:showAsAction="never"
android:visible="false" /> android:visible="false" />
<item <item
android:id="@+id/menu_settings" android:id="@+id/menu_settings"
android:title="@string/menu_settings" android:title="@string/menu_settings"
android:showAsAction="never" android:showAsAction="never"
android:visible="false" /> android:visible="false" />
</group>
</menu> </menu>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<color name="menu_search_background">#ff676f74</color>
</resources>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Indicates if search view is taking the whole toolbar space -->
<bool name="full_bar_search_view">false</bool>
</resources>

View File

@@ -24,7 +24,7 @@
<color name="window_background">#fff1f1f1</color> <color name="window_background">#fff1f1f1</color>
<color name="drawer_background">#fff1f1f1</color> <color name="drawer_background">#fff1f1f1</color>
<color name="directory_background">#fff7f7f7</color> <color name="directory_background">#fff7f7f7</color>
<color name="menu_search_background">#ff676f74</color> <color name="menu_search_background">@android:color/transparent</color>
<color name="primary_dark">@*android:color/primary_dark_material_dark</color> <color name="primary_dark">@*android:color/primary_dark_material_dark</color>
<color name="primary">@*android:color/material_blue_grey_900</color> <color name="primary">@*android:color/material_blue_grey_900</color>

View File

@@ -26,4 +26,6 @@
<bool name="home_root_hidden">true</bool> <bool name="home_root_hidden">true</bool>
<!-- Indicates if the advanced roots like internal storage should be hidden in the roots list) --> <!-- Indicates if the advanced roots like internal storage should be hidden in the roots list) -->
<bool name="advanced_roots_hidden">true</bool> <bool name="advanced_roots_hidden">true</bool>
<!-- Indicates if search view is taking the whole toolbar space -->
<bool name="full_bar_search_view">true</bool>
</resources> </resources>

View File

@@ -146,7 +146,8 @@ public abstract class BaseActivity extends Activity
getMenuInflater().inflate(R.menu.activity, menu); getMenuInflater().inflate(R.menu.activity, menu);
mNavigator.update(); mNavigator.update();
mSearchManager.install((DocumentsToolbar) findViewById(R.id.toolbar)); boolean fullBarSearch = getResources().getBoolean(R.bool.full_bar_search_view);
mSearchManager.install((DocumentsToolbar) findViewById(R.id.toolbar), fullBarSearch);
return showMenu; return showMenu;
} }
@@ -378,8 +379,12 @@ public abstract class BaseActivity extends Activity
public void onSearchChanged(@Nullable String query) { public void onSearchChanged(@Nullable String query) {
// We should not get here if root is not searchable // We should not get here if root is not searchable
assert(canSearchRoot()); assert(canSearchRoot());
reloadSearch(query); reloadSearch(query);
}
@Override
public void onSearchFinished() {
// Restores menu icons state
invalidateOptionsMenu(); invalidateOptionsMenu();
} }

View File

@@ -201,6 +201,8 @@ public class FilesActivity extends BaseActivity {
newWindow.setVisible(true); newWindow.setVisible(true);
Menus.disableHiddenItems(menu, pasteFromCb); Menus.disableHiddenItems(menu, pasteFromCb);
// It hides icon if searching in progress
mSearchManager.updateMenu();
return true; return true;
} }

View File

@@ -23,7 +23,9 @@ import android.os.Bundle;
import android.provider.DocumentsContract.Root; import android.provider.DocumentsContract.Root;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MenuItem.OnActionExpandListener;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener; import android.view.View.OnFocusChangeListener;
@@ -36,10 +38,12 @@ import com.android.documentsui.model.RootInfo;
* Manages searching UI behavior. * Manages searching UI behavior.
*/ */
final class SearchViewManager implements final class SearchViewManager implements
SearchView.OnCloseListener, OnQueryTextListener, OnClickListener, OnFocusChangeListener { SearchView.OnCloseListener, OnQueryTextListener, OnClickListener, OnFocusChangeListener,
OnActionExpandListener {
public interface SearchManagerListener { public interface SearchManagerListener {
void onSearchChanged(@Nullable String query); void onSearchChanged(@Nullable String query);
void onSearchFinished();
} }
public static final String TAG = "SearchManger"; public static final String TAG = "SearchManger";
@@ -48,10 +52,11 @@ final class SearchViewManager implements
private boolean mSearchExpanded; private boolean mSearchExpanded;
private String mCurrentSearch; private String mCurrentSearch;
private boolean mIgnoreNextClose; private boolean mIgnoreNextClose;
private boolean mFullBar;
private DocumentsToolbar mActionBar; private DocumentsToolbar mActionBar;
private MenuItem mMenu; private MenuItem mMenuItem;
private SearchView mView; private SearchView mSearchView;
public SearchViewManager(SearchManagerListener listener, @Nullable Bundle savedState) { public SearchViewManager(SearchManagerListener listener, @Nullable Bundle savedState) {
mListener = listener; mListener = listener;
@@ -62,45 +67,61 @@ final class SearchViewManager implements
mListener = listener; mListener = listener;
} }
public void install(DocumentsToolbar actionBar) { public void install(DocumentsToolbar actionBar, boolean isFullBarSearch) {
// assert(mActionBar == null);
mActionBar = actionBar; mActionBar = actionBar;
mMenu = actionBar.getSearchMenu(); mMenuItem = actionBar.getSearchMenu();
mView = (SearchView) mMenu.getActionView(); mSearchView = (SearchView) mMenuItem.getActionView();
mView.setOnQueryTextListener(this); mSearchView.setOnQueryTextListener(this);
mView.setOnCloseListener(this); mSearchView.setOnCloseListener(this);
mView.setOnSearchClickListener(this); mSearchView.setOnSearchClickListener(this);
mView.setOnQueryTextFocusChangeListener(this); mSearchView.setOnQueryTextFocusChangeListener(this);
mFullBar = isFullBarSearch;
if (mFullBar) {
mMenuItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
| MenuItem.SHOW_AS_ACTION_ALWAYS);
mMenuItem.setOnActionExpandListener(this);
}
restoreSearch(); restoreSearch();
} }
/**
* Used to hide menu icons, when the search is being restored. Needed because search restoration
* is done before onPrepareOptionsMenu(Menu menu) that is overriding the icons visibility.
*/
public void updateMenu() {
if (isSearching() && mFullBar) {
Menu menu = mActionBar.getMenu();
menu.setGroupVisible(R.id.group_hide_when_searching, false);
}
}
/** /**
* @param root Info about the current directory. * @param root Info about the current directory.
*/ */
void update(RootInfo root) { void update(RootInfo root) {
if (mMenu == null) { if (mMenuItem == null) {
if (DEBUG) Log.d(TAG, "update called before Search MenuItem installed."); if (DEBUG) Log.d(TAG, "update called before Search MenuItem installed.");
return; return;
} }
if (mCurrentSearch != null) { if (mCurrentSearch != null) {
mMenu.expandActionView(); mMenuItem.expandActionView();
mView.setIconified(false); mSearchView.setIconified(false);
mView.clearFocus(); mSearchView.clearFocus();
mView.setQuery(mCurrentSearch, false); mSearchView.setQuery(mCurrentSearch, false);
} else { } else {
mView.clearFocus(); mSearchView.clearFocus();
if (!mView.isIconified()) { if (!mSearchView.isIconified()) {
mIgnoreNextClose = true; mIgnoreNextClose = true;
mView.setIconified(true); mSearchView.setIconified(true);
} }
if (mMenu.isActionViewExpanded()) { if (mMenuItem.isActionViewExpanded()) {
mMenu.collapseActionView(); mMenuItem.collapseActionView();
} }
} }
@@ -109,7 +130,7 @@ final class SearchViewManager implements
} }
void showMenu(boolean visible) { void showMenu(boolean visible) {
if (mMenu == null) { if (mMenuItem == null) {
if (DEBUG) Log.d(TAG, "showMenu called before Search MenuItem installed."); if (DEBUG) Log.d(TAG, "showMenu called before Search MenuItem installed.");
return; return;
} }
@@ -118,7 +139,7 @@ final class SearchViewManager implements
mCurrentSearch = null; mCurrentSearch = null;
} }
mMenu.setVisible(visible); mMenuItem.setVisible(visible);
} }
/** /**
@@ -129,46 +150,46 @@ final class SearchViewManager implements
boolean cancelSearch() { boolean cancelSearch() {
if (isExpanded() || isSearching()) { if (isExpanded() || isSearching()) {
// If the query string is not empty search view won't get iconified // If the query string is not empty search view won't get iconified
mView.setQuery("", false); mSearchView.setQuery("", false);
// Causes calling onClose(). onClose() is triggering directory content update.
mView.setIconified(true); if (mFullBar) {
onClose();
} else {
// Causes calling onClose(). onClose() is triggering directory content update.
mSearchView.setIconified(true);
}
return true; return true;
} }
return false; return false;
} }
/**
* Sets search view into the searching state. Used to restore state after device orientation
* change.
*/
private void restoreSearch() { private void restoreSearch() {
if (isSearching()) { if (isSearching()) {
if(mFullBar) {
mMenuItem.expandActionView();
} else {
mSearchView.setIconified(false);
}
onSearchExpanded(); onSearchExpanded();
mView.setIconified(false); mSearchView.setQuery(mCurrentSearch, false);
mView.setQuery(mCurrentSearch, false); mSearchView.clearFocus();
mView.clearFocus();
} }
} }
private void onSearchExpanded() { private void onSearchExpanded() {
mSearchExpanded = true; mSearchExpanded = true;
} if(mFullBar) {
Menu menu = mActionBar.getMenu();
boolean isSearching() { menu.setGroupVisible(R.id.group_hide_when_searching, false);
return mCurrentSearch != null; }
}
boolean isExpanded() {
return mSearchExpanded;
} }
/** /**
* Called when owning activity is saving state to be used to restore state during creation. * Clears the search. Triggers refreshing of the directory content.
* @param state Bundle to save state too
*/
public void onSaveInstanceState(Bundle state) {
state.putString(Shared.EXTRA_QUERY, mCurrentSearch);
}
/**
* Clears the search. Clears the SearchView background color. Triggers refreshing of the
* directory content.
* @return True if the default behavior of clearing/dismissing SearchView should be overridden. * @return True if the default behavior of clearing/dismissing SearchView should be overridden.
* False otherwise. * False otherwise.
*/ */
@@ -187,13 +208,26 @@ final class SearchViewManager implements
mListener.onSearchChanged(mCurrentSearch); mListener.onSearchChanged(mCurrentSearch);
} }
} }
if(mFullBar) {
mMenuItem.collapseActionView();
}
mListener.onSearchFinished();
return false; return false;
} }
/** /**
* Sets mSearchExpanded. Called when search icon is clicked to start search. Used to detect when * Called when owning activity is saving state to be used to restore state during creation.
* the view expanded instead of onMenuItemActionExpand, because SearchView has showAsAction set * @param state Bundle to save state too
* to always and onMenuItemAction* methods are not called. */
public void onSaveInstanceState(Bundle state) {
state.putString(Shared.EXTRA_QUERY, mCurrentSearch);
}
/**
* Sets mSearchExpanded. Called when search icon is clicked to start search for both search view
* modes.
*/ */
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@@ -203,19 +237,22 @@ final class SearchViewManager implements
@Override @Override
public boolean onQueryTextSubmit(String query) { public boolean onQueryTextSubmit(String query) {
mCurrentSearch = query; mCurrentSearch = query;
mView.clearFocus(); mSearchView.clearFocus();
if (mListener != null) { if (mListener != null) {
mListener.onSearchChanged(mCurrentSearch); mListener.onSearchChanged(mCurrentSearch);
} }
return true; return true;
} }
/**
* Used to detect and handle back button pressed event when search is expanded.
*/
@Override @Override
public void onFocusChange(View v, boolean hasFocus) { public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) { if (!hasFocus) {
if (mCurrentSearch == null) { if (mCurrentSearch == null) {
mView.setIconified(true); mSearchView.setIconified(true);
} else if (TextUtils.isEmpty(mView.getQuery())) { } else if (TextUtils.isEmpty(mSearchView.getQuery())) {
cancelSearch(); cancelSearch();
} }
} }
@@ -226,8 +263,34 @@ final class SearchViewManager implements
return false; return false;
} }
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
Menu menu = mActionBar.getMenu();
menu.setGroupVisible(R.id.group_hide_when_searching, true);
// Handles case when search view is collapsed by using the arrow on the left of the bar
if (isExpanded() || isSearching()) {
cancelSearch();
return false;
}
return true;
}
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
return true;
}
String getCurrentSearch() { String getCurrentSearch() {
return mCurrentSearch; return mCurrentSearch;
} }
boolean isSearching() {
return mCurrentSearch != null;
}
boolean isExpanded() {
return mSearchExpanded;
}
} }