// 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.text.TextUtils;
import org.chromium.base.ObserverList;
import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
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();
}
/**
* Represents search engine with its index.
*/
public static class TemplateUrl {
private final int mIndex;
private final String mShortName;
private boolean mIsPrepopulated;
@CalledByNative("TemplateUrl")
public static TemplateUrl create(int id, String shortName, boolean isPrepopulated) {
return new TemplateUrl(id, shortName, isPrepopulated);
}
public TemplateUrl(int index, String shortName, boolean isPrepopulated) {
mIndex = index;
mShortName = shortName;
mIsPrepopulated = isPrepopulated;
}
public int getIndex() {
return mIndex;
}
public String getShortName() {
return mShortName;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + mIndex;
result = prime * result + ((mShortName == null) ? 0 : mShortName.hashCode());
return result;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof TemplateUrl)) return false;
TemplateUrl otherTemplateUrl = (TemplateUrl) other;
return mIndex == otherTemplateUrl.mIndex
&& TextUtils.equals(mShortName, otherTemplateUrl.mShortName);
}
}
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);
}
/**
* Returns a list of the prepopulated search engines.
*
* Warning: TemplateUrl.getIndex() is *not* an index into this list, since this list contains
* only prepopulated search engines. E.g. getLocalizedSearchEngines().get(0).getIndex() could
* return 3.
*/
public List<TemplateUrl> getLocalizedSearchEngines() {
ThreadUtils.assertOnUiThread();
int templateUrlCount = nativeGetTemplateUrlCount(mNativeTemplateUrlServiceAndroid);
List<TemplateUrl> templateUrls = new ArrayList<TemplateUrl>(templateUrlCount);
for (int i = 0; i < templateUrlCount; i++) {
TemplateUrl templateUrl = nativeGetTemplateUrlAt(mNativeTemplateUrlServiceAndroid, i);
if (templateUrl != null && templateUrl.mIsPrepopulated) {
templateUrls.add(templateUrl);
}
}
return templateUrls;
}
/**
* 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 The default search engine index (e.g., 0, 1, 2,...).
*/
public int getDefaultSearchEngineIndex() {
ThreadUtils.assertOnUiThread();
return nativeGetDefaultSearchProvider(mNativeTemplateUrlServiceAndroid);
}
/**
* @return {@link TemplateUrlService.TemplateUrl} for the default search engine.
*/
public TemplateUrl getDefaultSearchEngineTemplateUrl() {
if (!isLoaded()) return null;
int defaultSearchEngineIndex = getDefaultSearchEngineIndex();
if (defaultSearchEngineIndex == -1) return null;
assert defaultSearchEngineIndex >= 0;
assert defaultSearchEngineIndex < nativeGetTemplateUrlCount(
mNativeTemplateUrlServiceAndroid);
return nativeGetTemplateUrlAt(mNativeTemplateUrlServiceAndroid, defaultSearchEngineIndex);
}
public void setSearchEngine(int selectedIndex) {
ThreadUtils.assertOnUiThread();
nativeSetUserSelectedDefaultSearchProvider(mNativeTemplateUrlServiceAndroid, selectedIndex);
}
public boolean isSearchProviderManaged() {
return nativeIsSearchProviderManaged(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);
}
/**
* Registers a listener for the callback that indicates that the
* TemplateURLService has loaded.
*/
public void registerLoadListener(LoadListener listener) {
ThreadUtils.assertOnUiThread();
boolean added = mLoadListeners.addObserver(listener);
assert added;
}
/**
* 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 at the given index.
* @param index The templateUrl index to look up.
* @return A {@link String} that contains the url of the specified search engine.
*/
public String getSearchEngineUrlFromTemplateUrl(int index) {
return nativeGetSearchEngineUrlFromTemplateUrl(mNativeTemplateUrlServiceAndroid, index);
}
private native long nativeInit();
private native void nativeLoad(long nativeTemplateUrlServiceAndroid);
private native boolean nativeIsLoaded(long nativeTemplateUrlServiceAndroid);
private native int nativeGetTemplateUrlCount(long nativeTemplateUrlServiceAndroid);
private native TemplateUrl nativeGetTemplateUrlAt(long nativeTemplateUrlServiceAndroid, int i);
private native void nativeSetUserSelectedDefaultSearchProvider(
long nativeTemplateUrlServiceAndroid, int selectedIndex);
private native int nativeGetDefaultSearchProvider(long nativeTemplateUrlServiceAndroid);
private native boolean nativeIsSearchProviderManaged(long nativeTemplateUrlServiceAndroid);
private native boolean nativeIsSearchByImageAvailable(long nativeTemplateUrlServiceAndroid);
private native boolean nativeIsDefaultSearchEngineGoogle(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, int index);
}