Commit dbb74eaa authored by calamity@chromium.org's avatar calamity@chromium.org

Support "Pin to taskbar" for hosted app windows.

This CL allows hosted app windows to be pinned to the taskbar by
right-clicking the taskbar icon and pressing the "Pin to taskbar" button.

This CL pulls out the code that sets the relaunch details of v2 app
windows into web::UpdateRelaunchDetails.

BUG=368101
TEST=Run a hosted app as a window. Pin it from the taskbar icon right click
menu. Relaunch the app from the pinned icon.

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=272851

Review URL: https://codereview.chromium.org/258243002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272923 0039d316-1c4b-4281-b951-d872f2087c98
parent 693274b9
...@@ -35,42 +35,6 @@ ...@@ -35,42 +35,6 @@
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/win/hwnd_util.h" #include "ui/views/win/hwnd_util.h"
namespace {
void CreateIconAndSetRelaunchDetails(
const base::FilePath& web_app_path,
const base::FilePath& icon_file,
const web_app::ShortcutInfo& shortcut_info,
const HWND hwnd) {
DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
// Set the relaunch data so "Pin this program to taskbar" has the app's
// information.
CommandLine command_line = ShellIntegration::CommandLineArgsForLauncher(
shortcut_info.url,
shortcut_info.extension_id,
shortcut_info.profile_path);
base::FilePath chrome_exe;
if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
NOTREACHED();
return;
}
command_line.SetProgram(chrome_exe);
ui::win::SetRelaunchDetailsForWindow(command_line.GetCommandLineString(),
shortcut_info.title, hwnd);
if (!base::PathExists(web_app_path) &&
!base::CreateDirectory(web_app_path)) {
return;
}
ui::win::SetAppIconForWindow(icon_file.value(), hwnd);
web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon);
}
} // namespace
ChromeNativeAppWindowViewsWin::ChromeNativeAppWindowViewsWin() ChromeNativeAppWindowViewsWin::ChromeNativeAppWindowViewsWin()
: weak_ptr_factory_(this), glass_frame_view_(NULL) { : weak_ptr_factory_(this), glass_frame_view_(NULL) {
} }
...@@ -92,27 +56,6 @@ void ChromeNativeAppWindowViewsWin::ActivateParentDesktopIfNecessary() { ...@@ -92,27 +56,6 @@ void ChromeNativeAppWindowViewsWin::ActivateParentDesktopIfNecessary() {
} }
} }
void ChromeNativeAppWindowViewsWin::OnShortcutInfoLoaded(
const web_app::ShortcutInfo& shortcut_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
HWND hwnd = GetNativeAppWindowHWND();
// Set window's icon to the one we're about to create/update in the web app
// path. The icon cache will refresh on icon creation.
base::FilePath web_app_path = web_app::GetWebAppDataDirectory(
shortcut_info.profile_path, shortcut_info.extension_id,
shortcut_info.url);
base::FilePath icon_file = web_app_path
.Append(web_app::internals::GetSanitizedFileName(shortcut_info.title))
.ReplaceExtension(FILE_PATH_LITERAL(".ico"));
content::BrowserThread::PostBlockingPoolTask(
FROM_HERE,
base::Bind(&CreateIconAndSetRelaunchDetails,
web_app_path, icon_file, shortcut_info, hwnd));
}
HWND ChromeNativeAppWindowViewsWin::GetNativeAppWindowHWND() const { HWND ChromeNativeAppWindowViewsWin::GetNativeAppWindowHWND() const {
return views::HWNDForWidget(widget()->GetTopLevelWidget()); return views::HWNDForWidget(widget()->GetTopLevelWidget());
} }
...@@ -176,11 +119,7 @@ void ChromeNativeAppWindowViewsWin::InitializeDefaultWindow( ...@@ -176,11 +119,7 @@ void ChromeNativeAppWindowViewsWin::InitializeDefaultWindow(
profile->GetPath()); profile->GetPath());
ui::win::SetAppIdForWindow(app_model_id_, hwnd); ui::win::SetAppIdForWindow(app_model_id_, hwnd);
web_app::UpdateShortcutInfoAndIconForApp( web_app::UpdateRelaunchDetailsForApp(profile, extension, hwnd);
extension,
profile,
base::Bind(&ChromeNativeAppWindowViewsWin::OnShortcutInfoLoaded,
weak_ptr_factory_.GetWeakPtr()));
if (!create_params.transparent_background) if (!create_params.transparent_background)
EnsureCaptionStyleSet(); EnsureCaptionStyleSet();
......
...@@ -15,20 +15,30 @@ ...@@ -15,20 +15,30 @@
#include "base/win/scoped_propvariant.h" #include "base/win/scoped_propvariant.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_shortcut_manager_win.h" #include "chrome/browser/profiles/profile_shortcut_manager_win.h"
#include "chrome/browser/profiles/profiles_state.h" #include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_iterator.h"
#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_win.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/browser_distribution.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/test_switches.h" #include "chrome/test/base/test_switches.h"
#include "content/public/test/test_utils.h" #include "content/public/test/test_utils.h"
#include "extensions/common/extension.h"
#include "ui/views/win/hwnd_util.h" #include "ui/views/win/hwnd_util.h"
typedef ExtensionBrowserTest BrowserWindowPropertyManagerTest;
namespace { namespace {
// An observer that resumes test code after a new profile is initialized by // An observer that resumes test code after a new profile is initialized by
...@@ -85,6 +95,50 @@ void ValidateBrowserWindowProperties( ...@@ -85,6 +95,50 @@ void ValidateBrowserWindowProperties(
base::MessageLoop::current()->Quit(); base::MessageLoop::current()->Quit();
} }
void ValidateHostedAppWindowProperties(const Browser* browser,
const extensions::Extension* extension) {
HWND hwnd = views::HWNDForNativeWindow(browser->window()->GetNativeWindow());
base::win::ScopedComPtr<IPropertyStore> pps;
HRESULT result =
SHGetPropertyStoreForWindow(hwnd, IID_IPropertyStore, pps.ReceiveVoid());
EXPECT_TRUE(SUCCEEDED(result));
base::win::ScopedPropVariant prop_var;
// The relaunch name should be the extension name.
EXPECT_EQ(S_OK,
pps->GetValue(PKEY_AppUserModel_RelaunchDisplayNameResource,
prop_var.Receive()));
EXPECT_EQ(VT_LPWSTR, prop_var.get().vt);
EXPECT_EQ(base::UTF8ToWide(extension->name()), prop_var.get().pwszVal);
prop_var.Reset();
// The relaunch command should specify the profile and the app id.
EXPECT_EQ(
S_OK,
pps->GetValue(PKEY_AppUserModel_RelaunchCommand, prop_var.Receive()));
EXPECT_EQ(VT_LPWSTR, prop_var.get().vt);
CommandLine cmd_line(CommandLine::FromString(prop_var.get().pwszVal));
EXPECT_EQ(browser->profile()->GetPath().BaseName().value(),
cmd_line.GetSwitchValueNative(switches::kProfileDirectory));
EXPECT_EQ(base::UTF8ToWide(extension->id()),
cmd_line.GetSwitchValueNative(switches::kAppId));
prop_var.Reset();
// The app icon should be set to the extension app icon.
base::FilePath web_app_dir = web_app::GetWebAppDataDirectory(
browser->profile()->GetPath(), extension->id(), GURL());
EXPECT_EQ(S_OK,
pps->GetValue(PKEY_AppUserModel_RelaunchIconResource,
prop_var.Receive()));
EXPECT_EQ(VT_LPWSTR, prop_var.get().vt);
EXPECT_EQ(web_app::internals::GetIconFilePath(
web_app_dir, base::UTF8ToUTF16(extension->name())).value(),
prop_var.get().pwszVal);
prop_var.Reset();
base::MessageLoop::current()->Quit();
}
void PostValidationTaskToUIThread(const base::Closure& validation_task) { void PostValidationTaskToUIThread(const base::Closure& validation_task) {
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE, validation_task); content::BrowserThread::UI, FROM_HERE, validation_task);
...@@ -171,3 +225,43 @@ IN_PROC_BROWSER_TEST_F(BrowserTestWithProfileShortcutManager, ...@@ -171,3 +225,43 @@ IN_PROC_BROWSER_TEST_F(BrowserTestWithProfileShortcutManager,
profile2_browser, profile2_browser,
cache.GetNameOfProfileAtIndex(profile2_index))); cache.GetNameOfProfileAtIndex(profile2_index)));
} }
IN_PROC_BROWSER_TEST_F(BrowserWindowPropertyManagerTest, HostedApp) {
#if defined(USE_ASH)
// Disable this test in Metro+Ash where Windows window properties aren't used.
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
return;
#endif
// This test checks HWND properties that are only available on Win7+.
if (base::win::GetVersion() < base::win::VERSION_WIN7)
return;
// Load an app.
const extensions::Extension* extension =
LoadExtension(test_data_dir_.AppendASCII("app/"));
EXPECT_TRUE(extension);
OpenApplication(AppLaunchParams(browser()->profile(),
extension,
extensions::LAUNCH_CONTAINER_WINDOW,
NEW_FOREGROUND_TAB));
// Check that the new browser has an app name.
// The launch should have created a new browser.
ASSERT_EQ(2u,
chrome::GetBrowserCount(browser()->profile(),
browser()->host_desktop_type()));
// Find the new browser.
Browser* app_browser = NULL;
for (chrome::BrowserIterator it; !it.done() && !app_browser; it.Next()) {
if (*it != browser())
app_browser = *it;
}
ASSERT_TRUE(app_browser);
ASSERT_TRUE(app_browser != browser());
WaitAndValidateBrowserWindowProperties(
base::Bind(&ValidateHostedAppWindowProperties, app_browser, extension));
}
...@@ -15,10 +15,15 @@ ...@@ -15,10 +15,15 @@
#include "chrome/browser/shell_integration.h" #include "chrome/browser/shell_integration.h"
#include "chrome/browser/ui/host_desktop.h" #include "chrome/browser/ui/host_desktop.h"
#include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_win.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "extensions/browser/extension_registry.h"
#include "ui/base/win/shell.h" #include "ui/base/win/shell.h"
#include "ui/views/win/hwnd_util.h" #include "ui/views/win/hwnd_util.h"
using extensions::ExtensionRegistry;
BrowserWindowPropertyManager::BrowserWindowPropertyManager(BrowserView* view) BrowserWindowPropertyManager::BrowserWindowPropertyManager(BrowserView* view)
: view_(view) { : view_(view) {
DCHECK(view_); DCHECK(view_);
...@@ -53,6 +58,19 @@ void BrowserWindowPropertyManager::UpdateWindowProperties(HWND hwnd) { ...@@ -53,6 +58,19 @@ void BrowserWindowPropertyManager::UpdateWindowProperties(HWND hwnd) {
ProfileManager* profile_manager = g_browser_process->profile_manager(); ProfileManager* profile_manager = g_browser_process->profile_manager();
ProfileShortcutManager* shortcut_manager = NULL; ProfileShortcutManager* shortcut_manager = NULL;
// Apps set their relaunch details based on app's details.
if (browser->is_app()) {
ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
const extensions::Extension* extension = registry->GetExtensionById(
web_app::GetExtensionIdFromApplicationName(browser->app_name()),
ExtensionRegistry::EVERYTHING);
if (extension) {
ui::win::SetAppIdForWindow(app_id, hwnd);
web_app::UpdateRelaunchDetailsForApp(profile, extension, hwnd);
return;
}
}
// The profile manager may be NULL in testing. // The profile manager may be NULL in testing.
if (profile_manager) if (profile_manager)
shortcut_manager = profile_manager->profile_shortcut_manager(); shortcut_manager = profile_manager->profile_shortcut_manager();
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "chrome/installer/util/shell_util.h" #include "chrome/installer/util/shell_util.h"
#include "chrome/installer/util/util_constants.h" #include "chrome/installer/util/util_constants.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "ui/base/win/shell.h"
#include "ui/gfx/icon_util.h" #include "ui/gfx/icon_util.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_family.h" #include "ui/gfx/image/image_family.h"
...@@ -323,6 +324,58 @@ void GetShortcutLocationsAndDeleteShortcuts( ...@@ -323,6 +324,58 @@ void GetShortcutLocationsAndDeleteShortcuts(
} }
} }
void CreateIconAndSetRelaunchDetails(const base::FilePath& web_app_path,
const base::FilePath& icon_file,
const web_app::ShortcutInfo& shortcut_info,
HWND hwnd) {
DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
CommandLine command_line =
ShellIntegration::CommandLineArgsForLauncher(shortcut_info.url,
shortcut_info.extension_id,
shortcut_info.profile_path);
base::FilePath chrome_exe;
if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
NOTREACHED();
return;
}
command_line.SetProgram(chrome_exe);
ui::win::SetRelaunchDetailsForWindow(
command_line.GetCommandLineString(), shortcut_info.title, hwnd);
if (!base::PathExists(web_app_path) && !base::CreateDirectory(web_app_path))
return;
ui::win::SetAppIconForWindow(icon_file.value(), hwnd);
web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon);
}
void OnShortcutInfoLoadedForSetRelaunchDetails(
HWND hwnd,
const web_app::ShortcutInfo& shortcut_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Set window's icon to the one we're about to create/update in the web app
// path. The icon cache will refresh on icon creation.
base::FilePath web_app_path =
web_app::GetWebAppDataDirectory(shortcut_info.profile_path,
shortcut_info.extension_id,
shortcut_info.url);
base::FilePath icon_file =
web_app_path.Append(web_app::internals::GetSanitizedFileName(
shortcut_info.title))
.ReplaceExtension(FILE_PATH_LITERAL(".ico"));
content::BrowserThread::PostBlockingPoolTask(
FROM_HERE,
base::Bind(&CreateIconAndSetRelaunchDetails,
web_app_path,
icon_file,
shortcut_info,
hwnd));
}
} // namespace } // namespace
namespace web_app { namespace web_app {
...@@ -351,6 +404,15 @@ base::FilePath CreateShortcutInWebAppDir(const base::FilePath& web_app_dir, ...@@ -351,6 +404,15 @@ base::FilePath CreateShortcutInWebAppDir(const base::FilePath& web_app_dir,
return web_app_dir_shortcut; return web_app_dir_shortcut;
} }
void UpdateRelaunchDetailsForApp(Profile* profile,
const extensions::Extension* extension,
HWND hwnd) {
web_app::UpdateShortcutInfoAndIconForApp(
extension,
profile,
base::Bind(&OnShortcutInfoLoadedForSetRelaunchDetails, hwnd));
}
namespace internals { namespace internals {
// Saves |image| to |icon_file| if the file is outdated and refresh shell's // Saves |image| to |icon_file| if the file is outdated and refresh shell's
......
...@@ -8,10 +8,16 @@ ...@@ -8,10 +8,16 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app.h"
class Profile;
namespace content { namespace content {
class WebContents; class WebContents;
} }
namespace extensions {
class Extension;
}
namespace gfx { namespace gfx {
class ImageFamily; class ImageFamily;
} }
...@@ -23,6 +29,12 @@ namespace web_app { ...@@ -23,6 +29,12 @@ namespace web_app {
base::FilePath CreateShortcutInWebAppDir(const base::FilePath& web_app_path, base::FilePath CreateShortcutInWebAppDir(const base::FilePath& web_app_path,
const ShortcutInfo& shortcut_info); const ShortcutInfo& shortcut_info);
// Update the relaunch details for the given app's window, making the taskbar
// group's "Pin to the taskbar" button function correctly.
void UpdateRelaunchDetailsForApp(Profile* profile,
const extensions::Extension* extension,
HWND hwnd);
namespace internals { namespace internals {
bool CheckAndSaveIcon(const base::FilePath& icon_file, bool CheckAndSaveIcon(const base::FilePath& icon_file,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment