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 #ifndef ASH_HIGHLIGHTER_HIGHLIGHTER_CONTROLLER_H_
6 #define ASH_HIGHLIGHTER_HIGHLIGHTER_CONTROLLER_H_
7 
8 #include <memory>
9 
10 #include "ash/ash_export.h"
11 #include "ash/fast_ink/fast_ink_pointer_controller.h"
12 #include "base/callback.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/observer_list.h"
15 #include "ui/views/widget/unique_widget_ptr.h"
16 
17 namespace base {
18 class OneShotTimer;
19 }
20 
21 namespace gfx {
22 class Rect;
23 }
24 
25 namespace ash {
26 
27 class HighlighterView;
28 
29 // Highlighter enabled state that is notified to observers.
30 enum class HighlighterEnabledState {
31   // Highlighter is enabled by any ways.
32   kEnabled,
33   // Highlighter is disabled by user directly, for example disabling palette
34   // tool by user actions on palette menu.
35   kDisabledByUser,
36   // Highlighter is disabled on metalayer session complete.
37   kDisabledBySessionComplete,
38   // Highlighter is disabled on metalayer session abort. An abort may occur due
39   // to dismissal of Assistant UI or due to interruption by user via hotword.
40   kDisabledBySessionAbort,
41 };
42 
43 // Controller for the highlighter functionality.
44 // Enables/disables highlighter as well as receives points
45 // and passes them off to be rendered.
46 class ASH_EXPORT HighlighterController
47     : public fast_ink::FastInkPointerController {
48  public:
49   // Interface for classes that wish to be notified with highlighter status.
50   class Observer {
51    public:
52     // Called when highlighter enabled state changes.
OnHighlighterEnabledChanged(HighlighterEnabledState state)53     virtual void OnHighlighterEnabledChanged(HighlighterEnabledState state) {}
54 
55     // Called when highlighter selection is recognized.
OnHighlighterSelectionRecognized(const gfx::Rect & rect)56     virtual void OnHighlighterSelectionRecognized(const gfx::Rect& rect) {}
57 
58    protected:
59     virtual ~Observer() = default;
60   };
61 
62   HighlighterController();
63   ~HighlighterController() override;
64 
enabled_state()65   HighlighterEnabledState enabled_state() { return enabled_state_; }
66 
67   void AddObserver(Observer* observer);
68   void RemoveObserver(Observer* observer);
69 
70   // Set the callback to exit the highlighter mode. If |require_success| is
71   // true, the callback will be called only after a successful gesture
72   // recognition. If |require_success| is false, the callback will be  called
73   // after the first complete gesture, regardless of the recognition result.
74   void SetExitCallback(base::OnceClosure callback, bool require_success);
75 
76   // Update highlighter enabled |state| and notify observers.
77   void UpdateEnabledState(HighlighterEnabledState enabled_state);
78 
79   // Aborts the current metalayer session. If no metalayer session exists,
80   // calling this method is a no-op.
81   void AbortSession();
82 
83  private:
84   friend class HighlighterControllerTestApi;
85 
86   // fast_ink::FastInkPointerController:
87   void SetEnabled(bool enabled) override;
88   views::View* GetPointerView() const override;
89   void CreatePointerView(base::TimeDelta presentation_delay,
90                          aura::Window* root_window) override;
91   void UpdatePointerView(ui::TouchEvent* event) override;
92   void DestroyPointerView() override;
93   bool CanStartNewGesture(ui::TouchEvent* event) override;
94 
95   // Performs gesture recognition, initiates appropriate visual effects,
96   // notifies the observer if necessary.
97   void RecognizeGesture();
98 
99   // Destroys |highlighter_view_widget_|, if it exists.
100   void DestroyHighlighterView();
101 
102   // Destroys |result_view_widget_|, if it exists.
103   void DestroyResultView();
104 
105   // Calls and clears the mode exit callback, if it is set.
106   void CallExitCallback();
107 
108   // Returns the Widget contents view of the highlighter widget as
109   // HighlighterView*.
110   HighlighterView* GetHighlighterView();
111 
112   // Caches the highlighter enabled state.
113   HighlighterEnabledState enabled_state_ =
114       HighlighterEnabledState::kDisabledByUser;
115 
116   // |highlighter_view_widget_| will only hold an instance when the highlighter
117   // is enabled and activated (pressed or dragged) and until the fade out
118   // animation is done.
119   views::UniqueWidgetPtr highlighter_view_widget_;
120 
121   // |result_view_widget_| will only hold an instance when the selection result
122   // animation is in progress.
123   views::UniqueWidgetPtr result_view_widget_;
124 
125   // Time of the session start (e.g. when the controller was enabled).
126   base::TimeTicks session_start_;
127 
128   // Time of the previous gesture end, valid after the first gesture
129   // within the session is complete.
130   base::TimeTicks previous_gesture_end_;
131 
132   // Gesture counter withing a session.
133   int gesture_counter_ = 0;
134 
135   // Recognized gesture counter withing a session.
136   int recognized_gesture_counter_ = 0;
137 
138   // Not null while waiting for the next event to continue an interrupted
139   // stroke.
140   std::unique_ptr<base::OneShotTimer> interrupted_stroke_timer_;
141 
142   // The callback to exit the mode in the UI.
143   base::OnceClosure exit_callback_;
144 
145   // If true, the mode is not exited until a valid selection is made.
146   bool require_success_ = true;
147 
148   base::ObserverList<Observer>::Unchecked observers_;
149 
150   base::WeakPtrFactory<HighlighterController> weak_factory_{this};
151 
152   DISALLOW_COPY_AND_ASSIGN(HighlighterController);
153 };
154 
155 }  // namespace ash
156 
157 #endif  // ASH_HIGHLIGHTER_HIGHLIGHTER_CONTROLLER_H_
158