Commit efbcfdfd authored by xiyuan@chromium.org's avatar xiyuan@chromium.org

cros: Focus ring for view in keyboard drive OOBE.

BUG=242749

Review URL: https://chromiumcodereview.appspot.com/16337014

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@204092 0039d316-1c4b-4281-b951-d872f2087c98
parent a6b2d02a
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/cros_settings_names.h" #include "chrome/browser/chromeos/settings/cros_settings_names.h"
#include "chrome/browser/chromeos/system/statistics_provider.h" #include "chrome/browser/chromeos/system/statistics_provider.h"
#include "chrome/browser/chromeos/ui/focus_ring_controller.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/options/options_util.h" #include "chrome/browser/ui/options/options_util.h"
...@@ -192,6 +193,14 @@ void WizardController::Init( ...@@ -192,6 +193,14 @@ void WizardController::Init(
bool oobe_complete = StartupUtils::IsOobeCompleted(); bool oobe_complete = StartupUtils::IsOobeCompleted();
if (!oobe_complete || first_screen_name == kOutOfBoxScreenName) { if (!oobe_complete || first_screen_name == kOutOfBoxScreenName) {
is_out_of_box_ = true; is_out_of_box_ = true;
bool keyboard_driven_oobe = false;
system::StatisticsProvider::GetInstance()->GetMachineFlag(
chromeos::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
if (keyboard_driven_oobe) {
focus_ring_controller_.reset(new FocusRingController);
focus_ring_controller_->SetVisible(true);
}
} }
AdvanceToScreen(first_screen_name); AdvanceToScreen(first_screen_name);
......
...@@ -29,6 +29,7 @@ namespace chromeos { ...@@ -29,6 +29,7 @@ namespace chromeos {
class EnrollmentScreen; class EnrollmentScreen;
class ErrorScreen; class ErrorScreen;
class EulaScreen; class EulaScreen;
class FocusRingController;
class LoginDisplayHost; class LoginDisplayHost;
class NetworkScreen; class NetworkScreen;
class OobeDisplay; class OobeDisplay;
...@@ -292,6 +293,10 @@ class WizardController : public ScreenObserver { ...@@ -292,6 +293,10 @@ class WizardController : public ScreenObserver {
// True if OOBE should prevent exiting enterprise enrollment. // True if OOBE should prevent exiting enterprise enrollment.
bool can_exit_enrollment_; bool can_exit_enrollment_;
// A focus ring controller to draw focus ring around view for keyboard
// driven oobe.
scoped_ptr<FocusRingController> focus_ring_controller_;
FRIEND_TEST_ALL_PREFIXES(EnrollmentScreenTest, TestCancel); FRIEND_TEST_ALL_PREFIXES(EnrollmentScreenTest, TestCancel);
FRIEND_TEST_ALL_PREFIXES(WizardControllerFlowTest, Accelerators); FRIEND_TEST_ALL_PREFIXES(WizardControllerFlowTest, Accelerators);
friend class WizardControllerFlowTest; friend class WizardControllerFlowTest;
......
// Copyright 2013 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/chromeos/ui/focus_ring_controller.h"
#include "ash/wm/window_util.h"
#include "chrome/browser/chromeos/ui/focus_ring_layer.h"
#include "ui/views/widget/widget.h"
namespace chromeos {
FocusRingController::FocusRingController()
: visible_(false),
widget_(NULL) {
}
FocusRingController::~FocusRingController() {
SetVisible(false);
}
void FocusRingController::SetVisible(bool visible) {
if (visible_ == visible)
return;
visible_ = visible;
if (visible_) {
views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
SetWidget(views::Widget::GetWidgetForNativeWindow(
ash::wm::GetActiveWindow()));
} else {
views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
SetWidget(NULL);
}
}
void FocusRingController::UpdateFocusRing() {
views::View* focused_view = NULL;
if (widget_ && widget_->GetFocusManager())
focused_view = widget_->GetFocusManager()->GetFocusedView();
// No focus ring if no focused view or the focused view covers the whole
// widget content area (such as RenderWidgetHostWidgetAura).
if (!focused_view ||
focused_view->ConvertRectToWidget(focused_view->bounds()) ==
widget_->GetContentsView()->bounds()) {
focus_ring_layer_.reset();
return;
}
if (!focus_ring_layer_)
focus_ring_layer_.reset(new FocusRingLayer);
focus_ring_layer_->SetForView(focused_view);
}
void FocusRingController::SetWidget(views::Widget* widget) {
if (widget_) {
widget_->RemoveObserver(this);
if (widget_->GetFocusManager())
widget_->GetFocusManager()->RemoveFocusChangeListener(this);
}
widget_ = widget;
if (widget_) {
widget_->AddObserver(this);
if (widget_->GetFocusManager())
widget_->GetFocusManager()->AddFocusChangeListener(this);
}
UpdateFocusRing();
}
void FocusRingController::OnWidgetDestroying(views::Widget* widget) {
DCHECK_EQ(widget_, widget);
SetWidget(NULL);
}
void FocusRingController::OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) {
DCHECK_EQ(widget_, widget);
UpdateFocusRing();
}
void FocusRingController::OnNativeFocusChange(gfx::NativeView focused_before,
gfx::NativeView focused_now) {
views::Widget* widget = views::Widget::GetWidgetForNativeWindow(focused_now);
SetWidget(widget);
}
void FocusRingController::OnWillChangeFocus(views::View* focused_before,
views::View* focused_now) {
}
void FocusRingController::OnDidChangeFocus(views::View* focused_before,
views::View* focused_now) {
DCHECK_EQ(focused_now, widget_->GetFocusManager()->GetFocusedView());
UpdateFocusRing();
}
} // namespace chromeos
// Copyright 2013 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_CHROMEOS_UI_FOCUS_RING_CONTROLLER_H_
#define CHROME_BROWSER_CHROMEOS_UI_FOCUS_RING_CONTROLLER_H_
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/widget_focus_manager.h"
#include "ui/views/widget/widget_observer.h"
namespace views {
class View;
class Widget;
}
namespace chromeos {
class FocusRingLayer;
// FocusRingController manages the focus ring around the focused view. It
// follows widget focus change and update the focus ring layer when the focused
// view of the widget changes.
class FocusRingController : public views::WidgetObserver,
public views::WidgetFocusChangeListener,
public views::FocusChangeListener {
public:
FocusRingController();
virtual ~FocusRingController();
// Turns on/off the focus ring.
void SetVisible(bool visible);
private:
// Sets the focused |widget|.
void SetWidget(views::Widget* widget);
// Updates the focus ring to the focused view of |widget_|. If |widget_| is
// NULL or has no focused view, removes the focus ring. Otherwise, draws it.
void UpdateFocusRing();
// views::WidgetObserver overrides:
virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE;
virtual void OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) OVERRIDE;
// views::WidgetFocusChangeListener overrides:
virtual void OnNativeFocusChange(gfx::NativeView focused_before,
gfx::NativeView focused_now) OVERRIDE;
// views::FocusChangeListener overrides:
virtual void OnWillChangeFocus(views::View* focused_before,
views::View* focused_now) OVERRIDE;
virtual void OnDidChangeFocus(views::View* focused_before,
views::View* focused_now) OVERRIDE;
bool visible_;
views::Widget* widget_;
scoped_ptr<FocusRingLayer> focus_ring_layer_;
DISALLOW_COPY_AND_ASSIGN(FocusRingController);
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_UI_FOCUS_RING_CONTROLLER_H_
// Copyright 2013 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/chromeos/ui/focus_ring_layer.h"
#include "base/bind.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/canvas_image_source.h"
#include "ui/gfx/shadow_value.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/painter.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
namespace chromeos {
namespace {
const int kShadowRadius = 23;
const int kCenterBlockSize = 2 * kShadowRadius;
const int kFocusRingImageSize = kShadowRadius * 2 + kCenterBlockSize;
const SkColor kShadowColor = SkColorSetRGB(77, 144, 254);
// FocusRingImageSource generates a base image that could be used by
// ImagePainter to paint a focus ring around a rect. The base image is a
// transparent square block of kCenterBlockSize pixels with blue halo around.
class FocusRingImageSource : public gfx::CanvasImageSource {
public:
FocusRingImageSource()
: CanvasImageSource(gfx::Size(kFocusRingImageSize, kFocusRingImageSize),
false) {
shadows_.push_back(
gfx::ShadowValue(gfx::Point(), kShadowRadius, kShadowColor));
}
virtual void Draw(gfx::Canvas* canvas) OVERRIDE {
SkPaint paint;
paint.setColor(kShadowColor);
skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(shadows_);
paint.setLooper(looper.get());
const gfx::Rect rect(kShadowRadius, kShadowRadius,
kCenterBlockSize, kCenterBlockSize);
canvas->DrawRect(rect, paint);
canvas->FillRect(rect, SK_ColorTRANSPARENT, SkXfermode::kSrc_Mode);
}
private:
gfx::ShadowValues shadows_;
DISALLOW_COPY_AND_ASSIGN(FocusRingImageSource);
};
} // namespace
FocusRingLayer::FocusRingLayer() {
gfx::ImageSkia ring_image(
new FocusRingImageSource,
gfx::Size(kFocusRingImageSize, kFocusRingImageSize));
ring_painter_.reset(views::Painter::CreateImagePainter(
ring_image,
gfx::Insets(kShadowRadius, kShadowRadius, kShadowRadius, kShadowRadius)));
}
FocusRingLayer::~FocusRingLayer() {}
void FocusRingLayer::SetForView(views::View* view) {
if (!view ||
!view->GetWidget() ||
!view->GetWidget()->GetNativeWindow() ||
!view->GetWidget()->GetNativeWindow()->layer()) {
layer_.reset();
return;
}
if (!layer_) {
layer_.reset(new ui::Layer(ui::LAYER_TEXTURED));
layer_->set_name("FocusRing");
layer_->set_delegate(this);
layer_->SetFillsBoundsOpaquely(false);
}
// Puts the focus ring layer as a sibling layer of the widget layer so that
// it does not clip at the widget's boundary.
ui::Layer* widget_layer = view->GetWidget()->GetNativeWindow()->layer();
widget_layer->parent()->Add(layer_.get());
// A workaround that attempts to pick a better bounds for LabelButton.
gfx::Rect view_bounds = view->GetContentsBounds();
if (view->GetClassName() == views::LabelButton::kViewClassName) {
view_bounds = view->GetLocalBounds();
view_bounds.Inset(2, 2, 2, 2);
}
// Note the bounds calculation below assumes no transformation and ignores
// animations.
const gfx::Rect widget_bounds = widget_layer->GetTargetBounds();
gfx::Rect bounds = view->ConvertRectToWidget(view_bounds);
bounds.Offset(widget_bounds.OffsetFromOrigin());
bounds.Inset(-kShadowRadius, -kShadowRadius, -kShadowRadius, -kShadowRadius);
layer_->SetBounds(bounds);
}
void FocusRingLayer::OnPaintLayer(gfx::Canvas* canvas) {
ring_painter_->Paint(canvas, layer_->bounds().size());
}
void FocusRingLayer::OnDeviceScaleFactorChanged(float device_scale_factor) {
}
base::Closure FocusRingLayer::PrepareForLayerBoundsChange() {
return base::Bind(&base::DoNothing);
}
} // namespace chromeos
// Copyright 2013 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_CHROMEOS_UI_FOCUS_RING_LAYER_H_
#define CHROME_BROWSER_CHROMEOS_UI_FOCUS_RING_LAYER_H_
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "ui/compositor/layer_delegate.h"
namespace ui {
class Layer;
}
namespace views {
class Painter;
class View;
}
namespace chromeos {
// FocusRingLayer draws a focus ring for a given view.
class FocusRingLayer : public ui::LayerDelegate {
public:
FocusRingLayer();
virtual ~FocusRingLayer();
// Updates the focus ring layer for the view or clears it if |view| is NULL.
void SetForView(views::View* view);
private:
// ui::LayerDelegate overrides:
virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE;
virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE;
scoped_ptr<ui::Layer> layer_;
scoped_ptr<views::Painter> ring_painter_;
DISALLOW_COPY_AND_ASSIGN(FocusRingLayer);
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_UI_FOCUS_RING_LAYER_H_
...@@ -754,6 +754,10 @@ ...@@ -754,6 +754,10 @@
'browser/chromeos/ui/echo_dialog_listener.h', 'browser/chromeos/ui/echo_dialog_listener.h',
'browser/chromeos/ui/echo_dialog_view.cc', 'browser/chromeos/ui/echo_dialog_view.cc',
'browser/chromeos/ui/echo_dialog_view.h', 'browser/chromeos/ui/echo_dialog_view.h',
'browser/chromeos/ui/focus_ring_controller.cc',
'browser/chromeos/ui/focus_ring_controller.h',
'browser/chromeos/ui/focus_ring_layer.cc',
'browser/chromeos/ui/focus_ring_layer.h',
'browser/chromeos/ui/idle_logout_dialog_view.cc', 'browser/chromeos/ui/idle_logout_dialog_view.cc',
'browser/chromeos/ui/idle_logout_dialog_view.h', 'browser/chromeos/ui/idle_logout_dialog_view.h',
'browser/chromeos/ui/screen_capture_notification_ui_chromeos.cc', 'browser/chromeos/ui/screen_capture_notification_ui_chromeos.cc',
......
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