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

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java

Issue 2211353002: [TTS] Gather surrounding text on Tap before any UX. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Removed unused code and consolidated two functions, updated comments. Created 4 years, 3 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 unified diff | Download patch
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/action/ResolvedSearchAction.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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.os.Handler; 7 import android.os.Handler;
8 8
9 import org.chromium.base.VisibleForTesting; 9 import org.chromium.base.VisibleForTesting;
10 import org.chromium.chrome.browser.ChromeActivity; 10 import org.chromium.chrome.browser.ChromeActivity;
11 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; 11 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
12 import org.chromium.chrome.browser.contextualsearch.ContextualSearchBlacklist.Bl acklistReason; 12 import org.chromium.chrome.browser.contextualsearch.ContextualSearchBlacklist.Bl acklistReason;
13 import org.chromium.chrome.browser.contextualsearch.action.ResolvedSearchAction;
14 import org.chromium.chrome.browser.contextualsearch.action.SearchAction;
15 import org.chromium.chrome.browser.contextualsearch.action.SearchActionListener;
16 import org.chromium.chrome.browser.contextualsearch.gesture.SearchGestureHost;
13 import org.chromium.chrome.browser.preferences.ChromePreferenceManager; 17 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
14 import org.chromium.chrome.browser.tab.Tab; 18 import org.chromium.chrome.browser.tab.Tab;
15 import org.chromium.content.browser.ContentViewCore; 19 import org.chromium.content.browser.ContentViewCore;
16 import org.chromium.content_public.browser.GestureStateListener; 20 import org.chromium.content_public.browser.GestureStateListener;
21 import org.chromium.content_public.browser.WebContents;
17 import org.chromium.ui.touch_selection.SelectionEventType; 22 import org.chromium.ui.touch_selection.SelectionEventType;
18 23
19 import java.util.regex.Matcher; 24 import java.util.regex.Matcher;
20 import java.util.regex.Pattern; 25 import java.util.regex.Pattern;
21 26
22 /** 27 /**
23 * Controls selection gesture interaction for Contextual Search. 28 * Controls selection gesture interaction for Contextual Search.
24 */ 29 */
25 public class ContextualSearchSelectionController { 30 public class ContextualSearchSelectionController implements SearchGestureHost {
26
27 /** 31 /**
28 * The type of selection made by the user. 32 * The type of selection made by the user.
29 */ 33 */
30 public enum SelectionType { 34 public enum SelectionType {
31 UNDETERMINED, 35 UNDETERMINED,
32 TAP, 36 TAP,
33 LONG_PRESS 37 LONG_PRESS
34 } 38 }
35 39
36 // The number of milliseconds to wait for a selection change after a tap bef ore considering 40 // The number of milliseconds to wait for a selection change after a tap bef ore considering
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 private boolean mShouldHandleSelectionModification; 76 private boolean mShouldHandleSelectionModification;
73 private boolean mDidExpandSelection; 77 private boolean mDidExpandSelection;
74 78
75 // Position of the selection. 79 // Position of the selection.
76 private float mX; 80 private float mX;
77 private float mY; 81 private float mY;
78 82
79 // The time of the most last scroll activity, or 0 if none. 83 // The time of the most last scroll activity, or 0 if none.
80 private long mLastScrollTimeNs; 84 private long mLastScrollTimeNs;
81 85
86 // When the last tap gesture happened.
87 private long mTapTimeNanoseconds;
88
82 // Tracks whether a Context Menu has just been shown and the UX has been dis missed. 89 // Tracks whether a Context Menu has just been shown and the UX has been dis missed.
83 // The selection may be unreliable until the next reset. See crbug.com/6284 36. 90 // The selection may be unreliable until the next reset. See crbug.com/6284 36.
84 private boolean mIsContextMenuShown; 91 private boolean mIsContextMenuShown;
85 92
93 // Set to true when we have identified that a pending tap has not been handl ed by Blink.
94 private boolean mHasIdentifiedUnhandledTap;
95
96 // The current Search action.
97 private SearchAction mSearchAction;
98
86 private class ContextualSearchGestureStateListener extends GestureStateListe ner { 99 private class ContextualSearchGestureStateListener extends GestureStateListe ner {
87 @Override 100 @Override
88 public void onScrollStarted(int scrollOffsetY, int scrollExtentY) { 101 public void onScrollStarted(int scrollOffsetY, int scrollExtentY) {
89 mHandler.handleScroll(); 102 mHandler.handleScroll();
90 } 103 }
91 104
92 @Override 105 @Override
93 public void onScrollEnded(int scrollOffsetY, int scrollExtentY) { 106 public void onScrollEnded(int scrollOffsetY, int scrollExtentY) {
94 mLastScrollTimeNs = System.nanoTime(); 107 mLastScrollTimeNs = System.nanoTime();
95 } 108 }
(...skipping 10 matching lines...) Expand all
106 // notification in this case. 119 // notification in this case.
107 // See crbug.com/444114. 120 // See crbug.com/444114.
108 @Override 121 @Override
109 public void onSingleTap(boolean consumed, int x, int y) { 122 public void onSingleTap(boolean consumed, int x, int y) {
110 // We may be notified that a tap has happened even when the system c onsumed the event. 123 // We may be notified that a tap has happened even when the system c onsumed the event.
111 // This is being used to support tapping on an existing selection to show the selection 124 // This is being used to support tapping on an existing selection to show the selection
112 // handles. We should process this tap unless we have already shown the selection 125 // handles. We should process this tap unless we have already shown the selection
113 // handles (have a long-press selection) and the tap was consumed. 126 // handles (have a long-press selection) and the tap was consumed.
114 if (!(consumed && mSelectionType == SelectionType.LONG_PRESS)) { 127 if (!(consumed && mSelectionType == SelectionType.LONG_PRESS)) {
115 scheduleInvalidTapNotification(); 128 scheduleInvalidTapNotification();
129
130 if (mHasIdentifiedUnhandledTap) createSearchAction();
116 } 131 }
117 } 132 }
118 } 133 }
119 134
120 /** 135 /**
121 * Constructs a new Selection controller for the given activity. Callbacks will be issued 136 * Constructs a new Selection controller for the given activity. Callbacks will be issued
122 * through the given selection handler. 137 * through the given selection handler.
123 * @param activity The {@link ChromeActivity} to control. 138 * @param activity The {@link ChromeActivity} to control.
124 * @param handler The handler for callbacks. 139 * @param handler The handler for callbacks.
125 */ 140 */
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 } 334 }
320 335
321 /** 336 /**
322 * Re-enables selection modification handling and invokes 337 * Re-enables selection modification handling and invokes
323 * ContextualSearchSelectionHandler.handleSelection(). 338 * ContextualSearchSelectionHandler.handleSelection().
324 * @param selection The text that was selected. 339 * @param selection The text that was selected.
325 * @param type The type of selection made by the user. 340 * @param type The type of selection made by the user.
326 */ 341 */
327 private void handleSelection(String selection, SelectionType type) { 342 private void handleSelection(String selection, SelectionType type) {
328 mShouldHandleSelectionModification = true; 343 mShouldHandleSelectionModification = true;
344 destroySearchAction();
329 boolean isValidSelection = validateSelectionSuppression(selection); 345 boolean isValidSelection = validateSelectionSuppression(selection);
330 mHandler.handleSelection(selection, isValidSelection, type, mX, mY); 346 mHandler.handleSelection(selection, isValidSelection, type, mX, mY);
331 } 347 }
332 348
333 /** 349 /**
334 * Resets all internal state of this class, including the tap state. 350 * Resets all internal state of this class, including the tap state.
335 */ 351 */
336 private void resetAllStates() { 352 private void resetAllStates() {
337 resetSelectionStates(); 353 resetSelectionStates();
338 mLastTapState = null; 354 mLastTapState = null;
339 mLastScrollTimeNs = 0; 355 mLastScrollTimeNs = 0;
340 mIsContextMenuShown = false; 356 mIsContextMenuShown = false;
357 mHasIdentifiedUnhandledTap = false;
358 mTapTimeNanoseconds = 0;
341 } 359 }
342 360
343 /** 361 /**
344 * Resets all of the internal state of this class that handles the selection . 362 * Resets all of the internal state of this class that handles the selection .
345 */ 363 */
346 private void resetSelectionStates() { 364 private void resetSelectionStates() {
347 mSelectionType = SelectionType.UNDETERMINED; 365 mSelectionType = SelectionType.UNDETERMINED;
348 mSelectedText = null; 366 mSelectedText = null;
349 367
350 mWasTapGestureDetected = false; 368 mWasTapGestureDetected = false;
351 } 369 }
352 370
353 /** 371 /**
354 * Should be called when a new Tab is selected. 372 * Should be called when a new Tab is selected.
355 * Resets all of the internal state of this class. 373 * Resets all of the internal state of this class.
356 */ 374 */
357 void onTabSelected() { 375 void onTabSelected() {
358 resetAllStates(); 376 resetAllStates();
359 } 377 }
360 378
361 /** 379 /**
362 * Handles an unhandled tap gesture. 380 * Handles an unhandled tap gesture.
381 * @param x The x coordinate.
382 * @param y The y coordinate.
363 */ 383 */
364 void handleShowUnhandledTapUIIfNeeded(int x, int y) { 384 void handleShowUnhandledTapUIIfNeeded(int x, int y) {
365 mWasTapGestureDetected = false; 385 mWasTapGestureDetected = false;
366 // TODO(donnd): shouldn't we check == TAP here instead of LONG_PRESS? 386 // TODO(donnd): shouldn't we check == TAP here instead of LONG_PRESS?
367 // TODO(donnd): refactor to avoid needing a new handler API method as su ggested by Pedro. 387 // TODO(donnd): refactor to avoid needing a new handler API method as su ggested by Pedro.
368 if (mSelectionType != SelectionType.LONG_PRESS) { 388 if (mSelectionType != SelectionType.LONG_PRESS) {
369 mWasTapGestureDetected = true; 389 mWasTapGestureDetected = true;
370 long tapTimeNanoseconds = System.nanoTime(); 390 mTapTimeNanoseconds = System.nanoTime();
371 // TODO(donnd): add a policy method to get adjusted tap count. 391
372 ChromePreferenceManager prefs = ChromePreferenceManager.getInstance( mActivity); 392 // NOTE(donnd): We first acknowledge that a unhandled tap was identi fied, but
373 int adjustedTapsSinceOpen = prefs.getContextualSearchTapCount() 393 // we don't do anything now. Instead we'll wait for the onSingleTap( ) event to fire,
374 - prefs.getContextualSearchTapQuickAnswerCount(); 394 // and only do something when an unhandled tap was identified. onSin gleTap() will
375 TapSuppressionHeuristics tapHeuristics = 395 // always get fired, as opposed to showUnhandledTapUIIfNeeded().
376 new TapSuppressionHeuristics(this, mLastTapState, x, y, adju stedTapsSinceOpen); 396 mHasIdentifiedUnhandledTap = true;
377 // TODO(donnd): Move to be called when the panel closes to work with states that change. 397
378 tapHeuristics.logConditionState();
379 // Tell the manager what it needs in order to log metrics on whether the tap would have
380 // been suppressed if each of the heuristics were satisfied.
381 mHandler.handleMetricsForWouldSuppressTap(tapHeuristics);
382 mX = x; 398 mX = x;
383 mY = y; 399 mY = y;
384 boolean shouldSuppressTap = tapHeuristics.shouldSuppressTap();
385 if (shouldSuppressTap) {
386 mHandler.handleSuppressedTap();
387 } else {
388 // TODO(donnd): Find a better way to determine that a navigation will be triggered
389 // by the tap, or merge with other time-consuming actions like g athering surrounding
390 // text or detecting page mutations.
391 new Handler().postDelayed(new Runnable() {
392 @Override
393 public void run() {
394 mHandler.handleValidTap();
395 }
396 }, TAP_NAVIGATION_DETECTION_DELAY);
397 }
398 // Remember the tap state for subsequent tap evaluation.
399 mLastTapState =
400 new ContextualSearchTapState(x, y, tapTimeNanoseconds, shoul dSuppressTap);
401 } else { 400 } else {
402 // Long press; reset last tap state. 401 // Long press; reset last tap state.
403 mLastTapState = null; 402 mLastTapState = null;
404 mHandler.handleInvalidTap(); 403 mHandler.handleInvalidTap();
405 } 404 }
406 } 405 }
407 406
408 /** 407 /**
408 * Processes a {@link SearchAction}.
409 * This should be called when the associated {@code SearchAction} has built its context (by
410 * gathering surrounding text if needed, etc) but before showing any UX.
411 * @param searchAction The {@link SearchAction} for this Tap gesture.
412 * @param x The x coordinate.
413 * @param y The y coordinate.
414 */
415 void processSearchAction(SearchAction searchAction, int x, int y) {
416 // TODO(donnd): consider using the supplied searchAction, or remove if u sed from native!
417 // TODO(donnd): add a policy method to get adjusted tap count.
418 ChromePreferenceManager prefs = ChromePreferenceManager.getInstance(mAct ivity);
419 int adjustedTapsSinceOpen = prefs.getContextualSearchTapCount()
420 - prefs.getContextualSearchTapQuickAnswerCount();
421 TapSuppressionHeuristics tapHeuristics =
422 new TapSuppressionHeuristics(this, mLastTapState, x, y, adjusted TapsSinceOpen);
423 // TODO(donnd): Move to be called when the panel closes to work with sta tes that change.
424 tapHeuristics.logConditionState();
425 // Tell the manager what it needs in order to log metrics on whether the tap would have
426 // been suppressed if each of the heuristics were satisfied.
427 mHandler.handleMetricsForWouldSuppressTap(tapHeuristics);
428
429 boolean shouldSuppressTap = tapHeuristics.shouldSuppressTap();
430 if (shouldSuppressTap) {
431 mHandler.handleSuppressedTap();
432 } else {
433 // TODO(donnd): Find a better way to determine that a navigation wil l be triggered
434 // by the tap, or merge with other time-consuming actions like gathe ring surrounding
435 // text or detecting page mutations.
436 new Handler().postDelayed(new Runnable() {
437 @Override
438 public void run() {
439 mHandler.handleValidTap();
440 }
441 }, TAP_NAVIGATION_DETECTION_DELAY);
442 }
443 if (mTapTimeNanoseconds == 0) throw new RuntimeException("Tap time not s et!");
444 // Remember the tap state for subsequent tap evaluation.
445 mLastTapState = new ContextualSearchTapState(x, y, mTapTimeNanoseconds, shouldSuppressTap);
446 }
447
448 /**
449 * Creates the current {@link SearchAction}.
450 */
451 void createSearchAction() {
452 destroySearchAction();
453 mSearchAction = new ResolvedSearchAction(new SearchActionListener() {
454
455 @Override
456 protected void onContextReady(SearchAction action) {
457 processSearchAction(action, (int) mX, (int) mY);
458 }
459 }, this);
460
461 mSearchAction.extractContext();
462 }
463
464 /**
465 * Destroys the current {@link SearchAction}.
466 */
467 private void destroySearchAction() {
468 if (mSearchAction == null) return;
469
470 mSearchAction.destroyAction();
471 mSearchAction = null;
472 }
473
474 // ========================================================================= ===================
475 // SearchGestureHost
476 // ========================================================================= ===================
477
478 @Override
479 public WebContents getTabWebContents() {
480 Tab currentTab = mActivity.getActivityTab();
481 return currentTab != null ? currentTab.getWebContents() : null;
482 }
483
484 @Override
485 public void dismissGesture() {
486 destroySearchAction();
487 }
488
489 // ========================================================================= ===================
490 // Utilities
491 // ========================================================================= ===================
492
493 /**
409 * @return The Base Page's {@link ContentViewCore}, or {@code null} if there is no current tab. 494 * @return The Base Page's {@link ContentViewCore}, or {@code null} if there is no current tab.
410 */ 495 */
411 ContentViewCore getBaseContentView() { 496 ContentViewCore getBaseContentView() {
497 // TODO(donnd): switch to using WebContents over ContentViewCore.
412 Tab currentTab = mActivity.getActivityTab(); 498 Tab currentTab = mActivity.getActivityTab();
413 return currentTab != null ? currentTab.getContentViewCore() : null; 499 return currentTab != null ? currentTab.getContentViewCore() : null;
414 } 500 }
415 501
416 /** 502 /**
417 * Expands the current selection by the specified amounts. 503 * Expands the current selection by the specified amounts.
418 * @param selectionStartAdjust The start offset adjustment of the selection to use to highlight 504 * @param selectionStartAdjust The start offset adjustment of the selection to use to highlight
419 * the search term. 505 * the search term.
420 * @param selectionEndAdjust The end offset adjustment of the selection to u se to highlight 506 * @param selectionEndAdjust The end offset adjustment of the selection to u se to highlight
421 * the search term. 507 * the search term.
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 // Starts are inclusive and ends are non-inclusive for both GSAContext & matcher. 683 // Starts are inclusive and ends are non-inclusive for both GSAContext & matcher.
598 while (matcher.find()) { 684 while (matcher.find()) {
599 if (startOffset >= matcher.start() && endOffset <= matcher.end()) { 685 if (startOffset >= matcher.start() && endOffset <= matcher.end()) {
600 return true; 686 return true;
601 } 687 }
602 } 688 }
603 689
604 return false; 690 return false;
605 } 691 }
606 } 692 }
OLDNEW
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/action/ResolvedSearchAction.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698