Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(121)

Unified Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java

Issue 1206673003: Merge java_staging/src into java/src. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
deleted file mode 100644
index 8099d1beabc9bfdcd8c86cd79430628b08d24ae0..0000000000000000000000000000000000000000
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ /dev/null
@@ -1,1248 +0,0 @@
-// 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 android.app.Activity;
-import android.os.Handler;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
-
-import org.chromium.base.ActivityState;
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.ApplicationStatus.ActivityStateListener;
-import org.chromium.base.CalledByNative;
-import org.chromium.base.SysUtils;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.Tab;
-import org.chromium.chrome.browser.WebContentsFactory;
-import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchControl;
-import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel.PanelState;
-import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel.StateChangeReason;
-import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanelDelegate;
-import org.chromium.chrome.browser.contextualsearch.ContextualSearchSelectionController.SelectionType;
-import org.chromium.chrome.browser.device.DeviceClassManager;
-import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler;
-import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler.OverrideUrlLoadingResult;
-import org.chromium.chrome.browser.externalnav.ExternalNavigationParams;
-import org.chromium.chrome.browser.gsa.GSAContextDisplaySelection;
-import org.chromium.chrome.browser.infobar.InfoBarContainer;
-import org.chromium.chrome.browser.preferences.PrefServiceBridge;
-import org.chromium.chrome.browser.tab.TabRedirectHandler;
-import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
-import org.chromium.chrome.browser.tabmodel.TabModel;
-import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
-import org.chromium.chrome.browser.tabmodel.TabModelObserver;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
-import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
-import org.chromium.components.navigation_interception.NavigationParams;
-import org.chromium.components.web_contents_delegate_android.WebContentsDelegateAndroid;
-import org.chromium.content.browser.ContentView;
-import org.chromium.content.browser.ContentViewCore;
-import org.chromium.content.browser.ContextualSearchClient;
-import org.chromium.content_public.browser.GestureStateListener;
-import org.chromium.content_public.browser.LoadUrlParams;
-import org.chromium.content_public.browser.WebContents;
-import org.chromium.content_public.browser.WebContentsObserver;
-import org.chromium.content_public.common.TopControlsState;
-import org.chromium.ui.base.WindowAndroid;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.regex.Pattern;
-
-import javax.annotation.Nullable;
-
-
-/**
- * Manager for the Contextual Search feature.
- * This class keeps track of the status of Contextual Search and coordinates the control
- * with the layout.
- */
-public class ContextualSearchManager extends ContextualSearchObservable
- implements ContextualSearchManagementDelegate,
- ContextualSearchNetworkCommunicator, ContextualSearchSelectionHandler,
- ContextualSearchClient, ActivityStateListener {
-
- private static final String TAG = "ContextualSearch";
-
- private static final String CONTAINS_WORD_PATTERN = "(\\w|\\p{L}|\\p{N})+";
-
- // Max selection length must be limited or the entire request URL can go past the 2K limit.
- private static final int MAX_SELECTION_LENGTH = 100;
-
- private static final boolean ALWAYS_USE_RESOLVED_SEARCH_TERM = true;
- private static final boolean NEVER_USE_RESOLVED_SEARCH_TERM = false;
-
- private static final String INTENT_URL_PREFIX = "intent:";
-
- // The animation duration of a URL being promoted to a tab when triggered by an
- // intercept navigation. This is faster than the standard tab promotion animation
- // so that it completes before the navigation.
- private static final long INTERCEPT_NAVIGATION_PROMOTION_ANIMATION_DURATION_MS = 40;
-
- // We blacklist this URL because malformed URLs may bring up this page.
- private static final String BLACKLISTED_URL = "about:blank";
-
- private final ContextualSearchSelectionController mSelectionController;
- private final Pattern mContainsWordPattern;
- private final ChromeActivity mActivity;
- private ViewGroup mParentView;
- private final ViewTreeObserver.OnGlobalFocusChangeListener mOnFocusChangeListener;
-
- private final WindowAndroid mWindowAndroid;
- private ContentViewCore mSearchContentViewCore;
- private WebContentsObserver mSearchWebContentsObserver;
- private final WebContentsDelegateAndroid mWebContentsDelegate;
- private ContextualSearchContentViewDelegate mSearchContentViewDelegate;
- private final ContextualSearchTabPromotionDelegate mTabPromotionDelegate;
- private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
- private TabModelObserver mTabModelObserver;
- private boolean mIsSearchContentViewShowing;
- private boolean mDidLoadResolvedSearchRequest;
- private long mLoadedSearchUrlTimeMs;
- // TODO(donnd): consider changing this member's name to indicate "opened" instead of "seen".
- private boolean mWereSearchResultsSeen;
- private boolean mWereInfoBarsHidden;
- private boolean mDidLoadAnyUrl;
- private boolean mDidPromoteSearchNavigation;
- private boolean mDidBasePageLoadJustStart;
- private boolean mWasActivatedByTap;
- private boolean mIsInitialized;
-
- private boolean mIsShowingPromo;
- private boolean mDidLogPromoOutcome;
-
- /**
- * Whether contextual search manager is currently promoting a tab. We should be ignoring hide
- * requests when mIsPromotingTab is set to true.
- */
- private boolean mIsPromotingToTab;
-
- private ContextualSearchNetworkCommunicator mNetworkCommunicator;
- private ContextualSearchPanelDelegate mSearchPanelDelegate;
-
- // TODO(pedrosimonetti): also store selected text, surroundings, url, bounding rect of selected
- // text, and make sure that all states are cleared when starting a new contextual search to
- // avoid having the values in a funky state.
- private ContextualSearchRequest mSearchRequest;
-
- // The native manager associated with this object.
- private long mNativeContextualSearchManagerPtr;
-
- private TabRedirectHandler mTabRedirectHandler;
-
- /**
- * The delegate that is notified when the Search Panel ContentViewCore is ready to be rendered.
- */
- public interface ContextualSearchContentViewDelegate {
- /**
- * Sets the {@code ContentViewCore} associated to the Contextual Search Panel.
- * @param contentViewCore Reference to the ContentViewCore.
- */
- void setContextualSearchContentViewCore(ContentViewCore contentViewCore);
-
- /**
- * Releases the {@code ContentViewCore} associated to the Contextual Search Panel.
- */
- void releaseContextualSearchContentViewCore();
- }
-
- /**
- * The delegate that is responsible for promoting a {@link ContentViewCore} to a {@link Tab}
- * when necessary.
- */
- public interface ContextualSearchTabPromotionDelegate {
- /**
- * Called when {@code searchContentViewCore} should be promoted to a {@link Tab}.
- * @param searchContentViewCore The {@link ContentViewCore} to promote.
- * @return Whether or not {@code searchContentViewCore}'s ownership
- * was transferred to the new {@link Tab} or not. If
- * {@code false}, this {@link ContentViewCore} might be
- * destroyed after this call.
- */
- boolean createContextualSearchTab(ContentViewCore searchContentViewCore);
- }
-
- /**
- * Constructs the manager for the given activity, and will attach views to the given parent.
- * @param activity The {@code ChromeActivity} in use.
- * @param windowAndroid The {@code WindowAndroid} associated with Chrome.
- * @param tabPromotionDelegate The {@link ContextualSearchTabPromotionDelegate} that is
- * responsible for building tabs from contextual search
- * {@link ContentViewCore}s.
- */
- public ContextualSearchManager(ChromeActivity activity, WindowAndroid windowAndroid,
- ContextualSearchTabPromotionDelegate tabPromotionDelegate) {
- super(activity);
- mActivity = activity;
- mWindowAndroid = windowAndroid;
- mTabPromotionDelegate = tabPromotionDelegate;
- mContainsWordPattern = Pattern.compile(CONTAINS_WORD_PATTERN);
-
- mSelectionController = new ContextualSearchSelectionController(activity, this);
-
- mWebContentsDelegate = new WebContentsDelegateAndroid() {
- @Override
- public void onLoadStarted() {
- super.onLoadStarted();
- mSearchPanelDelegate.onLoadStarted();
- }
-
- @Override
- public void onLoadStopped() {
- super.onLoadStopped();
- mSearchPanelDelegate.onLoadStopped();
- }
-
- @Override
- public void onLoadProgressChanged(int progress) {
- super.onLoadProgressChanged(progress);
- mSearchPanelDelegate.onLoadProgressChanged(progress);
- }
- };
-
- final View controlContainer = mActivity.findViewById(R.id.control_container);
- mOnFocusChangeListener = new OnGlobalFocusChangeListener() {
- @Override
- public void onGlobalFocusChanged(View oldFocus, View newFocus) {
- if (controlContainer != null && controlContainer.hasFocus()) {
- hideContextualSearch(StateChangeReason.UNKNOWN);
- }
- }
- };
-
- mTabModelObserver = new EmptyTabModelObserver() {
- @Override
- public void didAddTab(Tab tab, TabLaunchType type) {
- // If we're in the process of promoting this tab, just return and don't mess with
- // this state.
- if (tab.getContentViewCore() == mSearchContentViewCore) return;
- hideContextualSearch(StateChangeReason.UNKNOWN);
- }
- };
- }
-
- /**
- * Initializes this manager. Must be called before {@link #getContextualSearchControl()}.
- * @param parentView The parent view to attach Contextual Search UX to.
- */
- public void initialize(ViewGroup parentView) {
- mParentView = parentView;
- mParentView.getViewTreeObserver().addOnGlobalFocusChangeListener(mOnFocusChangeListener);
- mNativeContextualSearchManagerPtr = nativeInit();
- listenForHideNotifications();
- mTabRedirectHandler = new TabRedirectHandler(mActivity);
-
- mIsShowingPromo = false;
- mDidLogPromoOutcome = false;
- mDidLoadResolvedSearchRequest = false;
- mWereSearchResultsSeen = false;
- mNetworkCommunicator = this;
- ApplicationStatus.registerStateListenerForActivity(this, mActivity);
- mIsInitialized = true;
- }
-
- /**
- * Destroys the native Contextual Search Manager.
- * Call this method before orphaning this object to allow it to be garbage collected.
- */
- public void destroy() {
- if (!mIsInitialized) return;
-
- hideContextualSearch(StateChangeReason.UNKNOWN);
- mParentView.getViewTreeObserver().removeOnGlobalFocusChangeListener(mOnFocusChangeListener);
- nativeDestroy(mNativeContextualSearchManagerPtr);
- stopListeningForHideNotifications();
- mTabRedirectHandler.clear();
- ApplicationStatus.unregisterActivityStateListener(this);
- }
-
- @Override
- public void setContextualSearchPanelDelegate(ContextualSearchPanelDelegate delegate) {
- mSearchPanelDelegate = delegate;
- }
-
- /**
- * @return The {@link ContextualSearchPanelDelegate}, for testing purposes only.
- */
- @VisibleForTesting
- public ContextualSearchPanelDelegate getContextualSearchPanelDelegate() {
- return mSearchPanelDelegate;
- }
-
- /**
- * Sets the selection controller for testing purposes.
- */
- @VisibleForTesting
- ContextualSearchSelectionController getSelectionController() {
- return mSelectionController;
- }
-
- @VisibleForTesting
- boolean isSearchPanelShowing() {
- return mSearchPanelDelegate.isShowing();
- }
-
- /**
- * @return Whether the Search Panel is opened. That is, whether it is EXPANDED or MAXIMIZED.
- */
- public boolean isSearchPanelOpened() {
- PanelState state = mSearchPanelDelegate.getPanelState();
- return state == PanelState.EXPANDED || state == PanelState.MAXIMIZED;
- }
-
- /**
- * @return The Base Page's {@link ContentViewCore}.
- */
- @Nullable private ContentViewCore getBaseContentView() {
- return mSelectionController.getBaseContentView();
- }
-
- @Override
- public void setPreferenceState(boolean enabled) {
- PrefServiceBridge.getInstance().setContextualSearchState(enabled);
- }
-
- @Override
- public boolean isPromoAvailable() {
- return mPolicy.isPromoAvailable();
- }
-
- /**
- * Hides the Contextual Search UX.
- * @param reason The {@link StateChangeReason} for hiding Contextual Search.
- */
- public void hideContextualSearch(StateChangeReason reason) {
- if (mSearchPanelDelegate == null) return;
-
- if (mSearchPanelDelegate.isShowing()) {
- mSearchPanelDelegate.closePanel(reason, false);
- }
- }
-
- @Override
- public void onCloseContextualSearch() {
- if (mSearchPanelDelegate == null) return;
-
- // NOTE(pedrosimonetti): hideContextualSearch() will also be called after swiping the
- // Panel down in order to dismiss it. In this case, hideContextualSearch() will be called
- // after completing the hide animation, and at that moment the Panel will not be showing
- // anymore. Therefore, we need to always clear selection, regardless of when the Panel
- // was still visible, in order to make sure the selection will be cleared appropriately.
- if (mSelectionController.getSelectionType() == SelectionType.TAP) {
- mSelectionController.clearSelection();
- }
-
- // Show the infobar container if it was visible before Contextual Search was shown.
- if (mWereInfoBarsHidden) {
- mWereInfoBarsHidden = false;
- InfoBarContainer container = getInfoBarContainer();
- if (container != null) {
- container.setVisibility(View.VISIBLE);
- container.setDoStayInvisible(false);
- }
- }
-
- if (!mWereSearchResultsSeen && mLoadedSearchUrlTimeMs != 0L) {
- removeLastSearchVisit();
- }
-
- // Clear the timestamp. This is to avoid future calls to hideContextualSearch clearing
- // the current URL.
- mLoadedSearchUrlTimeMs = 0L;
- mWereSearchResultsSeen = false;
-
- mNetworkCommunicator.destroySearchContentView();
- mSearchRequest = null;
-
- if (mIsShowingPromo && !mDidLogPromoOutcome) {
- logPromoOutcome();
- }
-
- mIsShowingPromo = false;
- mSearchPanelDelegate.setIsPromoActive(false);
- notifyHideContextualSearch();
- }
-
- /**
- * Called when the system back button is pressed. Will hide the layout.
- */
- public boolean onBackPressed() {
- if (!mIsInitialized || !mSearchPanelDelegate.isShowing()) return false;
- hideContextualSearch(StateChangeReason.BACK_PRESS);
- return true;
- }
-
- /**
- * Called when the orientation of the device changes.
- */
- public void onOrientationChange() {
- if (!mIsInitialized) return;
- hideContextualSearch(StateChangeReason.UNKNOWN);
- }
-
- /**
- * Sets the {@link ContextualSearchNetworkCommunicator} to use for server requests.
- * @param networkCommunicator The communicator for all future requests.
- */
- @VisibleForTesting
- public void setNetworkCommunicator(ContextualSearchNetworkCommunicator networkCommunicator) {
- mNetworkCommunicator = networkCommunicator;
- }
-
- /**
- * Determines if the given selection is valid or not.
- * @param selection The selection portion of the context.
- * @return whether the given selection is considered a valid target for a search.
- */
- private boolean isValidSelection(String selection) {
- return isValidSelection(selection, getBaseContentView());
- }
-
- @VisibleForTesting
- boolean isValidSelection(String selection, ContentViewCore baseContentView) {
- if (selection.length() > MAX_SELECTION_LENGTH || !doesContainAWord(selection)) {
- return false;
- }
- return (baseContentView != null) && !baseContentView.isFocusedNodeEditable();
- }
-
- /**
- * Shows the Contextual Search UX.
- * Calls back into onGetContextualSearchQueryResponse.
- * @param stateChangeReason The reason explaining the change of state.
- */
- private void showContextualSearch(StateChangeReason stateChangeReason) {
- if (!mSearchPanelDelegate.isShowing()) {
- // If visible, hide the infobar container before showing the Contextual Search panel.
- InfoBarContainer container = getInfoBarContainer();
- if (container != null && container.getVisibility() == View.VISIBLE) {
- mWereInfoBarsHidden = true;
- container.setVisibility(View.INVISIBLE);
- container.setDoStayInvisible(true);
- }
- }
-
- // If the user is jumping from one unseen search to another search, remove the last search
- // from history.
- PanelState state = mSearchPanelDelegate.getPanelState();
- if (!mWereSearchResultsSeen && mLoadedSearchUrlTimeMs != 0L
- && state != PanelState.UNDEFINED && state != PanelState.CLOSED) {
- removeLastSearchVisit();
- }
-
- // Make sure we'll create a new Content View when needed.
- mNetworkCommunicator.destroySearchContentView();
-
- boolean isTap = mSelectionController.getSelectionType() == SelectionType.TAP;
- boolean didRequestSurroundings = false;
- if (isTap && mPolicy.shouldPreviousTapResolve(
- mNetworkCommunicator.getBasePageUrl())) {
- mNetworkCommunicator.startSearchTermResolutionRequest(
- mSelectionController.getSelectedText());
- didRequestSurroundings = true;
- } else {
- boolean shouldPrefetch = mPolicy.shouldPrefetchSearchResult(isTap);
- mSearchRequest = new ContextualSearchRequest(mSelectionController.getSelectedText(),
- null, shouldPrefetch);
- mDidLoadResolvedSearchRequest = false;
- getContextualSearchControl().setCentralText(mSelectionController.getSelectedText());
- if (shouldPrefetch) loadSearchUrl();
- }
-
- if (!didRequestSurroundings) {
- // Gather surrounding text for Icing integration, which will make the selection and
- // a shorter version of the surroundings available for Conversational Search.
- // Although the surroundings are extracted, they will not be sent to the server as
- // part of search term resolution, just sent to Icing which keeps them local until
- // the user activates a Voice Search.
- nativeGatherSurroundingText(mNativeContextualSearchManagerPtr,
- mSelectionController.getSelectedText(), NEVER_USE_RESOLVED_SEARCH_TERM,
- getBaseContentView(), mPolicy.maySendBasePageUrl());
- }
-
- mWereSearchResultsSeen = false;
-
- // TODO(donnd): although we are showing the bar here, we have not yet set the text!
- // Refactor to show the bar and set the text at the same time!
- // TODO(donnd): If there was a previously ongoing contextual search, we should ensure
- // it's registered as closed.
- mSearchPanelDelegate.peekPanel(stateChangeReason);
-
- // Note: now that the contextual search has properly started, set the promo involvement.
- if (mPolicy.isPromoAvailable()) {
- mIsShowingPromo = true;
- mDidLogPromoOutcome = false;
- mSearchPanelDelegate.setIsPromoActive(true);
- mSearchPanelDelegate.setDidSearchInvolvePromo();
- }
-
- assert mSelectionController.getSelectionType() != SelectionType.UNDETERMINED;
- mWasActivatedByTap = mSelectionController.getSelectionType() == SelectionType.TAP;
- }
-
- @Override
- public void startSearchTermResolutionRequest(String selection) {
- ContentViewCore baseContentView = getBaseContentView();
- if (baseContentView != null) {
- nativeStartSearchTermResolutionRequest(mNativeContextualSearchManagerPtr, selection,
- ALWAYS_USE_RESOLVED_SEARCH_TERM, getBaseContentView(),
- mPolicy.maySendBasePageUrl());
- }
- }
-
- @Override
- @Nullable public URL getBasePageUrl() {
- ContentViewCore baseContentViewCore = getBaseContentView();
- if (baseContentViewCore == null) return null;
-
- try {
- return new URL(baseContentViewCore.getWebContents().getUrl());
- } catch (MalformedURLException e) {
- return null;
- }
- }
-
- @Override
- public void updateTopControlsState(int current, boolean animate) {
- Tab currentTab = mActivity.getActivityTab();
- if (currentTab != null) {
- currentTab.updateTopControlsState(current, animate);
- }
- }
-
- /**
- * Determines if the given selection contains a word or not.
- * @param selection The the selection to check for a word.
- * @return Whether the selection contains a word anywhere within it or not.
- */
- @VisibleForTesting
- public boolean doesContainAWord(String selection) {
- return mContainsWordPattern.matcher(selection).find();
- }
-
- /**
- * Accessor for the {@code InfoBarContainer} currently attached to the {@code Tab}.
- */
- private InfoBarContainer getInfoBarContainer() {
- Tab tab = mActivity.getActivityTab();
- return tab == null ? null : tab.getInfoBarContainer();
- }
-
- /**
- * Inflates the Contextual Search control, if needed.
- */
- private ContextualSearchControl getContextualSearchControl() {
- return mSearchPanelDelegate.getContextualSearchControl();
- }
-
- /**
- * Listens for notifications that should hide the Contextual Search bar.
- */
- private void listenForHideNotifications() {
- TabModelSelector selector = mActivity.getTabModelSelector();
-
- mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(selector) {
- @Override
- public void onPageLoadStarted(Tab tab, String url) {
- hideContextualSearch(StateChangeReason.UNKNOWN);
- mDidBasePageLoadJustStart = true;
- }
-
- @Override
- public void onCrash(Tab tab, boolean sadTabShown) {
- if (sadTabShown) {
- // Hide contextual search if the foreground tab crashed
- hideContextualSearch(StateChangeReason.UNKNOWN);
- }
- }
-
- @Override
- public void onClosingStateChanged(Tab tab, boolean closing) {
- if (closing) hideContextualSearch(StateChangeReason.UNKNOWN);
- }
- };
-
- for (TabModel tabModel : selector.getModels()) {
- tabModel.addObserver(mTabModelObserver);
- }
- }
-
- /**
- * Stops listening for notifications that should hide the Contextual Search bar.
- */
- private void stopListeningForHideNotifications() {
- if (mTabModelSelectorTabObserver != null) mTabModelSelectorTabObserver.destroy();
-
- TabModelSelector selector = mActivity.getTabModelSelector();
- if (selector != null) {
- for (TabModel tabModel : selector.getModels()) {
- tabModel.removeObserver(mTabModelObserver);
- }
- }
- }
-
- @Override
- public void onActivityStateChange(Activity activity, int newState) {
- if (newState == ActivityState.RESUMED || newState == ActivityState.STOPPED
- || newState == ActivityState.DESTROYED) {
- hideContextualSearch(StateChangeReason.UNKNOWN);
- } else if (newState == ActivityState.PAUSED) {
- mPolicy.logCurrentState(getBaseContentView());
- }
- }
-
- /**
- * Clears our private member referencing the native manager.
- */
- @CalledByNative
- public void clearNativeManager() {
- assert mNativeContextualSearchManagerPtr != 0;
- mNativeContextualSearchManagerPtr = 0;
- }
-
- /**
- * Sets our private member referencing the native manager.
- * @param nativeManager The pointer to the native Contextual Search manager.
- */
- @CalledByNative
- public void setNativeManager(long nativeManager) {
- assert mNativeContextualSearchManagerPtr == 0;
- mNativeContextualSearchManagerPtr = nativeManager;
- }
-
- /**
- * Called when surrounding text is available.
- * @param beforeText to be shown before the selected word.
- * @param afterText to be shown after the selected word.
- */
- @CalledByNative
- private void onSurroundingTextAvailable(final String beforeText, final String afterText) {
- if (mSearchPanelDelegate.isShowing()) {
- getContextualSearchControl().setSearchContext(
- mSelectionController.getSelectedText(), beforeText, afterText);
- }
- }
-
- /**
- * Called by native code when a selection is available to share with Icing (for Conversational
- * Search).
- */
- @CalledByNative
- private void onIcingSelectionAvailable(
- final String encoding, final String surroundingText, int startOffset, int endOffset) {
- GSAContextDisplaySelection selection =
- new GSAContextDisplaySelection(encoding, surroundingText, startOffset, endOffset);
- notifyShowContextualSearch(selection, mNetworkCommunicator.getBasePageUrl());
- }
-
- /**
- * Called in response to the
- * {@link ContextualSearchManager#nativeStartSearchTermResolutionRequest} method.
- * @param isNetworkUnavailable Indicates if the network is unavailable, in which case all other
- * parameters should be ignored.
- * @param responseCode The HTTP response code. If the code is not OK, the query
- * should be ignored.
- * @param searchTerm The term to use in our subsequent search.
- * @param displayText The text to display in our UX.
- * @param alternateTerm The alternate term to display on the results page.
- */
- @CalledByNative
- public void onSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode,
- final String searchTerm, final String displayText, final String alternateTerm,
- boolean doPreventPreload) {
- mNetworkCommunicator.handleSearchTermResolutionResponse(isNetworkUnavailable, responseCode,
- searchTerm, displayText, alternateTerm, doPreventPreload);
- }
-
- @Override
- public void handleSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode,
- String searchTerm, String displayText, String alternateTerm, boolean doPreventPreload) {
- if (!mSearchPanelDelegate.isShowing()) return;
-
- // Show an appropriate message for what to search for.
- String message;
- boolean doLiteralSearch = false;
- if (isNetworkUnavailable) {
- message = mActivity.getResources().getString(
- R.string.contextual_search_network_unavailable);
- } else if (!isHttpFailureCode(responseCode)) {
- message = displayText;
- } else if (!mPolicy.shouldShowErrorCodeInBar()) {
- message = mSelectionController.getSelectedText();
- doLiteralSearch = true;
- } else {
- message = mActivity.getResources().getString(
- R.string.contextual_search_error, responseCode);
- doLiteralSearch = true;
- }
- getContextualSearchControl().setCentralText(message);
-
- // If there was an error, fall back onto a literal search for the selection.
- // Since we're showing the panel, there must be a selection.
- if (doLiteralSearch) {
- searchTerm = mSelectionController.getSelectedText();
- alternateTerm = null;
- doPreventPreload = true;
- }
- if (!searchTerm.isEmpty()) {
- // TODO(donnd): Instead of preloading, we should prefetch (ie the URL should not
- // appear in the user's history until the user views it). See crbug.com/406446.
- boolean shouldPreload = !doPreventPreload && mPolicy.shouldPrefetchSearchResult(true);
- mSearchRequest = new ContextualSearchRequest(searchTerm, alternateTerm, shouldPreload);
- mDidLoadResolvedSearchRequest = false;
- if (mIsSearchContentViewShowing) {
- mSearchRequest.setNormalPriority();
- }
- if (mIsSearchContentViewShowing || shouldPreload) {
- loadSearchUrl();
- }
- mPolicy.logSearchTermResolutionDetails(searchTerm,
- mNetworkCommunicator.getBasePageUrl());
- }
- }
-
- /**
- * Loads a Search Request in the Contextual Search's Content View.
- */
- private void loadSearchUrl() {
- mLoadedSearchUrlTimeMs = System.currentTimeMillis();
- mNetworkCommunicator.loadUrl(mSearchRequest.getSearchUrl());
- mDidLoadResolvedSearchRequest = true;
-
- // TODO(pedrosimonetti): If the user taps on a word and quickly after that taps on the
- // peeking Search Bar, the Search Content View will not be displayed. It seems that
- // calling ContentViewCore.onShow() while it's being created has no effect. Need
- // to coordinate with Chrome-Android folks to come up with a proper fix for this.
- // For now, we force the ContentView to be displayed by calling onShow() again
- // when a URL is being loaded. See: crbug.com/398206
- if (mIsSearchContentViewShowing && mSearchContentViewCore != null) {
- mSearchContentViewCore.onShow();
- }
- }
-
- /**
- * @return Whether a Tap gesture is currently supported.
- */
- private boolean isTapSupported() {
- // Base page just started navigating away, so taps should be ignored.
- if (mDidBasePageLoadJustStart) return false;
-
- return mPolicy.isTapSupported();
- }
-
- // --------------------------------------------------------------------------------------------
- // Search Content View
- // --------------------------------------------------------------------------------------------
-
- /**
- * Gets the {@code ContentViewCore} associated with Contextual Search Panel.
- * @return Contextual Search Panel's {@code ContentViewCore}.
- */
- @Override
- public ContentViewCore getSearchContentViewCore() {
- return mSearchContentViewCore;
- }
-
- /**
- * Sets the {@code ContextualSearchContentViewDelegate} associated with the Content View.
- * @param delegate
- */
- public void setSearchContentViewDelegate(ContextualSearchContentViewDelegate delegate) {
- mSearchContentViewDelegate = delegate;
- }
-
- /**
- * Removes the last resolved search URL from the Chrome history.
- */
- private void removeLastSearchVisit() {
- if (mSearchRequest != null) {
- nativeRemoveLastSearchVisit(mNativeContextualSearchManagerPtr,
- mSearchRequest.getSearchUrl(), mLoadedSearchUrlTimeMs);
- }
- }
-
- /**
- * Called when the Search content view navigates to a contextual search request URL.
- * This navigation could be for a prefetch when the panel is still closed, or
- * a load of a user-visible search result.
- * @param isFailure Whether the navigation failed.
- */
- private void onContextualSearchRequestNavigation(boolean isFailure) {
- if (mSearchRequest == null) return;
-
- if (mSearchRequest.isUsingLowPriority()) {
- ContextualSearchUma.logLowPrioritySearchRequestOutcome(isFailure);
- } else {
- ContextualSearchUma.logNormalPrioritySearchRequestOutcome(isFailure);
- if (mSearchRequest.getHasFailed()) {
- ContextualSearchUma.logFallbackSearchRequestOutcome(isFailure);
- }
- }
-
- if (isFailure && mSearchRequest.isUsingLowPriority()) {
- // We're navigating to an error page, so we want to stop and retry.
- // Stop loading the page that displays the error to the user.
- if (mSearchContentViewCore != null) {
- // When running tests the Content View might not exist.
- mSearchContentViewCore.getWebContents().stop();
- }
- mSearchRequest.setHasFailed();
- mSearchRequest.setNormalPriority();
- // If the content view is showing, load at normal priority now.
- if (mIsSearchContentViewShowing) {
- loadSearchUrl();
- } else {
- mDidLoadResolvedSearchRequest = false;
- }
- }
- }
-
- @Override
- public void logPromoOutcome() {
- ContextualSearchUma.logPromoOutcome(mWasActivatedByTap);
- mDidLogPromoOutcome = true;
- }
-
- /**
- * Called when the Search Content view has finished loading to record how long it takes the SERP
- * to load after opening the panel.
- */
- private void onSearchResultsLoaded() {
- if (mSearchRequest == null) return;
-
- mSearchPanelDelegate.onSearchResultsLoaded(mSearchRequest.wasPrefetch());
- }
-
- /**
- * Creates a new Content View Core to display search results, if needed.
- */
- private void createNewSearchContentViewCoreIfNeeded() {
- if (mSearchContentViewCore == null) {
- mNetworkCommunicator.createNewSearchContentView();
- }
- }
-
- @Override
- public void loadUrl(String url) {
- createNewSearchContentViewCoreIfNeeded();
- if (mSearchContentViewCore != null && mSearchContentViewCore.getWebContents() != null) {
- mDidLoadAnyUrl = true;
- mSearchContentViewCore.getWebContents().getNavigationController().loadUrl(
- new LoadUrlParams(url));
- }
- }
-
- @Override
- public void createNewSearchContentView() {
- if (mSearchContentViewCore != null) {
- mNetworkCommunicator.destroySearchContentView();
- }
-
- mSearchContentViewCore = new ContentViewCore(mActivity);
- ContentView cv = new ContentView(mActivity, mSearchContentViewCore);
- // Creates an initially hidden WebContents which gets shown when the panel is opened.
- mSearchContentViewCore.initialize(cv, cv,
- WebContentsFactory.createWebContents(false, true), mWindowAndroid);
-
- // Transfers the ownership of the WebContents to the native ContextualSearchManager.
- nativeSetWebContents(mNativeContextualSearchManagerPtr, mSearchContentViewCore,
- mWebContentsDelegate);
-
- mSearchWebContentsObserver =
- new WebContentsObserver(mSearchContentViewCore.getWebContents()) {
- @Override
- public void didStartLoading(String url) {
- mDidPromoteSearchNavigation = false;
- }
-
- @Override
- public void didStartProvisionalLoadForFrame(long frameId, long parentFrameId,
- boolean isMainFrame, String validatedUrl, boolean isErrorPage,
- boolean isIframeSrcdoc) {
- if (isMainFrame) onExternalNavigation(validatedUrl);
- }
-
- @Override
- public void didNavigateMainFrame(String url, String baseUrl,
- boolean isNavigationToDifferentPage, boolean isNavigationInPage,
- int httpResultCode) {
- mNetworkCommunicator.handleDidNavigateMainFrame(url, httpResultCode);
- }
-
- @Override
- public void didFinishLoad(long frameId, String validatedUrl,
- boolean isMainFrame) {
- onSearchResultsLoaded();
-
- // Any time we place a page in a ContentViewCore, clear history if needed.
- // This prevents error URLs from appearing in the Tab's history stack.
- // Also please note that clearHistory() will not
- // clear the current entry (search results page in this case),
- // and it will not work properly if there are pending navigations.
- // That's why we need to clear the history here, after the navigation
- // is completed.
- boolean shouldClearHistory =
- mSearchRequest != null && mSearchRequest.getHasFailed();
- if (shouldClearHistory && mSearchContentViewCore != null) {
- mSearchContentViewCore.getWebContents().getNavigationController()
- .clearHistory();
- }
- }
- };
-
- mSearchContentViewDelegate.setContextualSearchContentViewCore(mSearchContentViewCore);
- nativeSetInterceptNavigationDelegate(mNativeContextualSearchManagerPtr,
- new InterceptNavigationDelegateImpl(), mSearchContentViewCore.getWebContents());
- }
-
- @Override
- public void handleDidNavigateMainFrame(String url, int httpResultCode) {
- if (shouldPromoteSearchNavigation()) {
- onExternalNavigation(url);
- } else {
- // Could be just prefetching, check if that failed.
- boolean isFailure = isHttpFailureCode(httpResultCode);
- onContextualSearchRequestNavigation(isFailure);
- }
- mDidLoadAnyUrl = false;
- }
-
- /**
- * @return Whether the given HTTP result code represents a failure or not.
- */
- private boolean isHttpFailureCode(int httpResultCode) {
- return httpResultCode <= 0 || httpResultCode >= 400;
- }
-
- /**
- * @return whether a navigation in the search content view should promote to a separate tab.
- */
- private boolean shouldPromoteSearchNavigation() {
- // A navigation can be due to us loading a URL, or a touch in the search content view.
- // Require a touch, but no recent loading, in order to promote to a separate tab.
- // Note that tapping the opt-in button requires checking for recent loading.
- return mSearchPanelDelegate.didTouchSearchContentView() && !mDidLoadAnyUrl;
- }
-
- /**
- * Called to check if an external navigation is being done and take the appropriate action:
- * Auto-promotes the panel into a separate tab if that's not already being done.
- * @param url The URL we are navigating to.
- */
- private void onExternalNavigation(String url) {
- if (!mDidPromoteSearchNavigation
- && !BLACKLISTED_URL.equals(url)
- && !url.startsWith(INTENT_URL_PREFIX)
- && shouldPromoteSearchNavigation()) {
- // Do not promote to a regular tab if we're loading our Resolved Search
- // URL, otherwise we'll promote it when prefetching the Serp.
- // Don't promote URLs when they are navigating to an intent - this is
- // handled by the InterceptNavigationDelegate which uses a faster
- // maximizing animation.
- mDidPromoteSearchNavigation = true;
- mSearchPanelDelegate.maximizePanelThenPromoteToTab(StateChangeReason.SERP_NAVIGATION);
- }
- }
-
- @Override
- public void destroySearchContentView() {
- if (mSearchContentViewCore != null && mSearchContentViewDelegate != null) {
- nativeDestroyWebContents(mNativeContextualSearchManagerPtr);
- mSearchContentViewDelegate.releaseContextualSearchContentViewCore();
- mSearchContentViewCore.destroy();
- mSearchContentViewCore = null;
- if (mSearchWebContentsObserver != null) {
- mSearchWebContentsObserver.destroy();
- mSearchWebContentsObserver = null;
- }
- }
-
- // This should be called last here. The setSearchContentViewVisibility method
- // will change the visibility the SearchContentView but also set the value of the
- // internal property mIsSearchContentViewShowing. If we call this after deleting
- // the SearchContentView, it will be faster, because only the internal property
- // will be changed, since there will be no need to change the visibility of the
- // SearchContentView.
- setSearchContentViewVisibility(false);
- }
-
- @Override
- public void openResolvedSearchUrlInNewTab() {
- if (mSearchRequest != null && mSearchRequest.getSearchUrl() != null) {
- openUrlInNewTab(mSearchRequest.getSearchUrl());
- }
- }
-
- /**
- * Convenience method for opening a specific |url| in a new Tab.
- */
- private void openUrlInNewTab(String url) {
- TabModelSelector tabModelSelector = mActivity.getTabModelSelector();
- tabModelSelector.openNewTab(
- new LoadUrlParams(url),
- TabLaunchType.FROM_MENU_OR_OVERVIEW,
- tabModelSelector.getCurrentTab(),
- tabModelSelector.isIncognitoSelected());
- }
-
- @Override
- public boolean isRunningInCompatibilityMode() {
- return DeviceClassManager.isAccessibilityModeEnabled(mActivity)
- || SysUtils.isLowEndDevice();
- }
-
- @Override
- public void promoteToTab(boolean shouldFocusOmnibox) {
- mIsPromotingToTab = true;
- // If the request object is null that means that a Contextual Search has just started
- // and the Search Term Resolution response hasn't arrived yet. In this case, promoting
- // the Panel to a Tab will result in creating a new tab with URL about:blank. To prevent
- // this problem, we are ignoring tap gestures in the Search Bar if we don't know what
- // to search for.
- if (mSearchRequest != null
- && mSearchContentViewCore != null
- && mSearchContentViewCore.getWebContents() != null) {
- nativeReleaseWebContents(mNativeContextualSearchManagerPtr);
- mSearchContentViewDelegate.releaseContextualSearchContentViewCore();
- if (!mTabPromotionDelegate.createContextualSearchTab(mSearchContentViewCore)) {
- nativeDestroyWebContentsFromContentViewCore(mNativeContextualSearchManagerPtr,
- mSearchContentViewCore);
- mSearchContentViewCore.destroy();
- }
- if (mSearchWebContentsObserver != null) {
- mSearchWebContentsObserver.destroy();
- mSearchWebContentsObserver = null;
- }
- mSearchContentViewCore = null;
- mIsSearchContentViewShowing = false;
- mSearchRequest = null;
-
- // NOTE(pedrosimonetti): The Panel should be closed after being promoted to a Tab
- // to prevent Chrome-Android from animating the creation of the new Tab.
- mSearchPanelDelegate.closePanel(StateChangeReason.TAB_PROMOTION, false);
-
- // Focus the Omnibox.
- if (shouldFocusOmnibox) {
- new Handler().post(new Runnable() {
- @Override
- public void run() {
- View urlBarView = mActivity.findViewById(R.id.url_bar);
- urlBarView.requestFocus();
- }
- });
- }
- }
- mIsPromotingToTab = false;
- }
-
- @Override
- public void resetSearchContentViewScroll() {
- if (mSearchContentViewCore != null) {
- mSearchContentViewCore.scrollTo(0, 0);
- }
- }
-
- @Override
- public float getSearchContentViewVerticalScroll() {
- return mSearchContentViewCore != null
- ? mSearchContentViewCore.computeVerticalScrollOffset() : -1.f;
- }
-
- @Override
- public void setSearchContentViewVisibility(boolean isVisible) {
- if (mIsSearchContentViewShowing == isVisible) return;
-
- mIsSearchContentViewShowing = isVisible;
- if (isVisible) {
- mWereSearchResultsSeen = true;
- // If there's no current request, then either a search term resolution
- // is in progress or we should do a verbatim search now.
- if (mSearchRequest == null
- && mPolicy.shouldCreateVerbatimRequest(mSelectionController,
- mNetworkCommunicator.getBasePageUrl())) {
- mSearchRequest = new ContextualSearchRequest(
- mSelectionController.getSelectedText());
- mDidLoadResolvedSearchRequest = false;
- }
- if (mSearchRequest != null && !mDidLoadResolvedSearchRequest) {
- mSearchRequest.setNormalPriority();
- loadSearchUrl();
- }
- // The CVC is created with the search request, but if none was made we'll need
- // one in order to display an empty panel.
- createNewSearchContentViewCoreIfNeeded();
- if (mSearchContentViewCore != null) mSearchContentViewCore.onShow();
- mSearchPanelDelegate.setWasSearchContentViewSeen();
- mPolicy.updateCountersForOpen();
- } else {
- if (mSearchContentViewCore != null) mSearchContentViewCore.onHide();
- }
- }
-
- @Override
- public void preserveBasePageSelectionOnNextLossOfFocus() {
- ContentViewCore basePageContentView = getBaseContentView();
- if (basePageContentView != null) {
- basePageContentView.preserveSelectionOnNextLossOfFocus();
- }
- }
-
- @Override
- public void dismissContextualSearchBar() {
- hideContextualSearch(StateChangeReason.UNKNOWN);
- }
-
- // Used to intercept intent navigations.
- // TODO(jeremycho): Consider creating a Tab with the Panel's ContentViewCore,
- // which would also handle functionality like long-press-to-paste.
- private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
- final ExternalNavigationHandler mExternalNavHandler = new ExternalNavigationHandler(
- mActivity);
- @Override
- public boolean shouldIgnoreNavigation(NavigationParams navigationParams) {
- mTabRedirectHandler.updateNewUrlLoading(navigationParams.pageTransitionType,
- navigationParams.isRedirect,
- navigationParams.hasUserGesture || navigationParams.hasUserGestureCarryover,
- mActivity.getLastUserInteractionTime(), TabRedirectHandler.INVALID_ENTRY_INDEX);
-
- ExternalNavigationParams params = new ExternalNavigationParams.Builder(
- navigationParams.url, false, navigationParams.referrer,
- navigationParams.pageTransitionType, navigationParams.isRedirect)
- .setApplicationMustBeInForeground(true)
- .setRedirectHandler(mTabRedirectHandler)
- .setIsMainFrame(navigationParams.isMainFrame)
- .build();
- if (mExternalNavHandler.shouldOverrideUrlLoading(params)
- != OverrideUrlLoadingResult.NO_OVERRIDE) {
- mSearchPanelDelegate.maximizePanelThenPromoteToTab(
- StateChangeReason.TAB_PROMOTION,
- INTERCEPT_NAVIGATION_PROMOTION_ANIMATION_DURATION_MS);
- return true;
- }
- return false;
- }
- }
-
- // --------------------------------------------------------------------------------------------
- // ContextualSearchClient -- interface used by ContentViewCore.
- // --------------------------------------------------------------------------------------------
-
- @Override
- public void onSelectionChanged(String selection) {
- mSelectionController.handleSelectionChanged(selection);
- updateTopControlsState(TopControlsState.BOTH, true);
- }
-
- @Override
- public void onSelectionEvent(int eventType, float posXPix, float posYPix) {
- mSelectionController.handleSelectionEvent(eventType, posXPix, posYPix);
- }
-
- @Override
- public void showUnhandledTapUIIfNeeded(final int x, final int y) {
- mDidBasePageLoadJustStart = false;
- mSelectionController.handleShowUnhandledTapUIIfNeeded(x, y);
- }
-
- // --------------------------------------------------------------------------------------------
- // Selection
- // --------------------------------------------------------------------------------------------
-
- /**
- * Returns a new {@code GestureStateListener} that will listen for events in the Base Page.
- * This listener will handle all Contextual Search-related interactions that go through the
- * listener.
- */
- public GestureStateListener getGestureStateListener() {
- return mSelectionController.getGestureStateListener();
- }
-
- @Override
- public void handleScroll() {
- hideContextualSearch(StateChangeReason.BASE_PAGE_SCROLL);
- }
-
- @Override
- public void handleInvalidTap() {
- hideContextualSearch(StateChangeReason.BASE_PAGE_TAP);
- }
-
- @Override
- public void handleValidTap() {
- if (isTapSupported()) {
- // Here we are starting a new Contextual Search with a Tap gesture, therefore
- // we need to clear to properly reflect that a search just started and we don't
- // have the resolved search term yet.
- mSearchRequest = null;
-
- // Let the policy know that a tap gesture has been received.
- mPolicy.registerTap();
-
- ContentViewCore baseContentView = getBaseContentView();
- if (baseContentView != null) baseContentView.getWebContents().selectWordAroundCaret();
- }
- }
-
- @Override
- public void handleSelection(String selection, SelectionType type, float x, float y) {
- if (!selection.isEmpty()) {
- boolean isSelectionValid = isValidSelection(selection);
-
- StateChangeReason stateChangeReason = type == SelectionType.TAP
- ? StateChangeReason.TEXT_SELECT_TAP : StateChangeReason.TEXT_SELECT_LONG_PRESS;
- ContextualSearchUma.logSelectionIsValid(isSelectionValid);
-
- if (isSelectionValid) {
- mSearchPanelDelegate.updateBasePageSelectionYPx(y);
- showContextualSearch(stateChangeReason);
- } else {
- hideContextualSearch(stateChangeReason);
- }
- }
- }
-
- @Override
- public void handleSelectionDismissal() {
- if (mSearchPanelDelegate.isShowing() && !mIsPromotingToTab) {
- hideContextualSearch(StateChangeReason.CLEARED_SELECTION);
- }
- }
-
- @Override
- public void handleSelectionModification(String selection, float x, float y) {
- if (mSearchPanelDelegate.isShowing()) {
- getContextualSearchControl().setCentralText(selection);
- }
- }
-
- // --------------------------------------------------------------------------------------------
- // Native calls
- // --------------------------------------------------------------------------------------------
-
- private native long nativeInit();
- private native void nativeDestroy(long nativeContextualSearchManager);
- private native void nativeStartSearchTermResolutionRequest(long nativeContextualSearchManager,
- String selection, boolean useResolvedSearchTerm, ContentViewCore baseContentViewCore,
- boolean maySendBasePageUrl);
- private native void nativeGatherSurroundingText(long nativeContextualSearchManager,
- String selection, boolean useResolvedSearchTerm, ContentViewCore baseContentViewCore,
- boolean maySendBasePageUrl);
- private native void nativeRemoveLastSearchVisit(
- long nativeContextualSearchManager, String searchUrl, long searchUrlTimeMs);
- private native void nativeSetWebContents(long nativeContextualSearchManager,
- ContentViewCore searchContentViewCore, WebContentsDelegateAndroid delegate);
- private native void nativeDestroyWebContents(long nativeContextualSearchManager);
- private native void nativeReleaseWebContents(long nativeContextualSearchManager);
- private native void nativeDestroyWebContentsFromContentViewCore(
- long nativeContextualSearchManager, ContentViewCore contentViewCore);
- private native void nativeSetInterceptNavigationDelegate(long nativeContextualSearchManager,
- InterceptNavigationDelegate delegate, WebContents webContents);
-}

Powered by Google App Engine
This is Rietveld 408576698