Merge "Add basic breadcrumb on search result."

This commit is contained in:
Fan Zhang
2017-01-22 18:24:27 +00:00
committed by Android (Google) Code Review
13 changed files with 274 additions and 174 deletions

View File

@@ -0,0 +1,26 @@
<?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.
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/breadcrumb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:ellipsize="marquee"/>

View File

@@ -0,0 +1,33 @@
<?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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/icon_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="60dp"
android:gravity="center_horizontal|top"
android:orientation="horizontal"
android:paddingEnd="12dp"
android:paddingTop="4dp"
android:paddingBottom="4dp">
<com.android.internal.widget.PreferenceImageView
android:id="@android:id/icon"
android:layout_width="36dp"
android:layout_height="36dp"
android:scaleType="fitCenter"/>
</LinearLayout>

View File

@@ -15,67 +15,49 @@
--> -->
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight" android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical" android:paddingTop="16dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingBottom="16dp"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:background="?android:attr/selectableItemBackground" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:clipToPadding="false"> android:background="?android:attr/selectableItemBackground"
android:clipToPadding="false">
<include layout="@layout/search_icon_view"/>
<LinearLayout <LinearLayout
android:id="@+id/icon_container" android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="60dp" android:singleLine="true"
android:gravity="start|center_vertical" android:textAppearance="?android:attr/textAppearanceListItem"
android:orientation="horizontal" android:ellipsize="marquee"/>
android:paddingEnd="12dp"
android:paddingTop="4dp" <TextView
android:paddingBottom="4dp"> android:id="@android:id/summary"
<com.android.internal.widget.PreferenceImageView android:layout_width="wrap_content"
android:id="@android:id/icon" android:layout_height="wrap_content"
android:layout_width="wrap_content" android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:layout_height="wrap_content" android:textColor="?android:attr/textColorSecondary"
android:maxWidth="48dp" android:maxLength="60"
android:maxHeight="48dp"/> android:maxLines="10"/>
<include layout="@layout/search_breadcrumb_view"/>
</LinearLayout> </LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:maxLength="60"
android:maxLines="10"/>
</RelativeLayout>
<Switch <Switch
android:id="@+id/switchView" android:id="@+id/switchView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="end|center_vertical" android:gravity="top"
android:paddingStart="16dp" android:paddingStart="16dp"/>
android:orientation="vertical"/>
</LinearLayout> </LinearLayout>

View File

@@ -15,58 +15,42 @@
--> -->
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight" android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical" android:paddingTop="16dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingBottom="16dp"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:background="?android:attr/selectableItemBackground" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:clipToPadding="false"> android:background="?android:attr/selectableItemBackground"
android:clipToPadding="false">
<include layout="@layout/search_icon_view"/>
<LinearLayout <LinearLayout
android:id="@+id/icon_container" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="60dp" android:singleLine="true"
android:gravity="start|center_vertical" android:textAppearance="?android:attr/textAppearanceListItem"
android:orientation="horizontal" android:ellipsize="marquee"/>
android:paddingEnd="12dp"
android:paddingTop="4dp" <TextView
android:paddingBottom="4dp"> android:id="@android:id/summary"
<com.android.internal.widget.PreferenceImageView android:layout_width="wrap_content"
android:id="@android:id/icon" android:layout_height="wrap_content"
android:layout_width="wrap_content" android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:layout_height="wrap_content" android:textColor="?android:attr/textColorSecondary"
android:maxWidth="48dp" android:maxLines="3"
android:maxHeight="48dp"/> android:ellipsize="marquee"/>
<include layout="@layout/search_breadcrumb_view"/>
</LinearLayout> </LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10"/>
</RelativeLayout>
</LinearLayout> </LinearLayout>

View File

@@ -5947,6 +5947,10 @@
<string name="search_menu">Search settings</string> <string name="search_menu">Search settings</string>
<!-- Text used as a search hint into the search box --> <!-- Text used as a search hint into the search box -->
<string name="query_hint_text">Search settings</string> <string name="query_hint_text">Search settings</string>
<!-- Search breadcrumb connector symbol -->
<string name="search_breadcrumb_connector" translatable="false">
<xliff:g name="first_item">%1$s</xliff:g> > <xliff:g name="second_item">%2$s</xliff:g>
</string>
<!-- Text used to identify the search query suggestions / recent searches --> <!-- Text used to identify the search query suggestions / recent searches -->
<string name="search_recents_queries_label">Recent searches</string> <string name="search_recents_queries_label">Recent searches</string>

View File

@@ -211,7 +211,12 @@ class CursorToSearchResultConverter {
} }
private List<String> getBreadcrumbs(Cursor cursor) { private List<String> getBreadcrumbs(Cursor cursor) {
return new ArrayList<>(); final List<String> breadcrumbs = new ArrayList<>();
final String screenTitle = cursor.getString(COLUMN_INDEX_SCREEN_TITLE);
if (!TextUtils.isEmpty(screenTitle)) {
breadcrumbs.add(screenTitle);
}
return breadcrumbs;
} }
/** Uses the breadcrumbs to determine the offset to the base rank. /** Uses the breadcrumbs to determine the offset to the base rank.

View File

@@ -56,6 +56,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE; import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE;
@@ -279,7 +280,7 @@ public class DatabaseIndexingManager {
* @param className the class name (typically a fragment name). * @param className the class name (typically a fragment name).
* @param rebuild true means that you want to delete the data from the Index first. * @param rebuild true means that you want to delete the data from the Index first.
* @param includeInSearchResults true means that you want the bit "enabled" set so that the * @param includeInSearchResults true means that you want the bit "enabled" set so that the
* data will be seen included into the search results * data will be seen included into the search results
*/ */
public void updateFromClassNameResource(String className, final boolean rebuild, public void updateFromClassNameResource(String className, final boolean rebuild,
boolean includeInSearchResults) { boolean includeInSearchResults) {
@@ -287,7 +288,7 @@ public class DatabaseIndexingManager {
throw new IllegalArgumentException("class name cannot be null!"); throw new IllegalArgumentException("class name cannot be null!");
} }
final SearchIndexableResource res = SearchIndexableResources.getResourceByName(className); final SearchIndexableResource res = SearchIndexableResources.getResourceByName(className);
if (res == null ) { if (res == null) {
Log.e(LOG_TAG, "Cannot find SearchIndexableResources for class name: " + className); Log.e(LOG_TAG, "Cannot find SearchIndexableResources for class name: " + className);
return; return;
} }
@@ -753,7 +754,7 @@ public class DatabaseIndexingManager {
} }
private void updateOneRowWithFilteredData(SQLiteDatabase database, DatabaseRow.Builder builder, private void updateOneRowWithFilteredData(SQLiteDatabase database, DatabaseRow.Builder builder,
String title, String summaryOn, String summaryOff,String keywords) { String title, String summaryOn, String summaryOff, String keywords) {
final String updatedTitle = DatabaseIndexingUtils.normalizeHyphen(title); final String updatedTitle = DatabaseIndexingUtils.normalizeHyphen(title);
final String updatedSummaryOn = DatabaseIndexingUtils.normalizeHyphen(summaryOn); final String updatedSummaryOn = DatabaseIndexingUtils.normalizeHyphen(summaryOn);
@@ -783,14 +784,8 @@ public class DatabaseIndexingManager {
return; return;
} }
// The DocID should contains more than the title string itself (you may have two settings
// with the same title). So we need to use a combination of the title and the screenTitle.
StringBuilder sb = new StringBuilder(row.updatedTitle);
sb.append(row.screenTitle);
int docId = sb.toString().hashCode();
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(IndexDatabaseHelper.IndexColumns.DOCID, docId); values.put(IndexDatabaseHelper.IndexColumns.DOCID, row.getDocId());
values.put(IndexDatabaseHelper.IndexColumns.LOCALE, row.locale); values.put(IndexDatabaseHelper.IndexColumns.LOCALE, row.locale);
values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, row.rank); values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, row.rank);
values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, row.updatedTitle); values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, row.updatedTitle);
@@ -919,7 +914,7 @@ public class DatabaseIndexingManager {
} }
if (!TextUtils.isEmpty(data.className)) { if (!TextUtils.isEmpty(data.className)) {
delete(database, IndexDatabaseHelper.IndexColumns.CLASS_NAME, data.className); delete(database, IndexDatabaseHelper.IndexColumns.CLASS_NAME, data.className);
} else { } else {
if (data instanceof SearchIndexableRaw) { if (data instanceof SearchIndexableRaw) {
final SearchIndexableRaw raw = (SearchIndexableRaw) data; final SearchIndexableRaw raw = (SearchIndexableRaw) data;
if (!TextUtils.isEmpty(raw.title)) { if (!TextUtils.isEmpty(raw.title)) {
@@ -938,7 +933,7 @@ public class DatabaseIndexingManager {
private int delete(SQLiteDatabase database, String columName, String value) { private int delete(SQLiteDatabase database, String columName, String value) {
final String whereClause = columName + "=?"; final String whereClause = columName + "=?";
final String[] whereArgs = new String[] { value }; final String[] whereArgs = new String[]{value};
return database.delete(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, whereClause, return database.delete(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, whereClause,
whereArgs); whereArgs);
@@ -993,6 +988,16 @@ public class DatabaseIndexingManager {
: null; : null;
} }
/**
* Returns the doc id for this row.
*/
public int getDocId() {
// The DocID should contains more than the title string itself (you may have two
// settings with the same title). So we need to use a combination of multiple
// attributes from this row.
return Objects.hash(updatedTitle, screenTitle, key, payloadType);
}
public static class Builder { public static class Builder {
private String mLocale; private String mLocale;
private String mUpdatedTitle; private String mUpdatedTitle;
@@ -1013,7 +1018,8 @@ public class DatabaseIndexingManager {
private boolean mEnabled; private boolean mEnabled;
private String mKey; private String mKey;
private int mUserId; private int mUserId;
@ResultPayload.PayloadType private int mPayloadType; @ResultPayload.PayloadType
private int mPayloadType;
private ResultPayload mPayload; private ResultPayload mPayload;
public Builder setLocale(String locale) { public Builder setLocale(String locale) {
@@ -1114,7 +1120,7 @@ public class DatabaseIndexingManager {
public Builder setPayload(ResultPayload payload) { public Builder setPayload(ResultPayload payload) {
mPayload = payload; mPayload = payload;
if(mPayload != null) { if (mPayload != null) {
setPayloadType(mPayload.getType()); setPayloadType(mPayload.getType());
} }
return this; return this;
@@ -1122,6 +1128,7 @@ public class DatabaseIndexingManager {
/** /**
* Payload type is added when a Payload is added to the Builder in {setPayload} * Payload type is added when a Payload is added to the Builder in {setPayload}
*
* @param payloadType PayloadType * @param payloadType PayloadType
* @return The Builder * @return The Builder
*/ */

View File

@@ -21,41 +21,32 @@ import android.content.Context;
import android.view.View; import android.view.View;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.Switch; import android.widget.Switch;
import android.widget.TextView;
import com.android.internal.widget.PreferenceImageView;
import com.android.settings.R; import com.android.settings.R;
/** /**
* ViewHolder for Settings represented as SwitchPreferences. * ViewHolder for Settings represented as SwitchPreferences.
*/ */
public class InlineSwitchViewHolder extends SearchViewHolder { public class InlineSwitchViewHolder extends SearchViewHolder {
public final TextView titleView;
public final TextView summaryView;
public final PreferenceImageView iconView;
public final Switch switchView; public final Switch switchView;
private final Context mContext; private final Context mContext;
private final String TAG = "SwitchViewHolder";
public InlineSwitchViewHolder(View view, Context context) { public InlineSwitchViewHolder(View view, Context context) {
super(view); super(view);
mContext = context; mContext = context;
titleView = (TextView) view.findViewById(android.R.id.title);
summaryView = (TextView) view.findViewById(android.R.id.summary);
iconView = (PreferenceImageView) view.findViewById(android.R.id.icon);
switchView = (Switch) view.findViewById(R.id.switchView); switchView = (Switch) view.findViewById(R.id.switchView);
} }
@Override @Override
public void onBind(SearchFragment fragment, SearchResult result) { public void onBind(SearchFragment fragment, SearchResult result) {
super.onBind(fragment, result);
if (mContext == null) { if (mContext == null) {
return; return;
} }
final InlineSwitchPayload payload = (InlineSwitchPayload) result.payload; final InlineSwitchPayload payload = (InlineSwitchPayload) result.payload;
switchView.setChecked(payload.getSwitchValue(mContext)); switchView.setChecked(payload.getSwitchValue(mContext));
switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
@@ -63,9 +54,5 @@ public class InlineSwitchViewHolder extends SearchViewHolder {
payload.setSwitchValue(mContext, isChecked); payload.setSwitchValue(mContext, isChecked);
} }
}); });
titleView.setText(result.title);
summaryView.setText(result.summary);
iconView.setImageDrawable(result.icon);
} }
} }

View File

@@ -28,6 +28,7 @@ import android.os.UserManager;
import android.provider.Settings; import android.provider.Settings;
import android.text.TextUtils; import android.text.TextUtils;
import com.android.settings.R;
import com.android.settings.applications.PackageManagerWrapper; import com.android.settings.applications.PackageManagerWrapper;
import com.android.settings.utils.AsyncLoader; import com.android.settings.utils.AsyncLoader;
@@ -45,6 +46,7 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
private static final Intent LAUNCHER_PROBE = new Intent(Intent.ACTION_MAIN) private static final Intent LAUNCHER_PROBE = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER); .addCategory(Intent.CATEGORY_LAUNCHER);
private final List<String> mBreadcrumb;
private final String mQuery; private final String mQuery;
private final UserManager mUserManager; private final UserManager mUserManager;
private final PackageManagerWrapper mPackageManager; private final PackageManagerWrapper mPackageManager;
@@ -53,6 +55,9 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
public InstalledAppResultLoader(Context context, PackageManagerWrapper pmWrapper, public InstalledAppResultLoader(Context context, PackageManagerWrapper pmWrapper,
String query) { String query) {
super(context); super(context);
mBreadcrumb = new ArrayList<>();
mBreadcrumb.add(context.getString(R.string.app_and_notification_dashboard_title));
mBreadcrumb.add(context.getString(R.string.applications_settings));
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mPackageManager = pmWrapper; mPackageManager = pmWrapper;
mQuery = query; mQuery = query;
@@ -87,6 +92,7 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
builder.addIcon(info.loadIcon(pm)) builder.addIcon(info.loadIcon(pm))
.addTitle(info.loadLabel(pm)) .addTitle(info.loadLabel(pm))
.addRank(wordDiff) .addRank(wordDiff)
.addBreadcrumbs(mBreadcrumb)
.addPayload(new IntentPayload(intent)); .addPayload(new IntentPayload(intent));
results.add(builder.build()); results.add(builder.build());
} }
@@ -127,7 +133,7 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
* perfectly, and larger values means they are less similar. * perfectly, and larger values means they are less similar.
* <p/> * <p/>
* Example: * Example:
* appName: Abcde, query: Abcde, Returns NAME_EXACT_MATCH * appName: Abcde, query: Abcde, Returns {@link #NAME_EXACT_MATCH}
* appName: Abcde, query: ade, Returns 2 * appName: Abcde, query: ade, Returns 2
* appName: Abcde, query: ae, Returns 3 * appName: Abcde, query: ae, Returns 3
* appName: Abcde, query: ea, Returns NAME_NO_MATCH * appName: Abcde, query: ea, Returns NAME_NO_MATCH

View File

@@ -16,10 +16,6 @@
package com.android.settings.search2; package com.android.settings.search2;
import android.view.View; import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.settings.R;
/** /**
* ViewHolder for intent based search results. * ViewHolder for intent based search results.
@@ -27,25 +23,14 @@ import com.android.settings.R;
*/ */
public class IntentSearchViewHolder extends SearchViewHolder { public class IntentSearchViewHolder extends SearchViewHolder {
public final TextView titleView;
public final TextView summaryView;
public final ImageView iconView;
public IntentSearchViewHolder(View view) { public IntentSearchViewHolder(View view) {
super(view); super(view);
titleView = (TextView) view.findViewById(android.R.id.title);
summaryView = (TextView) view.findViewById(android.R.id.summary);
iconView = (ImageView) view.findViewById(android.R.id.icon);
} }
@Override @Override
public void onBind(final SearchFragment fragment, final SearchResult result) { public void onBind(final SearchFragment fragment, final SearchResult result) {
titleView.setText(result.title); super.onBind(fragment, result);
summaryView.setText(result.summary);
iconView.setImageDrawable(result.icon);
if (result.icon == null) {
iconView.setBackgroundResource(R.drawable.empty_icon);
}
itemView.setOnClickListener(new View.OnClickListener() { itemView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {

View File

@@ -15,8 +15,14 @@
*/ */
package com.android.settings.search2; package com.android.settings.search2;
import android.content.Context;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.settings.R;
/** /**
* The ViewHolder for the Search RecyclerView. * The ViewHolder for the Search RecyclerView.
@@ -25,9 +31,47 @@ import android.view.View;
*/ */
public abstract class SearchViewHolder extends RecyclerView.ViewHolder { public abstract class SearchViewHolder extends RecyclerView.ViewHolder {
public final TextView titleView;
public final TextView summaryView;
public final TextView breadcrumbView;
public final ImageView iconView;
public SearchViewHolder(View view) { public SearchViewHolder(View view) {
super(view); super(view);
titleView = (TextView) view.findViewById(android.R.id.title);
summaryView = (TextView) view.findViewById(android.R.id.summary);
iconView = (ImageView) view.findViewById(android.R.id.icon);
breadcrumbView = (TextView) view.findViewById(R.id.breadcrumb);
} }
public abstract void onBind(SearchFragment fragment, SearchResult result); public void onBind(SearchFragment fragment, SearchResult result) {
titleView.setText(result.title);
if (TextUtils.isEmpty(result.summary)) {
summaryView.setVisibility(View.GONE);
} else {
summaryView.setText(result.summary);
summaryView.setVisibility(View.VISIBLE);
}
iconView.setImageDrawable(result.icon);
if (result.icon == null) {
iconView.setBackgroundResource(R.drawable.empty_icon);
}
bindBreadcrumbView(result);
}
private void bindBreadcrumbView(SearchResult result) {
if (result.breadcrumbs == null || result.breadcrumbs.isEmpty()) {
breadcrumbView.setVisibility(View.GONE);
return;
}
final Context context = breadcrumbView.getContext();
String breadcrumb = result.breadcrumbs.get(0);
final int count = result.breadcrumbs.size();
for (int i = 1; i < count; i++) {
breadcrumb = context.getString(R.string.search_breadcrumb_connector,
breadcrumb, result.breadcrumbs.get(i));
}
breadcrumbView.setText(breadcrumb);
breadcrumbView.setVisibility(View.VISIBLE);
}
} }

View File

@@ -196,7 +196,7 @@ public class DatabaseIndexingManagerTest {
@Test @Test
public void testNullResource_NothingInserted() { public void testNullResource_NothingInserted() {
mManager.indexOneSearchIndexableData(mDb, localeStr, null /* searchIndexableResource */, mManager.indexOneSearchIndexableData(mDb, localeStr, null /* searchIndexableResource */,
new HashMap<String, List<String>>()); new HashMap<>());
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null); Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
assertThat(cursor.getCount()).isEqualTo(0); assertThat(cursor.getCount()).isEqualTo(0);
} }
@@ -205,7 +205,7 @@ public class DatabaseIndexingManagerTest {
public void testAddResource_RowsInserted() { public void testAddResource_RowsInserted() {
SearchIndexableResource resource = getFakeResource(R.xml.gesture_settings); SearchIndexableResource resource = getFakeResource(R.xml.gesture_settings);
mManager.indexOneSearchIndexableData(mDb, localeStr, resource, mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
new HashMap<String, List<String>>()); new HashMap<>());
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null); Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
assertThat(cursor.getCount()).isEqualTo(6); assertThat(cursor.getCount()).isEqualTo(6);
} }
@@ -214,7 +214,7 @@ public class DatabaseIndexingManagerTest {
public void testAddResourceHeader_RowsMatch() { public void testAddResourceHeader_RowsMatch() {
SearchIndexableResource resource = getFakeResource(R.xml.application_settings); SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
mManager.indexOneSearchIndexableData(mDb, localeStr, resource, mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
new HashMap<String, List<String>>()); new HashMap<>());
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null); Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
cursor.moveToPosition(1); cursor.moveToPosition(1);
@@ -267,25 +267,27 @@ public class DatabaseIndexingManagerTest {
public void testAddResourceCustomSetting_RowsMatch() { public void testAddResourceCustomSetting_RowsMatch() {
SearchIndexableResource resource = getFakeResource(R.xml.gesture_settings); SearchIndexableResource resource = getFakeResource(R.xml.gesture_settings);
mManager.indexOneSearchIndexableData(mDb, localeStr, resource, mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
new HashMap<String, List<String>>()); new HashMap<>());
final String prefTitle =
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null); mContext.getString(R.string.fingerprint_swipe_for_notifications_title);
cursor.moveToPosition(0); final String prefSummary =
mContext.getString(R.string.fingerprint_swipe_for_notifications_summary);
Cursor cursor = mDb.rawQuery(
"SELECT * FROM prefs_index where data_title='" + prefTitle + "'", null);
cursor.moveToFirst();
// Locale // Locale
assertThat(cursor.getString(0)).isEqualTo(localeStr); assertThat(cursor.getString(0)).isEqualTo(localeStr);
// Data Rank // Data Rank
assertThat(cursor.getInt(1)).isEqualTo(rank); assertThat(cursor.getInt(1)).isEqualTo(rank);
// Data Title // Data Title
assertThat(cursor.getString(2)).isEqualTo("Swipe for notifications"); assertThat(cursor.getString(2)).isEqualTo(prefTitle);
// Normalized Title // Normalized Title
assertThat(cursor.getString(3)).isEqualTo("swipe for notifications"); assertThat(cursor.getString(3)).isEqualTo(prefTitle.toLowerCase());
// Summary On // Summary On
assertThat(cursor.getString(4)).isEqualTo("To check your notifications, " + assertThat(cursor.getString(4)).isEqualTo(prefSummary);
"swipe down on the fingerprint sensor on the back of your phone.");
// Summary On Normalized // Summary On Normalized
assertThat(cursor.getString(5)).isEqualTo("to check your notifications, " + assertThat(cursor.getString(5)).isEqualTo(prefSummary.toLowerCase());
"swipe down on the fingerprint sensor on the back of your phone.");
// Summary Off - only on for checkbox preferences // Summary Off - only on for checkbox preferences
assertThat(cursor.getString(6)).isEmpty(); assertThat(cursor.getString(6)).isEmpty();
// Summary off normalized - only on for checkbox preferences // Summary off normalized - only on for checkbox preferences
@@ -295,7 +297,8 @@ public class DatabaseIndexingManagerTest {
// Keywords // Keywords
assertThat(cursor.getString(9)).isEmpty(); assertThat(cursor.getString(9)).isEmpty();
// Screen Title // Screen Title
assertThat(cursor.getString(10)).isEqualTo("Gestures"); assertThat(cursor.getString(10)).isEqualTo(
mContext.getString(R.string.gesture_preference_title));
// Class Name // Class Name
assertThat(cursor.getString(11)).isEqualTo(className); assertThat(cursor.getString(11)).isEqualTo(className);
// Icon // Icon
@@ -322,7 +325,7 @@ public class DatabaseIndexingManagerTest {
public void testAddResourceCheckboxPreference_RowsMatch() { public void testAddResourceCheckboxPreference_RowsMatch() {
SearchIndexableResource resource = getFakeResource(R.xml.application_settings); SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
mManager.indexOneSearchIndexableData(mDb, localeStr, resource, mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
new HashMap<String, List<String>>()); new HashMap<>());
/* Should return 6 results, with the following titles: /* Should return 6 results, with the following titles:
* Advanced Settings, Apps, Manage Apps, Preferred install location, Running Services * Advanced Settings, Apps, Manage Apps, Preferred install location, Running Services
@@ -377,7 +380,7 @@ public class DatabaseIndexingManagerTest {
public void testAddResourceListPreference_RowsMatch() { public void testAddResourceListPreference_RowsMatch() {
SearchIndexableResource resource = getFakeResource(R.xml.application_settings); SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
mManager.indexOneSearchIndexableData(mDb, localeStr, resource, mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
new HashMap<String, List<String>>()); new HashMap<>());
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null); Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
cursor.moveToPosition(3); cursor.moveToPosition(3);
@@ -436,7 +439,7 @@ public class DatabaseIndexingManagerTest {
resource.className = "com.android.settings.display.ScreenZoomSettings"; resource.className = "com.android.settings.display.ScreenZoomSettings";
mManager.indexOneSearchIndexableData(mDb, localeStr, resource, mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
new HashMap<String, List<String>>()); new HashMap<>());
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null); Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
assertThat(cursor.getCount()).isEqualTo(1); assertThat(cursor.getCount()).isEqualTo(1);
} }
@@ -448,7 +451,7 @@ public class DatabaseIndexingManagerTest {
resource.className = "com.android.settings.display.ScreenZoomSettings"; resource.className = "com.android.settings.display.ScreenZoomSettings";
mManager.indexOneSearchIndexableData(mDb, localeStr, resource, mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
new HashMap<String, List<String>>()); new HashMap<>());
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null); Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
cursor.moveToPosition(0); cursor.moveToPosition(0);
@@ -504,7 +507,7 @@ public class DatabaseIndexingManagerTest {
resource.className = "com.android.settings.LegalSettings"; resource.className = "com.android.settings.LegalSettings";
mManager.indexOneSearchIndexableData(mDb, localeStr, resource, mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
new HashMap<String, List<String>>()); new HashMap<>());
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null); Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
assertThat(cursor.getCount()).isEqualTo(2); assertThat(cursor.getCount()).isEqualTo(2);
} }
@@ -516,7 +519,7 @@ public class DatabaseIndexingManagerTest {
resource.className = "com.android.settings.LegalSettings"; resource.className = "com.android.settings.LegalSettings";
mManager.indexOneSearchIndexableData(mDb, localeStr, resource, mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
new HashMap<String, List<String>>()); new HashMap<>());
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null); Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
cursor.moveToPosition(0); cursor.moveToPosition(0);

View File

@@ -41,6 +41,7 @@ import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.ShadowApplication;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
@@ -73,6 +74,7 @@ public class IntentSearchViewHolderTest {
assertThat(mHolder.titleView).isNotNull(); assertThat(mHolder.titleView).isNotNull();
assertThat(mHolder.summaryView).isNotNull(); assertThat(mHolder.summaryView).isNotNull();
assertThat(mHolder.iconView).isNotNull(); assertThat(mHolder.iconView).isNotNull();
assertThat(mHolder.breadcrumbView).isNotNull();
} }
@Test @Test
@@ -84,11 +86,43 @@ public class IntentSearchViewHolderTest {
assertThat(mHolder.titleView.getText()).isEqualTo(TITLE); assertThat(mHolder.titleView.getText()).isEqualTo(TITLE);
assertThat(mHolder.summaryView.getText()).isEqualTo(SUMMARY); assertThat(mHolder.summaryView.getText()).isEqualTo(SUMMARY);
assertThat(mHolder.iconView.getDrawable()).isEqualTo(mIcon); assertThat(mHolder.iconView.getDrawable()).isEqualTo(mIcon);
assertThat(mHolder.summaryView.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mHolder.breadcrumbView.getVisibility()).isEqualTo(View.GONE);
verify(mFragment).onSearchResultClicked(); verify(mFragment).onSearchResultClicked();
verify(mFragment).startActivity(any(Intent.class)); verify(mFragment).startActivity(any(Intent.class));
} }
@Test
public void testBindViewElements_emptySummary_hideSummaryView() {
final SearchResult result = new Builder().addTitle(TITLE)
.addRank(1)
.addPayload(new IntentPayload(null))
.addIcon(mIcon)
.build();
mHolder.onBind(mFragment, result);
assertThat(mHolder.summaryView.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testBindViewElements_withBreadcrumb_shouldFormatBreadcrumb() {
final List<String> breadcrumbs = new ArrayList<>();
breadcrumbs.add("a");
breadcrumbs.add("b");
breadcrumbs.add("c");
final SearchResult result = new Builder().addTitle(TITLE)
.addRank(1)
.addPayload(new IntentPayload(null))
.addBreadcrumbs(breadcrumbs)
.addIcon(mIcon)
.build();
mHolder.onBind(mFragment, result);
assertThat(mHolder.breadcrumbView.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mHolder.breadcrumbView.getText()).isEqualTo("a > b > c");
}
private SearchResult getSearchResult() { private SearchResult getSearchResult() {
Builder builder = new Builder(); Builder builder = new Builder();
builder.addTitle(TITLE) builder.addTitle(TITLE)