Merge "Add optional feedback button for settings search"
This commit is contained in:
committed by
Android (Google) Code Review
commit
8145b0f35a
59
res/drawable/no_search_results.xml
Normal file
59
res/drawable/no_search_results.xml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<!--
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector android:height="24dp" android:viewportHeight="267.9"
|
||||||
|
android:viewportWidth="236.3" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillAlpha="0.9" android:fillColor="#00000000"
|
||||||
|
android:pathData="M18,-19c0,-0.4 0,-0.5 -0.3,-0.3l-12,7c-0.3,0.2 -0.2,0.5 0.1,0.6l11.9,7C18,-4.5 18,-4.7 18,-5V-19z"
|
||||||
|
android:strokeColor="#FFFFFF" android:strokeWidth="2"/>
|
||||||
|
<path android:fillAlpha="0.9" android:fillColor="#00000000"
|
||||||
|
android:pathData="M18.9,-12c0,-3.8 -3.1,-6.9 -6.9,-6.9c-3.8,0 -6.9,3.1 -6.9,6.9c0,3.8 3.1,6.9 6.9,6.9C15.8,-5.1 18.9,-8.2 18.9,-12z"
|
||||||
|
android:strokeColor="#FFFFFF" android:strokeWidth="1.8033"/>
|
||||||
|
<path android:fillAlpha="0.9" android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,-5.7C19,-5.4 18.6,-5 18.2,-5H5.8C5.4,-5 5,-5.4 5,-5.7v-12.6C5,-18.6 5.4,-19 5.8,-19h12.4c0.4,0 0.8,0.4 0.8,0.7V-5.7z"
|
||||||
|
android:strokeColor="#FFFFFF" android:strokeWidth="2"/>
|
||||||
|
<path android:fillColor="#FAFAFA" android:pathData="M118.2,134.4m-118.2,0a118.2,118.2 0,1 1,236.4 0a118.2,118.2 0,1 1,-236.4 0"/>
|
||||||
|
<path android:fillColor="#F5F5F5" android:pathData="M22.8,239L96,206.2c0.2,-0.1 0.3,-0.1 0.5,-0.1l117.3,23c0.7,0.2 0.9,1.2 0.2,1.5l-75.9,37.2c-0.2,0.1 -0.3,0.1 -0.5,0.1L23,240.5C22.2,240.3 22.1,239.3 22.8,239z"/>
|
||||||
|
<path android:fillColor="#E8E8E8" android:pathData="M35.6,76.5l102,17.3l0,167.4l-102,-23.2z"/>
|
||||||
|
<path android:fillColor="#E8E8E8" android:pathData="M35.7,19.6l102,17.3l0,79.2l-102,-23.2z"/>
|
||||||
|
<path android:fillColor="#EFEFEF" android:pathData="M35.7,19.6l66.6,-19.6l100.5,19.1l-65.1,18.5z"/>
|
||||||
|
<path android:fillColor="#00000000"
|
||||||
|
android:pathData="M37.6,131.9L135.2,150"
|
||||||
|
android:strokeColor="#E0E0E0" android:strokeWidth="0.1816"/>
|
||||||
|
<path android:fillAlpha="0.5" android:fillColor="#00000000"
|
||||||
|
android:pathData="M39.1,185.3L132.3,204.8"
|
||||||
|
android:strokeColor="#C1C1C1" android:strokeWidth="0.1816"/>
|
||||||
|
<path android:fillColor="#00000000"
|
||||||
|
android:pathData="M137.7,147.6L116.5,154.5"
|
||||||
|
android:strokeColor="#E0E0E0" android:strokeWidth="0.1816"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M35.7,142.2"
|
||||||
|
android:strokeColor="#E0E0E0" android:strokeWidth="0.1816"/>
|
||||||
|
<path android:fillAlpha="5.000000e-02" android:fillColor="#FF000000" android:pathData="M35.7,140.9l101.7,9.2l0,33.1l-101.8,-21.3z"/>
|
||||||
|
<path android:fillColor="#CECECE" android:pathData="M71,36.9l28.8,5l0,5.8l-28.8,-5.3z"/>
|
||||||
|
<path android:fillAlpha="0.1" android:fillColor="#1F1F1F" android:pathData="M71,36.9l28.8,5l0,1.7l-28.8,-5.3z"/>
|
||||||
|
<path android:fillAlpha="0.5" android:fillColor="#CECECE" android:pathData="M68.4,147.3l28.8,5.1l0,5.8l-28.8,-5.4z"/>
|
||||||
|
<path android:fillAlpha="0.1" android:fillColor="#1F1F1F" android:pathData="M68.4,147.3l28.8,5.1l0,1.7l-28.8,-5.4z"/>
|
||||||
|
<path android:fillAlpha="0.7" android:fillColor="#CECECE" android:pathData="M68.4,201.2l28.8,5.4l0,5.8l-28.8,-5.7z"/>
|
||||||
|
<path android:fillAlpha="0.1" android:fillColor="#1F1F1F" android:pathData="M68.4,201.2l28.8,5.4l0,1.6l-28.8,-5.6z"/>
|
||||||
|
<path android:fillColor="#EAEAEA" android:pathData="M16.2,80.3l100.3,18.1l0,58.5l-100.3,-20.2z"/>
|
||||||
|
<path android:fillColor="#EFEFEF" android:pathData="M137.7,37.6l0,53.9l-21.2,6.9l0,58.5l21.2,-6.9l0,111.1l65.1,-30l0,-212z"/>
|
||||||
|
<path android:fillColor="#E57373" android:pathData="M16.2,80.3l19.5,-8.2l0,11.7z"/>
|
||||||
|
<path android:fillAlpha="0.6" android:fillColor="#E57373" android:pathData="M137.7,91.5l-102,-19.4l0,11.7l80.8,14.6z"/>
|
||||||
|
<path android:fillColor="#CECECE" android:pathData="M47.2,95.5l28.8,5l0,5.8l-28.8,-5.2z"/>
|
||||||
|
<path android:fillAlpha="0.1" android:fillColor="#1F1F1F" android:pathData="M47.2,95.5l28.8,5l0,1.7l-28.8,-5.2z"/>
|
||||||
|
<path android:fillColor="#EAEAEA" android:pathData="M35.7,72.1L35.7,72.1l-19.6,8.1l0,0.1l0,0l100.3,18.1l0,0l0,0l21.6,-7L35.7,72.1zM116.5,97.5L19.4,80l16.4,-6.8L134,91.8L116.5,97.5z"/>
|
||||||
|
</vector>
|
23
res/layout/search_feedback.xml
Normal file
23
res/layout/search_feedback.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<View
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/feedback_popup"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
</View>
|
@@ -13,18 +13,19 @@
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/search_panel"
|
android:id="@+id/search_panel"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center"
|
android:background="@drawable/search_panel_list_background">
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<LinearLayout android:id="@+id/layout_recent_searches"
|
<LinearLayout android:id="@+id/layout_recent_searches"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:layout_alignParentTop="true">
|
||||||
|
|
||||||
<!-- Padding is included in the background -->
|
<!-- Padding is included in the background -->
|
||||||
<android.support.v7.widget.RecyclerView android:id="@+id/list_recent_searches"
|
<android.support.v7.widget.RecyclerView android:id="@+id/list_recent_searches"
|
||||||
@@ -36,27 +37,47 @@
|
|||||||
android:paddingBottom="@dimen/dashboard_padding_bottom"
|
android:paddingBottom="@dimen/dashboard_padding_bottom"
|
||||||
android:scrollbarStyle="outsideOverlay"
|
android:scrollbarStyle="outsideOverlay"
|
||||||
android:headerDividersEnabled="false"
|
android:headerDividersEnabled="false"
|
||||||
android:background="@drawable/search_panel_list_background"
|
|
||||||
android:elevation="@dimen/search_panel_elevation"/>
|
android:elevation="@dimen/search_panel_elevation"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout android:id="@+id/layout_results"
|
<LinearLayout android:id="@+id/layout_results"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="fill_parent"
|
||||||
android:layout_gravity="center"
|
android:layout_above="@id/feedback_popup"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<!-- Padding is included in the background -->
|
<!-- Padding is included in the background -->
|
||||||
<android.support.v7.widget.RecyclerView android:id="@+id/list_results"
|
<android.support.v7.widget.RecyclerView android:id="@+id/list_results"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:paddingStart="@dimen/dashboard_padding_start"
|
android:paddingStart="@dimen/dashboard_padding_start"
|
||||||
android:paddingEnd="@dimen/dashboard_padding_end"
|
android:paddingEnd="@dimen/dashboard_padding_end"
|
||||||
android:paddingTop="@dimen/dashboard_padding_top"
|
android:paddingTop="@dimen/dashboard_padding_top"
|
||||||
android:paddingBottom="@dimen/dashboard_padding_bottom"
|
android:paddingBottom="@dimen/dashboard_padding_bottom"
|
||||||
android:scrollbarStyle="outsideOverlay"
|
android:scrollbarStyle="outsideOverlay"
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"/>
|
||||||
android:background="@drawable/search_panel_list_background"/>
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/no_results_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_height="112dp"
|
||||||
|
android:layout_width="112dp"
|
||||||
|
android:src="@drawable/no_search_results"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/search_settings_no_results"
|
||||||
|
android:gravity="center"/>
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
<include layout="@layout/search_feedback"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
@@ -2167,6 +2167,8 @@
|
|||||||
<string name="search_settings">Search</string>
|
<string name="search_settings">Search</string>
|
||||||
<!-- Main Settings screen, setting option summary to go into search settings -->
|
<!-- Main Settings screen, setting option summary to go into search settings -->
|
||||||
<string name="search_settings_summary">Manage search settings and history</string>
|
<string name="search_settings_summary">Manage search settings and history</string>
|
||||||
|
<!-- There are no search results for the user's search [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="search_settings_no_results">No results</string>
|
||||||
|
|
||||||
<!-- Display settings --><skip/>
|
<!-- Display settings --><skip/>
|
||||||
<!-- Sound & display settings screen, section header for settings related to display -->
|
<!-- Sound & display settings screen, section header for settings related to display -->
|
||||||
|
@@ -21,6 +21,7 @@ import android.app.Fragment;
|
|||||||
import android.app.FragmentManager;
|
import android.app.FragmentManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import android.view.WindowManager;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
public class SearchActivity extends Activity {
|
public class SearchActivity extends Activity {
|
||||||
@@ -29,6 +30,8 @@ public class SearchActivity extends Activity {
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.search_main);
|
setContentView(R.layout.search_main);
|
||||||
|
// Keeps layouts in-place when keyboard opens.
|
||||||
|
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
|
||||||
|
|
||||||
FragmentManager fragmentManager = getFragmentManager();
|
FragmentManager fragmentManager = getFragmentManager();
|
||||||
Fragment fragment = fragmentManager.findFragmentById(R.id.main_content);
|
Fragment fragment = fragmentManager.findFragmentById(R.id.main_content);
|
||||||
|
@@ -19,6 +19,7 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
import com.android.settings.dashboard.SiteMapManager;
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,4 +69,25 @@ public interface SearchFeatureProvider {
|
|||||||
* Updates the Settings indexes
|
* Updates the Settings indexes
|
||||||
*/
|
*/
|
||||||
void updateIndex(Context context);
|
void updateIndex(Context context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the feedback button in case it was dismissed.
|
||||||
|
*/
|
||||||
|
default void initFeedbackButton() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a button users can click to submit feedback on the quality of the search results.
|
||||||
|
*/
|
||||||
|
default void showFeedbackButton(SearchFragment fragment, View view) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the feedback button shown by
|
||||||
|
* {@link #showFeedbackButton(SearchFragment fragment, View view) showFeedbackButton}
|
||||||
|
*/
|
||||||
|
default void hideFeedbackButton() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@ 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.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.LinearLayout.LayoutParams;
|
import android.widget.LinearLayout.LayoutParams;
|
||||||
import android.widget.SearchView;
|
import android.widget.SearchView;
|
||||||
|
|
||||||
@@ -71,7 +72,7 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
static final String RESULT_CLICK_COUNT = "settings_search_result_click_count";
|
static final String RESULT_CLICK_COUNT = "settings_search_result_click_count";
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
@VisibleForTesting
|
||||||
String mQuery;
|
String mQuery;
|
||||||
|
|
||||||
private final SaveQueryRecorderCallback mSaveQueryRecorderCallback =
|
private final SaveQueryRecorderCallback mSaveQueryRecorderCallback =
|
||||||
@@ -89,6 +90,7 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
RecyclerView mResultsRecyclerView;
|
RecyclerView mResultsRecyclerView;
|
||||||
private SearchView mSearchView;
|
private SearchView mSearchView;
|
||||||
|
private LinearLayout mNoResultsView;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final RecyclerView.OnScrollListener mScrollListener =
|
final RecyclerView.OnScrollListener mScrollListener =
|
||||||
@@ -119,6 +121,8 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
mSearchAdapter = new SearchResultsAdapter(this);
|
mSearchAdapter = new SearchResultsAdapter(this);
|
||||||
|
|
||||||
|
mSearchFeatureProvider.initFeedbackButton();
|
||||||
|
|
||||||
final LoaderManager loaderManager = getLoaderManager();
|
final LoaderManager loaderManager = getLoaderManager();
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
@@ -155,6 +159,8 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
mResultsRecyclerView.setAdapter(mSearchAdapter);
|
mResultsRecyclerView.setAdapter(mSearchAdapter);
|
||||||
mResultsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
mResultsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
mResultsRecyclerView.addOnScrollListener(mScrollListener);
|
mResultsRecyclerView.addOnScrollListener(mScrollListener);
|
||||||
|
|
||||||
|
mNoResultsView = (LinearLayout) view.findViewById(R.id.no_results_layout);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,16 +190,26 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
if (TextUtils.equals(query, mQuery)) {
|
if (TextUtils.equals(query, mQuery)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final boolean isEmptyQuery = TextUtils.isEmpty(query);
|
||||||
|
|
||||||
|
// Hide no-results-view when the new query is not a super-string of the previous
|
||||||
|
if ((mQuery != null) && (mNoResultsView.getVisibility() == View.VISIBLE)
|
||||||
|
&& (query.length() < mQuery.length())) {
|
||||||
|
mNoResultsView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
mResultClickCount = 0;
|
mResultClickCount = 0;
|
||||||
mNeverEnteredQuery = false;
|
mNeverEnteredQuery = false;
|
||||||
mQuery = query;
|
mQuery = query;
|
||||||
mSearchAdapter.clearResults();
|
mSearchAdapter.clearResults();
|
||||||
|
|
||||||
if (TextUtils.isEmpty(mQuery)) {
|
if (isEmptyQuery) {
|
||||||
final LoaderManager loaderManager = getLoaderManager();
|
final LoaderManager loaderManager = getLoaderManager();
|
||||||
loaderManager.destroyLoader(LOADER_ID_DATABASE);
|
loaderManager.destroyLoader(LOADER_ID_DATABASE);
|
||||||
loaderManager.destroyLoader(LOADER_ID_INSTALLED_APPS);
|
loaderManager.destroyLoader(LOADER_ID_INSTALLED_APPS);
|
||||||
loaderManager.restartLoader(LOADER_ID_RECENTS, null /* args */, this /* callback */);
|
loaderManager.restartLoader(LOADER_ID_RECENTS, null /* args */, this /* callback */);
|
||||||
|
mSearchFeatureProvider.hideFeedbackButton();
|
||||||
} else {
|
} else {
|
||||||
restartLoaders();
|
restartLoaders();
|
||||||
}
|
}
|
||||||
@@ -232,7 +248,12 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
mSearchAdapter.addResultsToMap(data, loader.getClass().getName());
|
mSearchAdapter.addResultsToMap(data, loader.getClass().getName());
|
||||||
|
|
||||||
if (mUnfinishedLoadersCount.decrementAndGet() == 0) {
|
if (mUnfinishedLoadersCount.decrementAndGet() == 0) {
|
||||||
mSearchAdapter.mergeResults();
|
final int resultCount = mSearchAdapter.mergeResults();
|
||||||
|
mSearchFeatureProvider.showFeedbackButton(this, getView());
|
||||||
|
|
||||||
|
if (resultCount == 0) {
|
||||||
|
mNoResultsView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,6 +278,14 @@ 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 */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getQuery() {
|
||||||
|
return mQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SearchResult> getSearchResults() {
|
||||||
|
return mSearchAdapter.getSearchResults();
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting (otherwise = VisibleForTesting.PRIVATE)
|
@VisibleForTesting (otherwise = VisibleForTesting.PRIVATE)
|
||||||
SearchView makeSearchView(ActionBar actionBar, String query) {
|
SearchView makeSearchView(ActionBar actionBar, String query) {
|
||||||
final SearchView searchView = new SearchView(actionBar.getThemedContext());
|
final SearchView searchView = new SearchView(actionBar.getThemedContext());
|
||||||
|
@@ -106,8 +106,10 @@ public class SearchResultsAdapter extends Adapter<SearchViewHolder> {
|
|||||||
/**
|
/**
|
||||||
* Merge the results from each of the loaders into one list for the adapter.
|
* Merge the results from each of the loaders into one list for the adapter.
|
||||||
* Prioritizes results from the local database over installed apps.
|
* Prioritizes results from the local database over installed apps.
|
||||||
|
*
|
||||||
|
* @return Number of matched results
|
||||||
*/
|
*/
|
||||||
public void mergeResults() {
|
public int mergeResults() {
|
||||||
final List<? extends SearchResult> databaseResults = mResultsMap
|
final List<? extends SearchResult> databaseResults = mResultsMap
|
||||||
.get(DatabaseResultLoader.class.getName());
|
.get(DatabaseResultLoader.class.getName());
|
||||||
final List<? extends SearchResult> installedAppResults = mResultsMap
|
final List<? extends SearchResult> installedAppResults = mResultsMap
|
||||||
@@ -139,6 +141,8 @@ public class SearchResultsAdapter extends Adapter<SearchViewHolder> {
|
|||||||
|
|
||||||
mSearchResults.addAll(results);
|
mSearchResults.addAll(results);
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
|
|
||||||
|
return mSearchResults.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearResults() {
|
public void clearResults() {
|
||||||
|
@@ -60,7 +60,7 @@ import static org.mockito.Mockito.doReturn;
|
|||||||
|
|
||||||
@RunWith(SettingsRobolectricTestRunner.class)
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
public class SearchAdapterTest {
|
public class SearchResultsAdapterTest {
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private SearchFragment mFragment;
|
private SearchFragment mFragment;
|
||||||
@@ -114,7 +114,7 @@ public class SearchAdapterTest {
|
|||||||
InstalledAppResultLoader.class.getName());
|
InstalledAppResultLoader.class.getName());
|
||||||
mAdapter.addResultsToMap(getDummyDbResults(),
|
mAdapter.addResultsToMap(getDummyDbResults(),
|
||||||
DatabaseResultLoader.class.getName());
|
DatabaseResultLoader.class.getName());
|
||||||
mAdapter.mergeResults();
|
int count = mAdapter.mergeResults();
|
||||||
|
|
||||||
List<SearchResult> results = mAdapter.getSearchResults();
|
List<SearchResult> results = mAdapter.getSearchResults();
|
||||||
assertThat(results.get(0).title).isEqualTo("alpha");
|
assertThat(results.get(0).title).isEqualTo("alpha");
|
||||||
@@ -123,6 +123,7 @@ public class SearchAdapterTest {
|
|||||||
assertThat(results.get(3).title).isEqualTo("bravo");
|
assertThat(results.get(3).title).isEqualTo("bravo");
|
||||||
assertThat(results.get(4).title).isEqualTo("appCharlie");
|
assertThat(results.get(4).title).isEqualTo("appCharlie");
|
||||||
assertThat(results.get(5).title).isEqualTo("Charlie");
|
assertThat(results.get(5).title).isEqualTo("Charlie");
|
||||||
|
assertThat(count).isEqualTo(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SearchResult> getDummyDbResults() {
|
private List<SearchResult> getDummyDbResults() {
|
@@ -67,7 +67,6 @@ public class DatabaseResultLoaderTest {
|
|||||||
private final String summaryOne = "summaryOne";
|
private final String summaryOne = "summaryOne";
|
||||||
private final String summaryTwo = "summaryTwo";
|
private final String summaryTwo = "summaryTwo";
|
||||||
private final String summaryThree = "summaryThree";
|
private final String summaryThree = "summaryThree";
|
||||||
private final String summaryFour = "summaryFour";
|
|
||||||
|
|
||||||
SQLiteDatabase mDb;
|
SQLiteDatabase mDb;
|
||||||
|
|
||||||
|
@@ -16,10 +16,13 @@
|
|||||||
|
|
||||||
package com.android.settings.search2;
|
package com.android.settings.search2;
|
||||||
|
|
||||||
|
import android.app.LoaderManager;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Loader;
|
import android.content.Loader;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
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;
|
||||||
@@ -42,6 +45,7 @@ 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;
|
||||||
@@ -241,4 +245,52 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenNoQuery_HideFeedbackIsCalled() {
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getDatabaseSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(new MockDBLoader(RuntimeEnvironment.application));
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getInstalledAppSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(new MockAppLoader(RuntimeEnvironment.application));
|
||||||
|
|
||||||
|
ActivityController<SearchActivity> activityController =
|
||||||
|
Robolectric.buildActivity(SearchActivity.class);
|
||||||
|
activityController.setup();
|
||||||
|
SearchFragment fragment = (SearchFragment) spy(activityController.get().getFragmentManager()
|
||||||
|
.findFragmentById(R.id.main_content));
|
||||||
|
|
||||||
|
when(fragment.getLoaderManager()).thenReturn(mock(LoaderManager.class));
|
||||||
|
|
||||||
|
fragment.onQueryTextChange("");
|
||||||
|
|
||||||
|
Robolectric.flushForegroundThreadScheduler();
|
||||||
|
|
||||||
|
verify(mFeatureFactory.searchFeatureProvider).hideFeedbackButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onLoadFinished_ShowsFeedback() {
|
||||||
|
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getDatabaseSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(new MockDBLoader(RuntimeEnvironment.application));
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getInstalledAppSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(new MockAppLoader(RuntimeEnvironment.application));
|
||||||
|
|
||||||
|
ActivityController<SearchActivity> activityController =
|
||||||
|
Robolectric.buildActivity(SearchActivity.class);
|
||||||
|
activityController.setup();
|
||||||
|
SearchFragment fragment = (SearchFragment) spy(activityController.get().getFragmentManager()
|
||||||
|
.findFragmentById(R.id.main_content));
|
||||||
|
|
||||||
|
fragment.onQueryTextChange("non-empty");
|
||||||
|
|
||||||
|
Robolectric.flushForegroundThreadScheduler();
|
||||||
|
|
||||||
|
verify(mFeatureFactory.searchFeatureProvider).showFeedbackButton(any(SearchFragment.class),
|
||||||
|
any(View.class));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user