summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbenwells <benwells@chromium.org>2014-11-14 00:21:03 -0800
committerCommit bot <commit-bot@chromium.org>2014-11-14 08:21:31 +0000
commitc6d95e3927568ff81e4ad5768a816448ab789870 (patch)
treefa89ea116149aad8167e58ad7d46e68e9e0825a6
parent4d8fa6eab266bde91a0481df5357d315d2f3f62b (diff)
downloadchromium_src-c6d95e3927568ff81e4ad5768a816448ab789870.zip
chromium_src-c6d95e3927568ff81e4ad5768a816448ab789870.tar.gz
chromium_src-c6d95e3927568ff81e4ad5768a816448ab789870.tar.bz2
Add page info button into frame for streamlined hosted apps.
This let's users see the security level of the page their app is on. BUG=368372 Review URL: https://codereview.chromium.org/690023003 Cr-Commit-Position: refs/heads/master@{#304186}
-rw-r--r--ash/frame/caption_buttons/caption_button_types.h1
-rw-r--r--ash/frame/caption_buttons/frame_caption_button.h2
-rw-r--r--ash/frame/caption_buttons/frame_size_button.cc1
-rw-r--r--chrome/browser/ui/views/frame/browser_frame.cc8
-rw-r--r--chrome/browser/ui/views/frame/browser_frame.h9
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view.cc7
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view.h7
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc71
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h19
-rw-r--r--chrome/browser/ui/views/frame/browser_view.cc13
-rw-r--r--chrome/browser/ui/views/frame/web_app_left_header_view_ash.cc96
-rw-r--r--chrome/browser/ui/views/frame/web_app_left_header_view_ash.h68
-rw-r--r--chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc91
-rw-r--r--chrome/chrome_browser_ui.gypi2
-rw-r--r--chrome/chrome_tests_unit.gypi2
15 files changed, 336 insertions, 61 deletions
diff --git a/ash/frame/caption_buttons/caption_button_types.h b/ash/frame/caption_buttons/caption_button_types.h
index fb8b139..0e02c31 100644
--- a/ash/frame/caption_buttons/caption_button_types.h
+++ b/ash/frame/caption_buttons/caption_button_types.h
@@ -16,6 +16,7 @@ enum CaptionButtonIcon {
CAPTION_BUTTON_ICON_LEFT_SNAPPED,
CAPTION_BUTTON_ICON_RIGHT_SNAPPED,
CAPTION_BUTTON_ICON_BACK,
+ CAPTION_BUTTON_ICON_LOCATION,
CAPTION_BUTTON_ICON_COUNT
};
diff --git a/ash/frame/caption_buttons/frame_caption_button.h b/ash/frame/caption_buttons/frame_caption_button.h
index 9979d68..05028e4 100644
--- a/ash/frame/caption_buttons/frame_caption_button.h
+++ b/ash/frame/caption_buttons/frame_caption_button.h
@@ -62,6 +62,8 @@ class ASH_EXPORT FrameCaptionButton : public views::CustomButton {
return icon_;
}
+ int icon_image_id() const { return icon_image_id_; }
+
protected:
// views::CustomButton override:
void OnGestureEvent(ui::GestureEvent* event) override;
diff --git a/ash/frame/caption_buttons/frame_size_button.cc b/ash/frame/caption_buttons/frame_size_button.cc
index 05579bd..92a627f 100644
--- a/ash/frame/caption_buttons/frame_size_button.cc
+++ b/ash/frame/caption_buttons/frame_size_button.cc
@@ -215,6 +215,7 @@ void FrameSizeButton::UpdateSnapType(const ui::LocatedEvent& event) {
case CAPTION_BUTTON_ICON_MINIMIZE:
case CAPTION_BUTTON_ICON_CLOSE:
case CAPTION_BUTTON_ICON_BACK:
+ case CAPTION_BUTTON_ICON_LOCATION:
case CAPTION_BUTTON_ICON_COUNT:
NOTREACHED();
break;
diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc
index a0b98fd..b706c61 100644
--- a/chrome/browser/ui/views/frame/browser_frame.cc
+++ b/chrome/browser/ui/views/frame/browser_frame.cc
@@ -121,6 +121,14 @@ void BrowserFrame::UpdateThrobber(bool running) {
browser_frame_view_->UpdateThrobber(running);
}
+void BrowserFrame::UpdateToolbar() {
+ browser_frame_view_->UpdateToolbar();
+}
+
+views::View* BrowserFrame::GetLocationIconView() const {
+ return browser_frame_view_->GetLocationIconView();
+}
+
views::View* BrowserFrame::GetFrameView() const {
return browser_frame_view_;
}
diff --git a/chrome/browser/ui/views/frame/browser_frame.h b/chrome/browser/ui/views/frame/browser_frame.h
index 4bd323f..54b90a9 100644
--- a/chrome/browser/ui/views/frame/browser_frame.h
+++ b/chrome/browser/ui/views/frame/browser_frame.h
@@ -73,6 +73,15 @@ class BrowserFrame
// Tells the frame to update the throbber.
void UpdateThrobber(bool running);
+ // Tells the frame to update any toolbar elements it has.
+ void UpdateToolbar();
+
+ // Returns the location icon, if there is a location icon embedded into the
+ // frame. This is the case for web app frames, which do not have a visible
+ // toolbar. Instead of using the normal location icon from the location bar
+ // in the toolbar, these windows have a location icon in the frame.
+ views::View* GetLocationIconView() const;
+
// Returns the NonClientFrameView of this frame.
views::View* GetFrameView() const;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index 6f206ec..9930329 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -54,6 +54,13 @@ BrowserNonClientFrameView::~BrowserNonClientFrameView() {
}
}
+void BrowserNonClientFrameView::UpdateToolbar() {
+}
+
+views::View* BrowserNonClientFrameView::GetLocationIconView() const {
+ return nullptr;
+}
+
void BrowserNonClientFrameView::VisibilityChanged(views::View* starting_from,
bool is_visible) {
if (!is_visible)
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index d0d71c8..e5bd895 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -52,6 +52,13 @@ class BrowserNonClientFrameView : public views::NonClientFrameView,
// Updates the throbber.
virtual void UpdateThrobber(bool running) = 0;
+ // Updates any toolbar components in the frame. The default implementation
+ // does nothing.
+ virtual void UpdateToolbar();
+
+ // Returns the location icon, if this frame has any.
+ virtual views::View* GetLocationIconView() const;
+
// Overriden from views::View.
void VisibilityChanged(views::View* starting_from, bool is_visible) override;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index fc2bbd61..31fab2d 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -6,7 +6,6 @@
#include <algorithm>
-#include "ash/frame/caption_buttons/frame_caption_button.h"
#include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
#include "ash/frame/default_header_painter.h"
#include "ash/frame/frame_border_hit_test_controller.h"
@@ -21,12 +20,12 @@
#include "chrome/browser/ui/views/frame/browser_header_painter_ash.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
+#include "chrome/browser/ui/views/frame/web_app_left_header_view_ash.h"
#include "chrome/browser/ui/views/profiles/avatar_menu_button.h"
#include "chrome/browser/ui/views/tab_icon_view.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "components/signin/core/common/profile_management_switches.h"
#include "content/public/browser/web_contents.h"
-#include "grit/ash_resources.h"
#include "grit/theme_resources.h"
#include "ui/accessibility/ax_view_state.h"
#include "ui/aura/client/aura_constants.h"
@@ -102,7 +101,7 @@ BrowserNonClientFrameViewAsh::BrowserNonClientFrameViewAsh(
BrowserView* browser_view)
: BrowserNonClientFrameView(frame, browser_view),
caption_button_container_(nullptr),
- web_app_back_button_(nullptr),
+ web_app_left_header_view_(nullptr),
window_icon_(nullptr),
frame_border_hit_test_controller_(
new ash::FrameBorderHitTestController(frame)) {
@@ -111,9 +110,6 @@ BrowserNonClientFrameViewAsh::BrowserNonClientFrameViewAsh(
BrowserNonClientFrameViewAsh::~BrowserNonClientFrameViewAsh() {
ash::Shell::GetInstance()->RemoveShellObserver(this);
- // browser_view() outlives the frame, as destruction of sibling views happens
- // in the same order as creation - see BrowserView::CreateBrowserWindow.
- chrome::RemoveCommandObserver(browser_view()->browser(), IDC_BACK, this);
}
void BrowserNonClientFrameViewAsh::Init() {
@@ -145,23 +141,13 @@ void BrowserNonClientFrameViewAsh::Init() {
header_painter->UpdateLeftHeaderView(window_icon_);
}
} else if (UseWebAppHeaderStyle()) {
- web_app_back_button_ =
- new ash::FrameCaptionButton(this, ash::CAPTION_BUTTON_ICON_BACK);
- web_app_back_button_->SetImages(ash::CAPTION_BUTTON_ICON_BACK,
- ash::FrameCaptionButton::ANIMATE_NO,
- IDR_AURA_WINDOW_CONTROL_ICON_BACK,
- IDR_AURA_WINDOW_CONTROL_ICON_BACK_I,
- IDR_AURA_WINDOW_CONTROL_BACKGROUND_H,
- IDR_AURA_WINDOW_CONTROL_BACKGROUND_P);
-
- UpdateBackButtonState(true);
- chrome::AddCommandObserver(browser_view()->browser(), IDC_BACK, this);
- AddChildView(web_app_back_button_);
+ web_app_left_header_view_ = new WebAppLeftHeaderView(browser_view());
+ AddChildView(web_app_left_header_view_);
ash::DefaultHeaderPainter* header_painter = new ash::DefaultHeaderPainter;
header_painter_.reset(header_painter);
header_painter->Init(frame(), this, caption_button_container_);
- header_painter->UpdateLeftHeaderView(web_app_back_button_);
+ header_painter->UpdateLeftHeaderView(web_app_left_header_view_);
} else {
BrowserHeaderPainterAsh* header_painter = new BrowserHeaderPainterAsh;
header_painter_.reset(header_painter);
@@ -223,6 +209,18 @@ void BrowserNonClientFrameViewAsh::UpdateThrobber(bool running) {
window_icon_->Update();
}
+void BrowserNonClientFrameViewAsh::UpdateToolbar() {
+ if (web_app_left_header_view_)
+ web_app_left_header_view_->Update();
+}
+
+views::View* BrowserNonClientFrameViewAsh::GetLocationIconView() const {
+ if (web_app_left_header_view_)
+ return web_app_left_header_view_->GetLocationIconView();
+
+ return nullptr;
+}
+
///////////////////////////////////////////////////////////////////////////////
// views::NonClientFrameView:
@@ -257,8 +255,8 @@ int BrowserNonClientFrameViewAsh::NonClientHitTest(const gfx::Point& point) {
}
// See if the point is actually within the web app back button.
- if (hit_test == HTCAPTION && web_app_back_button_ &&
- ConvertedHitTest(this, web_app_back_button_, point)) {
+ if (hit_test == HTCAPTION && web_app_left_header_view_ &&
+ ConvertedHitTest(this, web_app_left_header_view_, point)) {
return HTCLIENT;
}
@@ -326,13 +324,8 @@ void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
}
caption_button_container_->SetPaintAsActive(ShouldPaintAsActive());
- if (web_app_back_button_) {
- // TODO(benwells): Check that the disabled and inactive states should be
- // drawn in the same way.
- web_app_back_button_->set_paint_as_active(
- ShouldPaintAsActive() &&
- chrome::IsCommandEnabled(browser_view()->browser(), IDC_BACK));
- }
+ if (web_app_left_header_view_)
+ web_app_left_header_view_->SetPaintAsActive(ShouldPaintAsActive());
ash::HeaderPainter::Mode header_mode = ShouldPaintAsActive() ?
ash::HeaderPainter::MODE_ACTIVE : ash::HeaderPainter::MODE_INACTIVE;
@@ -445,25 +438,12 @@ gfx::ImageSkia BrowserNonClientFrameViewAsh::GetFaviconForTabIconView() {
}
///////////////////////////////////////////////////////////////////////////////
-// CommandObserver:
-
-void BrowserNonClientFrameViewAsh::EnabledStateChangedForCommand(int id,
- bool enabled) {
- DCHECK_EQ(IDC_BACK, id);
- UpdateBackButtonState(enabled);
-}
-
-///////////////////////////////////////////////////////////////////////////////
// views::ButtonListener:
void BrowserNonClientFrameViewAsh::ButtonPressed(views::Button* sender,
const ui::Event& event) {
- if (sender == web_app_back_button_)
- chrome::ExecuteCommand(browser_view()->browser(), IDC_BACK);
- else if (sender == new_avatar_button())
- chrome::ExecuteCommand(browser_view()->browser(), IDC_SHOW_AVATAR_MENU);
- else
- NOTREACHED();
+ DCHECK(sender == new_avatar_button());
+ chrome::ExecuteCommand(browser_view()->browser(), IDC_SHOW_AVATAR_MENU);
}
///////////////////////////////////////////////////////////////////////////////
@@ -685,8 +665,3 @@ void BrowserNonClientFrameViewAsh::PaintContentEdge(gfx::Canvas* canvas) {
ThemeProperties::GetDefaultColor(
ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
}
-
-void BrowserNonClientFrameViewAsh::UpdateBackButtonState(bool enabled) {
- web_app_back_button_->SetState(enabled ? views::Button::STATE_NORMAL
- : views::Button::STATE_DISABLED);
-}
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
index b1abdb6..44ea358 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
@@ -8,12 +8,12 @@
#include "ash/shell_observer.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/command_observer.h"
#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
#include "chrome/browser/ui/views/tab_icon_view_model.h"
#include "ui/views/controls/button/button.h"
class TabIconView;
+class WebAppLeftHeaderView;
namespace ash {
class FrameBorderHitTestController;
@@ -21,6 +21,7 @@ class FrameCaptionButton;
class FrameCaptionButtonContainerView;
class HeaderPainter;
}
+
namespace views {
class ImageButton;
class ToggleImageButton;
@@ -29,7 +30,6 @@ class ToggleImageButton;
class BrowserNonClientFrameViewAsh : public BrowserNonClientFrameView,
public ash::ShellObserver,
public chrome::TabIconViewModel,
- public CommandObserver,
public views::ButtonListener {
public:
static const char kViewClassName[];
@@ -44,6 +44,8 @@ class BrowserNonClientFrameViewAsh : public BrowserNonClientFrameView,
int GetTopInset() const override;
int GetThemeBackgroundXInset() const override;
void UpdateThrobber(bool running) override;
+ void UpdateToolbar() override;
+ views::View* GetLocationIconView() const override;
// views::NonClientFrameView:
gfx::Rect GetBoundsForClientView() const override;
@@ -72,9 +74,6 @@ class BrowserNonClientFrameViewAsh : public BrowserNonClientFrameView,
bool ShouldTabIconViewAnimate() const override;
gfx::ImageSkia GetFaviconForTabIconView() override;
- // CommandObserver:
- void EnabledStateChangedForCommand(int id, bool enabled) override;
-
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
@@ -86,6 +85,8 @@ class BrowserNonClientFrameViewAsh : public BrowserNonClientFrameView,
ImmersiveFullscreen);
FRIEND_TEST_ALL_PREFIXES(BrowserNonClientFrameViewAshTest,
ToggleMaximizeModeRelayout);
+ FRIEND_TEST_ALL_PREFIXES(WebAppLeftHeaderViewTest, BackButton);
+ FRIEND_TEST_ALL_PREFIXES(WebAppLeftHeaderViewTest, LocationIcon);
// views::NonClientFrameView:
bool DoesIntersectRect(const views::View* target,
@@ -131,14 +132,12 @@ class BrowserNonClientFrameViewAsh : public BrowserNonClientFrameView,
// the packaged app header style.
void PaintContentEdge(gfx::Canvas* canvas);
- // Update the state of the back button.
- void UpdateBackButtonState(bool enabled);
-
// View which contains the window controls.
ash::FrameCaptionButtonContainerView* caption_button_container_;
- // The back button for web app style header.
- ash::FrameCaptionButton* web_app_back_button_;
+ // The holder for the buttons on the left side of the header. This is included
+ // for web app style frames, and includes a back button and location icon.
+ WebAppLeftHeaderView* web_app_left_header_view_;
// For popups, the window icon.
TabIconView* window_icon_;
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 3ac5922..affbd09 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1027,6 +1027,7 @@ void BrowserView::UpdateToolbar(content::WebContents* contents) {
// We may end up here during destruction.
if (toolbar_)
toolbar_->Update(contents);
+ frame_->UpdateToolbar();
}
void BrowserView::FocusToolbar() {
@@ -1265,9 +1266,15 @@ void BrowserView::ShowWebsiteSettings(Profile* profile,
content::WebContents* web_contents,
const GURL& url,
const content::SSLStatus& ssl) {
- WebsiteSettingsPopupView::ShowPopup(
- GetLocationBarView()->location_icon_view(), profile,
- web_contents, url, ssl, browser_.get());
+ views::View* popup_anchor = GetLocationBarView()->location_icon_view();
+
+ // If the toolbar isn't showing this might be a web app window that has a
+ // location icon.
+ if (!IsToolbarVisible())
+ popup_anchor = frame_->GetLocationIconView();
+
+ WebsiteSettingsPopupView::ShowPopup(popup_anchor, profile, web_contents, url,
+ ssl, browser_.get());
}
void BrowserView::ShowAppMenu() {
diff --git a/chrome/browser/ui/views/frame/web_app_left_header_view_ash.cc b/chrome/browser/ui/views/frame/web_app_left_header_view_ash.cc
new file mode 100644
index 0000000..23e9256
--- /dev/null
+++ b/chrome/browser/ui/views/frame/web_app_left_header_view_ash.cc
@@ -0,0 +1,96 @@
+// Copyright 2014 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/ui/views/frame/web_app_left_header_view_ash.h"
+
+#include "ash/frame/caption_buttons/frame_caption_button.h"
+#include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "content/public/browser/navigation_entry.h"
+#include "grit/ash_resources.h"
+#include "ui/views/layout/box_layout.h"
+
+// static
+const char WebAppLeftHeaderView::kViewClassName[] = "WebAppLeftHeaderView";
+
+WebAppLeftHeaderView::WebAppLeftHeaderView(BrowserView* browser_view)
+ : browser_view_(browser_view) {
+ SetLayoutManager(
+ new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
+
+ back_button_ =
+ new ash::FrameCaptionButton(this, ash::CAPTION_BUTTON_ICON_BACK);
+ back_button_->SetImages(
+ ash::CAPTION_BUTTON_ICON_BACK, ash::FrameCaptionButton::ANIMATE_NO,
+ IDR_AURA_WINDOW_CONTROL_ICON_BACK, IDR_AURA_WINDOW_CONTROL_ICON_BACK_I,
+ IDR_AURA_WINDOW_CONTROL_BACKGROUND_H,
+ IDR_AURA_WINDOW_CONTROL_BACKGROUND_P);
+ AddChildView(back_button_);
+
+ location_icon_ =
+ new ash::FrameCaptionButton(this, ash::CAPTION_BUTTON_ICON_LOCATION);
+ AddChildView(location_icon_);
+
+ Update();
+}
+
+WebAppLeftHeaderView::~WebAppLeftHeaderView() {
+}
+
+void WebAppLeftHeaderView::Update() {
+ int icon_resource = browser_view_->browser()->toolbar_model()->GetIcon();
+ location_icon_->SetImages(
+ ash::CAPTION_BUTTON_ICON_LOCATION, ash::FrameCaptionButton::ANIMATE_NO,
+ icon_resource, icon_resource, IDR_AURA_WINDOW_CONTROL_BACKGROUND_H,
+ IDR_AURA_WINDOW_CONTROL_BACKGROUND_P);
+
+ back_button_->SetState(
+ chrome::IsCommandEnabled(browser_view_->browser(), IDC_BACK)
+ ? views::Button::STATE_NORMAL
+ : views::Button::STATE_DISABLED);
+}
+
+void WebAppLeftHeaderView::SetPaintAsActive(bool active) {
+ // TODO(benwells): Check that the disabled and inactive states should be
+ // drawn in the same way.
+ back_button_->set_paint_as_active(
+ active && chrome::IsCommandEnabled(browser_view_->browser(), IDC_BACK));
+ location_icon_->set_paint_as_active(active);
+}
+
+views::View* WebAppLeftHeaderView::GetLocationIconView() const {
+ return location_icon_;
+}
+
+const char* WebAppLeftHeaderView::GetClassName() const {
+ return kViewClassName;
+}
+
+void WebAppLeftHeaderView::ButtonPressed(views::Button* sender,
+ const ui::Event& event) {
+ if (sender == back_button_)
+ chrome::ExecuteCommand(browser_view_->browser(), IDC_BACK);
+ else if (sender == location_icon_)
+ ShowWebsiteSettings();
+ else
+ NOTREACHED();
+}
+
+void WebAppLeftHeaderView::ShowWebsiteSettings() const {
+ content::WebContents* tab = browser_view_->GetActiveWebContents();
+ if (!tab)
+ return;
+
+ // Important to use GetVisibleEntry to match what's showing in the title area.
+ content::NavigationEntry* nav_entry = tab->GetController().GetVisibleEntry();
+ // The visible entry can be NULL in the case of window.open("").
+ if (!nav_entry)
+ return;
+
+ chrome::ShowWebsiteSettings(browser_view_->browser(), tab,
+ nav_entry->GetURL(), nav_entry->GetSSL());
+}
diff --git a/chrome/browser/ui/views/frame/web_app_left_header_view_ash.h b/chrome/browser/ui/views/frame/web_app_left_header_view_ash.h
new file mode 100644
index 0000000..fbbf65c
--- /dev/null
+++ b/chrome/browser/ui/views/frame/web_app_left_header_view_ash.h
@@ -0,0 +1,68 @@
+// Copyright 2014 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_UI_VIEWS_FRAME_WEB_APP_LEFT_HEADER_VIEW_ASH_H_
+#define CHROME_BROWSER_UI_VIEWS_FRAME_WEB_APP_LEFT_HEADER_VIEW_ASH_H_
+
+#include "ui/views/controls/button/button.h"
+
+class BrowserView;
+
+namespace ash {
+class FrameCaptionButton;
+}
+
+namespace views {
+class ImageButton;
+}
+
+// WebAppLeftHeaderView is a container view for any icons on the left of the
+// frame used for web app style windows. It contains a back button and a
+// location icon.
+class WebAppLeftHeaderView : public views::View,
+ public views::ButtonListener {
+ public:
+ static const char kViewClassName[];
+
+ explicit WebAppLeftHeaderView(BrowserView* browser_view);
+ ~WebAppLeftHeaderView() override;
+
+ // Updates the view.
+ void Update();
+
+ // Update whether to paint the header view as active or not.
+ void SetPaintAsActive(bool active);
+
+ views::View* GetLocationIconView() const;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(WebAppLeftHeaderViewTest, BackButton);
+ FRIEND_TEST_ALL_PREFIXES(WebAppLeftHeaderViewTest, LocationIcon);
+
+ // views::View:
+ const char* GetClassName() const override;
+
+ // views::ButtonListener:
+ void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
+ // Ask the browser to show the website settings dialog.
+ void ShowWebsiteSettings() const;
+
+ // Update the state of the back button.
+ void UpdateBackButtonState(bool enabled);
+
+ // The BrowserView for the frame.
+ BrowserView* browser_view_;
+
+ // The back button.
+ ash::FrameCaptionButton* back_button_;
+
+ // The location icon indicator. Shows the connection security status and
+ // allows the user to bring up the website settings dialog.
+ ash::FrameCaptionButton* location_icon_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebAppLeftHeaderView);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_FRAME_WEB_APP_LEFT_HEADER_VIEW_ASH_H_
diff --git a/chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc b/chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc
new file mode 100644
index 0000000..fe51e60
--- /dev/null
+++ b/chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc
@@ -0,0 +1,91 @@
+// Copyright 2014 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/ui/views/frame/web_app_left_header_view_ash.h"
+
+#include "ash/frame/caption_buttons/frame_caption_button.h"
+#include "base/command_line.h"
+#include "chrome/browser/ui/toolbar/test_toolbar_model.h"
+#include "chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/test_with_browser_view.h"
+#include "chrome/common/chrome_switches.h"
+#include "grit/theme_resources.h"
+#include "ui/aura/window.h"
+#include "ui/views/controls/button/button.h"
+#include "url/gurl.h"
+
+class WebAppLeftHeaderViewTest : public TestWithBrowserView {
+ public:
+ WebAppLeftHeaderViewTest()
+ : TestWithBrowserView(Browser::TYPE_TABBED,
+ chrome::HOST_DESKTOP_TYPE_ASH,
+ true),
+ frame_view_(nullptr),
+ test_toolbar_model_(nullptr) {}
+ ~WebAppLeftHeaderViewTest() override {}
+
+ // TestWithBrowserView override:
+ void SetUp() override {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableStreamlinedHostedApps);
+
+ TestWithBrowserView::SetUp();
+
+ // Setup a fake toolbar to enable testing.
+ test_toolbar_model_ = new TestToolbarModel();
+ scoped_ptr<ToolbarModel> toolbar_model(test_toolbar_model_);
+ browser()->swap_toolbar_models(&toolbar_model);
+ test_toolbar_model_->set_icon(IDR_LOCATION_BAR_HTTP);
+
+ AddTab(browser(), GURL("about:blank"));
+ NavigateAndCommitActiveTab(GURL("http://www.google.com"));
+ browser()->window()->Show();
+
+ views::Widget* widget = browser_view()->GetWidget();
+ frame_view_ = static_cast<BrowserNonClientFrameViewAsh*>(
+ widget->non_client_view()->frame_view());
+ }
+
+ protected:
+ // Owned by the browser view.
+ BrowserNonClientFrameViewAsh* frame_view_;
+
+ // Owned by the browser.
+ TestToolbarModel* test_toolbar_model_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebAppLeftHeaderViewTest);
+};
+
+TEST_F(WebAppLeftHeaderViewTest, BackButton) {
+ WebAppLeftHeaderView* view = frame_view_->web_app_left_header_view_;
+
+ // The left header view should not be null or our test is broken.
+ ASSERT_TRUE(view);
+
+ // The back button should be inactive until a navigate happens.
+ EXPECT_EQ(views::Button::STATE_DISABLED, view->back_button_->state());
+
+ NavigateAndCommitActiveTab(GURL("www2.google.com"));
+
+ // The back button should be active now that a navigation happened.
+ EXPECT_EQ(views::Button::STATE_NORMAL, view->back_button_->state());
+}
+
+TEST_F(WebAppLeftHeaderViewTest, LocationIcon) {
+ WebAppLeftHeaderView* view = frame_view_->web_app_left_header_view_;
+
+ // The left header view should not be null or our test is broken.
+ ASSERT_TRUE(view);
+
+ // The location icon should be non-secure one.
+ EXPECT_EQ(IDR_LOCATION_BAR_HTTP, view->location_icon_->icon_image_id());
+
+ test_toolbar_model_->set_icon(IDR_OMNIBOX_HTTPS_VALID);
+ NavigateAndCommitActiveTab(GURL("https://secure.google.com"));
+
+ // The location icon should now be the secure one.
+ EXPECT_EQ(IDR_OMNIBOX_HTTPS_VALID, view->location_icon_->icon_image_id());
+}
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 21ad064..ffe3ab3 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -2453,6 +2453,8 @@
'browser/ui/views/frame/browser_non_client_frame_view_ash.h',
'browser/ui/views/frame/immersive_mode_controller_ash.cc',
'browser/ui/views/frame/immersive_mode_controller_ash.h',
+ 'browser/ui/views/frame/web_app_left_header_view_ash.cc',
+ 'browser/ui/views/frame/web_app_left_header_view_ash.h',
'browser/ui/views/tabs/window_finder_ash.cc',
],
# Used when Ash is enabled but not Athena.
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 2f6815d..4a4edc7 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -1205,6 +1205,7 @@
'browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc',
'browser/ui/views/frame/test_with_browser_view.cc',
'browser/ui/views/frame/test_with_browser_view.h',
+ 'browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc',
'browser/ui/views/frame/web_contents_close_handler_unittest.cc',
'browser/ui/views/select_file_dialog_extension_unittest.cc',
'browser/ui/views/status_icons/status_tray_win_unittest.cc',
@@ -2338,6 +2339,7 @@
# BrowserWithTestWindowTest::SetUp() for a comment explaining why
# this is broken.
'browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc',
+ 'browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc',
'browser/ui/views/select_file_dialog_extension_unittest.cc',
],
}],