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.os.Handler; | |
8 import android.text.TextUtils; | 7 import android.text.TextUtils; |
9 | 8 |
10 import org.chromium.base.VisibleForTesting; | 9 import org.chromium.base.VisibleForTesting; |
11 import org.chromium.chrome.browser.ChromeActivity; | 10 import org.chromium.chrome.browser.ChromeActivity; |
12 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; | 11 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; |
13 import org.chromium.chrome.browser.contextualsearch.ContextualSearchBlacklist.Bl
acklistReason; | 12 import org.chromium.chrome.browser.contextualsearch.ContextualSearchBlacklist.Bl
acklistReason; |
14 import org.chromium.chrome.browser.preferences.ChromePreferenceManager; | 13 import org.chromium.chrome.browser.preferences.ChromePreferenceManager; |
15 import org.chromium.chrome.browser.tab.Tab; | 14 import org.chromium.chrome.browser.tab.Tab; |
16 import org.chromium.content.browser.ContentViewCore; | 15 import org.chromium.content.browser.ContentViewCore; |
17 import org.chromium.content_public.browser.GestureStateListener; | 16 import org.chromium.content_public.browser.GestureStateListener; |
(...skipping 10 matching lines...) Expand all Loading... |
28 | 27 |
29 /** | 28 /** |
30 * The type of selection made by the user. | 29 * The type of selection made by the user. |
31 */ | 30 */ |
32 public enum SelectionType { | 31 public enum SelectionType { |
33 UNDETERMINED, | 32 UNDETERMINED, |
34 TAP, | 33 TAP, |
35 LONG_PRESS | 34 LONG_PRESS |
36 } | 35 } |
37 | 36 |
38 // The number of milliseconds to wait for a selection change after a tap bef
ore considering | |
39 // the tap invalid. This can't be too small or the subsequent taps may not
have established | |
40 // a new selection in time. This is because selectWordAroundCaret doesn't a
lways select. | |
41 // TODO(donnd): Fix in Blink, crbug.com/435778. | |
42 private static final int INVALID_IF_NO_SELECTION_CHANGE_AFTER_TAP_MS = 50; | |
43 | |
44 // The default navigation-detection-delay in milliseconds. | |
45 private static final int TAP_NAVIGATION_DETECTION_DELAY = 16; | |
46 | |
47 private static final String CONTAINS_WORD_PATTERN = "(\\w|\\p{L}|\\p{N})+"; | 37 private static final String CONTAINS_WORD_PATTERN = "(\\w|\\p{L}|\\p{N})+"; |
48 // A URL is: | 38 // A URL is: |
49 // 1: scheme:// | 39 // 1: scheme:// |
50 // 1+: any word char, _ or - | 40 // 1+: any word char, _ or - |
51 // 1+: . followed by 1+ of any word char, _ or - | 41 // 1+: . followed by 1+ of any word char, _ or - |
52 // 0-1: 0+ of any word char or .,@?^=%&:/~#- followed by any word char or
@?^-%&/~+#- | 42 // 0-1: 0+ of any word char or .,@?^=%&:/~#- followed by any word char or
@?^-%&/~+#- |
53 // TODO(twellington): expand accepted schemes? | 43 // TODO(twellington): expand accepted schemes? |
54 private static final Pattern URL_PATTERN = Pattern.compile("((http|https|fil
e|ftp|ssh)://)" | 44 private static final Pattern URL_PATTERN = Pattern.compile("((http|https|fil
e|ftp|ssh)://)" |
55 + "([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#
-])?"); | 45 + "([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#
-])?"); |
56 | 46 |
57 // Max selection length must be limited or the entire request URL can go pas
t the 2K limit. | 47 // Max selection length must be limited or the entire request URL can go pas
t the 2K limit. |
58 private static final int MAX_SELECTION_LENGTH = 100; | 48 private static final int MAX_SELECTION_LENGTH = 100; |
59 | 49 |
60 private final ChromeActivity mActivity; | 50 private final ChromeActivity mActivity; |
61 private final ContextualSearchSelectionHandler mHandler; | 51 private final ContextualSearchSelectionHandler mHandler; |
62 private final Runnable mHandleInvalidTapRunnable; | |
63 private final Handler mRunnableHandler; | |
64 private final float mPxToDp; | 52 private final float mPxToDp; |
65 private final Pattern mContainsWordPattern; | 53 private final Pattern mContainsWordPattern; |
66 | 54 |
67 private String mSelectedText; | 55 private String mSelectedText; |
68 private SelectionType mSelectionType; | 56 private SelectionType mSelectionType; |
69 private boolean mWasTapGestureDetected; | 57 private boolean mWasTapGestureDetected; |
70 // Reflects whether the last tap was valid and whether we still have a tap-b
ased selection. | 58 // Reflects whether the last tap was valid and whether we still have a tap-b
ased selection. |
71 private ContextualSearchTapState mLastTapState; | 59 private ContextualSearchTapState mLastTapState; |
72 private TapSuppressionHeuristics mTapHeuristics; | |
73 private boolean mIsWaitingForInvalidTapDetection; | 60 private boolean mIsWaitingForInvalidTapDetection; |
74 private boolean mShouldHandleSelectionModification; | 61 private boolean mShouldHandleSelectionModification; |
75 private boolean mDidExpandSelection; | 62 private boolean mDidExpandSelection; |
76 | 63 |
77 // Position of the selection. | 64 // Position of the selection. |
78 private float mX; | 65 private float mX; |
79 private float mY; | 66 private float mY; |
80 | 67 |
81 // The time of the most last scroll activity, or 0 if none. | 68 // The time of the most last scroll activity, or 0 if none. |
82 private long mLastScrollTimeNs; | 69 private long mLastScrollTimeNs; |
83 | 70 |
| 71 // When the last tap gesture happened. |
| 72 private long mTapTimeNanoseconds; |
| 73 |
84 // Tracks whether a Context Menu has just been shown and the UX has been dis
missed. | 74 // Tracks whether a Context Menu has just been shown and the UX has been dis
missed. |
85 // The selection may be unreliable until the next reset. See crbug.com/6284
36. | 75 // The selection may be unreliable until the next reset. See crbug.com/6284
36. |
86 private boolean mIsContextMenuShown; | 76 private boolean mIsContextMenuShown; |
87 | 77 |
88 private class ContextualSearchGestureStateListener extends GestureStateListe
ner { | 78 private class ContextualSearchGestureStateListener extends GestureStateListe
ner { |
89 @Override | 79 @Override |
90 public void onScrollStarted(int scrollOffsetY, int scrollExtentY) { | 80 public void onScrollStarted(int scrollOffsetY, int scrollExtentY) { |
91 mHandler.handleScroll(); | 81 mHandler.handleScroll(); |
92 } | 82 } |
93 | 83 |
94 @Override | 84 @Override |
95 public void onScrollEnded(int scrollOffsetY, int scrollExtentY) { | 85 public void onScrollEnded(int scrollOffsetY, int scrollExtentY) { |
96 mLastScrollTimeNs = System.nanoTime(); | 86 mLastScrollTimeNs = System.nanoTime(); |
97 } | 87 } |
98 | 88 |
99 @Override | 89 @Override |
100 public void onScrollUpdateGestureConsumed() { | 90 public void onScrollUpdateGestureConsumed() { |
101 // The onScrollEnded notification is unreliable, so mark time during
scroll updates too. | 91 // The onScrollEnded notification is unreliable, so mark time during
scroll updates too. |
102 // See crbug.com/600863. | 92 // See crbug.com/600863. |
103 mLastScrollTimeNs = System.nanoTime(); | 93 mLastScrollTimeNs = System.nanoTime(); |
104 } | 94 } |
105 | 95 |
106 // TODO(donnd): Remove this once we get notification of the selection ch
anging | 96 // TODO(donnd): Remove this once we get notification of the selection ch
anging |
107 // after a tap-select gets a subsequent tap nearby. Currently there's n
o | 97 // after a tap-select gets a subsequent tap nearby. Currently there's n
o |
108 // notification in this case. | 98 // notification in this case. |
109 // See crbug.com/444114. | 99 // See crbug.com/444114. |
110 @Override | 100 @Override |
111 public void onSingleTap(boolean consumed) { | 101 public void onSingleTap(boolean consumed) { |
112 // We may be notified that a tap has happened even when the system c
onsumed the event. | 102 // TODO(donnd): remove completely! |
113 // This is being used to support tapping on an existing selection to
show the selection | |
114 // handles. We should process this tap unless we have already shown
the selection | |
115 // handles (have a long-press selection) and the tap was consumed. | |
116 if (!(consumed && mSelectionType == SelectionType.LONG_PRESS)) { | |
117 scheduleInvalidTapNotification(); | |
118 } | |
119 } | 103 } |
120 } | 104 } |
121 | 105 |
122 /** | 106 /** |
123 * Constructs a new Selection controller for the given activity. Callbacks
will be issued | 107 * Constructs a new Selection controller for the given activity. Callbacks
will be issued |
124 * through the given selection handler. | 108 * through the given selection handler. |
125 * @param activity The {@link ChromeActivity} to control. | 109 * @param activity The {@link ChromeActivity} to control. |
126 * @param handler The handler for callbacks. | 110 * @param handler The handler for callbacks. |
127 */ | 111 */ |
128 public ContextualSearchSelectionController(ChromeActivity activity, | 112 public ContextualSearchSelectionController(ChromeActivity activity, |
129 ContextualSearchSelectionHandler handler) { | 113 ContextualSearchSelectionHandler handler) { |
130 mActivity = activity; | 114 mActivity = activity; |
131 mHandler = handler; | 115 mHandler = handler; |
132 mPxToDp = 1.f / mActivity.getResources().getDisplayMetrics().density; | 116 mPxToDp = 1.f / mActivity.getResources().getDisplayMetrics().density; |
133 | |
134 mRunnableHandler = new Handler(); | |
135 mHandleInvalidTapRunnable = new Runnable() { | |
136 @Override | |
137 public void run() { | |
138 onInvalidTapDetectionTimeout(); | |
139 } | |
140 }; | |
141 | |
142 mContainsWordPattern = Pattern.compile(CONTAINS_WORD_PATTERN); | 117 mContainsWordPattern = Pattern.compile(CONTAINS_WORD_PATTERN); |
143 } | 118 } |
144 | 119 |
145 /** | 120 /** |
146 * Notifies that the base page has started loading a page. | 121 * Notifies that the base page has started loading a page. |
147 */ | 122 */ |
148 void onBasePageLoadStarted() { | 123 void onBasePageLoadStarted() { |
149 resetAllStates(); | 124 resetAllStates(); |
150 } | 125 } |
151 | 126 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 * @param selection The selection portion of the context. | 214 * @param selection The selection portion of the context. |
240 */ | 215 */ |
241 void handleSelectionChanged(String selection) { | 216 void handleSelectionChanged(String selection) { |
242 if (mDidExpandSelection) { | 217 if (mDidExpandSelection) { |
243 mSelectedText = selection; | 218 mSelectedText = selection; |
244 mDidExpandSelection = false; | 219 mDidExpandSelection = false; |
245 return; | 220 return; |
246 } | 221 } |
247 | 222 |
248 if (selection == null || selection.isEmpty()) { | 223 if (selection == null || selection.isEmpty()) { |
249 scheduleInvalidTapNotification(); | 224 mHandler.handleSelectionCleared(); |
250 // When the user taps on the page it will place the caret in that po
sition, which | 225 // When the user taps on the page it will place the caret in that po
sition, which |
251 // will trigger a onSelectionChanged event with an empty string. | 226 // will trigger a onSelectionChanged event with an empty string. |
252 if (mSelectionType == SelectionType.TAP) { | 227 if (mSelectionType == SelectionType.TAP) { |
253 // Since we mostly ignore a selection that's empty, we only need
to partially reset. | 228 // Since we mostly ignore a selection that's empty, we only need
to partially reset. |
254 resetSelectionStates(); | 229 resetSelectionStates(); |
255 return; | 230 return; |
256 } | 231 } |
257 } | 232 } |
258 if (!selection.isEmpty()) { | |
259 unscheduleInvalidTapNotification(); | |
260 } | |
261 | 233 |
262 mSelectedText = selection; | 234 mSelectedText = selection; |
263 | 235 |
264 if (mWasTapGestureDetected) { | 236 if (mWasTapGestureDetected) { |
265 mSelectionType = SelectionType.TAP; | 237 assert mSelectionType == SelectionType.TAP; |
266 handleSelection(selection, mSelectionType); | 238 handleSelection(selection, mSelectionType); |
267 mWasTapGestureDetected = false; | 239 mWasTapGestureDetected = false; |
268 } else { | 240 } else { |
269 boolean isValidSelection = validateSelectionSuppression(selection); | 241 boolean isValidSelection = validateSelectionSuppression(selection); |
270 mHandler.handleSelectionModification(selection, isValidSelection, mX
, mY); | 242 mHandler.handleSelectionModification(selection, isValidSelection, mX
, mY); |
271 } | 243 } |
272 } | 244 } |
273 | 245 |
274 /** | 246 /** |
275 * Handles a notification that a selection event took place. | 247 * Handles a notification that a selection event took place. |
276 * @param eventType The type of event that took place. | 248 * @param eventType The type of event that took place. |
277 * @param posXPix The x coordinate of the selection start handle. | 249 * @param posXPix The x coordinate of the selection start handle. |
278 * @param posYPix The y coordinate of the selection start handle. | 250 * @param posYPix The y coordinate of the selection start handle. |
279 */ | 251 */ |
280 void handleSelectionEvent(int eventType, float posXPix, float posYPix) { | 252 void handleSelectionEvent(int eventType, float posXPix, float posYPix) { |
281 boolean shouldHandleSelection = false; | 253 boolean shouldHandleSelection = false; |
282 switch (eventType) { | 254 switch (eventType) { |
283 case SelectionEventType.SELECTION_HANDLES_SHOWN: | 255 case SelectionEventType.SELECTION_HANDLES_SHOWN: |
284 if (!mIsContextMenuShown) { | 256 if (!mIsContextMenuShown) { |
285 mWasTapGestureDetected = false; | 257 mWasTapGestureDetected = false; |
286 mSelectionType = SelectionType.LONG_PRESS; | 258 mSelectionType = SelectionType.LONG_PRESS; |
287 shouldHandleSelection = true; | 259 shouldHandleSelection = true; |
288 // Since we're showing pins, we don't care if the previous t
ap was invalid | |
289 // anymore. | |
290 unscheduleInvalidTapNotification(); | |
291 } | 260 } |
292 break; | 261 break; |
293 case SelectionEventType.SELECTION_HANDLES_CLEARED: | 262 case SelectionEventType.SELECTION_HANDLES_CLEARED: |
294 mHandler.handleSelectionDismissal(); | 263 mHandler.handleSelectionDismissal(); |
295 resetAllStates(); | 264 resetAllStates(); |
296 break; | 265 break; |
297 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED: | 266 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED: |
298 shouldHandleSelection = mShouldHandleSelectionModification; | 267 shouldHandleSelection = mShouldHandleSelectionModification; |
299 break; | 268 break; |
300 default: | 269 default: |
(...skipping 26 matching lines...) Expand all Loading... |
327 } | 296 } |
328 | 297 |
329 /** | 298 /** |
330 * Resets all internal state of this class, including the tap state. | 299 * Resets all internal state of this class, including the tap state. |
331 */ | 300 */ |
332 private void resetAllStates() { | 301 private void resetAllStates() { |
333 resetSelectionStates(); | 302 resetSelectionStates(); |
334 mLastTapState = null; | 303 mLastTapState = null; |
335 mLastScrollTimeNs = 0; | 304 mLastScrollTimeNs = 0; |
336 mIsContextMenuShown = false; | 305 mIsContextMenuShown = false; |
| 306 mTapTimeNanoseconds = 0; |
| 307 mDidExpandSelection = false; |
337 } | 308 } |
338 | 309 |
339 /** | 310 /** |
340 * Resets all of the internal state of this class that handles the selection
. | 311 * Resets all of the internal state of this class that handles the selection
. |
341 */ | 312 */ |
342 private void resetSelectionStates() { | 313 private void resetSelectionStates() { |
343 mSelectionType = SelectionType.UNDETERMINED; | 314 mSelectionType = SelectionType.UNDETERMINED; |
344 mSelectedText = null; | 315 mSelectedText = null; |
345 | 316 |
346 mWasTapGestureDetected = false; | 317 mWasTapGestureDetected = false; |
(...skipping 10 matching lines...) Expand all Loading... |
357 /** | 328 /** |
358 * Handles an unhandled tap gesture. | 329 * Handles an unhandled tap gesture. |
359 * @param x The x coordinate in px. | 330 * @param x The x coordinate in px. |
360 * @param y The y coordinate in px. | 331 * @param y The y coordinate in px. |
361 */ | 332 */ |
362 void handleShowUnhandledTapUIIfNeeded(int x, int y) { | 333 void handleShowUnhandledTapUIIfNeeded(int x, int y) { |
363 mWasTapGestureDetected = false; | 334 mWasTapGestureDetected = false; |
364 // TODO(donnd): refactor to avoid needing a new handler API method as su
ggested by Pedro. | 335 // TODO(donnd): refactor to avoid needing a new handler API method as su
ggested by Pedro. |
365 if (mSelectionType != SelectionType.LONG_PRESS) { | 336 if (mSelectionType != SelectionType.LONG_PRESS) { |
366 mWasTapGestureDetected = true; | 337 mWasTapGestureDetected = true; |
367 long tapTimeNanoseconds = System.nanoTime(); | 338 mSelectionType = SelectionType.TAP; |
368 // TODO(donnd): add a policy method to get adjusted tap count. | 339 mTapTimeNanoseconds = System.nanoTime(); |
369 ChromePreferenceManager prefs = ChromePreferenceManager.getInstance(
); | |
370 int adjustedTapsSinceOpen = prefs.getContextualSearchTapCount() | |
371 - prefs.getContextualSearchTapQuickAnswerCount(); | |
372 // Explicitly destroy the old heuristics so native code can dispose
data. | |
373 if (mTapHeuristics != null) mTapHeuristics.destroy(); | |
374 mTapHeuristics = | |
375 new TapSuppressionHeuristics(this, mLastTapState, x, y, adju
stedTapsSinceOpen); | |
376 // TODO(donnd): Move to be called when the panel closes to work with
states that change. | |
377 mTapHeuristics.logConditionState(); | |
378 // Tell the manager what it needs in order to log metrics on whether
the tap would have | |
379 // been suppressed if each of the heuristics were satisfied. | |
380 mHandler.handleMetricsForWouldSuppressTap(mTapHeuristics); | |
381 mX = x; | 340 mX = x; |
382 mY = y; | 341 mY = y; |
383 boolean shouldSuppressTap = mTapHeuristics.shouldSuppressTap(); | 342 mHandler.handleValidTap(); |
384 if (shouldSuppressTap) { | |
385 mHandler.handleSuppressedTap(); | |
386 } else { | |
387 // TODO(donnd): Find a better way to determine that a navigation
will be triggered | |
388 // by the tap, or merge with other time-consuming actions like g
athering surrounding | |
389 // text or detecting page mutations. | |
390 new Handler().postDelayed(new Runnable() { | |
391 @Override | |
392 public void run() { | |
393 mHandler.handleValidTap(); | |
394 } | |
395 }, TAP_NAVIGATION_DETECTION_DELAY); | |
396 } | |
397 // Remember the tap state for subsequent tap evaluation. | |
398 mLastTapState = | |
399 new ContextualSearchTapState(x, y, tapTimeNanoseconds, shoul
dSuppressTap); | |
400 } else { | 343 } else { |
401 // Long press; reset last tap state. | 344 // Long press; reset last tap state. |
402 mLastTapState = null; | 345 mLastTapState = null; |
403 mHandler.handleInvalidTap(); | 346 mHandler.handleInvalidTap(); |
404 } | 347 } |
405 } | 348 } |
406 | 349 |
407 /** | 350 /** |
| 351 * Handles Tap suppression by making a callback to either the handler's #han
dleSuppressedTap() |
| 352 * or #handleNonSuppressedTap() after a possible delay. |
| 353 * This should be called when the context is fully built (by gathering surro
unding text |
| 354 * if needed, etc) but before showing any UX. |
| 355 */ |
| 356 void handleShouldSuppressTap() { |
| 357 int x = (int) mX; |
| 358 int y = (int) mY; |
| 359 |
| 360 // TODO(donnd): add a policy method to get adjusted tap count. |
| 361 ChromePreferenceManager prefs = ChromePreferenceManager.getInstance(); |
| 362 int adjustedTapsSinceOpen = prefs.getContextualSearchTapCount() |
| 363 - prefs.getContextualSearchTapQuickAnswerCount(); |
| 364 TapSuppressionHeuristics tapHeuristics = |
| 365 new TapSuppressionHeuristics(this, mLastTapState, x, y, adjusted
TapsSinceOpen); |
| 366 // TODO(donnd): Move to be called when the panel closes to work with sta
tes that change. |
| 367 tapHeuristics.logConditionState(); |
| 368 // Tell the manager what it needs in order to log metrics on whether the
tap would have |
| 369 // been suppressed if each of the heuristics were satisfied. |
| 370 mHandler.handleMetricsForWouldSuppressTap(tapHeuristics); |
| 371 |
| 372 boolean shouldSuppressTap = tapHeuristics.shouldSuppressTap(); |
| 373 if (mTapTimeNanoseconds != 0) { |
| 374 // Remember the tap state for subsequent tap evaluation. |
| 375 mLastTapState = |
| 376 new ContextualSearchTapState(x, y, mTapTimeNanoseconds, shou
ldSuppressTap); |
| 377 } else { |
| 378 mLastTapState = null; |
| 379 } |
| 380 |
| 381 if (shouldSuppressTap) { |
| 382 mHandler.handleSuppressedTap(); |
| 383 } else { |
| 384 mHandler.handleNonSuppressedTap(); |
| 385 } |
| 386 } |
| 387 |
| 388 /** |
408 * Gets the base page ContentViewCore. | 389 * Gets the base page ContentViewCore. |
409 * Deprecated, use getBaseWebContents instead. | 390 * Deprecated, use getBaseWebContents instead. |
410 * @return The Base Page's {@link ContentViewCore}, or {@code null} if there
is no current tab. | 391 * @return The Base Page's {@link ContentViewCore}, or {@code null} if there
is no current tab. |
411 */ | 392 */ |
412 @Deprecated | 393 @Deprecated |
413 ContentViewCore getBaseContentView() { | 394 ContentViewCore getBaseContentView() { |
414 Tab currentTab = mActivity.getActivityTab(); | 395 Tab currentTab = mActivity.getActivityTab(); |
415 return currentTab != null ? currentTab.getContentViewCore() : null; | 396 return currentTab != null ? currentTab.getContentViewCore() : null; |
416 } | 397 } |
417 | 398 |
(...skipping 12 matching lines...) Expand all Loading... |
430 } | 411 } |
431 | 412 |
432 /** | 413 /** |
433 * Expands the current selection by the specified amounts. | 414 * Expands the current selection by the specified amounts. |
434 * @param selectionStartAdjust The start offset adjustment of the selection
to use to highlight | 415 * @param selectionStartAdjust The start offset adjustment of the selection
to use to highlight |
435 * the search term. | 416 * the search term. |
436 * @param selectionEndAdjust The end offset adjustment of the selection to u
se to highlight | 417 * @param selectionEndAdjust The end offset adjustment of the selection to u
se to highlight |
437 * the search term. | 418 * the search term. |
438 */ | 419 */ |
439 void adjustSelection(int selectionStartAdjust, int selectionEndAdjust) { | 420 void adjustSelection(int selectionStartAdjust, int selectionEndAdjust) { |
440 // TODO(donnd): add code to verify that the selection is still valid bef
ore changing it. | |
441 // crbug.com/508354 | |
442 | |
443 if (selectionStartAdjust == 0 && selectionEndAdjust == 0) return; | 421 if (selectionStartAdjust == 0 && selectionEndAdjust == 0) return; |
444 WebContents basePageWebContents = getBaseWebContents(); | 422 WebContents basePageWebContents = getBaseWebContents(); |
445 if (basePageWebContents != null) { | 423 if (basePageWebContents != null) { |
446 mDidExpandSelection = true; | 424 mDidExpandSelection = true; |
447 basePageWebContents.adjustSelectionByCharacterOffset( | 425 basePageWebContents.adjustSelectionByCharacterOffset( |
448 selectionStartAdjust, selectionEndAdjust); | 426 selectionStartAdjust, selectionEndAdjust); |
449 } | 427 } |
450 } | 428 } |
451 | 429 |
452 // =========================================================================
=================== | 430 // =========================================================================
=================== |
453 // Invalid Tap Notification | |
454 // =========================================================================
=================== | |
455 | |
456 /** | |
457 * Schedules a notification to check if the tap was invalid. | |
458 * When we call selectWordAroundCaret it selects nothing in cases where the
tap was invalid. | |
459 * We have no way to know other than scheduling a notification to check late
r. | |
460 * This allows us to hide the bar when there's no selection. | |
461 */ | |
462 private void scheduleInvalidTapNotification() { | |
463 // TODO(donnd): Fix selectWordAroundCaret to we can tell if it selects,
instead | |
464 // of using a timer here! See crbug.com/435778. | |
465 mRunnableHandler.postDelayed(mHandleInvalidTapRunnable, | |
466 INVALID_IF_NO_SELECTION_CHANGE_AFTER_TAP_MS); | |
467 } | |
468 | |
469 /** | |
470 * Un-schedules all pending notifications to check if a tap was invalid. | |
471 */ | |
472 private void unscheduleInvalidTapNotification() { | |
473 mRunnableHandler.removeCallbacks(mHandleInvalidTapRunnable); | |
474 mIsWaitingForInvalidTapDetection = true; | |
475 } | |
476 | |
477 /** | |
478 * Notify's the system that tap gesture has been completed. | |
479 */ | |
480 private void onInvalidTapDetectionTimeout() { | |
481 mHandler.handleInvalidTap(); | |
482 mIsWaitingForInvalidTapDetection = false; | |
483 } | |
484 | |
485 // =========================================================================
=================== | |
486 // Selection Modification | 431 // Selection Modification |
487 // =========================================================================
=================== | 432 // =========================================================================
=================== |
488 | 433 |
489 /** | 434 /** |
490 * This method checks whether the selection modification should be handled.
This method | 435 * This method checks whether the selection modification should be handled.
This method |
491 * is needed to allow modifying selections that are occluded by the Panel. | 436 * is needed to allow modifying selections that are occluded by the Panel. |
492 * See crbug.com/489461. | 437 * See crbug.com/489461. |
493 * | 438 * |
494 * @param reason The reason the panel is closing. | 439 * @param reason The reason the panel is closing. |
495 * @return Whether the selection modification should be handled. | 440 * @return Whether the selection modification should be handled. |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
621 // Starts are inclusive and ends are non-inclusive for both GSAContext &
matcher. | 566 // Starts are inclusive and ends are non-inclusive for both GSAContext &
matcher. |
622 while (matcher.find()) { | 567 while (matcher.find()) { |
623 if (startOffset >= matcher.start() && endOffset <= matcher.end()) { | 568 if (startOffset >= matcher.start() && endOffset <= matcher.end()) { |
624 return true; | 569 return true; |
625 } | 570 } |
626 } | 571 } |
627 | 572 |
628 return false; | 573 return false; |
629 } | 574 } |
630 } | 575 } |
OLD | NEW |