| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.contextualsearch; | 5 package org.chromium.chrome.browser.contextualsearch; |
| 6 | 6 |
| 7 import android.app.Activity; | 7 import android.app.Activity; |
| 8 import android.content.Context; |
| 8 import android.view.View; | 9 import android.view.View; |
| 9 import android.view.ViewGroup; | 10 import android.view.ViewGroup; |
| 10 import android.view.ViewTreeObserver; | 11 import android.view.ViewTreeObserver; |
| 11 import android.view.ViewTreeObserver.OnGlobalFocusChangeListener; | 12 import android.view.ViewTreeObserver.OnGlobalFocusChangeListener; |
| 12 | 13 |
| 13 import org.chromium.base.ActivityState; | 14 import org.chromium.base.ActivityState; |
| 14 import org.chromium.base.ApplicationStatus; | 15 import org.chromium.base.ApplicationStatus; |
| 15 import org.chromium.base.ApplicationStatus.ActivityStateListener; | 16 import org.chromium.base.ApplicationStatus.ActivityStateListener; |
| 16 import org.chromium.base.SysUtils; | 17 import org.chromium.base.SysUtils; |
| 17 import org.chromium.base.VisibleForTesting; | 18 import org.chromium.base.VisibleForTesting; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 41 import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager; | 42 import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager; |
| 42 import org.chromium.chrome.browser.widget.findinpage.FindToolbarObserver; | 43 import org.chromium.chrome.browser.widget.findinpage.FindToolbarObserver; |
| 43 import org.chromium.components.navigation_interception.NavigationParams; | 44 import org.chromium.components.navigation_interception.NavigationParams; |
| 44 import org.chromium.content.browser.ContentViewCore; | 45 import org.chromium.content.browser.ContentViewCore; |
| 45 import org.chromium.content.browser.ContextualSearchClient; | 46 import org.chromium.content.browser.ContextualSearchClient; |
| 46 import org.chromium.content_public.browser.GestureStateListener; | 47 import org.chromium.content_public.browser.GestureStateListener; |
| 47 import org.chromium.content_public.browser.LoadUrlParams; | 48 import org.chromium.content_public.browser.LoadUrlParams; |
| 48 import org.chromium.content_public.browser.NavigationEntry; | 49 import org.chromium.content_public.browser.NavigationEntry; |
| 49 import org.chromium.content_public.browser.WebContentsObserver; | 50 import org.chromium.content_public.browser.WebContentsObserver; |
| 50 import org.chromium.content_public.common.TopControlsState; | 51 import org.chromium.content_public.common.TopControlsState; |
| 52 import org.chromium.ui.UiUtils; |
| 51 import org.chromium.ui.base.WindowAndroid; | 53 import org.chromium.ui.base.WindowAndroid; |
| 52 | 54 |
| 53 import java.net.MalformedURLException; | 55 import java.net.MalformedURLException; |
| 54 import java.net.URL; | 56 import java.net.URL; |
| 57 import java.util.ArrayList; |
| 58 import java.util.LinkedHashSet; |
| 59 import java.util.List; |
| 60 import java.util.Locale; |
| 61 import java.util.Set; |
| 55 | 62 |
| 56 import javax.annotation.Nullable; | 63 import javax.annotation.Nullable; |
| 57 | 64 |
| 58 | 65 |
| 59 /** | 66 /** |
| 60 * Manager for the Contextual Search feature. | 67 * Manager for the Contextual Search feature. |
| 61 * This class keeps track of the status of Contextual Search and coordinates the
control | 68 * This class keeps track of the status of Contextual Search and coordinates the
control |
| 62 * with the layout. | 69 * with the layout. |
| 63 */ | 70 */ |
| 64 public class ContextualSearchManager extends ContextualSearchObservable | 71 public class ContextualSearchManager extends ContextualSearchObservable |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 | 114 |
| 108 /** | 115 /** |
| 109 * This boolean is used for loading content after a long-press when content
is not immediately | 116 * This boolean is used for loading content after a long-press when content
is not immediately |
| 110 * loaded. | 117 * loaded. |
| 111 */ | 118 */ |
| 112 private boolean mShouldLoadDelayedSearch; | 119 private boolean mShouldLoadDelayedSearch; |
| 113 | 120 |
| 114 private boolean mIsShowingPromo; | 121 private boolean mIsShowingPromo; |
| 115 private boolean mDidLogPromoOutcome; | 122 private boolean mDidLogPromoOutcome; |
| 116 | 123 |
| 124 // Cached target languages for translation; |
| 125 private List<String> mTargetLanguages; |
| 126 |
| 117 /** | 127 /** |
| 118 * Whether contextual search manager is currently promoting a tab. We should
be ignoring hide | 128 * Whether contextual search manager is currently promoting a tab. We should
be ignoring hide |
| 119 * requests when mIsPromotingTab is set to true. | 129 * requests when mIsPromotingTab is set to true. |
| 120 */ | 130 */ |
| 121 private boolean mIsPromotingToTab; | 131 private boolean mIsPromotingToTab; |
| 122 | 132 |
| 123 private ContextualSearchNetworkCommunicator mNetworkCommunicator; | 133 private ContextualSearchNetworkCommunicator mNetworkCommunicator; |
| 124 private ContextualSearchPanel mSearchPanel; | 134 private ContextualSearchPanel mSearchPanel; |
| 125 | 135 |
| 126 // TODO(pedrosimonetti): also store selected text, surroundings, url, boundi
ng rect of selected | 136 // TODO(pedrosimonetti): also store selected text, surroundings, url, boundi
ng rect of selected |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 | 293 |
| 284 /** | 294 /** |
| 285 * @return The {@link ContextualSearchPanel}, for testing purposes only. | 295 * @return The {@link ContextualSearchPanel}, for testing purposes only. |
| 286 */ | 296 */ |
| 287 @VisibleForTesting | 297 @VisibleForTesting |
| 288 public ContextualSearchPanel getContextualSearchPanel() { | 298 public ContextualSearchPanel getContextualSearchPanel() { |
| 289 return mSearchPanel; | 299 return mSearchPanel; |
| 290 } | 300 } |
| 291 | 301 |
| 292 /** | 302 /** |
| 293 * Sets the selection controller for testing purposes. | 303 * @return The selection controller, for testing purposes. |
| 294 */ | 304 */ |
| 295 @VisibleForTesting | 305 @VisibleForTesting |
| 296 ContextualSearchSelectionController getSelectionController() { | 306 ContextualSearchSelectionController getSelectionController() { |
| 297 return mSelectionController; | 307 return mSelectionController; |
| 298 } | 308 } |
| 299 | 309 |
| 310 /** |
| 311 * @return The current search request, or {@code null} if there is none, for
testing. |
| 312 */ |
| 313 @VisibleForTesting |
| 314 ContextualSearchRequest getRequest() { |
| 315 return mSearchRequest; |
| 316 } |
| 317 |
| 300 @VisibleForTesting | 318 @VisibleForTesting |
| 301 boolean isSearchPanelShowing() { | 319 boolean isSearchPanelShowing() { |
| 302 return mSearchPanel.isShowing(); | 320 return mSearchPanel.isShowing(); |
| 303 } | 321 } |
| 304 | 322 |
| 305 /** | 323 /** |
| 306 * @return Whether the Search Panel is opened. That is, whether it is EXPAND
ED or MAXIMIZED. | 324 * @return Whether the Search Panel is opened. That is, whether it is EXPAND
ED or MAXIMIZED. |
| 307 */ | 325 */ |
| 308 public boolean isSearchPanelOpened() { | 326 public boolean isSearchPanelOpened() { |
| 309 PanelState state = mSearchPanel.getPanelState(); | 327 PanelState state = mSearchPanel.getPanelState(); |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 if (isTap) { | 487 if (isTap) { |
| 470 // If the user action was not a long-press, immediately start loadin
g content. | 488 // If the user action was not a long-press, immediately start loadin
g content. |
| 471 mShouldLoadDelayedSearch = false; | 489 mShouldLoadDelayedSearch = false; |
| 472 } | 490 } |
| 473 | 491 |
| 474 if (isTap && mPolicy.shouldPreviousTapResolve( | 492 if (isTap && mPolicy.shouldPreviousTapResolve( |
| 475 mNetworkCommunicator.getBasePageUrl())) { | 493 mNetworkCommunicator.getBasePageUrl())) { |
| 476 mNetworkCommunicator.startSearchTermResolutionRequest( | 494 mNetworkCommunicator.startSearchTermResolutionRequest( |
| 477 mSelectionController.getSelectedText()); | 495 mSelectionController.getSelectedText()); |
| 478 didRequestSurroundings = true; | 496 didRequestSurroundings = true; |
| 497 // Cache the target languages in case they are needed for translatio
n. |
| 498 if (mPolicy.isTranslationEnabled()) getTargetLanguages(); |
| 479 } else { | 499 } else { |
| 480 boolean shouldPrefetch = mPolicy.shouldPrefetchSearchResult(isTap); | 500 boolean shouldPrefetch = mPolicy.shouldPrefetchSearchResult(isTap); |
| 481 mSearchRequest = new ContextualSearchRequest(mSelectionController.ge
tSelectedText(), | 501 mSearchRequest = new ContextualSearchRequest(mSelectionController.ge
tSelectedText(), |
| 482 null, shouldPrefetch); | 502 null, shouldPrefetch); |
| 503 // TODO(donnd): figure out a way to do translation on long-press sel
ections. |
| 483 mDidStartLoadingResolvedSearchRequest = false; | 504 mDidStartLoadingResolvedSearchRequest = false; |
| 484 mSearchPanel.displaySearchTerm(mSelectionController.getSelectedText(
)); | 505 mSearchPanel.displaySearchTerm(mSelectionController.getSelectedText(
)); |
| 485 if (shouldPrefetch) loadSearchUrl(); | 506 if (shouldPrefetch) loadSearchUrl(); |
| 486 } | 507 } |
| 487 | 508 |
| 488 if (!didRequestSurroundings) { | 509 if (!didRequestSurroundings) { |
| 489 // Gather surrounding text for Icing integration, which will make th
e selection and | 510 // Gather surrounding text for Icing integration, which will make th
e selection and |
| 490 // a shorter version of the surroundings available for Conversationa
l Search. | 511 // a shorter version of the surroundings available for Conversationa
l Search. |
| 491 // Although the surroundings are extracted, they will not be sent to
the server as | 512 // Although the surroundings are extracted, they will not be sent to
the server as |
| 492 // part of search term resolution, just sent to Icing which keeps th
em local until | 513 // part of search term resolution, just sent to Icing which keeps th
em local until |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 668 * parameters should be ignored. | 689 * parameters should be ignored. |
| 669 * @param responseCode The HTTP response code. If the code is not OK, the q
uery | 690 * @param responseCode The HTTP response code. If the code is not OK, the q
uery |
| 670 * should be ignored. | 691 * should be ignored. |
| 671 * @param searchTerm The term to use in our subsequent search. | 692 * @param searchTerm The term to use in our subsequent search. |
| 672 * @param displayText The text to display in our UX. | 693 * @param displayText The text to display in our UX. |
| 673 * @param alternateTerm The alternate term to display on the results page. | 694 * @param alternateTerm The alternate term to display on the results page. |
| 674 * @param selectionStartAdjust A positive number of characters that the star
t of the existing | 695 * @param selectionStartAdjust A positive number of characters that the star
t of the existing |
| 675 * selection should be expanded by. | 696 * selection should be expanded by. |
| 676 * @param selectionEndAdjust A positive number of characters that the end of
the existing | 697 * @param selectionEndAdjust A positive number of characters that the end of
the existing |
| 677 * selection should be expanded by. | 698 * selection should be expanded by. |
| 699 * @param contextLanguage The language of the original search term, or an em
pty string. |
| 678 */ | 700 */ |
| 679 @CalledByNative | 701 @CalledByNative |
| 680 public void onSearchTermResolutionResponse(boolean isNetworkUnavailable, int
responseCode, | 702 public void onSearchTermResolutionResponse(boolean isNetworkUnavailable, int
responseCode, |
| 681 final String searchTerm, final String displayText, final String alte
rnateTerm, | 703 final String searchTerm, final String displayText, final String alte
rnateTerm, |
| 682 boolean doPreventPreload, int selectionStartAdjust, int selectionEnd
Adjust) { | 704 boolean doPreventPreload, int selectionStartAdjust, int selectionEnd
Adjust, |
| 705 final String contextLanguage) { |
| 683 mNetworkCommunicator.handleSearchTermResolutionResponse(isNetworkUnavail
able, responseCode, | 706 mNetworkCommunicator.handleSearchTermResolutionResponse(isNetworkUnavail
able, responseCode, |
| 684 searchTerm, displayText, alternateTerm, doPreventPreload, select
ionStartAdjust, | 707 searchTerm, displayText, alternateTerm, doPreventPreload, select
ionStartAdjust, |
| 685 selectionEndAdjust); | 708 selectionEndAdjust, contextLanguage); |
| 686 } | 709 } |
| 687 | 710 |
| 688 @Override | 711 @Override |
| 689 public void handleSearchTermResolutionResponse(boolean isNetworkUnavailable,
int responseCode, | 712 public void handleSearchTermResolutionResponse(boolean isNetworkUnavailable,
int responseCode, |
| 690 String searchTerm, String displayText, String alternateTerm, boolean
doPreventPreload, | 713 String searchTerm, String displayText, String alternateTerm, boolean
doPreventPreload, |
| 691 int selectionStartAdjust, int selectionEndAdjust) { | 714 int selectionStartAdjust, int selectionEndAdjust, String contextLang
uage) { |
| 692 if (!mSearchPanel.isShowing()) return; | 715 if (!mSearchPanel.isShowing()) return; |
| 693 | 716 |
| 694 // Show an appropriate message for what to search for. | 717 // Show an appropriate message for what to search for. |
| 695 String message; | 718 String message; |
| 696 boolean doLiteralSearch = false; | 719 boolean doLiteralSearch = false; |
| 697 if (isNetworkUnavailable) { | 720 if (isNetworkUnavailable) { |
| 698 message = mActivity.getResources().getString( | 721 message = mActivity.getResources().getString( |
| 699 R.string.contextual_search_network_unavailable); | 722 R.string.contextual_search_network_unavailable); |
| 700 } else if (!isHttpFailureCode(responseCode)) { | 723 } else if (!isHttpFailureCode(responseCode)) { |
| 701 message = displayText; | 724 message = displayText; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 714 if (doLiteralSearch) { | 737 if (doLiteralSearch) { |
| 715 searchTerm = mSelectionController.getSelectedText(); | 738 searchTerm = mSelectionController.getSelectedText(); |
| 716 alternateTerm = null; | 739 alternateTerm = null; |
| 717 doPreventPreload = true; | 740 doPreventPreload = true; |
| 718 } | 741 } |
| 719 if (!searchTerm.isEmpty()) { | 742 if (!searchTerm.isEmpty()) { |
| 720 // TODO(donnd): Instead of preloading, we should prefetch (ie the UR
L should not | 743 // TODO(donnd): Instead of preloading, we should prefetch (ie the UR
L should not |
| 721 // appear in the user's history until the user views it). See crbug
.com/406446. | 744 // appear in the user's history until the user views it). See crbug
.com/406446. |
| 722 boolean shouldPreload = !doPreventPreload && mPolicy.shouldPrefetchS
earchResult(true); | 745 boolean shouldPreload = !doPreventPreload && mPolicy.shouldPrefetchS
earchResult(true); |
| 723 mSearchRequest = new ContextualSearchRequest(searchTerm, alternateTe
rm, shouldPreload); | 746 mSearchRequest = new ContextualSearchRequest(searchTerm, alternateTe
rm, shouldPreload); |
| 747 // Trigger translation, if enabled. |
| 748 if (!contextLanguage.isEmpty() && mPolicy.isTranslationEnabled()) { |
| 749 List<String> targetLanguages = getTargetLanguages(); |
| 750 if (mPolicy.needsTranslation(contextLanguage, targetLanguages))
{ |
| 751 mSearchRequest.forceTranslation( |
| 752 contextLanguage, mPolicy.bestTargetLanguage(targetLa
nguages)); |
| 753 } |
| 754 } |
| 724 mDidStartLoadingResolvedSearchRequest = false; | 755 mDidStartLoadingResolvedSearchRequest = false; |
| 725 if (mSearchPanel.isContentShowing()) { | 756 if (mSearchPanel.isContentShowing()) { |
| 726 mSearchRequest.setNormalPriority(); | 757 mSearchRequest.setNormalPriority(); |
| 727 } | 758 } |
| 728 if (mSearchPanel.isContentShowing() || shouldPreload) { | 759 if (mSearchPanel.isContentShowing() || shouldPreload) { |
| 729 loadSearchUrl(); | 760 loadSearchUrl(); |
| 730 } | 761 } |
| 731 mPolicy.logSearchTermResolutionDetails(searchTerm, | 762 mPolicy.logSearchTermResolutionDetails(searchTerm, |
| 732 mNetworkCommunicator.getBasePageUrl()); | 763 mNetworkCommunicator.getBasePageUrl()); |
| 733 } | 764 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 762 * @return Whether a Tap gesture is currently supported. | 793 * @return Whether a Tap gesture is currently supported. |
| 763 */ | 794 */ |
| 764 private boolean isTapSupported() { | 795 private boolean isTapSupported() { |
| 765 // Base page just started navigating away, so taps should be ignored. | 796 // Base page just started navigating away, so taps should be ignored. |
| 766 if (mDidBasePageLoadJustStart) return false; | 797 if (mDidBasePageLoadJustStart) return false; |
| 767 | 798 |
| 768 return mPolicy.isTapSupported(); | 799 return mPolicy.isTapSupported(); |
| 769 } | 800 } |
| 770 | 801 |
| 771 // =========================================================================
=================== | 802 // =========================================================================
=================== |
| 803 // Translation support |
| 804 // =========================================================================
=================== |
| 805 |
| 806 /** |
| 807 * Gets the list of target languages for the current user, with the first |
| 808 * item in the list being the user's primary language. |
| 809 * @return The {@link List} of languages the user understands with their pri
mary language first. |
| 810 */ |
| 811 private List<String> getTargetLanguages() { |
| 812 // May be cached. |
| 813 if (mTargetLanguages != null) return mTargetLanguages; |
| 814 |
| 815 // Using LinkedHashSet keeps the entries both unique and ordered. |
| 816 Set<String> uniqueLanguages = new LinkedHashSet<String>(); |
| 817 |
| 818 // The primary language always comes first. |
| 819 uniqueLanguages.add( |
| 820 trimLocaleToLanguage(nativeGetTargetLanguage(mNativeContextualSe
archManagerPtr))); |
| 821 |
| 822 // Next add languages the user knows how to type. |
| 823 Context context = mActivity.getApplicationContext(); |
| 824 List<String> locales = context != null |
| 825 ? new ArrayList<String>(UiUtils.getIMELocales(context)) |
| 826 : new ArrayList<String>(); |
| 827 for (int i = 0; i < locales.size(); i++) { |
| 828 uniqueLanguages.add(trimLocaleToLanguage(locales.get(i))); |
| 829 } |
| 830 |
| 831 // Add the accept languages last, since they are a weaker hint than pres
ence of a keyboard. |
| 832 List<String> acceptLanguages = getAcceptLanguages(); |
| 833 for (int i = 0; i < acceptLanguages.size(); i++) { |
| 834 uniqueLanguages.add(trimLocaleToLanguage(acceptLanguages.get(i))); |
| 835 } |
| 836 mTargetLanguages = new ArrayList<String>(uniqueLanguages); |
| 837 return mTargetLanguages; |
| 838 } |
| 839 |
| 840 /** |
| 841 * Gets the list of accept languages for this user. |
| 842 * @return The {@link List} of languages the user understands or does not wa
nt translated. |
| 843 */ |
| 844 private List<String> getAcceptLanguages() { |
| 845 String acceptLanguages = nativeGetAcceptLanguages(mNativeContextualSearc
hManagerPtr); |
| 846 List<String> result = new ArrayList<String>(); |
| 847 for (String language : acceptLanguages.split(",")) { |
| 848 result.add(language); |
| 849 } |
| 850 return result; |
| 851 } |
| 852 |
| 853 /** |
| 854 * @return The given locale as a language code. |
| 855 */ |
| 856 private String trimLocaleToLanguage(String locale) { |
| 857 // TODO(donnd): use getScript or getLanguageTag (both API 21), or some o
ther standard way to |
| 858 // strip the country, instead of hard-coding the two character language
code. |
| 859 // TODO(donnd): Shouldn't getLanguage() do this? |
| 860 String trimmedLocale = locale.substring(0, 2); |
| 861 return new Locale(trimmedLocale).getLanguage(); |
| 862 } |
| 863 |
| 864 // =========================================================================
=================== |
| 772 // OverlayContentDelegate | 865 // OverlayContentDelegate |
| 773 // =========================================================================
=================== | 866 // =========================================================================
=================== |
| 774 | 867 |
| 775 @Override | 868 @Override |
| 776 public OverlayContentDelegate getOverlayContentDelegate() { | 869 public OverlayContentDelegate getOverlayContentDelegate() { |
| 777 return new SearchOverlayContentDelegate(); | 870 return new SearchOverlayContentDelegate(); |
| 778 } | 871 } |
| 779 | 872 |
| 780 /** | 873 /** |
| 781 * Implementation of OverlayContentDelegate. Made public for testing purpose
s. | 874 * Implementation of OverlayContentDelegate. Made public for testing purpose
s. |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1187 // -------------------------------------------------------------------------
------------------- | 1280 // -------------------------------------------------------------------------
------------------- |
| 1188 | 1281 |
| 1189 private native long nativeInit(); | 1282 private native long nativeInit(); |
| 1190 private native void nativeDestroy(long nativeContextualSearchManager); | 1283 private native void nativeDestroy(long nativeContextualSearchManager); |
| 1191 private native void nativeStartSearchTermResolutionRequest(long nativeContex
tualSearchManager, | 1284 private native void nativeStartSearchTermResolutionRequest(long nativeContex
tualSearchManager, |
| 1192 String selection, boolean useResolvedSearchTerm, ContentViewCore bas
eContentViewCore, | 1285 String selection, boolean useResolvedSearchTerm, ContentViewCore bas
eContentViewCore, |
| 1193 boolean maySendBasePageUrl); | 1286 boolean maySendBasePageUrl); |
| 1194 private native void nativeGatherSurroundingText(long nativeContextualSearchM
anager, | 1287 private native void nativeGatherSurroundingText(long nativeContextualSearchM
anager, |
| 1195 String selection, boolean useResolvedSearchTerm, ContentViewCore bas
eContentViewCore, | 1288 String selection, boolean useResolvedSearchTerm, ContentViewCore bas
eContentViewCore, |
| 1196 boolean maySendBasePageUrl); | 1289 boolean maySendBasePageUrl); |
| 1290 private native String nativeGetTargetLanguage(long nativeContextualSearchMan
ager); |
| 1291 private native String nativeGetAcceptLanguages(long nativeContextualSearchMa
nager); |
| 1197 } | 1292 } |
| OLD | NEW |