Merge "Handle tap on intent based search results."

This commit is contained in:
TreeHugger Robot
2016-12-09 23:04:02 +00:00
committed by Android (Google) Code Review
6 changed files with 166 additions and 58 deletions

View File

@@ -16,32 +16,37 @@
package com.android.settings.search2;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.search.Index;
import com.android.settings.search.IndexDatabaseHelper;
import com.android.settings.utils.AsyncLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_ICON_RESID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_ON;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RANK;
import java.util.Map;
/**
* AsyncTask to retrieve Settings, First party app and any intent based results.
*/
public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
private static final String LOG = "DatabaseResultLoader";
private final String mQueryText;
private final Context mContext;
protected final SQLiteDatabase mDatabase;
@@ -65,7 +70,7 @@ public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
}
String query = getSQLQuery();
Cursor result = mDatabase.rawQuery(query, null);
Cursor result = mDatabase.rawQuery(query, null);
return parseCursorForSearch(result);
}
@@ -78,10 +83,12 @@ public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
protected String getSQLQuery() {
return String.format("SELECT data_rank, data_title, data_summary_on, " +
"data_summary_off, data_entries, data_keywords, class_name, screen_title, icon, " +
"intent_action, intent_target_package, intent_target_class, enabled, " +
"data_key_reference FROM prefs_index WHERE prefs_index MATCH 'data_title:%s* " +
"OR data_title_normalized:%s* OR data_keywords:%s*' AND locale = 'en_US'",
"data_summary_off, data_entries, data_keywords, class_name, screen_title,"
+ " icon, " +
"intent_action, intent_target_package, intent_target_class, enabled, " +
"data_key_reference FROM prefs_index WHERE prefs_index MATCH "
+ "'data_title:%s* " +
"OR data_title_normalized:%s* OR data_keywords:%s*' AND locale = 'en_US'",
mQueryText, mQueryText, mQueryText);
}
@@ -90,35 +97,89 @@ public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
if (cursorResults == null) {
return null;
}
final Map<String, Context> contextMap = new HashMap<>();
final ArrayList<SearchResult> results = new ArrayList<>();
while (cursorResults.moveToNext()) {
final String title = cursorResults.getString(Index.COLUMN_INDEX_TITLE);
final String summaryOn = cursorResults.getString(COLUMN_INDEX_RAW_SUMMARY_ON);
final ArrayList<String> breadcrumbs = new ArrayList<>();
final int rank = cursorResults.getInt(COLUMN_INDEX_XML_RES_RANK);
final String intentString = cursorResults.getString(Index.COLUMN_INDEX_INTENT_ACTION);
final IntentPayload intentPayload = new IntentPayload(new Intent(intentString));
final int iconID = cursorResults.getInt(COLUMN_INDEX_RAW_ICON_RESID);
Drawable icon;
try {
icon = mContext.getDrawable(iconID);
} catch (Resources.NotFoundException nfe) {
icon = mContext.getDrawable(R.drawable.ic_search_history);
SearchResult result = buildSingleSearchResultFromCursor(contextMap, cursorResults);
if (result != null) {
results.add(result);
}
SearchResult.Builder builder = new SearchResult.Builder();
builder.addTitle(title)
.addSummary(summaryOn)
.addBreadcrumbs(breadcrumbs)
.addRank(rank)
.addIcon(icon)
.addPayload(intentPayload);
results.add(builder.build());
}
Collections.sort(results);
return results;
}
private SearchResult buildSingleSearchResultFromCursor(Map<String, Context> contextMap,
Cursor cursor) {
final String pkgName = cursor.getString(Index.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE);
final String action = cursor.getString(Index.COLUMN_INDEX_INTENT_ACTION);
final String title = cursor.getString(Index.COLUMN_INDEX_TITLE);
final String summaryOn = cursor.getString(Index.COLUMN_INDEX_SUMMARY_ON);
final String className = cursor.getString(Index.COLUMN_INDEX_CLASS_NAME);
final int rank = cursor.getInt(Index.COLUMN_INDEX_RANK);
final String key = cursor.getString(Index.COLUMN_INDEX_KEY);
final String iconResStr = cursor.getString(Index.COLUMN_INDEX_ICON);
final ResultPayload payload;
if (TextUtils.isEmpty(action)) {
final String screenTitle = cursor.getString(Index.COLUMN_INDEX_SCREEN_TITLE);
// Action is null, we will launch it as a sub-setting
final Bundle args = new Bundle();
args.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key);
final Intent intent = Utils.onBuildStartFragmentIntent(mContext,
className, args, null, 0, screenTitle, false);
payload = new IntentPayload(intent);
} else {
final Intent intent = new Intent(action);
final String targetClass = cursor.getString(
Index.COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS);
if (!TextUtils.isEmpty(pkgName) && !TextUtils.isEmpty(targetClass)) {
final ComponentName component = new ComponentName(pkgName, targetClass);
intent.setComponent(component);
}
intent.putExtra(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key);
payload = new IntentPayload(intent);
}
SearchResult.Builder builder = new SearchResult.Builder();
builder.addTitle(title)
.addSummary(summaryOn)
.addRank(rank)
.addIcon(getIconForPackage(contextMap, pkgName, className, iconResStr))
.addPayload(payload);
return builder.build();
}
private Drawable getIconForPackage(Map<String, Context> contextMap, String pkgName,
String className, String iconResStr) {
final int iconId = TextUtils.isEmpty(iconResStr)
? 0 : Integer.parseInt(iconResStr);
Drawable icon;
Context packageContext;
if (iconId == 0) {
icon = null;
} else {
if (TextUtils.isEmpty(className) && !TextUtils.isEmpty(pkgName)) {
packageContext = contextMap.get(pkgName);
if (packageContext == null) {
try {
packageContext = mContext.createPackageContext(pkgName, 0);
} catch (PackageManager.NameNotFoundException e) {
Log.e(LOG, "Cannot create Context for package: " + pkgName);
return null;
}
contextMap.put(pkgName, packageContext);
}
} else {
packageContext = mContext;
}
try {
icon = packageContext.getDrawable(iconId);
} catch (Resources.NotFoundException nfe) {
icon = null;
}
}
return icon;
}
}

View File

@@ -44,6 +44,9 @@ public class IntentSearchViewHolder extends SearchViewHolder {
titleView.setText(result.title);
summaryView.setText(result.summary);
iconView.setImageDrawable(result.icon);
if (result.icon == null) {
iconView.setBackgroundResource(R.drawable.empty_icon);
}
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

View File

@@ -31,8 +31,19 @@ public abstract class ResultPayload implements Parcelable {
@IntDef({PayloadType.INLINE_SLIDER, PayloadType.INLINE_SWITCH, PayloadType.INTENT})
@Retention(RetentionPolicy.SOURCE)
public @interface PayloadType {
/**
* Resulting page will be started using an intent
*/
int INTENT = 0;
/**
* Result is a inline widget, using a slider widget as UI.
*/
int INLINE_SLIDER = 1;
/**
* Result is a inline widget, using a toggle widget as UI.
*/
int INLINE_SWITCH = 2;
}

View File

@@ -83,7 +83,6 @@ public class SearchResult implements Comparable<SearchResult> {
payload = builder.mResultPayload;
viewType = payload.getType();
stableId = Objects.hash(title, summary, breadcrumbs, rank, icon, payload, viewType);
}
@Override
@@ -98,7 +97,7 @@ public class SearchResult implements Comparable<SearchResult> {
protected CharSequence mTitle;
protected CharSequence mSummary;
protected ArrayList<String> mBreadcrumbs;
protected int mRank = -1;
protected int mRank = 42;
protected ResultPayload mResultPayload;
protected Drawable mIcon;
@@ -118,10 +117,9 @@ public class SearchResult implements Comparable<SearchResult> {
}
public Builder addRank(int rank) {
if (rank < 0 || rank > 9) {
rank = 42;
if (rank >= 0 && rank <= 9) {
mRank = rank;
}
mRank = rank;
return this;
}
@@ -139,10 +137,6 @@ public class SearchResult implements Comparable<SearchResult> {
// Check that all of the mandatory fields are set.
if (mTitle == null) {
throw new IllegalArgumentException("SearchResult missing title argument");
} else if (mRank == -1) {
throw new IllegalArgumentException("SearchResult missing rank argument");
} else if (mIcon == null) {
throw new IllegalArgumentException("SearchResult missing icon argument");
} else if (mResultPayload == null) {
throw new IllegalArgumentException("SearchResult missing Payload argument");
}