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 |