Merge "SearchView keyboard opens and closes appropriately"
This commit is contained in:
committed by
Android (Google) Code Review
commit
f1c80deab0
@@ -30,6 +30,7 @@ import android.util.Log;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.LinearLayout.LayoutParams;
|
import android.widget.LinearLayout.LayoutParams;
|
||||||
import android.widget.SearchView;
|
import android.widget.SearchView;
|
||||||
|
|
||||||
@@ -48,6 +49,9 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
{
|
{
|
||||||
private static final String TAG = "SearchFragment";
|
private static final String TAG = "SearchFragment";
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static final int SEARCH_TAG = "SearchViewTag".hashCode();
|
||||||
|
|
||||||
// State values
|
// State values
|
||||||
private static final String STATE_QUERY = "state_query";
|
private static final String STATE_QUERY = "state_query";
|
||||||
private static final String STATE_NEVER_ENTERED_QUERY = "state_never_entered_query";
|
private static final String STATE_NEVER_ENTERED_QUERY = "state_never_entered_query";
|
||||||
@@ -80,12 +84,23 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
@VisibleForTesting (otherwise = VisibleForTesting.PRIVATE)
|
@VisibleForTesting (otherwise = VisibleForTesting.PRIVATE)
|
||||||
SearchFeatureProvider mSearchFeatureProvider;
|
SearchFeatureProvider mSearchFeatureProvider;
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
private SearchResultsAdapter mSearchAdapter;
|
||||||
SearchResultsAdapter mSearchAdapter;
|
|
||||||
|
|
||||||
private RecyclerView mResultsRecyclerView;
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
|
RecyclerView mResultsRecyclerView;
|
||||||
private SearchView mSearchView;
|
private SearchView mSearchView;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
final RecyclerView.OnScrollListener mScrollListener =
|
||||||
|
new RecyclerView.OnScrollListener() {
|
||||||
|
@Override
|
||||||
|
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
||||||
|
if (dy != 0) {
|
||||||
|
hideKeyboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
return MetricsProto.MetricsEvent.DASHBOARD_SEARCH_RESULTS;
|
return MetricsProto.MetricsEvent.DASHBOARD_SEARCH_RESULTS;
|
||||||
@@ -122,6 +137,7 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
actionBar.setCustomView(mSearchView);
|
actionBar.setCustomView(mSearchView);
|
||||||
actionBar.setDisplayShowCustomEnabled(true);
|
actionBar.setDisplayShowCustomEnabled(true);
|
||||||
actionBar.setDisplayShowTitleEnabled(false);
|
actionBar.setDisplayShowTitleEnabled(false);
|
||||||
|
mSearchView.requestFocus();
|
||||||
|
|
||||||
// Run the Index update only if we have some space
|
// Run the Index update only if we have some space
|
||||||
if (!Utils.isLowStorage(activity)) {
|
if (!Utils.isLowStorage(activity)) {
|
||||||
@@ -138,6 +154,7 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
mResultsRecyclerView = (RecyclerView) view.findViewById(R.id.list_results);
|
mResultsRecyclerView = (RecyclerView) view.findViewById(R.id.list_results);
|
||||||
mResultsRecyclerView.setAdapter(mSearchAdapter);
|
mResultsRecyclerView.setAdapter(mSearchAdapter);
|
||||||
mResultsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
mResultsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
|
mResultsRecyclerView.addOnScrollListener(mScrollListener);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +206,7 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
// Save submitted query.
|
// Save submitted query.
|
||||||
getLoaderManager().restartLoader(SaveQueryRecorderCallback.LOADER_ID_SAVE_QUERY_TASK, null,
|
getLoaderManager().restartLoader(SaveQueryRecorderCallback.LOADER_ID_SAVE_QUERY_TASK, null,
|
||||||
mSaveQueryRecorderCallback);
|
mSaveQueryRecorderCallback);
|
||||||
|
hideKeyboard();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,17 +257,33 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
loaderManager.restartLoader(LOADER_ID_INSTALLED_APPS, null /* args */, this /* callback */);
|
loaderManager.restartLoader(LOADER_ID_INSTALLED_APPS, null /* args */, this /* callback */);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SearchView makeSearchView(ActionBar actionBar, String query) {
|
@VisibleForTesting (otherwise = VisibleForTesting.PRIVATE)
|
||||||
|
SearchView makeSearchView(ActionBar actionBar, String query) {
|
||||||
final SearchView searchView = new SearchView(actionBar.getThemedContext());
|
final SearchView searchView = new SearchView(actionBar.getThemedContext());
|
||||||
searchView.setIconifiedByDefault(false);
|
searchView.setIconifiedByDefault(false);
|
||||||
searchView.setQuery(query, false /* submitQuery */);
|
searchView.setQuery(query, false /* submitQuery */);
|
||||||
searchView.setOnQueryTextListener(this);
|
searchView.setOnQueryTextListener(this);
|
||||||
|
searchView.setTag(SEARCH_TAG, searchView);
|
||||||
final LayoutParams lp =
|
final LayoutParams lp =
|
||||||
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
|
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
|
||||||
searchView.setLayoutParams(lp);
|
searchView.setLayoutParams(lp);
|
||||||
return searchView;
|
return searchView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void hideKeyboard() {
|
||||||
|
final Activity activity = getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
View view = activity.getCurrentFocus();
|
||||||
|
InputMethodManager imm = (InputMethodManager)
|
||||||
|
activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mResultsRecyclerView != null) {
|
||||||
|
mResultsRecyclerView.requestFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class SaveQueryRecorderCallback implements LoaderManager.LoaderCallbacks<Void> {
|
private class SaveQueryRecorderCallback implements LoaderManager.LoaderCallbacks<Void> {
|
||||||
// TODO: make a generic background task manager to handle one-off tasks like this one.
|
// TODO: make a generic background task manager to handle one-off tasks like this one.
|
||||||
|
|
||||||
|
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.search2;
|
||||||
|
|
||||||
|
import android.support.test.filters.SmallTest;
|
||||||
|
import android.support.test.rule.ActivityTestRule;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.widget.SearchView;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static android.support.test.espresso.Espresso.onView;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.hasFocus;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withTagKey;
|
||||||
|
import static android.support.test.espresso.assertion.ViewAssertions.matches;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.core.AllOf.allOf;
|
||||||
|
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class SearchFragmentEspressoTest {
|
||||||
|
@Rule
|
||||||
|
public ActivityTestRule<SearchActivity> mActivityRule =
|
||||||
|
new ActivityTestRule<>(SearchActivity.class, true, true);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_OpenKeyboardOnSearchLaunch() {
|
||||||
|
onView(allOf(hasFocus(), withTagKey(SearchFragment.SEARCH_TAG)))
|
||||||
|
.check(matches(withClassName(containsString(SearchView.class.getName()))));
|
||||||
|
}
|
||||||
|
}
|
@@ -20,16 +20,12 @@ import android.content.Context;
|
|||||||
import android.content.Loader;
|
import android.content.Loader;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import android.os.UserManager;
|
|
||||||
import com.android.internal.logging.nano.MetricsProto;
|
import com.android.internal.logging.nano.MetricsProto;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsRobolectricTestRunner;
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
import com.android.settings.dashboard.SiteMapManager;
|
|
||||||
import com.android.settings.testutils.DatabaseTestUtils;
|
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -41,14 +37,11 @@ import org.robolectric.RuntimeEnvironment;
|
|||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.util.ActivityController;
|
import org.robolectric.util.ActivityController;
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyString;
|
import static org.mockito.Matchers.anyString;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
@@ -248,5 +241,4 @@ public class SearchFragmentTest {
|
|||||||
|
|
||||||
verify(fragment, times(2)).onLoadFinished(any(Loader.class), any(List.class));
|
verify(fragment, times(2)).onLoadFinished(any(Loader.class), any(List.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user