diff options
author | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-04 22:12:49 +0000 |
---|---|---|
committer | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-04 22:12:49 +0000 |
commit | cbe224d9ac80770b08f36035505358c397431e4b (patch) | |
tree | ec40d89290fd2deb5764c04d0d881880e3cab1c3 | |
parent | 52e3f6aeeb805db5051f33f9fdf79671dbe839bc (diff) | |
download | chromium_src-cbe224d9ac80770b08f36035505358c397431e4b.zip chromium_src-cbe224d9ac80770b08f36035505358c397431e4b.tar.gz chromium_src-cbe224d9ac80770b08f36035505358c397431e4b.tar.bz2 |
Add a flag that lets the webstore show a different UI on app install.
When people install apps, they seem to get confused about how to launch them.
We want to experiment with a different UI after install, that instead of
immediately transitioning to the New Tab Page, instead shows a bubble pointing
at the New Tab button on the tabstrip with a "show me" link which will open a
new tab and animate the app icon showing up there.
This CL has the views implementation - OSX and GTK implementations will come in
a separate CL.
BUG=89687
TEST=Requires webstore changes to fully test (the CL includes an automated
browser test)
Review URL: http://codereview.chromium.org/7529011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@95514 0039d316-1c4b-4281-b951-d872f2087c98
24 files changed, 225 insertions, 45 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 434a4ca..6570e4d 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -3879,6 +3879,10 @@ are declared in build/common.gypi. <ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph> is now installed. </message> + <message name="IDS_EXTENSION_INSTALLED_APP_INFO" desc="Text displayed inside a link when an app is installed. Clicking this link opens up the New Tab Page to show the app's icon."> + Show me + </message> + <message name="IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO" desc="Text displayed in the InfoBubble which explains that the UI of this extension is a Page Action icon which may appear for some pages."> This icon will be visible when the extension can act on the current page. </message> @@ -4310,6 +4314,12 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_DESCRIPTION" desc="Description of the 'Experimental Extension APIs' lab."> Enables experimental extension APIs. Note that the extension gallery doesn't allow you to upload extensions that use experimental APIs. </message> + <message name="IDS_FLAGS_APPS_NEW_INSTALL_BUBBLE_NAME" desc="Name of the 'New Apps Install Bubble' lab"> + New Apps Install Bubble + </message> + <message name="IDS_FLAGS_APPS_NEW_INSTALL_BUBBLE_DESCRIPTION" desc="Description of the 'New Apps Install Bubble' lab"> + When installing an app, always show a bubble pointing at the new tab page button on the tabstrip instead of opening a new tab page. + </message> <message name="IDS_FLAGS_CLICK_TO_PLAY_NAME" desc="Name of the 'Click to play' lab."> Click to play </message> diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 5181032..2828e70 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc @@ -188,6 +188,13 @@ const Experiment kExperiments[] = { SINGLE_VALUE_TYPE(switches::kEnableExperimentalExtensionApis) }, { + "apps-new-install-bubble", + IDS_FLAGS_APPS_NEW_INSTALL_BUBBLE_NAME, + IDS_FLAGS_APPS_NEW_INSTALL_BUBBLE_DESCRIPTION, + kOsAll, + SINGLE_VALUE_TYPE(switches::kAppsNewInstallBubble) + }, + { "click-to-play", // FLAGS:RECORD_UMA IDS_FLAGS_CLICK_TO_PLAY_NAME, IDS_FLAGS_CLICK_TO_PLAY_DESCRIPTION, diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc index c28c5e4..e5a008f 100644 --- a/chrome/browser/extensions/crx_installer.cc +++ b/chrome/browser/extensions/crx_installer.cc @@ -52,7 +52,8 @@ static base::LazyInstance<Whitelist> } // namespace -CrxInstaller::WhitelistEntry::WhitelistEntry() {} +CrxInstaller::WhitelistEntry::WhitelistEntry() + : use_app_installed_bubble(false) {} CrxInstaller::WhitelistEntry::~WhitelistEntry() {} // static @@ -406,6 +407,8 @@ void CrxInstaller::ConfirmInstall() { return; } whitelisted = true; + if (entry->use_app_installed_bubble) + client_->set_use_app_installed_bubble(true); } if (client_ && diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h index 171105b..1db8104 100644 --- a/chrome/browser/extensions/crx_installer.h +++ b/chrome/browser/extensions/crx_installer.h @@ -61,6 +61,10 @@ class CrxInstaller scoped_ptr<base::DictionaryValue> parsed_manifest; std::string localized_name; + + // Whether to use a bubble notification when an app is installed, instead of + // the default behavior of transitioning to the new tab page. + bool use_app_installed_bubble; }; // Exempt the next extension install with |id| from displaying a confirmation diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc index bdbd839..dc9a6a90 100644 --- a/chrome/browser/extensions/extension_install_ui.cc +++ b/chrome/browser/extensions/extension_install_ui.cc @@ -25,6 +25,7 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/chrome_notification_types.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_icon_set.h" #include "chrome/common/extensions/extension_resource.h" @@ -88,10 +89,8 @@ void ShowAppInstalledAnimation(Browser* browser, const std::string& app_id) { } } - // If there isn't an NTP, open one and pass it the ID of the installed app. - std::string url = base::StringPrintf( - "%s#app-id=%s", chrome::kChromeUINewTabURL, app_id.c_str()); - browser->AddSelectedTabWithURL(GURL(url), PageTransition::TYPED); + // If there isn't an NTP, open one. + ExtensionInstallUI::OpenAppInstalledNTP(browser, app_id); } } // namespace @@ -103,7 +102,8 @@ ExtensionInstallUI::ExtensionInstallUI(Profile* profile) extension_(NULL), delegate_(NULL), prompt_type_(NUM_PROMPT_TYPES), - ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) { + ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)), + use_app_installed_bubble_(false) { // Remember the current theme in case the user presses undo. if (profile_) { const Extension* previous_theme = @@ -177,7 +177,15 @@ void ExtensionInstallUI::OnInstallSuccess(const Extension* extension, browser->AddBlankTab(true); browser->window()->Show(); - if (extension->GetFullLaunchURL().is_valid()) { + bool use_bubble_for_apps = false; + +#if defined(TOOLKIT_VIEWS) + CommandLine* cmdline = CommandLine::ForCurrentProcess(); + use_bubble_for_apps = (use_app_installed_bubble_ || + cmdline->HasSwitch(switches::kAppsNewInstallBubble)); +#endif + + if (extension->is_app() && !use_bubble_for_apps) { ShowAppInstalledAnimation(browser, extension->id()); return; } @@ -240,6 +248,14 @@ void ExtensionInstallUI::OnImageLoaded( } // static +void ExtensionInstallUI::OpenAppInstalledNTP(Browser* browser, + const std::string& app_id) { + std::string url = base::StringPrintf( + "%s#app-id=%s", chrome::kChromeUINewTabURL, app_id.c_str()); + browser->AddSelectedTabWithURL(GURL(url), PageTransition::TYPED); +} + +// static void ExtensionInstallUI::DisableFailureUIForTests() { disable_failure_ui_for_tests = true; } diff --git a/chrome/browser/extensions/extension_install_ui.h b/chrome/browser/extensions/extension_install_ui.h index 19965e5..4ce5720 100644 --- a/chrome/browser/extensions/extension_install_ui.h +++ b/chrome/browser/extensions/extension_install_ui.h @@ -15,6 +15,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/native_widget_types.h" +class Browser; class Extension; class ExtensionPermissionSet; class MessageLoop; @@ -56,6 +57,14 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer { explicit ExtensionInstallUI(Profile* profile); virtual ~ExtensionInstallUI(); + // TODO(asargent) Normally we navigate to the new tab page when an app is + // installed, but we're experimenting with instead showing a bubble when + // an app is installed which points to the new tab button. This may become + // the default behavior in the future. + void set_use_app_installed_bubble(bool use_bubble) { + use_app_installed_bubble_ = use_bubble; + } + // This is called by the installer to verify whether the installation should // proceed. This is declared virtual for testing. // @@ -86,6 +95,10 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer { virtual void OnImageLoaded( SkBitmap* image, const ExtensionResource& resource, int index); + // Opens a new tab page and animates the app icon for the app with id + // |app_id|. + static void OpenAppInstalledNTP(Browser* browser, const std::string& app_id); + protected: friend class ExtensionWebstorePrivateApiTest; @@ -145,6 +158,10 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer { // Keeps track of extension images being loaded on the File thread for the // purpose of showing the install UI. ImageLoadingTracker tracker_; + + // Whether to show an installed bubble on app install, or use the default + // action of opening a new tab page. + bool use_app_installed_bubble_; }; #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_UI_H_ diff --git a/chrome/browser/extensions/extension_webstore_private_api.cc b/chrome/browser/extensions/extension_webstore_private_api.cc index 8276e81..0f56c34 100644 --- a/chrome/browser/extensions/extension_webstore_private_api.cc +++ b/chrome/browser/extensions/extension_webstore_private_api.cc @@ -37,6 +37,7 @@ namespace { +const char kAppInstallBubbleKey[] = "appInstallBubble"; const char kIconDataKey[] = "iconData"; const char kIdKey[] = "id"; const char kLocalizedNameKey[] = "localizedName"; @@ -293,7 +294,8 @@ class SafeBeginInstallHelper : public UtilityProcessHost::Client { BeginInstallWithManifestFunction::ResultCode parse_error_; }; -BeginInstallWithManifestFunction::BeginInstallWithManifestFunction() {} +BeginInstallWithManifestFunction::BeginInstallWithManifestFunction() + : use_app_installed_bubble_(false) {} BeginInstallWithManifestFunction::~BeginInstallWithManifestFunction() {} @@ -329,6 +331,10 @@ bool BeginInstallWithManifestFunction::RunImpl() { EXTENSION_FUNCTION_VALIDATE(details->GetString(kLocalizedNameKey, &localized_name_)); + if (details->HasKey(kAppInstallBubbleKey)) + EXTENSION_FUNCTION_VALIDATE(details->GetBoolean( + kAppInstallBubbleKey, &use_app_installed_bubble_)); + scoped_refptr<SafeBeginInstallHelper> helper = new SafeBeginInstallHelper(this, icon_data_, manifest_); // The helper will call us back via OnParseSucces or OnParseFailure. @@ -451,6 +457,7 @@ void BeginInstallWithManifestFunction::InstallUIProceed() { CrxInstaller::WhitelistEntry* entry = new CrxInstaller::WhitelistEntry; entry->parsed_manifest.reset(parsed_manifest_.release()); entry->localized_name = localized_name_; + entry->use_app_installed_bubble = use_app_installed_bubble_; CrxInstaller::SetWhitelistEntry(id_, entry); SetResult(ERROR_NONE); SendResponse(true); diff --git a/chrome/browser/extensions/extension_webstore_private_api.h b/chrome/browser/extensions/extension_webstore_private_api.h index 19eec7a..081e6b7 100644 --- a/chrome/browser/extensions/extension_webstore_private_api.h +++ b/chrome/browser/extensions/extension_webstore_private_api.h @@ -108,6 +108,7 @@ class BeginInstallWithManifestFunction : public AsyncExtensionFunction, std::string manifest_; std::string icon_data_; std::string localized_name_; + bool use_app_installed_bubble_; // The results of parsing manifest_ and icon_data_ go into these two. scoped_ptr<base::DictionaryValue> parsed_manifest_; diff --git a/chrome/browser/extensions/extension_webstore_private_apitest.cc b/chrome/browser/extensions/extension_webstore_private_apitest.cc index 88e772c..68be872 100644 --- a/chrome/browser/extensions/extension_webstore_private_apitest.cc +++ b/chrome/browser/extensions/extension_webstore_private_apitest.cc @@ -106,3 +106,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, ASSERT_TRUE(RunInstallTest("incorrect_manifest2.html", "extension.crx")); observer.Wait(); } + +// Tests that we can request an app installed bubble (instead of the default +// UI when an app is installed). +IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, + AppInstallBubble) { + ASSERT_TRUE(RunInstallTest("app_install_bubble.html", "app.crx")); +} diff --git a/chrome/browser/ui/touch/tabs/touch_tab_strip.cc b/chrome/browser/ui/touch/tabs/touch_tab_strip.cc index 6d7bf25..c4e3240 100644 --- a/chrome/browser/ui/touch/tabs/touch_tab_strip.cc +++ b/chrome/browser/ui/touch/tabs/touch_tab_strip.cc @@ -59,6 +59,10 @@ void TouchTabStrip::SetBackgroundOffset(const gfx::Point& offset) { GetTabAtTabDataIndex(i)->set_background_offset(offset); } +views::View* TouchTabStrip::GetNewTabButton() { + return NULL; +} + //////////////////////////////////////////////////////////////////////////////// // TouchTabStrip, BaseTabStrip implementation: diff --git a/chrome/browser/ui/touch/tabs/touch_tab_strip.h b/chrome/browser/ui/touch/tabs/touch_tab_strip.h index cf4c686..1ecaa68 100644 --- a/chrome/browser/ui/touch/tabs/touch_tab_strip.h +++ b/chrome/browser/ui/touch/tabs/touch_tab_strip.h @@ -32,8 +32,9 @@ class TouchTabStrip : public BaseTabStrip { virtual ~TouchTabStrip(); // AbstractTabStripView implementation: - virtual bool IsPositionInWindowCaption(const gfx::Point& point); - virtual void SetBackgroundOffset(const gfx::Point& offset); + virtual bool IsPositionInWindowCaption(const gfx::Point& point) OVERRIDE; + virtual void SetBackgroundOffset(const gfx::Point& offset) OVERRIDE; + virtual views::View* GetNewTabButton() OVERRIDE; // BaseTabStrip implementation: virtual void PrepareForCloseAt(int model_index); diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble.cc index f9e30ab..5e0ff1e 100644 --- a/chrome/browser/ui/views/extensions/extension_installed_bubble.cc +++ b/chrome/browser/ui/views/extensions/extension_installed_bubble.cc @@ -9,12 +9,14 @@ #include "base/i18n/rtl.h" #include "base/message_loop.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/extensions/extension_install_ui.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/views/browser_actions_container.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/location_bar/location_bar_view.h" +#include "chrome/browser/ui/views/tabs/tab_strip.h" #include "chrome/browser/ui/views/toolbar_view.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/extensions/extension.h" @@ -28,6 +30,8 @@ #include "views/controls/button/image_button.h" #include "views/controls/image_view.h" #include "views/controls/label.h" +#include "views/controls/link.h" +#include "views/controls/link_listener.h" #include "views/layout/layout_constants.h" #include "views/view.h" @@ -78,12 +82,16 @@ void ShowExtensionInstalledBubble( // ExtensionInstalledBubble. It displays the install icon and explanatory // text about the installed extension. class InstalledBubbleContent : public views::View, - public views::ButtonListener { + public views::ButtonListener, + public views::LinkListener { public: - InstalledBubbleContent(const Extension* extension, + InstalledBubbleContent(Browser* browser, + const Extension* extension, ExtensionInstalledBubble::BubbleType type, SkBitmap* icon) - : bubble_(NULL), + : browser_(browser), + extension_id_(extension->id()), + bubble_(NULL), type_(type), info_(NULL) { ResourceBundle& rb = ResourceBundle::GetSharedInstance(); @@ -108,32 +116,50 @@ class InstalledBubbleContent : public views::View, heading_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); AddChildView(heading_); - if (type_ == ExtensionInstalledBubble::PAGE_ACTION) { - info_ = new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( - IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO))); - info_->SetFont(font); - info_->SetMultiLine(true); - info_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); - AddChildView(info_); + switch (type_) { + case ExtensionInstalledBubble::PAGE_ACTION: { + info_ = new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( + IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO))); + info_->SetFont(font); + info_->SetMultiLine(true); + info_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + AddChildView(info_); + break; + } + case ExtensionInstalledBubble::OMNIBOX_KEYWORD: { + info_ = new views::Label(UTF16ToWide(l10n_util::GetStringFUTF16( + IDS_EXTENSION_INSTALLED_OMNIBOX_KEYWORD_INFO, + UTF8ToUTF16(extension->omnibox_keyword())))); + info_->SetFont(font); + info_->SetMultiLine(true); + info_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + AddChildView(info_); + break; + } + case ExtensionInstalledBubble::APP: { + views::Link* link = new views::Link(UTF16ToWide( + l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_APP_INFO))); + link->set_listener(this); + manage_ = link; + manage_->SetFont(font); + manage_->SetMultiLine(true); + manage_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + AddChildView(manage_); + break; + } + default: + break; } - if (type_ == ExtensionInstalledBubble::OMNIBOX_KEYWORD) { - info_ = new views::Label(UTF16ToWide(l10n_util::GetStringFUTF16( - IDS_EXTENSION_INSTALLED_OMNIBOX_KEYWORD_INFO, - UTF8ToUTF16(extension->omnibox_keyword())))); - info_->SetFont(font); - info_->SetMultiLine(true); - info_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); - AddChildView(info_); + if (type_ != ExtensionInstalledBubble::APP) { + manage_ = new views::Label(UTF16ToWide( + l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_INFO))); + manage_->SetFont(font); + manage_->SetMultiLine(true); + manage_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + AddChildView(manage_); } - manage_ = new views::Label(UTF16ToWide( - l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_INFO))); - manage_->SetFont(font); - manage_->SetMultiLine(true); - manage_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); - AddChildView(manage_); - close_button_ = new views::ImageButton(this); close_button_->SetImage(views::CustomButton::BS_NORMAL, rb.GetBitmapNamed(IDR_CLOSE_BAR)); @@ -157,6 +183,12 @@ class InstalledBubbleContent : public views::View, } } + // Implements the views::LinkListener interface. + virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE { + GetWidget()->Close(); + ExtensionInstallUI::OpenAppInstalledNTP(browser_, extension_id_); + } + private: virtual gfx::Size GetPreferredSize() { int width = kHorizOuterMargin; @@ -169,8 +201,7 @@ class InstalledBubbleContent : public views::View, int height = kVertOuterMargin; height += heading_->GetHeightForWidth(kRightColumnWidth); height += kVertInnerMargin; - if (type_ == ExtensionInstalledBubble::PAGE_ACTION || - type_ == ExtensionInstalledBubble::OMNIBOX_KEYWORD) { + if (info_) { height += info_->GetHeightForWidth(kRightColumnWidth); height += kVertInnerMargin; } @@ -195,8 +226,7 @@ class InstalledBubbleContent : public views::View, y += heading_->height(); y += kVertInnerMargin; - if (type_ == ExtensionInstalledBubble::PAGE_ACTION || - type_ == ExtensionInstalledBubble::OMNIBOX_KEYWORD) { + if (info_) { info_->SizeToFit(kRightColumnWidth); info_->SetX(x); info_->SetY(y); @@ -220,6 +250,12 @@ class InstalledBubbleContent : public views::View, close_button_->SetBounds(x - 1, y - 1, sz.width(), sz.height()); } + // The browser we're associated with. + Browser* browser_; + + // The id of the extension just installed. + const std::string extension_id_; + // The Bubble showing us. Bubble* bubble_; @@ -248,7 +284,9 @@ ExtensionInstalledBubble::ExtensionInstalledBubble(const Extension* extension, animation_wait_retries_(0) { AddRef(); // Balanced in BubbleClosing. - if (!extension_->omnibox_keyword().empty()) { + if (extension->is_app()) { + type_ = APP; + } else if (!extension_->omnibox_keyword().empty()) { type_ = OMNIBOX_KEYWORD; } else if (extension_->browser_action()) { type_ = BROWSER_ACTION; @@ -298,7 +336,18 @@ void ExtensionInstalledBubble::ShowInternal() { browser_->window()->GetNativeHandle()); const views::View* reference_view = NULL; - if (type_ == BROWSER_ACTION) { + if (type_ == APP) { + if (browser_view->IsTabStripVisible()) { + AbstractTabStripView* tabstrip = browser_view->tabstrip(); + views::View* ntp_button = tabstrip->GetNewTabButton(); + if (ntp_button && ntp_button->IsVisibleInRootView()) { + reference_view = ntp_button; + } else { + // Just have the bubble point at the tab strip. + reference_view = tabstrip; + } + } + } else if (type_ == BROWSER_ACTION) { BrowserActionsContainer* container = browser_view->GetToolbarView()->browser_actions(); if (container->animating() && @@ -352,7 +401,8 @@ void ExtensionInstalledBubble::ShowInternal() { arrow_location = BubbleBorder::TOP_LEFT; } - bubble_content_ = new InstalledBubbleContent(extension_, type_, &icon_); + bubble_content_ = new InstalledBubbleContent( + browser_, extension_, type_, &icon_); Bubble* bubble = Bubble::Show(browser_view->GetWidget(), bounds, arrow_location, bubble_content_, this); bubble_content_->set_bubble(bubble); diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble.h b/chrome/browser/ui/views/extensions/extension_installed_bubble.h index 8f5f5b7..887a2df 100644 --- a/chrome/browser/ui/views/extensions/extension_installed_bubble.h +++ b/chrome/browser/ui/views/extensions/extension_installed_bubble.h @@ -24,6 +24,7 @@ class SkBitmap; // BROWSER_ACTION -> The browserAction icon in the toolbar. // PAGE_ACTION -> A preview of the pageAction icon in the location // bar which is shown while the Bubble is shown. +// APP -> The plus button in the tabstrip (for the New Tab Page). // GENERIC -> The wrench menu. This case includes pageActions that // don't specify a default icon. // @@ -38,6 +39,7 @@ class ExtensionInstalledBubble OMNIBOX_KEYWORD, BROWSER_ACTION, PAGE_ACTION, + APP, GENERIC }; diff --git a/chrome/browser/ui/views/tabs/abstract_tab_strip_view.h b/chrome/browser/ui/views/tabs/abstract_tab_strip_view.h index 756680a..1ce1814 100644 --- a/chrome/browser/ui/views/tabs/abstract_tab_strip_view.h +++ b/chrome/browser/ui/views/tabs/abstract_tab_strip_view.h @@ -32,7 +32,9 @@ class AbstractTabStripView : public views::View { // Set the background offset used by inactive tabs to match the frame image. virtual void SetBackgroundOffset(const gfx::Point& offset) = 0; + + // Returns the new tab button, or NULL if there isn't one. + virtual views::View* GetNewTabButton() = 0; }; #endif // CHROME_BROWSER_UI_VIEWS_TABS_ABSTRACT_TAB_STRIP_VIEW_H_ - diff --git a/chrome/browser/ui/views/tabs/side_tab_strip.cc b/chrome/browser/ui/views/tabs/side_tab_strip.cc index f7edbfa..82c457f 100644 --- a/chrome/browser/ui/views/tabs/side_tab_strip.cc +++ b/chrome/browser/ui/views/tabs/side_tab_strip.cc @@ -155,6 +155,10 @@ bool SideTabStrip::IsPositionInWindowCaption(const gfx::Point& point) { void SideTabStrip::SetBackgroundOffset(const gfx::Point& offset) { } +views::View* SideTabStrip::GetNewTabButton() { + return newtab_button_; +} + //////////////////////////////////////////////////////////////////////////////// // SideTabStrip, BaseTabStrip implementation: diff --git a/chrome/browser/ui/views/tabs/side_tab_strip.h b/chrome/browser/ui/views/tabs/side_tab_strip.h index 6a5ef7e..9fc316f 100644 --- a/chrome/browser/ui/views/tabs/side_tab_strip.h +++ b/chrome/browser/ui/views/tabs/side_tab_strip.h @@ -23,6 +23,7 @@ class SideTabStrip : public BaseTabStrip, public views::ButtonListener { // AbstractTabStripView implementation: virtual bool IsPositionInWindowCaption(const gfx::Point& point) OVERRIDE; virtual void SetBackgroundOffset(const gfx::Point& offset) OVERRIDE; + virtual views::View* GetNewTabButton() OVERRIDE; // BaseTabStrip implementation: virtual void StartHighlight(int model_index) OVERRIDE; diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index ea1451a..6b6894b3 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc @@ -189,6 +189,10 @@ void TabStrip::SetBackgroundOffset(const gfx::Point& offset) { GetTabAtTabDataIndex(i)->set_background_offset(offset); } +views::View* TabStrip::GetNewTabButton() { + return newtab_button_; +} + //////////////////////////////////////////////////////////////////////////////// // TabStrip, BaseTabStrip implementation: diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h index b064e9a..009cf2a 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.h +++ b/chrome/browser/ui/views/tabs/tab_strip.h @@ -54,6 +54,7 @@ class TabStrip : public BaseTabStrip, // AbstractTabStripView implementation: virtual bool IsPositionInWindowCaption(const gfx::Point& point) OVERRIDE; virtual void SetBackgroundOffset(const gfx::Point& offset) OVERRIDE; + virtual views::View* GetNewTabButton() OVERRIDE; // BaseTabStrip implementation: virtual void PrepareForCloseAt(int model_index) OVERRIDE; diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 5f6ec9e..afaf93a 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -70,6 +70,9 @@ const char kAppsGalleryURL[] = "apps-gallery-url"; // The update url used by gallery/webstore extensions. const char kAppsGalleryUpdateURL[] = "apps-gallery-update-url"; +// Whether to always use the new app install bubble when installing an app. +const char kAppsNewInstallBubble[] = "apps-new-install-bubble"; + // Disable throbber for extension apps. const char kAppsNoThrob[] = "apps-no-throb"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 7879e04..fca7bb5 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -32,12 +32,13 @@ extern const char kAllowWebSocketProxy[]; extern const char kAllowWebUICompositing[]; extern const char kAllowWebUIOobe[]; extern const char kAlwaysAuthorizePlugins[]; -extern const char kApp[]; extern const char kAppId[]; +extern const char kApp[]; extern const char kAppsCheckoutURL[]; extern const char kAppsGalleryReturnTokens[]; extern const char kAppsGalleryURL[]; extern const char kAppsGalleryUpdateURL[]; +extern const char kAppsNewInstallBubble[]; extern const char kAppsNoThrob[]; extern const char kAuthNegotiateDelegateWhitelist[]; extern const char kAuthSchemes[]; diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json index ada7737..0341101 100644 --- a/chrome/common/extensions/api/extension_api.json +++ b/chrome/common/extensions/api/extension_api.json @@ -6559,6 +6559,11 @@ "type": "string", "optional": true, "description": "The name of the locale used for generating localizedName. This should be the name of one of the directories in the _locales folder of the extension, or the default_locale setting from the manifest." + }, + "appInstallBubble": { + "type": "boolean", + "optional": true, + "description": "A flag to change the UI we show when an app is installed - a value of true means to show a bubble pointing at the new tab button (instead of the default behavior of opening the new tab page and animating the app icon)." } } }, diff --git a/chrome/test/data/extensions/api_test/webstore_private/app_install_bubble.html b/chrome/test/data/extensions/api_test/webstore_private/app_install_bubble.html new file mode 100644 index 0000000..61a5113c --- /dev/null +++ b/chrome/test/data/extensions/api_test/webstore_private/app_install_bubble.html @@ -0,0 +1,2 @@ +<script src="common.js"></script> +<script src="app_install_bubble.js"></script> diff --git a/chrome/test/data/extensions/api_test/webstore_private/app_install_bubble.js b/chrome/test/data/extensions/api_test/webstore_private/app_install_bubble.js new file mode 100644 index 0000000..d1ac1b8 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webstore_private/app_install_bubble.js @@ -0,0 +1,25 @@ +// Copyright (c) 2011 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. + +var tests = [ + function appInstallBubble() { + // See things through all the way to a successful install. + listenOnce(chrome.management.onInstalled, callbackPass(function(info) { + assertEq(info.id, appId); + })); + + var manifest = getManifest("app/manifest.json"); + // Begin installing. + chrome.webstorePrivate.beginInstallWithManifest2( + {'id': appId,'manifest': manifest, 'appInstallBubble':true}, + callbackPass(function(result) { + assertEq(result, ""); + + // Now complete the installation. + chrome.webstorePrivate.completeInstall(appId, callbackPass()); + })); + } +]; + +runTests(tests); diff --git a/chrome/test/data/extensions/api_test/webstore_private/common.js b/chrome/test/data/extensions/api_test/webstore_private/common.js index 933b032..358ced0 100644 --- a/chrome/test/data/extensions/api_test/webstore_private/common.js +++ b/chrome/test/data/extensions/api_test/webstore_private/common.js @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// The id of the extension we're using for install tests. +// The id of an extension we're using for install tests. var extensionId = "enfkhcelefdadlmkffamgdlgplcionje"; +// The id of an app we're using for install tests. +var appId = "iladmdjkfniedhfhcfoefgojhgaiaccc"; + var assertEq = chrome.test.assertEq; var assertNoLastError = chrome.test.assertNoLastError; var callbackFail = chrome.test.callbackFail; |