Index: chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java |
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b334ae1fdc3b46816e3d742eee67b570f849a788 |
--- /dev/null |
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java |
@@ -0,0 +1,192 @@ |
+// Copyright 2015 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.contextualsearch; |
+ |
+import org.chromium.base.CalledByNative; |
+import org.chromium.chrome.browser.CompositorChromeActivity; |
+import org.chromium.chrome.browser.EmptyTabObserver; |
+import org.chromium.chrome.browser.Tab; |
+import org.chromium.chrome.browser.preferences.PrefServiceBridge; |
+import org.chromium.chrome.browser.profiles.Profile; |
+import org.chromium.chrome.browser.search_engines.TemplateUrlService; |
+import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver; |
+import org.chromium.content.browser.ContentViewCore; |
+import org.chromium.content_public.browser.GestureStateListener; |
+ |
+/** |
+ * Manages the activation and gesture listeners for ContextualSearch on a given tab. |
+ */ |
+public class ContextualSearchTabHelper extends EmptyTabObserver { |
+ /** |
+ * Notification handler for Contextual Search events. |
+ */ |
+ private final TemplateUrlServiceObserver mTemplateUrlObserver = |
+ new TemplateUrlServiceObserver() { |
+ @Override |
+ public void onTemplateURLServiceChanged() { |
+ onContextualSearchPrefChanged(); |
+ } |
+ }; |
+ |
+ /** |
+ * The current ContentViewCore for the Tab which this helper is monitoring. |
+ */ |
+ private ContentViewCore mBaseContentViewCore; |
+ |
+ /** |
+ * The GestureListener used for handling events from the current ContentViewCore. |
+ */ |
+ private GestureStateListener mGestureStateListener; |
+ |
+ private long mNativeHelper = 0; |
+ |
+ /** |
+ * Creates a contextual search tab helper for the given tab. |
+ * @param tab The tab whose contextual search actions will be handled by this helper. |
+ */ |
+ public static void createForTab(Tab tab) { |
+ new ContextualSearchTabHelper(tab); |
+ } |
+ |
+ private ContextualSearchTabHelper(Tab tab) { |
+ tab.addObserver(this); |
+ } |
+ |
+ @Override |
+ public void onPageLoadStarted(Tab tab) { |
+ if (tab.getContentViewCore() == null) { |
+ // Nothing to do yet. |
+ return; |
+ } |
+ |
+ mBaseContentViewCore = tab.getContentViewCore(); |
+ // Add Contextual Search here in case it couldn't get added in onContentChanged() due to |
+ // being too early in initialization of Chrome (ContextualSearchManager being null). |
+ setContextualSearchHooks(mBaseContentViewCore); |
+ } |
+ |
+ @Override |
+ public void onPageLoadFinished(Tab tab) { |
+ // Native initialization happens after a page loads to ensure profile is initialized. |
+ if (mNativeHelper == 0) { |
+ mNativeHelper = nativeInit(tab.getProfile()); |
+ } |
+ } |
+ |
+ @Override |
+ public void onContentChanged(Tab tab) { |
+ updateHooksForNewContentViewCore(tab); |
+ } |
+ |
+ @Override |
+ public void onWebContentsSwapped(Tab tab, boolean didStartLoad, boolean didFinishLoad) { |
+ updateHooksForNewContentViewCore(tab); |
+ } |
+ |
+ @Override |
+ public void onDestroyed(Tab tab) { |
+ if (mNativeHelper != 0) { |
+ nativeDestroy(mNativeHelper); |
+ mNativeHelper = 0; |
+ } |
+ removeContextualSearchHooks(mBaseContentViewCore); |
+ mBaseContentViewCore = null; |
+ } |
+ |
+ /** |
+ * Should be called whenever the Tab's ContentViewCore changes. Removes hooks from the |
+ * existing ContentViewCore, if necessary and then adds hooks for the new ContentViewCore. |
+ * @param tab |
+ */ |
+ private void updateHooksForNewContentViewCore(Tab tab) { |
+ removeContextualSearchHooks(mBaseContentViewCore); |
+ mBaseContentViewCore = tab.getContentViewCore(); |
+ setContextualSearchHooks(mBaseContentViewCore); |
+ } |
+ |
+ /** |
+ * Sets up the Contextual Search hooks, adding or removing them depending on whether it is |
+ * currently active. |
+ * @param cvc The content view core to attach the gesture state listener to. |
+ */ |
+ private void setContextualSearchHooks(ContentViewCore cvc) { |
+ if (cvc == null) return; |
+ |
+ if (isContextualSearchActive(cvc)) { |
+ addContextualSearchHooks(cvc); |
+ } else { |
+ removeContextualSearchHooks(cvc); |
+ } |
+ } |
+ |
+ /** |
+ * Adds Contextual Search hooks for its client and listener to the given content view core. |
+ * @param cvc The content view core to attach the gesture state listener to. |
+ */ |
+ private void addContextualSearchHooks(ContentViewCore cvc) { |
+ if (ContextualSearchFieldTrial.isEnabled(cvc.getContext().getApplicationContext())) { |
+ ContextualSearchUma.logPreferenceState( |
+ ContextualSearchPolicy.getInstance(cvc.getContext()).getPromoTapsRemaining()); |
+ } |
+ if (mGestureStateListener == null) { |
+ mGestureStateListener = getContextualSearchManager(cvc).getGestureStateListener(); |
+ cvc.addGestureStateListener(mGestureStateListener); |
+ cvc.setContextualSearchClient(getContextualSearchManager(cvc)); |
+ TemplateUrlService.getInstance().addObserver(mTemplateUrlObserver); |
+ } |
+ } |
+ |
+ /** |
+ * Removes Contextual Search hooks for its client and listener from the given content view core. |
+ * @param cvc The content view core to detach the gesture state listener from. |
+ */ |
+ private void removeContextualSearchHooks(ContentViewCore cvc) { |
+ if (cvc == null) return; |
+ |
+ if (ContextualSearchFieldTrial.isEnabled(cvc.getContext().getApplicationContext())) { |
+ ContextualSearchUma.logPreferenceState( |
+ ContextualSearchPolicy.getInstance(cvc.getContext()).getPromoTapsRemaining()); |
+ } |
+ if (mGestureStateListener != null) { |
+ cvc.removeGestureStateListener(mGestureStateListener); |
+ mGestureStateListener = null; |
+ cvc.setContextualSearchClient(null); |
+ TemplateUrlService.getInstance().removeObserver(mTemplateUrlObserver); |
+ } |
+ } |
+ |
+ /** |
+ * @return whether Contextual Search is enabled and active in this tab. |
+ */ |
+ private static boolean isContextualSearchActive(ContentViewCore cvc) { |
+ return !cvc.getWebContents().isIncognito() && getContextualSearchManager(cvc) != null |
+ && !PrefServiceBridge.getInstance().isContextualSearchDisabled() |
+ && TemplateUrlService.getInstance().isDefaultSearchEngineGoogle() |
+ // Svelte and Accessibility devices are incompatible with the first-run flow and |
+ // Talkback has poor interaction with tap to search (see http://crbug.com/399708 and |
+ // http://crbug.com/396934). |
+ // TODO(jeremycho): Handle these cases. |
+ && !getContextualSearchManager(cvc).isRunningInCompatibilityMode(); |
+ } |
+ |
+ /** |
+ * @return the Contextual Search manager. |
+ */ |
+ private static ContextualSearchManager getContextualSearchManager(ContentViewCore cvc) { |
+ // TODO(yfriedman): Decouple this from the activity. |
+ if (cvc.getContext() instanceof CompositorChromeActivity) { |
+ return ((CompositorChromeActivity) cvc.getContext()).getContextualSearchManager(); |
+ } |
+ return null; |
+ } |
+ |
+ @CalledByNative |
+ private void onContextualSearchPrefChanged() { |
+ setContextualSearchHooks(mBaseContentViewCore); |
+ } |
+ |
+ private native long nativeInit(Profile profile); |
+ private native void nativeDestroy(long nativeContextualSearchTabHelper); |
+} |