OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "ash/touch/touch_uma.h" | 5 #include "ash/touch/touch_uma.h" |
6 | 6 |
7 #include "ash/common/wm_shell.h" | 7 #include "ash/common/wm_shell.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
10 #include "ui/aura/env.h" | 10 #include "ui/aura/env.h" |
(...skipping 22 matching lines...) Expand all Loading... |
33 | 33 |
34 // Last time-stamp of the last touch-end event. | 34 // Last time-stamp of the last touch-end event. |
35 base::TimeTicks last_release_time_; | 35 base::TimeTicks last_release_time_; |
36 | 36 |
37 // Stores the time of the last touch released on this window (if there was a | 37 // Stores the time of the last touch released on this window (if there was a |
38 // multi-touch gesture on the window, then this is the release-time of the | 38 // multi-touch gesture on the window, then this is the release-time of the |
39 // last touch on the window). | 39 // last touch on the window). |
40 base::TimeTicks last_mt_time_; | 40 base::TimeTicks last_mt_time_; |
41 }; | 41 }; |
42 | 42 |
43 DEFINE_OWNED_WINDOW_PROPERTY_KEY(WindowTouchDetails, | 43 DEFINE_OWNED_WINDOW_PROPERTY_KEY(WindowTouchDetails, kWindowTouchDetails, NULL); |
44 kWindowTouchDetails, | |
45 NULL); | |
46 } | 44 } |
47 | 45 |
48 DECLARE_WINDOW_PROPERTY_TYPE(WindowTouchDetails*); | 46 DECLARE_WINDOW_PROPERTY_TYPE(WindowTouchDetails*); |
49 | 47 |
50 namespace ash { | 48 namespace ash { |
51 | 49 |
52 // static | 50 // static |
53 TouchUMA* TouchUMA::GetInstance() { | 51 TouchUMA* TouchUMA::GetInstance() { |
54 return base::Singleton<TouchUMA>::get(); | 52 return base::Singleton<TouchUMA>::get(); |
55 } | 53 } |
(...skipping 11 matching lines...) Expand all Loading... |
67 " events"; | 65 " events"; |
68 return; | 66 return; |
69 } | 67 } |
70 details->last_mt_time_ = event.time_stamp(); | 68 details->last_mt_time_ = event.time_stamp(); |
71 } | 69 } |
72 } | 70 } |
73 | 71 |
74 void TouchUMA::RecordGestureAction(GestureActionType action) { | 72 void TouchUMA::RecordGestureAction(GestureActionType action) { |
75 if (action == GESTURE_UNKNOWN || action >= GESTURE_ACTION_COUNT) | 73 if (action == GESTURE_UNKNOWN || action >= GESTURE_ACTION_COUNT) |
76 return; | 74 return; |
77 UMA_HISTOGRAM_ENUMERATION("Ash.GestureTarget", action, | 75 UMA_HISTOGRAM_ENUMERATION("Ash.GestureTarget", action, GESTURE_ACTION_COUNT); |
78 GESTURE_ACTION_COUNT); | |
79 } | 76 } |
80 | 77 |
81 void TouchUMA::RecordTouchEvent(aura::Window* target, | 78 void TouchUMA::RecordTouchEvent(aura::Window* target, |
82 const ui::TouchEvent& event) { | 79 const ui::TouchEvent& event) { |
83 UMA_HISTOGRAM_CUSTOM_COUNTS( | 80 UMA_HISTOGRAM_CUSTOM_COUNTS( |
84 "Ash.TouchRadius", | 81 "Ash.TouchRadius", |
85 static_cast<int>(std::max(event.pointer_details().radius_x, | 82 static_cast<int>(std::max(event.pointer_details().radius_x, |
86 event.pointer_details().radius_y)), | 83 event.pointer_details().radius_y)), |
87 1, 500, 100); | 84 1, 500, 100); |
88 | 85 |
89 UpdateTouchState(event); | 86 UpdateTouchState(event); |
90 | 87 |
91 WindowTouchDetails* details = target->GetProperty(kWindowTouchDetails); | 88 WindowTouchDetails* details = target->GetProperty(kWindowTouchDetails); |
92 if (!details) { | 89 if (!details) { |
93 details = new WindowTouchDetails; | 90 details = new WindowTouchDetails; |
94 target->SetProperty(kWindowTouchDetails, details); | 91 target->SetProperty(kWindowTouchDetails, details); |
95 } | 92 } |
96 | 93 |
97 // Record the location of the touch points. | 94 // Record the location of the touch points. |
98 const int kBucketCountForLocation = 100; | 95 const int kBucketCountForLocation = 100; |
99 const gfx::Rect bounds = target->GetRootWindow()->bounds(); | 96 const gfx::Rect bounds = target->GetRootWindow()->bounds(); |
100 const int bucket_size_x = std::max(1, | 97 const int bucket_size_x = |
101 bounds.width() / kBucketCountForLocation); | 98 std::max(1, bounds.width() / kBucketCountForLocation); |
102 const int bucket_size_y = std::max(1, | 99 const int bucket_size_y = |
103 bounds.height() / kBucketCountForLocation); | 100 std::max(1, bounds.height() / kBucketCountForLocation); |
104 | 101 |
105 gfx::Point position = event.root_location(); | 102 gfx::Point position = event.root_location(); |
106 | 103 |
107 // Prefer raw event location (when available) over calibrated location. | 104 // Prefer raw event location (when available) over calibrated location. |
108 if (event.HasNativeEvent()) { | 105 if (event.HasNativeEvent()) { |
109 position = ui::EventLocationFromNative(event.native_event()); | 106 position = ui::EventLocationFromNative(event.native_event()); |
110 position = gfx::ScaleToFlooredPoint( | 107 position = gfx::ScaleToFlooredPoint( |
111 position, 1.f / target->layer()->device_scale_factor()); | 108 position, 1.f / target->layer()->device_scale_factor()); |
112 } | 109 } |
113 | 110 |
114 position.set_x(std::min(bounds.width() - 1, std::max(0, position.x()))); | 111 position.set_x(std::min(bounds.width() - 1, std::max(0, position.x()))); |
115 position.set_y(std::min(bounds.height() - 1, std::max(0, position.y()))); | 112 position.set_y(std::min(bounds.height() - 1, std::max(0, position.y()))); |
116 | 113 |
117 UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.TouchPositionX", | 114 UMA_HISTOGRAM_CUSTOM_COUNTS( |
118 position.x() / bucket_size_x, | 115 "Ash.TouchPositionX", position.x() / bucket_size_x, 0, |
119 0, kBucketCountForLocation, kBucketCountForLocation + 1); | 116 kBucketCountForLocation, kBucketCountForLocation + 1); |
120 UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.TouchPositionY", | 117 UMA_HISTOGRAM_CUSTOM_COUNTS( |
121 position.y() / bucket_size_y, | 118 "Ash.TouchPositionY", position.y() / bucket_size_y, 0, |
122 0, kBucketCountForLocation, kBucketCountForLocation + 1); | 119 kBucketCountForLocation, kBucketCountForLocation + 1); |
123 | 120 |
124 if (event.type() == ui::ET_TOUCH_PRESSED) { | 121 if (event.type() == ui::ET_TOUCH_PRESSED) { |
125 WmShell::Get()->RecordUserMetricsAction(UMA_TOUCHSCREEN_TAP_DOWN); | 122 WmShell::Get()->RecordUserMetricsAction(UMA_TOUCHSCREEN_TAP_DOWN); |
126 | 123 |
127 details->last_start_time_[event.touch_id()] = event.time_stamp(); | 124 details->last_start_time_[event.touch_id()] = event.time_stamp(); |
128 details->start_touch_position_[event.touch_id()] = event.root_location(); | 125 details->start_touch_position_[event.touch_id()] = event.root_location(); |
129 details->last_touch_position_[event.touch_id()] = event.location(); | 126 details->last_touch_position_[event.touch_id()] = event.location(); |
130 | 127 |
131 if (details->last_release_time_.ToInternalValue()) { | 128 if (details->last_release_time_.ToInternalValue()) { |
132 // Measuring the interval between a touch-release and the next | 129 // Measuring the interval between a touch-release and the next |
133 // touch-start is probably less useful when doing multi-touch (e.g. | 130 // touch-start is probably less useful when doing multi-touch (e.g. |
134 // gestures, or multi-touch friendly apps). So count this only if the user | 131 // gestures, or multi-touch friendly apps). So count this only if the user |
135 // hasn't done any multi-touch during the last 30 seconds. | 132 // hasn't done any multi-touch during the last 30 seconds. |
136 base::TimeDelta diff = event.time_stamp() - details->last_mt_time_; | 133 base::TimeDelta diff = event.time_stamp() - details->last_mt_time_; |
137 if (diff.InSeconds() > 30) { | 134 if (diff.InSeconds() > 30) { |
138 base::TimeDelta gap = event.time_stamp() - details->last_release_time_; | 135 base::TimeDelta gap = event.time_stamp() - details->last_release_time_; |
139 UMA_HISTOGRAM_COUNTS_10000("Ash.TouchStartAfterEnd", | 136 UMA_HISTOGRAM_COUNTS_10000("Ash.TouchStartAfterEnd", |
140 gap.InMilliseconds()); | 137 gap.InMilliseconds()); |
141 } | 138 } |
142 } | 139 } |
143 | 140 |
144 // Record the number of touch-points currently active for the window. | 141 // Record the number of touch-points currently active for the window. |
145 const int kMaxTouchPoints = 10; | 142 const int kMaxTouchPoints = 10; |
146 UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.ActiveTouchPoints", | 143 UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.ActiveTouchPoints", |
147 details->last_start_time_.size(), | 144 details->last_start_time_.size(), 1, |
148 1, kMaxTouchPoints, kMaxTouchPoints + 1); | 145 kMaxTouchPoints, kMaxTouchPoints + 1); |
149 } else if (event.type() == ui::ET_TOUCH_RELEASED) { | 146 } else if (event.type() == ui::ET_TOUCH_RELEASED) { |
150 if (details->last_start_time_.count(event.touch_id())) { | 147 if (details->last_start_time_.count(event.touch_id())) { |
151 base::TimeDelta duration = event.time_stamp() - | 148 base::TimeDelta duration = |
152 details->last_start_time_[event.touch_id()]; | 149 event.time_stamp() - details->last_start_time_[event.touch_id()]; |
153 // Look for touches that were [almost] stationary for a long time. | 150 // Look for touches that were [almost] stationary for a long time. |
154 const double kLongStationaryTouchDuration = 10; | 151 const double kLongStationaryTouchDuration = 10; |
155 const int kLongStationaryTouchDistanceSquared = 100; | 152 const int kLongStationaryTouchDistanceSquared = 100; |
156 if (duration.InSecondsF() > kLongStationaryTouchDuration) { | 153 if (duration.InSecondsF() > kLongStationaryTouchDuration) { |
157 gfx::Vector2d distance = event.root_location() - | 154 gfx::Vector2d distance = |
| 155 event.root_location() - |
158 details->start_touch_position_[event.touch_id()]; | 156 details->start_touch_position_[event.touch_id()]; |
159 if (distance.LengthSquared() < kLongStationaryTouchDistanceSquared) { | 157 if (distance.LengthSquared() < kLongStationaryTouchDistanceSquared) { |
160 UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.StationaryTouchDuration", | 158 UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.StationaryTouchDuration", |
161 duration.InSeconds(), | 159 duration.InSeconds(), |
162 kLongStationaryTouchDuration, | 160 kLongStationaryTouchDuration, 1000, 20); |
163 1000, | |
164 20); | |
165 } | 161 } |
166 } | 162 } |
167 } | 163 } |
168 details->last_start_time_.erase(event.touch_id()); | 164 details->last_start_time_.erase(event.touch_id()); |
169 details->last_move_time_.erase(event.touch_id()); | 165 details->last_move_time_.erase(event.touch_id()); |
170 details->start_touch_position_.erase(event.touch_id()); | 166 details->start_touch_position_.erase(event.touch_id()); |
171 details->last_touch_position_.erase(event.touch_id()); | 167 details->last_touch_position_.erase(event.touch_id()); |
172 details->last_release_time_ = event.time_stamp(); | 168 details->last_release_time_ = event.time_stamp(); |
173 } else if (event.type() == ui::ET_TOUCH_MOVED) { | 169 } else if (event.type() == ui::ET_TOUCH_MOVED) { |
174 int distance = 0; | 170 int distance = 0; |
175 if (details->last_touch_position_.count(event.touch_id())) { | 171 if (details->last_touch_position_.count(event.touch_id())) { |
176 gfx::Point lastpos = details->last_touch_position_[event.touch_id()]; | 172 gfx::Point lastpos = details->last_touch_position_[event.touch_id()]; |
177 distance = | 173 distance = |
178 std::abs(lastpos.x() - event.x()) + std::abs(lastpos.y() - event.y()); | 174 std::abs(lastpos.x() - event.x()) + std::abs(lastpos.y() - event.y()); |
179 } | 175 } |
180 | 176 |
181 if (details->last_move_time_.count(event.touch_id())) { | 177 if (details->last_move_time_.count(event.touch_id())) { |
182 base::TimeDelta move_delay = event.time_stamp() - | 178 base::TimeDelta move_delay = |
183 details->last_move_time_[event.touch_id()]; | 179 event.time_stamp() - details->last_move_time_[event.touch_id()]; |
184 UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.TouchMoveInterval", | 180 UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.TouchMoveInterval", |
185 move_delay.InMilliseconds(), | 181 move_delay.InMilliseconds(), 1, 50, 25); |
186 1, 50, 25); | |
187 } | 182 } |
188 | 183 |
189 UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.TouchMoveSteps", distance, 1, 1000, 50); | 184 UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.TouchMoveSteps", distance, 1, 1000, 50); |
190 | 185 |
191 details->last_move_time_[event.touch_id()] = event.time_stamp(); | 186 details->last_move_time_[event.touch_id()] = event.time_stamp(); |
192 details->last_touch_position_[event.touch_id()] = event.location(); | 187 details->last_touch_position_[event.touch_id()] = event.location(); |
193 } | 188 } |
194 } | 189 } |
195 | 190 |
196 TouchUMA::TouchUMA() | 191 TouchUMA::TouchUMA() |
197 : is_single_finger_gesture_(false), | 192 : is_single_finger_gesture_(false), |
198 touch_in_progress_(false), | 193 touch_in_progress_(false), |
199 burst_length_(0) { | 194 burst_length_(0) {} |
200 } | |
201 | 195 |
202 TouchUMA::~TouchUMA() { | 196 TouchUMA::~TouchUMA() {} |
203 } | |
204 | 197 |
205 void TouchUMA::UpdateTouchState(const ui::TouchEvent& event) { | 198 void TouchUMA::UpdateTouchState(const ui::TouchEvent& event) { |
206 if (event.type() == ui::ET_TOUCH_PRESSED) { | 199 if (event.type() == ui::ET_TOUCH_PRESSED) { |
207 if (!touch_in_progress_) { | 200 if (!touch_in_progress_) { |
208 is_single_finger_gesture_ = true; | 201 is_single_finger_gesture_ = true; |
209 base::TimeDelta difference = event.time_stamp() - last_touch_down_time_; | 202 base::TimeDelta difference = event.time_stamp() - last_touch_down_time_; |
210 if (difference > base::TimeDelta::FromMilliseconds(250)) { | 203 if (difference > base::TimeDelta::FromMilliseconds(250)) { |
211 if (burst_length_) { | 204 if (burst_length_) { |
212 UMA_HISTOGRAM_COUNTS_100("Ash.TouchStartBurst", | 205 UMA_HISTOGRAM_COUNTS_100("Ash.TouchStartBurst", |
213 std::min(burst_length_, 100)); | 206 std::min(burst_length_, 100)); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 return GESTURE_UNKNOWN; | 258 return GESTURE_UNKNOWN; |
266 | 259 |
267 // |widget| may be in the process of destroying if it has ownership | 260 // |widget| may be in the process of destroying if it has ownership |
268 // views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET and |event| was | 261 // views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET and |event| was |
269 // dispatched as part of gesture state cleanup. In this case the RootView | 262 // dispatched as part of gesture state cleanup. In this case the RootView |
270 // of |widget| may no longer exist, so check before calling into any | 263 // of |widget| may no longer exist, so check before calling into any |
271 // RootView methods. | 264 // RootView methods. |
272 if (!widget->GetRootView()) | 265 if (!widget->GetRootView()) |
273 return GESTURE_UNKNOWN; | 266 return GESTURE_UNKNOWN; |
274 | 267 |
275 views::View* view = widget->GetRootView()-> | 268 views::View* view = |
276 GetEventHandlerForPoint(event.location()); | 269 widget->GetRootView()->GetEventHandlerForPoint(event.location()); |
277 if (!view) | 270 if (!view) |
278 return GESTURE_UNKNOWN; | 271 return GESTURE_UNKNOWN; |
279 | 272 |
280 name = view->GetClassName(); | 273 name = view->GetClassName(); |
281 | 274 |
282 const char kTabStrip[] = "TabStrip"; | 275 const char kTabStrip[] = "TabStrip"; |
283 const char kTab[] = "BrowserTab"; | 276 const char kTab[] = "BrowserTab"; |
284 if (name == kTabStrip || name == kTab) { | 277 if (name == kTabStrip || name == kTab) { |
285 if (event.type() == ui::ET_GESTURE_SCROLL_BEGIN) | 278 if (event.type() == ui::ET_GESTURE_SCROLL_BEGIN) |
286 return GESTURE_TABSTRIP_SCROLL; | 279 return GESTURE_TABSTRIP_SCROLL; |
(...skipping 10 matching lines...) Expand all Loading... |
297 return GESTURE_OMNIBOX_SCROLL; | 290 return GESTURE_OMNIBOX_SCROLL; |
298 if (event.type() == ui::ET_GESTURE_PINCH_BEGIN) | 291 if (event.type() == ui::ET_GESTURE_PINCH_BEGIN) |
299 return GESTURE_OMNIBOX_PINCH; | 292 return GESTURE_OMNIBOX_PINCH; |
300 return GESTURE_UNKNOWN; | 293 return GESTURE_UNKNOWN; |
301 } | 294 } |
302 | 295 |
303 return GESTURE_UNKNOWN; | 296 return GESTURE_UNKNOWN; |
304 } | 297 } |
305 | 298 |
306 } // namespace ash | 299 } // namespace ash |
OLD | NEW |