blob: 22e9a58d3b517a81a51234574079da712ca6baff [file] [log] [blame]
/*
* Copyright (C) 2009 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.globalsearch;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.util.TypedValue;
import android.app.SearchManager;
import android.text.TextUtils;
import android.text.util.Regex;
import java.util.List;
import static com.android.globalsearch.SourceSuggestionBacker.SourceStat;
/**
* Implements {@link SuggestionFactory}.
*/
public class SuggestionFactoryImpl implements SuggestionFactory {
public static final ComponentName BUILTIN_SOURCE_COMPONENT
= new ComponentName("com.android.globalsearch",
"com.android.globalsearch.GlobalSearch");
private final Context mContext;
// The ID of the ColorStateList to be applied to urls of website suggestions, as derived from
// the current theme. This is not set until/unless applySearchUrlColor is called, at which point
// this variable caches the color value.
private static String mSearchUrlColorId;
// The background color of the 'more' item and other corpus items.
private int mCorpusItemBackgroundColor;
/**
* @param context The context.
*/
public SuggestionFactoryImpl(Context context) {
mContext = context;
TypedValue colorValue = new TypedValue();
mContext.getTheme().resolveAttribute(
com.android.internal.R.attr.searchWidgetCorpusItemBackground,
colorValue, true);
mCorpusItemBackgroundColor = mContext.getResources().getColor(colorValue.resourceId);
}
public ComponentName getSource() {
return BUILTIN_SOURCE_COMPONENT;
}
/** {@inheritDoc} */
public SuggestionData getMoreEntry(
boolean expanded, List<SourceSuggestionBacker.SourceStat> sourceStats) {
String desc = "";
boolean anyPending = false;
final int sourceCount = sourceStats.size();
for (int i = 0; i < sourceCount; i++) {
SourceSuggestionBacker.SourceStat sourceStat = sourceStats.get(i);
if (sourceStat.getResponseStatus() != SourceStat.RESPONSE_FINISHED) {
anyPending = true;
}
int suggestionCount = sourceStat.getNumResults();
if (suggestionCount > 0) {
String appLabel = sourceStat.getLabel();
String count = getCountString(suggestionCount, sourceStat.getQueryLimit());
String appCount = mContext.getString(R.string.result_count_count_separator,
appLabel, count);
if (TextUtils.isEmpty(desc)) {
desc = appCount;
} else {
desc = mContext.getString(R.string.result_count_app_separator, desc, appCount);
}
}
}
int icon = expanded ? R.drawable.more_results_expanded : R.drawable.more_results;
final SuggestionData.Builder builder = new SuggestionData.Builder(BUILTIN_SOURCE_COMPONENT)
.format("html")
.title("<i>" + mContext.getString(R.string.more_results) + "</i>")
.description("<i>" + desc.toString() + "</i>")
.icon1(icon)
.shortcutId(SearchManager.SUGGEST_NEVER_MAKE_SHORTCUT)
.backgroundColor(mCorpusItemBackgroundColor)
.intentAction(SearchManager.INTENT_ACTION_NONE); // no intent launched for this
if (anyPending) {
builder.icon2(com.android.internal.R.drawable.search_spinner);
}
return builder.build();
}
/**
* Return a rounded representation of a suggestion count if, e.g. "10+".
*
* @param count The number of items.
* @param limit The maximum number that was requested.
* @return If the {@code count} is exact, the value of {@code count} is returned.
* Otherwise, a rounded valued followed by "+" is returned.
*/
private String getCountString(int count, int limit) {
if (limit == 0 || count < limit) {
return String.valueOf(count);
} else {
if (limit > 10) {
// round to nearest lower multiple of 10
count = 10 * ((limit - 1) / 10);
}
return count + "+";
}
}
/** {@inheritDoc} */
public SuggestionData getCorpusEntry(
String query, SourceSuggestionBacker.SourceStat sourceStat) {
int suggestionCount = sourceStat.getNumResults();
final SuggestionData.Builder builder = new SuggestionData.Builder(sourceStat.getName())
.title(sourceStat.getLabel())
.shortcutId(SearchManager.SUGGEST_NEVER_MAKE_SHORTCUT)
.icon1(sourceStat.getIcon())
.intentAction(SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE)
.intentData(sourceStat.getName().flattenToString())
.backgroundColor(mCorpusItemBackgroundColor)
.intentQuery(query);
final int responseStatus = sourceStat.getResponseStatus();
if (responseStatus == SourceStat.RESPONSE_FINISHED) {
final Resources resources = mContext.getResources();
final String description = sourceStat.isShowingPromotedResults() ?
resources.getQuantityString(
R.plurals.additional_result_count, suggestionCount, suggestionCount) :
resources.getQuantityString(
R.plurals.total_result_count, suggestionCount, suggestionCount);
builder.description(description);
}
if (responseStatus == SourceStat.RESPONSE_IN_PROGRESS) {
builder.icon2(com.android.internal.R.drawable.search_spinner);
}
return builder.build();
}
/**
* Creates a one-off suggestion for searching the web with the current query.
* The description can be a format string with one string value, which will be
* filled in by the provided query argument.
*
* @param query The query
*/
public SuggestionData createSearchTheWebSuggestion(String query) {
if (TextUtils.isEmpty(query)) {
return null;
}
String suggestion = mContext.getString(R.string.search_the_web, query);
int ix = suggestion.indexOf('\n');
return new SuggestionData.Builder(BUILTIN_SOURCE_COMPONENT)
.title(suggestion.substring(0, ix))
.description(suggestion.substring(ix + 1))
.icon1(R.drawable.magnifying_glass)
.intentAction(Intent.ACTION_WEB_SEARCH)
.intentQuery(query)
.build();
}
/**
* Creates a shortcut for a search made by the user without using a suggestion.
*
* @param query The query
*/
public SuggestionData createWebSearchShortcut(String query) {
if (TextUtils.isEmpty(query)) {
return null;
}
return new SuggestionData.Builder(BUILTIN_SOURCE_COMPONENT)
.title(query)
.icon1(R.drawable.magnifying_glass)
.intentAction(Intent.ACTION_WEB_SEARCH)
.intentQuery(query)
.build();
}
/**
* Creates a one-off suggestion for visiting the url specified by the current query,
* or null if the current query does not look like a url.
*
* @param query The query
*/
public SuggestionData createGoToWebsiteSuggestion(String query) {
if (!Regex.WEB_URL_PATTERN.matcher(query).matches()) {
return null;
}
String url = query.trim();
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "http://" + url;
}
return new SuggestionData.Builder(BUILTIN_SOURCE_COMPONENT)
.format("html")
.title(mContext.getString(R.string.go_to_website_title))
.description(applySearchUrlColor(query))
.icon1(R.drawable.globe)
.intentAction(Intent.ACTION_VIEW)
.intentData(url)
.build();
}
/**
* Wraps the provided url string in the appropriate html formatting to apply the
* theme-based search url color.
*/
private String applySearchUrlColor(String url) {
if (mSearchUrlColorId == null) {
// Get the color used for this purpose from the current theme.
TypedValue colorValue = new TypedValue();
mContext.getTheme().resolveAttribute(
com.android.internal.R.attr.textColorSearchUrl, colorValue, true);
mSearchUrlColorId = Integer.toString(colorValue.resourceId);
}
return "<font color=\"@" + mSearchUrlColorId + "\">" + url + "</font>";
}
}