forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reland "Add the LaunchUninstallFlow() function"
This is a reland of 5e06564 Original change's description: > Add the LaunchUninstallFlow() function > > This function uses automation to automatically write the name of a > program into the search box of the Apps & Features page. > > Bug: 717696 > Change-Id: Ifc6a1be295a3d06ac33f394dcf3fc4688bd4a907 > Reviewed-on: https://chromium-review.googlesource.com/907590 > Reviewed-by: Demetrios Papadopoulos <dpapad@chromium.org> > Reviewed-by: Greg Thompson <grt@chromium.org> > Commit-Queue: Patrick Monette <pmonette@chromium.org> > Cr-Commit-Position: refs/heads/master@{#540209} TBR: grt@chromium.org, dpapad@chromium.org Bug: 717696 Change-Id: I9048a36c52113311496abe5d2d5d1ac3fe3c79fc Reviewed-on: https://chromium-review.googlesource.com/944202 Reviewed-by: Patrick Monette <pmonette@chromium.org> Commit-Queue: Patrick Monette <pmonette@chromium.org> Cr-Commit-Position: refs/heads/master@{#540296}
- Loading branch information
1 parent
6151dae
commit 10fd49a
Showing
7 changed files
with
283 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
// Copyright 2018 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "chrome/browser/conflicts/uninstall_application_win.h" | ||
|
||
#include <atlbase.h> | ||
#include <wrl/client.h> | ||
|
||
#include <memory> | ||
#include <utility> | ||
|
||
#include "base/bind.h" | ||
#include "base/callback.h" | ||
#include "base/location.h" | ||
#include "base/macros.h" | ||
#include "base/memory/ref_counted.h" | ||
#include "base/memory/weak_ptr.h" | ||
#include "base/sequenced_task_runner.h" | ||
#include "base/single_thread_task_runner.h" | ||
#include "base/strings/pattern.h" | ||
#include "base/strings/string_util.h" | ||
#include "base/threading/sequenced_task_runner_handle.h" | ||
#include "base/win/scoped_variant.h" | ||
#include "chrome/browser/win/automation_controller.h" | ||
#include "chrome/browser/win/ui_automation_util.h" | ||
#include "chrome/installer/util/shell_util.h" | ||
|
||
namespace uninstall_application { | ||
|
||
namespace { | ||
|
||
bool FindSearchBoxElement(IUIAutomation* automation, | ||
IUIAutomationElement* sender, | ||
IUIAutomationElement** search_box) { | ||
// Create a condition that will include only elements with the right | ||
// automation id in the tree walker. | ||
base::win::ScopedVariant search_box_id( | ||
L"SystemSettings_StorageSense_AppSizesListFilter_DisplayStringValue"); | ||
Microsoft::WRL::ComPtr<IUIAutomationCondition> condition; | ||
HRESULT result = automation->CreatePropertyCondition( | ||
UIA_AutomationIdPropertyId, search_box_id, condition.GetAddressOf()); | ||
if (FAILED(result)) | ||
return false; | ||
|
||
Microsoft::WRL::ComPtr<IUIAutomationTreeWalker> tree_walker; | ||
result = | ||
automation->CreateTreeWalker(condition.Get(), tree_walker.GetAddressOf()); | ||
if (FAILED(result)) | ||
return false; | ||
|
||
// Setup a cache request so that the element contains the needed property | ||
// afterwards. | ||
Microsoft::WRL::ComPtr<IUIAutomationCacheRequest> cache_request; | ||
result = automation->CreateCacheRequest(cache_request.GetAddressOf()); | ||
if (FAILED(result)) | ||
return false; | ||
cache_request->AddPattern(UIA_ValuePatternId); | ||
|
||
result = tree_walker->GetNextSiblingElementBuildCache( | ||
sender, cache_request.Get(), search_box); | ||
return SUCCEEDED(result) && *search_box; | ||
} | ||
|
||
// UninstallAppController ------------------------------------------------------ | ||
|
||
class UninstallAppController { | ||
public: | ||
// Launches the Apps & Features page, ensuring the |application_name| is | ||
// written into the search box. | ||
static void Launch(const base::string16& application_name); | ||
|
||
private: | ||
class AutomationControllerDelegate; | ||
|
||
// The unique instance of this class. | ||
static UninstallAppController* instance_; | ||
|
||
explicit UninstallAppController(const base::string16& application_name); | ||
~UninstallAppController(); | ||
|
||
void OnUninstallFinished(); | ||
|
||
// Allows the use of the UI Automation API. | ||
std::unique_ptr<AutomationController> automation_controller_; | ||
|
||
base::WeakPtrFactory<UninstallAppController> weak_ptr_factory_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(UninstallAppController); | ||
}; | ||
|
||
// static | ||
UninstallAppController* UninstallAppController::instance_ = nullptr; | ||
|
||
// static | ||
void UninstallAppController::Launch(const base::string16& application_name) { | ||
// If an instance already exists, the previous controller is deleted to make | ||
// sure it doesn't interfere with the current call. | ||
delete instance_; | ||
|
||
// The instance handles its own lifetime. | ||
instance_ = new UninstallAppController(application_name); | ||
} | ||
|
||
UninstallAppController::UninstallAppController( | ||
const base::string16& application_name) | ||
: weak_ptr_factory_(this) { | ||
auto automation_controller_delegate = | ||
std::make_unique<AutomationControllerDelegate>( | ||
base::SequencedTaskRunnerHandle::Get(), | ||
base::BindOnce(&UninstallAppController::OnUninstallFinished, | ||
weak_ptr_factory_.GetWeakPtr()), | ||
application_name); | ||
|
||
automation_controller_ = std::make_unique<AutomationController>( | ||
std::move(automation_controller_delegate)); | ||
} | ||
|
||
UninstallAppController::~UninstallAppController() = default; | ||
|
||
void UninstallAppController::OnUninstallFinished() { | ||
DCHECK_EQ(this, instance_); | ||
|
||
delete this; | ||
instance_ = nullptr; | ||
} | ||
|
||
// UninstallAppController::AutomationControllerDelegate ------------------------ | ||
|
||
class UninstallAppController::AutomationControllerDelegate | ||
: public AutomationController::Delegate { | ||
public: | ||
AutomationControllerDelegate( | ||
scoped_refptr<base::SequencedTaskRunner> controller_runner, | ||
base::OnceClosure on_automation_finished, | ||
const base::string16& application_name); | ||
~AutomationControllerDelegate() override; | ||
|
||
// AutomationController::Delegate: | ||
void OnInitialized(HRESULT result) const override; | ||
void ConfigureCacheRequest( | ||
IUIAutomationCacheRequest* cache_request) const override; | ||
void OnAutomationEvent(IUIAutomation* automation, | ||
IUIAutomationElement* sender, | ||
EVENTID event_id) const override; | ||
void OnFocusChangedEvent(IUIAutomation* automation, | ||
IUIAutomationElement* sender) const override; | ||
|
||
private: | ||
// The task runner on which the UninstallAppController lives. | ||
scoped_refptr<base::SequencedTaskRunner> controller_runner_; | ||
|
||
// Called once when the automation work is done. Only used by | ||
// OnFocusChangedEvent(). | ||
mutable base::OnceClosure on_automation_finished_; | ||
|
||
const base::string16 application_name_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(AutomationControllerDelegate); | ||
}; | ||
|
||
UninstallAppController::AutomationControllerDelegate:: | ||
AutomationControllerDelegate( | ||
scoped_refptr<base::SequencedTaskRunner> controller_runner, | ||
base::OnceClosure on_automation_finished, | ||
const base::string16& application_name) | ||
: controller_runner_(std::move(controller_runner)), | ||
on_automation_finished_(std::move(on_automation_finished)), | ||
application_name_(application_name) {} | ||
|
||
UninstallAppController::AutomationControllerDelegate:: | ||
~AutomationControllerDelegate() = default; | ||
|
||
void UninstallAppController::AutomationControllerDelegate::OnInitialized( | ||
HRESULT result) const { | ||
// Launch the Apps & Features settings page regardless of the |result| of the | ||
// initialization. An initialization failure only means that the application | ||
// will not be written into the search box. | ||
ShellUtil::LaunchUninstallAppsSettings(); | ||
} | ||
|
||
void UninstallAppController::AutomationControllerDelegate:: | ||
ConfigureCacheRequest(IUIAutomationCacheRequest* cache_request) const { | ||
cache_request->AddPattern(UIA_ValuePatternId); | ||
cache_request->AddProperty(UIA_AutomationIdPropertyId); | ||
cache_request->AddProperty(UIA_IsWindowPatternAvailablePropertyId); | ||
} | ||
|
||
void UninstallAppController::AutomationControllerDelegate::OnAutomationEvent( | ||
IUIAutomation* automation, | ||
IUIAutomationElement* sender, | ||
EVENTID event_id) const {} | ||
|
||
void UninstallAppController::AutomationControllerDelegate::OnFocusChangedEvent( | ||
IUIAutomation* automation, | ||
IUIAutomationElement* sender) const { | ||
base::string16 combo_box_id( | ||
GetCachedBstrValue(sender, UIA_AutomationIdPropertyId)); | ||
if (combo_box_id != L"SystemSettings_AppsFeatures_AppControl_ComboBox") | ||
return; | ||
|
||
Microsoft::WRL::ComPtr<IUIAutomationElement> search_box; | ||
if (!FindSearchBoxElement(automation, sender, search_box.GetAddressOf())) | ||
return; | ||
|
||
Microsoft::WRL::ComPtr<IUIAutomationValuePattern> value_pattern; | ||
HRESULT result = search_box->GetCachedPatternAs( | ||
UIA_ValuePatternId, IID_PPV_ARGS(value_pattern.GetAddressOf())); | ||
if (FAILED(result)) | ||
return; | ||
|
||
CComBSTR bstr(application_name_.c_str()); | ||
value_pattern->SetValue(bstr); | ||
|
||
controller_runner_->PostTask(FROM_HERE, std::move(on_automation_finished_)); | ||
} | ||
|
||
} // namespace | ||
|
||
void LaunchUninstallFlow(const base::string16& application_name) { | ||
UninstallAppController::Launch(application_name); | ||
} | ||
|
||
} // namespace uninstall_application |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Copyright 2018 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CHROME_BROWSER_CONFLICTS_UNINSTALL_APPLICATION_WIN_H_ | ||
#define CHROME_BROWSER_CONFLICTS_UNINSTALL_APPLICATION_WIN_H_ | ||
|
||
#include "base/strings/string16.h" | ||
|
||
namespace uninstall_application { | ||
|
||
// Uses UI automation to asynchronously open the Apps & Features page with the | ||
// application name written in the search box, to filter out other applications. | ||
void LaunchUninstallFlow(const base::string16& application_name); | ||
|
||
} // namespace uninstall_application | ||
|
||
#endif // CHROME_BROWSER_CONFLICTS_UNINSTALL_APPLICATION_WIN_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters