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

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

Issue 2703473002: [TTS] Extract tapped text before showing UI. (Closed)
Patch Set: Minor update. Created 3 years, 9 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
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.contextualsearch;
6
7 import android.util.Log;
8
9 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChange Reason;
10 import org.chromium.chrome.browser.contextualsearch.ContextualSearchSelectionCon troller.SelectionType;
11
12 import javax.annotation.Nullable;
13
14 /**
15 * Controls the State of the Contextual Search Manager.
16 * <p>
17 * This class keeps track of the current state of the {@code ContextualSearchMan ager} and helps it
18 * to transition between states return to the idle state when work has been inte rrupted.
19 * <p>
20 * Usage: Call {@link #reset(StateChangeReason)} to reset to the {@code IDLE} st ate.<br>
21 * Call {@link #enter(State)} to enter a start-state (when a gesture is recogniz ed).
22 * When doing some work in an asynchronous manner:<ol>
23 * <li>call {@link #notifyStartingWorkOn(State)} to note that work is starting o n that state
24 * <li>call {@link #notifyFinishedWorkOn(State)} when work is completed.
25 * <li>If a handler needs to do additional work, such as updating the UX, it sho uld first call
26 * {@link #isStillWorkingOn(State)} to check that work has not been interrupted.
27 * </ol><p>
28 * The {@link #notifyFinishedWorkOn(State)} method will automatically start a tr ansition to the
29 * next state.
30 * <p>
31 * Policy decisions about state transitions should only be done in the private
32 * {@link #transitionTo(State)} method of this class, not in the {@code Contextu alSearchManager}.
33 */
34 class ContextualSearchStateController {
35 private static final String TAG = "Contextual Search";
36
37 private final ContextualSearchSelectionController mSelectionController;
38 private final ContextualSearchPolicy mPolicy;
39 private final ContextualSearchStateControlled mControlled;
Theresa 2017/03/28 15:52:55 I'd prefer a different name for this class. Maybe
Donn Denman 2017/03/29 18:56:51 Changed to ContextualSearchInternalStateHandler.
40
41 /** The current state of the manager. */
42 public static enum State {
43 // When not yet initialized or already destroyed only
44 UNDEFINED,
45 // This is the default resting state.
46 IDLE,
Theresa 2017/03/28 15:52:55 Is this equivalent to the panel "closed" state (as
Donn Denman 2017/03/29 18:56:51 Yes, updated the comment to reflect that the IDLE
47
48 // This is a sequence of transition states needed to get to the SHOWING_ TAP resting state.
Theresa 2017/03/28 15:52:55 s/SHOWING_STATE/SHOWING_LONGPRESS_SEARCH?
Donn Denman 2017/03/29 18:56:51 Done.
49 LONG_PRESS_RECOGNIZED,
50 // Transitional state when extending the selection.
51 EXTENDING_SELECTION, // needed???
Theresa 2017/03/28 15:52:55 Would this be used when the user is dragging the s
Donn Denman 2017/03/29 18:56:51 Yep. Still not sure it's needed, but we're suppos
52 // Resting state when showing the panel in response to a Long-press gest ure.
53 SHOWING_LONGPRESS_SEARCH,
54
55 // This is a sequence of transition states needed to get to the SHOWING_ TAP resting state.
56 TAP_RECOGNIZED,
57 // May be done for Tap or Long-press.
58 GATHERING_SURROUNDINGS,
59 DECIDING_SUPPRESSION,
Theresa 2017/03/28 15:52:55 I expected tap suppression be synchronous (for now
Donn Denman 2017/03/29 18:56:51 This CL adds both sequencing and handling of async
60 WAITING_FOR_POSSIBLE_NAVIGATION,
61 SELECTING_WORD,
62 // Resolving the Search Term using the surrounding text and additional c ontext.
63 RESOLVING,
64 // Resting state when showing the panel in response to a Tap gesture.
65 SHOWING_TAP_SEARCH
66 }
67
68 // The current state of this instance.
69 private State mState;
70
71 // Whether work has started on the current state.
72 private boolean mDidStartWork;
73
74 /**
75 * Constructs an instance of this class, which has the same lifetime as the
76 * {@code ContextualSearchManager} and the given parameters.
77 */
78 ContextualSearchStateController(ContextualSearchSelectionController selectio nController,
79 ContextualSearchPolicy policy, ContextualSearchStateControlled contr olled) {
80 mSelectionController = selectionController;
81 mPolicy = policy;
82 mControlled = controlled;
83 }
84
85 // ========================================================================= ===================
86 // State-transition management.
87 // This code is designed to solve several problems:
88 // 1) Document the sequencing of handling a gesture in code. Now there's a single method that
89 // determines the sequence that should be followed for Tap handling (our most complicated
90 // case.
91 // 2) Document the initiation and subsequent notification/handling of operat ions. Now the
92 // method that starts an operation and the notification handler are tied together by their
93 // references to the same state. This allows a simple search to find the
94 // initiation and handler together (which is not always easy, e.g. Select WordAroundCaret
95 // does not yet have an ACK so we infer that it's complete when the selec tion change -- or
96 // does not change after some short waiting period).
97 // 3) Gracefully handle sequence interruptions. When an asynchronous operat ion is in progress
98 // the user may start a new sequence or abort the current sequence. Now the handler for an
99 // asynchronous operation can easily detect that it's no longer working o n that operation
100 // and skip the normal completion of the operation.
101 // ========================================================================= ===================
102
103 /**
104 * Reset the current state to the IDLE state.
105 * @param reason the reason for the reset
106 */
107 void reset(StateChangeReason reason) {
108 transitionTo(State.IDLE, reason);
109 }
110
111 /**
112 * Enters the given starting state immediately.
113 * @param state the new starting {@link State} we're now in
114 */
115 void enter(State state) {
116 assert state == State.UNDEFINED || state == State.IDLE
117 || state == State.LONG_PRESS_RECOGNIZED || state == State.TAP_RE COGNIZED;
118 mState = state;
119 System.out.println("ctxs enter : " + mSelectionController.getSelectionTy pe());
120 notifyStartingWorkOn(mState);
121 notifyFinishedWorkOn(mState);
122 }
123
124 /**
125 * Confirms that work is starting on the given state.
126 * @param state the {@link State} that we're now working on
127 */
128 void notifyStartingWorkOn(State state) {
129 assert mState == state;
130 mDidStartWork = true;
131 }
132
133 /**
134 * @return whether we're still working on the given state
135 */
136 boolean isStillWorkingOn(State state) {
137 return mState == state;
138 }
139
140 /**
141 * Confirms that work has been finished on the given state.
142 * This should be called by every operation that waits for some kind of comp letion when it
143 * completes. The operation's start must be flagged using {@link #starting} .
144 * @param state the {@link State} that we've finished working on.
145 */
146 void notifyFinishedWorkOn(State state) {
Theresa 2017/03/28 15:52:55 There's nothing here enforcing the order of state
Donn Denman 2017/03/29 18:56:51 I tried to do this with the initial implementation
147 if (state != mState) return;
148
149 assert mDidStartWork;
150
151 if (mState == State.IDLE) {
152 Log.w(TAG, "Warning, the " + state.toString() + " state was aborted. ");
153 return;
154 }
155
156 switch (state) {
157 case LONG_PRESS_RECOGNIZED:
158 transitionTo(State.GATHERING_SURROUNDINGS);
159 break;
160 case TAP_RECOGNIZED:
161 transitionTo(State.GATHERING_SURROUNDINGS);
162 break;
163 case GATHERING_SURROUNDINGS:
164 System.out.println("ctxs finished gathering, checking if tap..."
165 + mSelectionController.getSelectionType());
166 if (mSelectionController.getSelectionType() == SelectionType.TAP ) {
167 transitionTo(State.DECIDING_SUPPRESSION);
168 } else {
169 // No suppression yet for Long-press.
170 transitionTo(State.SHOWING_LONGPRESS_SEARCH,
171 StateChangeReason.TEXT_SELECT_LONG_PRESS);
172 }
173 break;
174 case DECIDING_SUPPRESSION:
175 transitionTo(State.WAITING_FOR_POSSIBLE_NAVIGATION);
176 break;
177 case WAITING_FOR_POSSIBLE_NAVIGATION:
178 transitionTo(State.SELECTING_WORD);
179 break;
180 case SELECTING_WORD:
181 System.out.println("checking if we should resolve...");
182 if (mPolicy.shouldPreviousTapResolve()) {
183 transitionTo(State.RESOLVING);
184 } else {
185 transitionTo(State.SHOWING_TAP_SEARCH);
186 }
187 break;
188 case RESOLVING:
189 transitionTo(State.SHOWING_TAP_SEARCH);
190 break;
191 default:
192 System.out.println("The state " + state.toString() + " is not tr ansitional!");
193 Log.e(TAG, "The state " + state.toString() + " is not transition al!");
194 assert false;
195 }
196 }
197
198 /**
199 * @return The current State.
200 */
201 State getState() {
202 return mState;
203 }
204
205 /**
206 * Establishes the given state by calling code that starts work on that stat e.
207 * @param state the new {@link State} to establish.
208 */
209 private void transitionTo(State state) {
210 transitionTo(state, null);
211 }
212
213 // TODO(donnd): remove!
214 private String nameOf(State state) {
215 if (state == null) return "null";
216 return state.name();
217 }
218
219 /**
220 * Establishes the given state by calling code that starts work on that stat e or simply
221 * displays the appropriate UX for that state.
222 * @param state the new {@link State} to establish.
223 * @param reason the reason we're starting this state, or {@code null} if no t significant
224 * or known. Only needed when we enter the IDLE state.
225 */
226 private void transitionTo(State state, @Nullable StateChangeReason reason) {
227 State previousState = mState;
228 mState = state;
229 mDidStartWork = false;
230 System.out.println(
231 "ctxs transition from " + nameOf(previousState) + " to " + nameO f(mState));
232
233 switch (state) {
234 case IDLE:
235 assert reason != null;
236 mControlled.hideContextualSearchUx(reason);
237 break;
238 case SHOWING_LONGPRESS_SEARCH:
239 mControlled.showContextualSearchUx(StateChangeReason.TEXT_SELECT _LONG_PRESS);
240 break;
241
242 case TAP_RECOGNIZED:
243 // Fall through:
244 case LONG_PRESS_RECOGNIZED:
245 // Fall through:
246 case GATHERING_SURROUNDINGS:
247 System.out.println(
248 "ctxs gather... is tap? " + mSelectionController.getSel ectionType());
249 mControlled.gatherSurroundingText();
250 break;
251 case WAITING_FOR_POSSIBLE_NAVIGATION:
252 mControlled.waitForPossibleNavigation();
253 break;
254 case SELECTING_WORD:
255 mControlled.selectWordAroundCaret();
256 break;
257 case DECIDING_SUPPRESSION:
258 mControlled.decideTapSuppression();
259 break;
260 case RESOLVING:
261 System.out.println("RESOLVING...");
262 mControlled.showContextualSearchUx(StateChangeReason.TEXT_SELECT _TAP);
263 mControlled.startSearchTermResolutionRequest();
264 break;
265 case SHOWING_TAP_SEARCH:
266 System.out.println("SHOWING_TAP_SEARCH...");
267 // The panel may already be showing a Tap, but we'll make sure i t's showing now.
268 mControlled.showContextualSearchUx(StateChangeReason.TEXT_SELECT _TAP);
269 break;
270
271 default:
272 System.out.println("ctxs Warning! Transition ignored to " + stat e);
273 break;
274 }
275 }
276 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698