blob: 3aa6620a2843aaabbc08b3730a3f8f4eadfffcfc [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.search_engines;
import android.support.annotation.Nullable;
import org.chromium.base.ObserverList;
import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.task.PostTask;
import org.chromium.content_public.browser.UiThreadTaskTraits;
import java.util.ArrayList;
import java.util.List;
/**
* Android wrapper of the TemplateUrlService which provides access from the Java
* layer.
*
* Only usable from the UI thread as it's primary purpose is for supporting the Android
* preferences UI.
*
* See components/search_engines/template_url_service.h for more details.
*/
public class TemplateUrlService {
/**
* This listener will be notified when template url service is done loading.
*/
public interface LoadListener {
void onTemplateUrlServiceLoaded();
}
/**
* Observer to be notified whenever the set of TemplateURLs are modified.
*/
public interface TemplateUrlServiceObserver {
/**
* Notification that the template url model has changed in some way.
*/
void onTemplateURLServiceChanged();
}
private static TemplateUrlService sService;
public static TemplateUrlService getInstance() {
ThreadUtils.assertOnUiThread();
if (sService == null) {
sService = new TemplateUrlService();
}
return sService;
}
private final long mNativeTemplateUrlServiceAndroid;
private final ObserverList<LoadListener> mLoadListeners = new ObserverList<LoadListener>();
private final ObserverList<TemplateUrlServiceObserver> mObservers =
new ObserverList<TemplateUrlServiceObserver>();
private TemplateUrlService() {
// Note that this technically leaks the native object, however, TemlateUrlService
// is a singleton that lives forever and there's no clean shutdown of Chrome on Android
mNativeTemplateUrlServiceAndroid = nativeInit();
}
public boolean isLoaded() {
ThreadUtils.assertOnUiThread();
return nativeIsLoaded(mNativeTemplateUrlServiceAndroid);
}
public void load() {
ThreadUtils.assertOnUiThread();
nativeLoad(mNativeTemplateUrlServiceAndroid);
}
/**
* Ensure the TemplateUrlService is loaded before running the specified action. If the service
* is already loaded, then run the action immediately.
* <p>
* Because this can introduce an arbitrary delay in the action being executed, ensure the state
* is still valid in the action before interacting with anything that might no longer be
* available (i.e. an Activity that has since been destroyed).
*
* @param action The action to be run.
*/
public void runWhenLoaded(final Runnable action) {
if (isLoaded()) {
action.run();
} else {
registerLoadListener(new LoadListener() {
@Override
public void onTemplateUrlServiceLoaded() {
unregisterLoadListener(this);
action.run();
}
});
load();
}
}
/**
* Returns a list of the all available search engines.
*/
public List<TemplateUrl> getTemplateUrls() {
ThreadUtils.assertOnUiThread();
List<TemplateUrl> templateUrls = new ArrayList<>();
nativeGetTemplateUrls(mNativeTemplateUrlServiceAndroid, templateUrls);
return templateUrls;
}
/**
* Called from native to populate the list of all available search engines.
* @param templateUrls The list of {@link TemplateUrl} to be added.
* @param templateUrl The {@link TemplateUrl} would add to the list.
*/
@CalledByNative
private static void addTemplateUrlToList(
List<TemplateUrl> templateUrls, TemplateUrl templateUrl) {
templateUrls.add(templateUrl);
}
/**
* Called from native when template URL service is done loading.
*/
@CalledByNative
private void templateUrlServiceLoaded() {
ThreadUtils.assertOnUiThread();
for (LoadListener listener : mLoadListeners) {
listener.onTemplateUrlServiceLoaded();
}
}
@CalledByNative
private void onTemplateURLServiceChanged() {
for (TemplateUrlServiceObserver observer : mObservers) {
observer.onTemplateURLServiceChanged();
}
}
/**
* @return {@link TemplateUrl} for the default search engine. This can
* be null if DSEs are disabled entirely by administrators.
*/
public @Nullable TemplateUrl getDefaultSearchEngineTemplateUrl() {
if (!isLoaded()) return null;
return nativeGetDefaultSearchEngine(mNativeTemplateUrlServiceAndroid);
}
public void setSearchEngine(String selectedKeyword) {
ThreadUtils.assertOnUiThread();
nativeSetUserSelectedDefaultSearchProvider(
mNativeTemplateUrlServiceAndroid, selectedKeyword);
}
/**
* @return Whether the default search engine is managed and controlled by policy. If true, the
* DSE can not be modified by the user.
*/
public boolean isDefaultSearchManaged() {
return nativeIsDefaultSearchManaged(mNativeTemplateUrlServiceAndroid);
}
/**
* @return Whether or not the default search engine has search by image support.
*/
public boolean isSearchByImageAvailable() {
ThreadUtils.assertOnUiThread();
return nativeIsSearchByImageAvailable(mNativeTemplateUrlServiceAndroid);
}
/**
* @return Whether the default configured search engine is for a Google property.
*/
public boolean isDefaultSearchEngineGoogle() {
return nativeIsDefaultSearchEngineGoogle(mNativeTemplateUrlServiceAndroid);
}
public boolean doesDefaultSearchEngineHaveLogo() {
return nativeDoesDefaultSearchEngineHaveLogo(mNativeTemplateUrlServiceAndroid);
}
/**
* Checks whether a search result page is from a default search provider.
* @param url The url for the search result page.
* @return Whether the search result page with the given url from the default search provider.
*/
public boolean isSearchResultsPageFromDefaultSearchProvider(String url) {
ThreadUtils.assertOnUiThread();
return nativeIsSearchResultsPageFromDefaultSearchProvider(
mNativeTemplateUrlServiceAndroid, url);
}
/**
* Registers a listener for the callback that indicates that the
* TemplateURLService has loaded.
*/
public void registerLoadListener(final LoadListener listener) {
ThreadUtils.assertOnUiThread();
boolean added = mLoadListeners.addObserver(listener);
assert added;
// If the load has already been completed, post a load complete to the observer. Done
// as an asynchronous call to keep the client code predictable in the loaded/unloaded state.
if (isLoaded()) {
PostTask.postTask(UiThreadTaskTraits.DEFAULT, new Runnable() {
@Override
public void run() {
if (!mLoadListeners.hasObserver(listener)) return;
listener.onTemplateUrlServiceLoaded();
}
});
}
}
/**
* Unregisters a listener for the callback that indicates that the
* TemplateURLService has loaded.
*/
public void unregisterLoadListener(LoadListener listener) {
ThreadUtils.assertOnUiThread();
boolean removed = mLoadListeners.removeObserver(listener);
assert removed;
}
/**
* Adds an observer to be notified on changes to the template URLs.
* @param observer The observer to be added.
*/
public void addObserver(TemplateUrlServiceObserver observer) {
mObservers.addObserver(observer);
}
/**
* Removes an observer for changes to the template URLs.
* @param observer The observer to be removed.
*/
public void removeObserver(TemplateUrlServiceObserver observer) {
mObservers.removeObserver(observer);
}
/**
* Finds the default search engine for the default provider and returns the url query
* {@link String} for {@code query}.
* @param query The {@link String} that represents the text query the search url should
* represent.
* @return A {@link String} that contains the url of the default search engine with
* {@code query} inserted as the search parameter.
*/
public String getUrlForSearchQuery(String query) {
return nativeGetUrlForSearchQuery(mNativeTemplateUrlServiceAndroid, query);
}
/**
* Finds the default search engine for the default provider and returns the url query
* {@link String} for {@code query} with voice input source param set.
* @param query The {@link String} that represents the text query the search url should
* represent.
* @return A {@link String} that contains the url of the default search engine with
* {@code query} inserted as the search parameter and voice input source param set.
*/
public String getUrlForVoiceSearchQuery(String query) {
return nativeGetUrlForVoiceSearchQuery(mNativeTemplateUrlServiceAndroid, query);
}
/**
* Replaces the search terms from {@code query} in {@code url}.
* @param query The {@link String} that represents the text query that should replace the
* existing query in {@code url}.
* @param url The {@link String} that contains the search url with another search query that
* will be replaced with {@code query}.
* @return A new version of {@code url} with the search term replaced with {@code query}.
*/
public String replaceSearchTermsInUrl(String query, String url) {
return nativeReplaceSearchTermsInUrl(mNativeTemplateUrlServiceAndroid, query, url);
}
/**
* Finds the default search engine for the default provider and returns the url query
* {@link String} for {@code query} with the contextual search version param set.
* @param query The search term to use as the main query in the returned search url.
* @param alternateTerm The alternate search term to use as an alternate suggestion.
* @param shouldPrefetch Whether the returned url should include a prefetch parameter.
* @param protocolVersion The version of the Contextual Search API protocol to use.
* @return A {@link String} that contains the url of the default search engine with
* {@code query} and {@code alternateTerm} inserted as parameters and contextual
* search and prefetch parameters conditionally set.
*/
public String getUrlForContextualSearchQuery(
String query, String alternateTerm, boolean shouldPrefetch, String protocolVersion) {
return nativeGetUrlForContextualSearchQuery(mNativeTemplateUrlServiceAndroid, query,
alternateTerm, shouldPrefetch, protocolVersion);
}
/**
* Finds the URL for the search engine for the given keyword.
* @param keyword The templateUrl keyword to look up.
* @return A {@link String} that contains the url of the specified search engine.
*/
public String getSearchEngineUrlFromTemplateUrl(String keyword) {
return nativeGetSearchEngineUrlFromTemplateUrl(mNativeTemplateUrlServiceAndroid, keyword);
}
/**
* Finds the search engine type for the given keyword.
* @param keyword The templateUrl keyword to look up.
* @return The search engine type of the specified search engine that contains the keyword.
*/
public int getSearchEngineTypeFromTemplateUrl(String keyword) {
return nativeGetSearchEngineTypeFromTemplateUrl(mNativeTemplateUrlServiceAndroid, keyword);
}
/**
* Extracts the search query terms from a SRP URL.
* @param url The SRP URL.
* @return A string containing just the search terms stripped from the SRP URL.
*/
public String extractSearchTermsFromUrl(String url) {
return nativeExtractSearchTermsFromUrl(mNativeTemplateUrlServiceAndroid, url);
}
@VisibleForTesting
public String addSearchEngineForTesting(String keyword, int ageInDays) {
return nativeAddSearchEngineForTesting(
mNativeTemplateUrlServiceAndroid, keyword, ageInDays);
}
@VisibleForTesting
public String updateLastVisitedForTesting(String keyword) {
return nativeUpdateLastVisitedForTesting(mNativeTemplateUrlServiceAndroid, keyword);
}
private native long nativeInit();
private native void nativeLoad(long nativeTemplateUrlServiceAndroid);
private native boolean nativeIsLoaded(long nativeTemplateUrlServiceAndroid);
private native void nativeSetUserSelectedDefaultSearchProvider(
long nativeTemplateUrlServiceAndroid, String selectedKeyword);
private native boolean nativeIsDefaultSearchManaged(long nativeTemplateUrlServiceAndroid);
private native boolean nativeIsSearchResultsPageFromDefaultSearchProvider(
long nativeTemplateUrlServiceAndroid, String url);
private native boolean nativeIsSearchByImageAvailable(long nativeTemplateUrlServiceAndroid);
private native boolean nativeIsDefaultSearchEngineGoogle(long nativeTemplateUrlServiceAndroid);
private native boolean nativeDoesDefaultSearchEngineHaveLogo(
long nativeTemplateUrlServiceAndroid);
private native String nativeGetUrlForSearchQuery(long nativeTemplateUrlServiceAndroid,
String query);
private native String nativeGetUrlForVoiceSearchQuery(long nativeTemplateUrlServiceAndroid,
String query);
private native String nativeReplaceSearchTermsInUrl(long nativeTemplateUrlServiceAndroid,
String query, String currentUrl);
private native String nativeGetUrlForContextualSearchQuery(long nativeTemplateUrlServiceAndroid,
String query, String alternateTerm, boolean shouldPrefetch, String protocolVersion);
private native String nativeGetSearchEngineUrlFromTemplateUrl(
long nativeTemplateUrlServiceAndroid, String keyword);
private native int nativeGetSearchEngineTypeFromTemplateUrl(
long nativeTemplateUrlServiceAndroid, String keyword);
private native String nativeAddSearchEngineForTesting(
long nativeTemplateUrlServiceAndroid, String keyword, int offset);
private native String nativeUpdateLastVisitedForTesting(
long nativeTemplateUrlServiceAndroid, String keyword);
private native String nativeExtractSearchTermsFromUrl(
long nativeTemplateUrlServiceAndroid, String url);
private native void nativeGetTemplateUrls(
long nativeTemplateUrlServiceAndroid, List<TemplateUrl> templateUrls);
private native TemplateUrl nativeGetDefaultSearchEngine(long nativeTemplateUrlServiceAndroid);
}