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

Side by Side Diff: chrome/browser/win/settings_app_monitor.cc

Issue 2003553003: Report user actions for interactions with the Windows Settings app. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix histograms.xml typo Created 4 years, 7 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 | « chrome/browser/win/settings_app_monitor.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 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 #include "chrome/browser/win/settings_app_monitor.h"
6
7 #include <atlbase.h>
8 #include <atlcom.h>
9 #include <oleauto.h>
10 #include <stdint.h>
11 #include <uiautomation.h>
12
13 #include <algorithm>
14 #include <iterator>
15 #include <string>
16 #include <utility>
17 #include <vector>
18
19 #include "base/bind.h"
20 #include "base/callback.h"
21 #include "base/location.h"
22 #include "base/memory/ref_counted.h"
23 #include "base/sequenced_task_runner.h"
24 #include "base/single_thread_task_runner.h"
25 #include "base/strings/pattern.h"
26 #include "base/strings/string16.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/string_util.h"
29 #include "base/threading/sequenced_task_runner_handle.h"
30 #include "base/win/scoped_comptr.h"
31 #include "base/win/scoped_variant.h"
32 #include "ui/base/win/atl_module.h"
33
34 namespace shell_integration {
35 namespace win {
36
37 // SettingsAppMonitor::Context -------------------------------------------------
38
39 // The guts of the monitor which runs on a dedicated thread in the
40 // multi-threaded COM apartment. An instance may be constructed on any thread,
41 // but Initialize() must be invoked on a thread in the MTA.
42 class SettingsAppMonitor::Context {
43 public:
44 // Returns a new instance ready for initialization and use on another thread.
45 static base::WeakPtr<Context> Create();
46
47 // Deletes the instance.
48 void DeleteOnAutomationThread();
49
50 // Initializes the context, invoking the monitor's |OnInitialized| method via
51 // |monitor_runner| when done. On success, the monitor's other On* methods
52 // will be invoked as events are observed. On failure, this instance
53 // self-destructs after posting |init_callback|. |task_runner| is the runner
54 // for the dedicated thread on which the context lives (owned by its
55 // UIAutomationClient).
56 void Initialize(base::SingleThreadTaskRunner* task_runner,
57 base::SequencedTaskRunner* monitor_runner,
58 const base::WeakPtr<SettingsAppMonitor>& monitor);
59
60 private:
61 class EventHandler;
62
63 // The one and only method that may be called from outside of the automation
64 // thread.
65 Context();
66 ~Context();
67
68 // Method(s) invoked by event handlers via weak pointers.
69
70 // Handles a focus change event on |sender|. Dispatches OnAppFocused if
71 // |sender| is the settings app.
72 void HandleFocusChangedEvent(
73 base::win::ScopedComPtr<IUIAutomationElement> sender);
74
75 // Handles the invocation of the element that opens the browser chooser.
76 void HandleChooserInvoked();
77
78 // Handles the invocation of an element in the browser chooser.
79 void HandleBrowserChosen(const base::string16& browser_name);
80
81 // Returns an event handler for all event types of interest.
82 base::win::ScopedComPtr<IUnknown> GetEventHandler();
83
84 // Returns a pointer to the event handler's generic interface.
85 base::win::ScopedComPtr<IUIAutomationEventHandler>
86 GetAutomationEventHandler();
87
88 // Returns a pointer to the event handler's focus changed interface.
89 base::win::ScopedComPtr<IUIAutomationFocusChangedEventHandler>
90 GetFocusChangedEventHandler();
91
92 // Installs an event handler to observe events of interest.
93 HRESULT InstallObservers();
94
95 // The task runner for the automation thread.
96 base::SingleThreadTaskRunner* task_runner_ = nullptr;
97
98 // The task runner on which the owning monitor lives.
99 base::SequencedTaskRunner* monitor_runner_ = nullptr;
100
101 // The monitor that owns this context.
102 base::WeakPtr<SettingsAppMonitor> monitor_;
103
104 // The automation client.
105 base::win::ScopedComPtr<IUIAutomation> automation_;
106
107 // The event handler.
108 base::win::ScopedComPtr<IUnknown> event_handler_;
109
110 // State to suppress duplicate OnAppFocused notifications.
111 bool observed_app_focused_ = false;
112
113 // Weak pointers to the context are given to event handlers.
114 base::WeakPtrFactory<Context> weak_ptr_factory_;
115
116 DISALLOW_COPY_AND_ASSIGN(Context);
117 };
118
119
120 // SettingsAppMonitor::Context::EventHandler -----------------------------------
121
122 // A handler of events on arbitrary threads in the MTA.
123 class SettingsAppMonitor::Context::EventHandler
124 : public ATL::CComObjectRootEx<ATL::CComMultiThreadModel>,
125 public IUIAutomationEventHandler,
126 public IUIAutomationFocusChangedEventHandler {
127 public:
128 BEGIN_COM_MAP(SettingsAppMonitor::Context::EventHandler)
129 COM_INTERFACE_ENTRY(IUIAutomationEventHandler)
130 COM_INTERFACE_ENTRY(IUIAutomationFocusChangedEventHandler)
131 END_COM_MAP()
132
133 EventHandler();
134 ~EventHandler();
135
136 // Initializes the object. Events will be dispatched back to |context| via
137 // |context_runner|.
138 void Initialize(scoped_refptr<base::SingleThreadTaskRunner> context_runner,
139 const base::WeakPtr<SettingsAppMonitor::Context>& context);
140
141 // IUIAutomationEventHandler:
142 STDMETHOD(HandleAutomationEvent)(IUIAutomationElement *sender,
143 EVENTID eventId) override;
144
145 // IUIAutomationFocusChangedEventHandler:
146 STDMETHOD(HandleFocusChangedEvent)(IUIAutomationElement* sender) override;
147
148 private:
149 // The task runner for the monitor client context.
150 scoped_refptr<base::SingleThreadTaskRunner> context_runner_;
151
152 // The monitor context that owns this event handler.
153 base::WeakPtr<SettingsAppMonitor::Context> context_;
154
155 DISALLOW_COPY_AND_ASSIGN(EventHandler);
156 };
157
158
159 // Utility functions -----------------------------------------------------------
160
161 base::string16 GetCachedBstrValue(IUIAutomationElement* element,
162 PROPERTYID property_id) {
163 HRESULT result = S_OK;
164 base::win::ScopedVariant var;
165
166 result = element->GetCachedPropertyValueEx(property_id, TRUE, var.Receive());
167 if (FAILED(result))
168 return base::string16();
169
170 if (V_VT(var.ptr()) != VT_BSTR) {
171 LOG_IF(ERROR, V_VT(var.ptr()) != VT_UNKNOWN)
172 << __FUNCTION__ << " property is not a BSTR: " << V_VT(var.ptr());
173 return base::string16();
174 }
175
176 return base::string16(V_BSTR(var.ptr()));
177 }
178
179 enum class ElementType {
180 // The "Web browser" element in the "Default apps" pane.
181 DEFAULT_BROWSER,
182 // The element representing a browser in the "Choose an app" popup.
183 BROWSER_BUTTON,
184 // Any other element.
185 UNKNOWN,
186 };
187
188 ElementType DetectElementType(IUIAutomationElement* sender) {
189 base::string16 aid(GetCachedBstrValue(sender, UIA_AutomationIdPropertyId));
190 if (aid == L"SystemSettings_DefaultApps_Browser_Button")
191 return ElementType::DEFAULT_BROWSER;
192 if (base::MatchPattern(aid, L"SystemSettings_DefaultApps_Browser_*_Button"))
193 return ElementType::BROWSER_BUTTON;
194 return ElementType::UNKNOWN;
195 }
196
197 // Configures a cache request so that it includes all properties needed by
198 // DetectElementType() to detect the elements of interest.
199 void ConfigureCacheRequest(IUIAutomationCacheRequest* cache_request) {
200 DCHECK(cache_request);
201 cache_request->AddProperty(UIA_AutomationIdPropertyId);
202 cache_request->AddProperty(UIA_NamePropertyId);
203 #if ENABLE_DLOG
204 cache_request->AddProperty(UIA_ClassNamePropertyId);
205 cache_request->AddProperty(UIA_ControlTypePropertyId);
206 cache_request->AddProperty(UIA_IsPeripheralPropertyId);
207 cache_request->AddProperty(UIA_ProcessIdPropertyId);
208 cache_request->AddProperty(UIA_ValueValuePropertyId);
209 cache_request->AddProperty(UIA_RuntimeIdPropertyId);
210 #endif // ENABLE_DLOG
211 }
212
213
214 // Debug logging utility functions ---------------------------------------------
215
216 bool GetCachedBoolValue(IUIAutomationElement* element, PROPERTYID property_id) {
217 #if ENABLE_DLOG
218 base::win::ScopedVariant var;
219
220 if (FAILED(element->GetCachedPropertyValueEx(property_id, TRUE,
221 var.Receive()))) {
222 return false;
223 }
224
225 if (V_VT(var.ptr()) != VT_BOOL) {
226 LOG_IF(ERROR, V_VT(var.ptr()) != VT_UNKNOWN)
227 << __FUNCTION__ << " property is not a BOOL: " << V_VT(var.ptr());
228 return false;
229 }
230
231 return V_BOOL(var.ptr()) != 0;
232 #else // ENABLE_DLOG
233 return false;
234 #endif // !ENABLE_DLOG
235 }
236
237 int32_t GetCachedInt32Value(IUIAutomationElement* element,
238 PROPERTYID property_id) {
239 #if ENABLE_DLOG
240 base::win::ScopedVariant var;
241
242 if (FAILED(element->GetCachedPropertyValueEx(property_id, TRUE,
243 var.Receive()))) {
244 return false;
245 }
246
247 if (V_VT(var.ptr()) != VT_I4) {
248 LOG_IF(ERROR, V_VT(var.ptr()) != VT_UNKNOWN)
249 << __FUNCTION__ << " property is not an I4: " << V_VT(var.ptr());
250 return false;
251 }
252
253 return V_I4(var.ptr());
254 #else // ENABLE_DLOG
255 return 0;
256 #endif // !ENABLE_DLOG
257 }
258
259 std::vector<int32_t> GetCachedInt32ArrayValue(IUIAutomationElement* element,
260 PROPERTYID property_id) {
261 std::vector<int32_t> values;
262 #if ENABLE_DLOG
263 base::win::ScopedVariant var;
264
265 if (FAILED(element->GetCachedPropertyValueEx(property_id, TRUE,
266 var.Receive()))) {
267 return values;
268 }
269
270 if (V_VT(var.ptr()) != (VT_I4 | VT_ARRAY)) {
271 LOG_IF(ERROR, V_VT(var.ptr()) != VT_UNKNOWN)
272 << __FUNCTION__ << " property is not an I4 array: " << V_VT(var.ptr());
273 return values;
274 }
275
276 SAFEARRAY* array = V_ARRAY(var.ptr());
277 if (SafeArrayGetDim(array) != 1)
278 return values;
279 long lower_bound = 0;
280 long upper_bound = 0;
281 SafeArrayGetLBound(array, 1, &lower_bound);
282 SafeArrayGetUBound(array, 1, &upper_bound);
283 if (lower_bound || upper_bound <= lower_bound)
284 return values;
285 int32_t* data = nullptr;
286 SafeArrayAccessData(array, reinterpret_cast<void**>(&data));
287 values.assign(data, data + upper_bound + 1);
288 SafeArrayUnaccessData(array);
289 #endif // ENABLE_DLOG
290 return values;
291 }
292
293 std::string IntArrayToString(const std::vector<int32_t>& values) {
294 #if ENABLE_DLOG
295 std::vector<std::string> value_strings;
296 std::transform(values.begin(), values.end(),
297 std::back_inserter(value_strings), &base::IntToString);
298 return base::JoinString(value_strings, ", ");
299 #else // ENABLE_DLOG
300 return std::string();
301 #endif // !ENABLE_DLOG
302 }
303
304 const char* GetEventName(EVENTID event_id) {
305 #if ENABLE_DLOG
306 switch (event_id) {
307 case UIA_ToolTipOpenedEventId:
308 return "UIA_ToolTipOpenedEventId";
309 case UIA_ToolTipClosedEventId:
310 return "UIA_ToolTipClosedEventId";
311 case UIA_StructureChangedEventId:
312 return "UIA_StructureChangedEventId";
313 case UIA_MenuOpenedEventId:
314 return "UIA_MenuOpenedEventId";
315 case UIA_AutomationPropertyChangedEventId:
316 return "UIA_AutomationPropertyChangedEventId";
317 case UIA_AutomationFocusChangedEventId:
318 return "UIA_AutomationFocusChangedEventId";
319 case UIA_AsyncContentLoadedEventId:
320 return "UIA_AsyncContentLoadedEventId";
321 case UIA_MenuClosedEventId:
322 return "UIA_MenuClosedEventId";
323 case UIA_LayoutInvalidatedEventId:
324 return "UIA_LayoutInvalidatedEventId";
325 case UIA_Invoke_InvokedEventId:
326 return "UIA_Invoke_InvokedEventId";
327 case UIA_SelectionItem_ElementAddedToSelectionEventId:
328 return "UIA_SelectionItem_ElementAddedToSelectionEventId";
329 case UIA_SelectionItem_ElementRemovedFromSelectionEventId:
330 return "UIA_SelectionItem_ElementRemovedFromSelectionEventId";
331 case UIA_SelectionItem_ElementSelectedEventId:
332 return "UIA_SelectionItem_ElementSelectedEventId";
333 case UIA_Selection_InvalidatedEventId:
334 return "UIA_Selection_InvalidatedEventId";
335 case UIA_Text_TextSelectionChangedEventId:
336 return "UIA_Text_TextSelectionChangedEventId";
337 case UIA_Text_TextChangedEventId:
338 return "UIA_Text_TextChangedEventId";
339 case UIA_Window_WindowOpenedEventId:
340 return "UIA_Window_WindowOpenedEventId";
341 case UIA_Window_WindowClosedEventId:
342 return "UIA_Window_WindowClosedEventId";
343 case UIA_MenuModeStartEventId:
344 return "UIA_MenuModeStartEventId";
345 case UIA_MenuModeEndEventId:
346 return "UIA_MenuModeEndEventId";
347 case UIA_InputReachedTargetEventId:
348 return "UIA_InputReachedTargetEventId";
349 case UIA_InputReachedOtherElementEventId:
350 return "UIA_InputReachedOtherElementEventId";
351 case UIA_InputDiscardedEventId:
352 return "UIA_InputDiscardedEventId";
353 case UIA_SystemAlertEventId:
354 return "UIA_SystemAlertEventId";
355 case UIA_LiveRegionChangedEventId:
356 return "UIA_LiveRegionChangedEventId";
357 case UIA_HostedFragmentRootsInvalidatedEventId:
358 return "UIA_HostedFragmentRootsInvalidatedEventId";
359 case UIA_Drag_DragStartEventId:
360 return "UIA_Drag_DragStartEventId";
361 case UIA_Drag_DragCancelEventId:
362 return "UIA_Drag_DragCancelEventId";
363 case UIA_Drag_DragCompleteEventId:
364 return "UIA_Drag_DragCompleteEventId";
365 case UIA_DropTarget_DragEnterEventId:
366 return "UIA_DropTarget_DragEnterEventId";
367 case UIA_DropTarget_DragLeaveEventId:
368 return "UIA_DropTarget_DragLeaveEventId";
369 case UIA_DropTarget_DroppedEventId:
370 return "UIA_DropTarget_DroppedEventId";
371 case UIA_TextEdit_TextChangedEventId:
372 return "UIA_TextEdit_TextChangedEventId";
373 case UIA_TextEdit_ConversionTargetChangedEventId:
374 return "UIA_TextEdit_ConversionTargetChangedEventId";
375 }
376 #endif // ENABLE_DLOG
377 return "";
378 }
379
380 const char* GetControlType(long control_type) {
381 #if ENABLE_DLOG
382 switch (control_type) {
383 case UIA_ButtonControlTypeId:
384 return "UIA_ButtonControlTypeId";
385 case UIA_CalendarControlTypeId:
386 return "UIA_CalendarControlTypeId";
387 case UIA_CheckBoxControlTypeId:
388 return "UIA_CheckBoxControlTypeId";
389 case UIA_ComboBoxControlTypeId:
390 return "UIA_ComboBoxControlTypeId";
391 case UIA_EditControlTypeId:
392 return "UIA_EditControlTypeId";
393 case UIA_HyperlinkControlTypeId:
394 return "UIA_HyperlinkControlTypeId";
395 case UIA_ImageControlTypeId:
396 return "UIA_ImageControlTypeId";
397 case UIA_ListItemControlTypeId:
398 return "UIA_ListItemControlTypeId";
399 case UIA_ListControlTypeId:
400 return "UIA_ListControlTypeId";
401 case UIA_MenuControlTypeId:
402 return "UIA_MenuControlTypeId";
403 case UIA_MenuBarControlTypeId:
404 return "UIA_MenuBarControlTypeId";
405 case UIA_MenuItemControlTypeId:
406 return "UIA_MenuItemControlTypeId";
407 case UIA_ProgressBarControlTypeId:
408 return "UIA_ProgressBarControlTypeId";
409 case UIA_RadioButtonControlTypeId:
410 return "UIA_RadioButtonControlTypeId";
411 case UIA_ScrollBarControlTypeId:
412 return "UIA_ScrollBarControlTypeId";
413 case UIA_SliderControlTypeId:
414 return "UIA_SliderControlTypeId";
415 case UIA_SpinnerControlTypeId:
416 return "UIA_SpinnerControlTypeId";
417 case UIA_StatusBarControlTypeId:
418 return "UIA_StatusBarControlTypeId";
419 case UIA_TabControlTypeId:
420 return "UIA_TabControlTypeId";
421 case UIA_TabItemControlTypeId:
422 return "UIA_TabItemControlTypeId";
423 case UIA_TextControlTypeId:
424 return "UIA_TextControlTypeId";
425 case UIA_ToolBarControlTypeId:
426 return "UIA_ToolBarControlTypeId";
427 case UIA_ToolTipControlTypeId:
428 return "UIA_ToolTipControlTypeId";
429 case UIA_TreeControlTypeId:
430 return "UIA_TreeControlTypeId";
431 case UIA_TreeItemControlTypeId:
432 return "UIA_TreeItemControlTypeId";
433 case UIA_CustomControlTypeId:
434 return "UIA_CustomControlTypeId";
435 case UIA_GroupControlTypeId:
436 return "UIA_GroupControlTypeId";
437 case UIA_ThumbControlTypeId:
438 return "UIA_ThumbControlTypeId";
439 case UIA_DataGridControlTypeId:
440 return "UIA_DataGridControlTypeId";
441 case UIA_DataItemControlTypeId:
442 return "UIA_DataItemControlTypeId";
443 case UIA_DocumentControlTypeId:
444 return "UIA_DocumentControlTypeId";
445 case UIA_SplitButtonControlTypeId:
446 return "UIA_SplitButtonControlTypeId";
447 case UIA_WindowControlTypeId:
448 return "UIA_WindowControlTypeId";
449 case UIA_PaneControlTypeId:
450 return "UIA_PaneControlTypeId";
451 case UIA_HeaderControlTypeId:
452 return "UIA_HeaderControlTypeId";
453 case UIA_HeaderItemControlTypeId:
454 return "UIA_HeaderItemControlTypeId";
455 case UIA_TableControlTypeId:
456 return "UIA_TableControlTypeId";
457 case UIA_TitleBarControlTypeId:
458 return "UIA_TitleBarControlTypeId";
459 case UIA_SeparatorControlTypeId:
460 return "UIA_SeparatorControlTypeId";
461 case UIA_SemanticZoomControlTypeId:
462 return "UIA_SemanticZoomControlTypeId";
463 case UIA_AppBarControlTypeId:
464 return "UIA_AppBarControlTypeId";
465 }
466 #endif // ENABLE_DLOG
467 return "";
468 }
469
470
471 // SettingsAppMonitor::Context::EventHandler -----------------------------------
472
473 SettingsAppMonitor::Context::EventHandler::EventHandler() = default;
474
475 SettingsAppMonitor::Context::EventHandler::~EventHandler() = default;
476
477 void SettingsAppMonitor::Context::EventHandler::Initialize(
478 scoped_refptr<base::SingleThreadTaskRunner> context_runner,
479 const base::WeakPtr<SettingsAppMonitor::Context>& context) {
480 context_runner_ = std::move(context_runner);
481 context_ = context;
482 }
483
484 HRESULT SettingsAppMonitor::Context::EventHandler::HandleAutomationEvent(
485 IUIAutomationElement* sender,
486 EVENTID event_id) {
487 DVLOG(1) << "event id: " << GetEventName(event_id) << ", automation id: "
488 << GetCachedBstrValue(sender, UIA_AutomationIdPropertyId)
489 << ", name: " << GetCachedBstrValue(sender, UIA_NamePropertyId)
490 << ", control type: " << GetControlType(GetCachedInt32Value(
491 sender, UIA_ControlTypePropertyId))
492 << ", is peripheral: "
493 << GetCachedBoolValue(sender, UIA_IsPeripheralPropertyId)
494 << ", class name: "
495 << GetCachedBstrValue(sender, UIA_ClassNamePropertyId)
496 << ", pid: " << GetCachedInt32Value(sender, UIA_ProcessIdPropertyId)
497 << ", value: "
498 << GetCachedBstrValue(sender, UIA_ValueValuePropertyId)
499 << ", runtime id: " << IntArrayToString(GetCachedInt32ArrayValue(
500 sender, UIA_RuntimeIdPropertyId));
501
502 switch (DetectElementType(sender)) {
503 case ElementType::DEFAULT_BROWSER:
504 context_runner_->PostTask(
505 FROM_HERE,
506 base::Bind(&SettingsAppMonitor::Context::HandleChooserInvoked,
507 context_));
508 break;
509 case ElementType::BROWSER_BUTTON: {
510 base::string16 browser_name(
511 GetCachedBstrValue(sender, UIA_NamePropertyId));
512 if (!browser_name.empty()) {
513 context_runner_->PostTask(
514 FROM_HERE,
515 base::Bind(&SettingsAppMonitor::Context::HandleBrowserChosen,
516 context_, browser_name));
517 }
518 break;
519 }
520 case ElementType::UNKNOWN:
521 break;
522 }
523
524 return S_OK;
525 }
526
527 HRESULT SettingsAppMonitor::Context::EventHandler::HandleFocusChangedEvent(
528 IUIAutomationElement* sender) {
529 DVLOG(1) << "focus changed for automation id: "
530 << GetCachedBstrValue(sender, UIA_AutomationIdPropertyId)
531 << ", name: " << GetCachedBstrValue(sender, UIA_NamePropertyId)
532 << ", control type: " << GetControlType(GetCachedInt32Value(
533 sender, UIA_ControlTypePropertyId))
534 << ", is peripheral: "
535 << GetCachedBoolValue(sender, UIA_IsPeripheralPropertyId)
536 << ", class name: "
537 << GetCachedBstrValue(sender, UIA_ClassNamePropertyId)
538 << ", pid: " << GetCachedInt32Value(sender, UIA_ProcessIdPropertyId)
539 << ", value: "
540 << GetCachedBstrValue(sender, UIA_ValueValuePropertyId)
541 << ", runtime id: " << IntArrayToString(GetCachedInt32ArrayValue(
542 sender, UIA_RuntimeIdPropertyId));
543 context_runner_->PostTask(
544 FROM_HERE,
545 base::Bind(&SettingsAppMonitor::Context::HandleFocusChangedEvent,
546 context_,
547 base::win::ScopedComPtr<IUIAutomationElement>(sender)));
548
549 return S_OK;
550 }
551
552 // SettingsAppMonitor::Context -------------------------------------------------
553
554 base::WeakPtr<SettingsAppMonitor::Context>
555 SettingsAppMonitor::Context::Create() {
556 Context* context = new Context();
557 return context->weak_ptr_factory_.GetWeakPtr();
558 }
559
560 void SettingsAppMonitor::Context::DeleteOnAutomationThread() {
561 DCHECK(task_runner_->BelongsToCurrentThread());
562 delete this;
563 }
564
565 void SettingsAppMonitor::Context::Initialize(
566 base::SingleThreadTaskRunner* task_runner,
567 base::SequencedTaskRunner* monitor_runner,
568 const base::WeakPtr<SettingsAppMonitor>& monitor) {
569 // This and all other methods must be called on the automation thread.
570 DCHECK(task_runner->BelongsToCurrentThread());
571 DCHECK(!monitor_runner->RunsTasksOnCurrentThread());
572
573 task_runner_ = task_runner;
574 monitor_runner_ = monitor_runner;
575 monitor_ = monitor;
576
577 HRESULT result = automation_.CreateInstance(CLSID_CUIAutomation, nullptr,
578 CLSCTX_INPROC_SERVER);
579 if (SUCCEEDED(result))
580 result = automation_ ? InstallObservers() : E_FAIL;
581
582 // Tell the monitor that initialization is complete one way or the other.
583 monitor_runner_->PostTask(
584 FROM_HERE,
585 base::Bind(&SettingsAppMonitor::OnInitialized, monitor_, result));
586
587 // Self-destruct immediately if initialization failed to reduce overhead.
588 if (FAILED(result))
589 delete this;
590 }
591
592 SettingsAppMonitor::Context::Context() : weak_ptr_factory_(this) {}
593
594 SettingsAppMonitor::Context::~Context() {
595 DCHECK(task_runner_->BelongsToCurrentThread());
596
597 if (event_handler_) {
598 event_handler_.Release();
599 automation_->RemoveAllEventHandlers();
600 }
601 }
602
603 void SettingsAppMonitor::Context::HandleFocusChangedEvent(
604 base::win::ScopedComPtr<IUIAutomationElement> sender) {
605 DCHECK(task_runner_->BelongsToCurrentThread());
606
607 if (DetectElementType(sender.get()) == ElementType::DEFAULT_BROWSER) {
608 if (!observed_app_focused_) {
609 observed_app_focused_ = true;
610 monitor_runner_->PostTask(
611 FROM_HERE, base::Bind(&SettingsAppMonitor::OnAppFocused, monitor_));
612 }
613 } else {
614 observed_app_focused_ = false;
615 }
616 }
617
618 void SettingsAppMonitor::Context::HandleChooserInvoked() {
619 DCHECK(task_runner_->BelongsToCurrentThread());
620 monitor_runner_->PostTask(
621 FROM_HERE, base::Bind(&SettingsAppMonitor::OnChooserInvoked, monitor_));
622 }
623
624 void SettingsAppMonitor::Context::HandleBrowserChosen(
625 const base::string16& browser_name) {
626 DCHECK(task_runner_->BelongsToCurrentThread());
627 monitor_runner_->PostTask(
628 FROM_HERE,
629 base::Bind(&SettingsAppMonitor::OnBrowserChosen, monitor_, browser_name));
630 }
631
632 base::win::ScopedComPtr<IUnknown>
633 SettingsAppMonitor::Context::GetEventHandler() {
634 DCHECK(task_runner_->BelongsToCurrentThread());
635 if (!event_handler_) {
636 ATL::CComObject<EventHandler>* obj = nullptr;
637 HRESULT result = ATL::CComObject<EventHandler>::CreateInstance(&obj);
638 if (SUCCEEDED(result)) {
639 obj->Initialize(task_runner_, weak_ptr_factory_.GetWeakPtr());
640 obj->QueryInterface(event_handler_.Receive());
641 }
642 }
643 return event_handler_;
644 }
645
646 base::win::ScopedComPtr<IUIAutomationEventHandler>
647 SettingsAppMonitor::Context::GetAutomationEventHandler() {
648 DCHECK(task_runner_->BelongsToCurrentThread());
649 base::win::ScopedComPtr<IUIAutomationEventHandler> handler;
650 handler.QueryFrom(GetEventHandler().get());
651 return handler;
652 }
653
654 base::win::ScopedComPtr<IUIAutomationFocusChangedEventHandler>
655 SettingsAppMonitor::Context::GetFocusChangedEventHandler() {
656 DCHECK(task_runner_->BelongsToCurrentThread());
657 base::win::ScopedComPtr<IUIAutomationFocusChangedEventHandler> handler;
658 handler.QueryFrom(GetEventHandler().get());
659 return handler;
660 }
661
662 HRESULT SettingsAppMonitor::Context::InstallObservers() {
663 DCHECK(task_runner_->BelongsToCurrentThread());
664 DCHECK(automation_);
665
666 // Create a cache request so that elements received by way of events contain
667 // all data needed for procesing.
668 base::win::ScopedComPtr<IUIAutomationCacheRequest> cache_request;
669 HRESULT result = automation_->CreateCacheRequest(cache_request.Receive());
670 if (FAILED(result))
671 return result;
672 ConfigureCacheRequest(cache_request.get());
673
674 // Observe changes in focus.
675 result = automation_->AddFocusChangedEventHandler(
676 cache_request.get(), GetFocusChangedEventHandler().get());
677 if (FAILED(result))
678 return result;
679
680 // Observe invocations.
681 base::win::ScopedComPtr<IUIAutomationElement> desktop;
682 result = automation_->GetRootElement(desktop.Receive());
683 if (desktop) {
684 result = automation_->AddAutomationEventHandler(
685 UIA_Invoke_InvokedEventId, desktop.get(), TreeScope_Subtree,
686 cache_request.get(), GetAutomationEventHandler().get());
687 }
688
689 return result;
690 }
691
692
693 // SettingsAppMonitor ----------------------------------------------------------
694
695 SettingsAppMonitor::SettingsAppMonitor(Delegate* delegate)
696 : delegate_(delegate),
697 automation_thread_("SettingsAppMonitorAutomation"),
698 weak_ptr_factory_(this) {
699 ui::win::CreateATLModuleIfNeeded();
700 // Start the automation thread and initialize the automation client on it.
701 context_ = Context::Create();
702 automation_thread_.init_com_with_mta(true);
703 automation_thread_.Start();
704 automation_thread_.task_runner()->PostTask(
705 FROM_HERE,
706 base::Bind(&SettingsAppMonitor::Context::Initialize, context_,
707 base::Unretained(automation_thread_.task_runner().get()),
708 base::Unretained(base::SequencedTaskRunnerHandle::Get().get()),
709 weak_ptr_factory_.GetWeakPtr()));
710 }
711
712 SettingsAppMonitor::~SettingsAppMonitor() {
713 DCHECK(thread_checker_.CalledOnValidThread());
714
715 // context_ is still valid when the caller destroys the instance before the
716 // callback(s) have fired. In this case, delete the context on the automation
717 // thread before joining with it. DeleteSoon is not used because the monitor
718 // has only a WeakPtr to the context that is bound to the automation thread.
719 automation_thread_.task_runner()->PostTask(
720 FROM_HERE,
721 base::Bind(&SettingsAppMonitor::Context::DeleteOnAutomationThread,
722 context_));
723 }
724
725 void SettingsAppMonitor::OnInitialized(HRESULT result) {
726 DCHECK(thread_checker_.CalledOnValidThread());
727 delegate_->OnInitialized(result);
728 }
729
730 void SettingsAppMonitor::OnAppFocused() {
731 DCHECK(thread_checker_.CalledOnValidThread());
732 delegate_->OnAppFocused();
733 }
734
735 void SettingsAppMonitor::OnChooserInvoked() {
736 DCHECK(thread_checker_.CalledOnValidThread());
737 delegate_->OnChooserInvoked();
738 }
739
740 void SettingsAppMonitor::OnBrowserChosen(const base::string16& browser_name) {
741 DCHECK(thread_checker_.CalledOnValidThread());
742 delegate_->OnBrowserChosen(browser_name);
743 }
744
745 } // namespace win
746 } // namespace shell_integration
OLDNEW
« no previous file with comments | « chrome/browser/win/settings_app_monitor.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698