| 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.annotation.SuppressLint; | 7 import android.annotation.SuppressLint; |
| 8 import android.os.Handler; | 8 import android.os.Handler; |
| 9 import android.text.TextUtils; | 9 import android.text.TextUtils; |
| 10 import android.view.View; | 10 import android.view.View; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 | 87 |
| 88 // How long to wait for a tap near a previous tap before hiding the UI or sh
owing a re-Tap. | 88 // How long to wait for a tap near a previous tap before hiding the UI or sh
owing a re-Tap. |
| 89 // This setting is not critical: in practice it determines how long to wait
after an invalid | 89 // This setting is not critical: in practice it determines how long to wait
after an invalid |
| 90 // tap for the page to respond before hiding the UI. Specifically this setti
ng just needs to be | 90 // tap for the page to respond before hiding the UI. Specifically this setti
ng just needs to be |
| 91 // long enough for Blink's decisions before calling handleShowUnhandledTapUI
IfNeeded (which | 91 // long enough for Blink's decisions before calling handleShowUnhandledTapUI
IfNeeded (which |
| 92 // probably are page-dependent), and short enough that the Bar goes away fai
rly quickly after a | 92 // probably are page-dependent), and short enough that the Bar goes away fai
rly quickly after a |
| 93 // tap on non-text or whitespace: We currently do not get notification in th
ese cases (hence the | 93 // tap on non-text or whitespace: We currently do not get notification in th
ese cases (hence the |
| 94 // timer). | 94 // timer). |
| 95 private static final int TAP_NEAR_PREVIOUS_DETECTION_DELAY_MS = 100; | 95 private static final int TAP_NEAR_PREVIOUS_DETECTION_DELAY_MS = 100; |
| 96 | 96 |
| 97 private static final int NANOSECONDS_IN_A_MILLISECOND = 1000000; |
| 98 |
| 97 private final ObserverList<ContextualSearchObserver> mObservers = | 99 private final ObserverList<ContextualSearchObserver> mObservers = |
| 98 new ObserverList<ContextualSearchObserver>(); | 100 new ObserverList<ContextualSearchObserver>(); |
| 99 | 101 |
| 100 private final ChromeActivity mActivity; | 102 private final ChromeActivity mActivity; |
| 101 private final ContextualSearchTabPromotionDelegate mTabPromotionDelegate; | 103 private final ContextualSearchTabPromotionDelegate mTabPromotionDelegate; |
| 102 private final ViewTreeObserver.OnGlobalFocusChangeListener mOnFocusChangeLis
tener; | 104 private final ViewTreeObserver.OnGlobalFocusChangeListener mOnFocusChangeLis
tener; |
| 103 private final TabModelObserver mTabModelObserver; | 105 private final TabModelObserver mTabModelObserver; |
| 104 | 106 |
| 107 // The Ranker logger to use to write Tap Suppression Ranker logs to UMA. |
| 108 private final ContextualSearchRankerLogger mTapSuppressionRankerLogger; |
| 109 |
| 105 private ContextualSearchSelectionController mSelectionController; | 110 private ContextualSearchSelectionController mSelectionController; |
| 106 private ContextualSearchNetworkCommunicator mNetworkCommunicator; | 111 private ContextualSearchNetworkCommunicator mNetworkCommunicator; |
| 107 private ContextualSearchPolicy mPolicy; | 112 private ContextualSearchPolicy mPolicy; |
| 108 private ContextualSearchInternalStateController mInternalStateController; | 113 private ContextualSearchInternalStateController mInternalStateController; |
| 109 | 114 |
| 110 @VisibleForTesting | 115 @VisibleForTesting |
| 111 protected ContextualSearchTranslateController mTranslateController; | 116 protected ContextualSearchTranslateController mTranslateController; |
| 112 | 117 |
| 113 // The Overlay panel. | 118 // The Overlay panel. |
| 114 private ContextualSearchPanel mSearchPanel; | 119 private ContextualSearchPanel mSearchPanel; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 @Override | 222 @Override |
| 218 public void didAddTab(Tab tab, TabLaunchType type) { | 223 public void didAddTab(Tab tab, TabLaunchType type) { |
| 219 // If we're in the process of promoting this tab, just return an
d don't mess with | 224 // If we're in the process of promoting this tab, just return an
d don't mess with |
| 220 // this state. | 225 // this state. |
| 221 if (tab.getContentViewCore() == mSearchPanel.getContentViewCore(
)) return; | 226 if (tab.getContentViewCore() == mSearchPanel.getContentViewCore(
)) return; |
| 222 hideContextualSearch(StateChangeReason.UNKNOWN); | 227 hideContextualSearch(StateChangeReason.UNKNOWN); |
| 223 } | 228 } |
| 224 }; | 229 }; |
| 225 | 230 |
| 226 mSelectionController = new ContextualSearchSelectionController(activity,
this); | 231 mSelectionController = new ContextualSearchSelectionController(activity,
this); |
| 227 | |
| 228 mNetworkCommunicator = this; | 232 mNetworkCommunicator = this; |
| 229 | |
| 230 mPolicy = new ContextualSearchPolicy(mSelectionController, mNetworkCommu
nicator); | 233 mPolicy = new ContextualSearchPolicy(mSelectionController, mNetworkCommu
nicator); |
| 231 | |
| 232 mTranslateController = new ContextualSearchTranslateController(activity,
mPolicy, this); | 234 mTranslateController = new ContextualSearchTranslateController(activity,
mPolicy, this); |
| 233 | |
| 234 mInternalStateController = new ContextualSearchInternalStateController( | 235 mInternalStateController = new ContextualSearchInternalStateController( |
| 235 mPolicy, getContextualSearchInternalStateHandler()); | 236 mPolicy, getContextualSearchInternalStateHandler()); |
| 237 mTapSuppressionRankerLogger = new ContextualSearchRankerLoggerImpl(); |
| 236 } | 238 } |
| 237 | 239 |
| 238 /** | 240 /** |
| 239 * Initializes this manager. | 241 * Initializes this manager. |
| 240 * @param parentView The parent view to attach Contextual Search UX to. | 242 * @param parentView The parent view to attach Contextual Search UX to. |
| 241 */ | 243 */ |
| 242 public void initialize(ViewGroup parentView) { | 244 public void initialize(ViewGroup parentView) { |
| 243 mNativeContextualSearchManagerPtr = nativeInit(); | 245 mNativeContextualSearchManagerPtr = nativeInit(); |
| 244 | 246 |
| 245 mParentView = parentView; | 247 mParentView = parentView; |
| (...skipping 1038 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1284 } | 1286 } |
| 1285 | 1287 |
| 1286 @Override | 1288 @Override |
| 1287 public void handleSuppressedTap() { | 1289 public void handleSuppressedTap() { |
| 1288 if (mIsAccessibilityModeEnabled) return; | 1290 if (mIsAccessibilityModeEnabled) return; |
| 1289 | 1291 |
| 1290 hideContextualSearch(StateChangeReason.BASE_PAGE_TAP); | 1292 hideContextualSearch(StateChangeReason.BASE_PAGE_TAP); |
| 1291 } | 1293 } |
| 1292 | 1294 |
| 1293 @Override | 1295 @Override |
| 1294 public void handleNonSuppressedTap() { | 1296 public void handleNonSuppressedTap(long tapTimeNanoseconds) { |
| 1295 if (mIsAccessibilityModeEnabled) return; | 1297 if (mIsAccessibilityModeEnabled) return; |
| 1296 | 1298 |
| 1297 mInternalStateController.notifyFinishedWorkOn(InternalState.DECIDING_SUP
PRESSION); | 1299 // If there's a wait-after-tap experiment then we may want to delay a bi
t longer for |
| 1300 // the user to take an action like scrolling that will reset our interna
l state. |
| 1301 long delayBeforeFinishingWorkMs = 0; |
| 1302 if (ContextualSearchFieldTrial.getWaitAfterTapDelayMs() > 0 && tapTimeNa
noseconds > 0) { |
| 1303 delayBeforeFinishingWorkMs = ContextualSearchFieldTrial.getWaitAfter
TapDelayMs() |
| 1304 - (System.nanoTime() - tapTimeNanoseconds) / NANOSECONDS_IN_
A_MILLISECOND; |
| 1305 } |
| 1306 |
| 1307 // Finish work on the current state, either immediately or with a delay. |
| 1308 if (delayBeforeFinishingWorkMs <= 0) { |
| 1309 finishSuppressionDecision(); |
| 1310 } else { |
| 1311 new Handler().postDelayed(new Runnable() { |
| 1312 @Override |
| 1313 public void run() { |
| 1314 finishSuppressionDecision(); |
| 1315 } |
| 1316 }, delayBeforeFinishingWorkMs); |
| 1317 } |
| 1318 } |
| 1319 |
| 1320 /** |
| 1321 * Finishes work on the suppression decision if that work is still in progre
ss. |
| 1322 * If no longer working on the suppression decision then resets the Ranker-l
ogger. |
| 1323 */ |
| 1324 private void finishSuppressionDecision() { |
| 1325 if (mInternalStateController.isStillWorkingOn(InternalState.DECIDING_SUP
PRESSION)) { |
| 1326 mInternalStateController.notifyFinishedWorkOn(InternalState.DECIDING
_SUPPRESSION); |
| 1327 } else { |
| 1328 mTapSuppressionRankerLogger.reset(); |
| 1329 } |
| 1298 } | 1330 } |
| 1299 | 1331 |
| 1300 @Override | 1332 @Override |
| 1301 public void handleMetricsForWouldSuppressTap(ContextualSearchHeuristics tapH
euristics) { | 1333 public void handleMetricsForWouldSuppressTap(ContextualSearchHeuristics tapH
euristics) { |
| 1302 mHeuristics = tapHeuristics; | 1334 mHeuristics = tapHeuristics; |
| 1303 | 1335 |
| 1304 // TODO(donnd): QuickAnswersHeuristic is getting added to TapSuppression
Heuristics and | 1336 // TODO(donnd): QuickAnswersHeuristic is getting added to TapSuppression
Heuristics and |
| 1305 // and getting considered in TapSuppressionHeuristics#shouldSuppressTap(
). It should | 1337 // and getting considered in TapSuppressionHeuristics#shouldSuppressTap(
). It should |
| 1306 // be a part of ContextualSearchHeuristics for logging purposes but not
for suppression. | 1338 // be a part of ContextualSearchHeuristics for logging purposes but not
for suppression. |
| 1307 mQuickAnswersHeuristic = new QuickAnswersHeuristic(); | 1339 mQuickAnswersHeuristic = new QuickAnswersHeuristic(); |
| 1308 mHeuristics.add(mQuickAnswersHeuristic); | 1340 mHeuristics.add(mQuickAnswersHeuristic); |
| 1309 | 1341 |
| 1310 mSearchPanel.getPanelMetrics().setResultsSeenExperiments(mHeuristics); | 1342 mSearchPanel.getPanelMetrics().setResultsSeenExperiments(mHeuristics); |
| 1311 mSearchPanel.getPanelMetrics().setRankerLogExperiments(mHeuristics, getB
asePageUrl()); | 1343 mSearchPanel.getPanelMetrics().setRankerLogger(mTapSuppressionRankerLogg
er); |
| 1312 } | 1344 } |
| 1313 | 1345 |
| 1314 @Override | 1346 @Override |
| 1315 public void handleValidTap() { | 1347 public void handleValidTap() { |
| 1316 if (mIsAccessibilityModeEnabled) return; | 1348 if (mIsAccessibilityModeEnabled) return; |
| 1317 | 1349 |
| 1318 mInternalStateController.enter(InternalState.TAP_RECOGNIZED); | 1350 mInternalStateController.enter(InternalState.TAP_RECOGNIZED); |
| 1319 } | 1351 } |
| 1320 | 1352 |
| 1321 /** | 1353 /** |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1435 mNativeContextualSearchManagerPtr, mContext, webCont
ents); | 1467 mNativeContextualSearchManagerPtr, mContext, webCont
ents); |
| 1436 } else { | 1468 } else { |
| 1437 mInternalStateController.reset(StateChangeReason.UNKNOWN); | 1469 mInternalStateController.reset(StateChangeReason.UNKNOWN); |
| 1438 } | 1470 } |
| 1439 } | 1471 } |
| 1440 | 1472 |
| 1441 /** Starts the process of deciding if we'll suppress the current Tap
gesture or not. */ | 1473 /** Starts the process of deciding if we'll suppress the current Tap
gesture or not. */ |
| 1442 @Override | 1474 @Override |
| 1443 public void decideSuppression() { | 1475 public void decideSuppression() { |
| 1444 mInternalStateController.notifyStartingWorkOn(InternalState.DECI
DING_SUPPRESSION); | 1476 mInternalStateController.notifyStartingWorkOn(InternalState.DECI
DING_SUPPRESSION); |
| 1445 mSelectionController.handleShouldSuppressTap(); | 1477 // Ranker will handle the suppression, but our legacy implementa
tion uses |
| 1478 // TapSuppressionHeuristics (run from the ContextualSearchSelect
ionConroller). |
| 1479 mTapSuppressionRankerLogger.setupLoggingForPage(getBasePageUrl()
); |
| 1480 |
| 1481 // TODO(donnd): Move handleShouldSuppressTap out of the Selectio
n Controller. |
| 1482 mSelectionController.handleShouldSuppressTap(mTapSuppressionRank
erLogger); |
| 1446 } | 1483 } |
| 1447 | 1484 |
| 1448 /** Starts showing the Tap UI by selecting a word around the current
caret. */ | 1485 /** Starts showing the Tap UI by selecting a word around the current
caret. */ |
| 1449 @Override | 1486 @Override |
| 1450 public void startShowingTapUi() { | 1487 public void startShowingTapUi() { |
| 1451 WebContents baseWebContents = getBaseWebContents(); | 1488 WebContents baseWebContents = getBaseWebContents(); |
| 1452 // TODO(donnd): Call isTapSupported earlier so we don't waste ti
me gathering | 1489 // TODO(donnd): Call isTapSupported earlier so we don't waste ti
me gathering |
| 1453 // surrounding text and deciding suppression when unsupported, o
r remove the whole | 1490 // surrounding text and deciding suppression when unsupported, o
r remove the whole |
| 1454 // idea of unsupported taps in favor of deciding suppression bet
ter. | 1491 // idea of unsupported taps in favor of deciding suppression bet
ter. |
| 1455 // Details in crbug.com/715297. | 1492 // Details in crbug.com/715297. |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1596 private native void nativeStartSearchTermResolutionRequest(long nativeContex
tualSearchManager, | 1633 private native void nativeStartSearchTermResolutionRequest(long nativeContex
tualSearchManager, |
| 1597 ContextualSearchContext contextualSearchContext, WebContents baseWeb
Contents); | 1634 ContextualSearchContext contextualSearchContext, WebContents baseWeb
Contents); |
| 1598 protected native void nativeGatherSurroundingText(long nativeContextualSearc
hManager, | 1635 protected native void nativeGatherSurroundingText(long nativeContextualSearc
hManager, |
| 1599 ContextualSearchContext contextualSearchContext, WebContents baseWeb
Contents); | 1636 ContextualSearchContext contextualSearchContext, WebContents baseWeb
Contents); |
| 1600 private native void nativeEnableContextualSearchJsApiForOverlay( | 1637 private native void nativeEnableContextualSearchJsApiForOverlay( |
| 1601 long nativeContextualSearchManager, WebContents overlayWebContents); | 1638 long nativeContextualSearchManager, WebContents overlayWebContents); |
| 1602 // Don't call these directly, instead call the private methods that cache th
e results. | 1639 // Don't call these directly, instead call the private methods that cache th
e results. |
| 1603 private native String nativeGetTargetLanguage(long nativeContextualSearchMan
ager); | 1640 private native String nativeGetTargetLanguage(long nativeContextualSearchMan
ager); |
| 1604 private native String nativeGetAcceptLanguages(long nativeContextualSearchMa
nager); | 1641 private native String nativeGetAcceptLanguages(long nativeContextualSearchMa
nager); |
| 1605 } | 1642 } |
| OLD | NEW |