Commit 65059c07 authored by estade@chromium.org's avatar estade@chromium.org

rAc: Enforce a 3 second grace period for generated card bubble.

Bubble may not be dismissed for the first 3 seconds (except by clicking on the Learn More link). The length of the grace period is subject to future tweaking.

BUG=282671

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221601 0039d316-1c4b-4281-b951-d872f2087c98
parent d0c6a7fd
...@@ -34,9 +34,19 @@ views::View* GetAnchor( ...@@ -34,9 +34,19 @@ views::View* GetAnchor(
GeneratedCreditCardBubbleViews::~GeneratedCreditCardBubbleViews() {} GeneratedCreditCardBubbleViews::~GeneratedCreditCardBubbleViews() {}
void GeneratedCreditCardBubbleViews::Show() { void GeneratedCreditCardBubbleViews::Show() {
// TODO(dbeam): investigate why this steals focus from the web contents.
views::BubbleDelegateView::CreateBubble(this)->Show(); views::BubbleDelegateView::CreateBubble(this)->Show();
// Grab mouse events for 3 seconds after showing. This prevents clicks outside
// of the bubble from dismissing the bubble. After 3 seconds, it will revert
// to normal close-on-deactivate behavior.
GetWidget()->SetCapture(NULL);
GetWidget()->set_auto_release_capture(false);
capture_timer_.Start(
FROM_HERE,
base::TimeDelta::FromSeconds(3),
this,
&GeneratedCreditCardBubbleViews::ReleaseCapture);
// This bubble doesn't render correctly on Windows without calling // This bubble doesn't render correctly on Windows without calling
// |SizeToContents()|. This must be called after showing the widget. // |SizeToContents()|. This must be called after showing the widget.
SizeToContents(); SizeToContents();
...@@ -105,4 +115,8 @@ GeneratedCreditCardBubbleViews::GeneratedCreditCardBubbleViews( ...@@ -105,4 +115,8 @@ GeneratedCreditCardBubbleViews::GeneratedCreditCardBubbleViews(
set_margins(gfx::Insets(0, insets.left(), insets.top(), insets.left())); set_margins(gfx::Insets(0, insets.left(), insets.top(), insets.left()));
} }
void GeneratedCreditCardBubbleViews::ReleaseCapture() {
GetWidget()->ReleaseCapture();
}
} // namespace autofill } // namespace autofill
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "chrome/browser/ui/autofill/generated_credit_card_bubble_view.h" #include "chrome/browser/ui/autofill/generated_credit_card_bubble_view.h"
#include "ui/views/bubble/bubble_delegate.h" #include "ui/views/bubble/bubble_delegate.h"
#include "ui/views/controls/styled_label_listener.h" #include "ui/views/controls/styled_label_listener.h"
...@@ -47,10 +48,16 @@ class GeneratedCreditCardBubbleViews : public GeneratedCreditCardBubbleView, ...@@ -47,10 +48,16 @@ class GeneratedCreditCardBubbleViews : public GeneratedCreditCardBubbleView,
explicit GeneratedCreditCardBubbleViews( explicit GeneratedCreditCardBubbleViews(
const base::WeakPtr<GeneratedCreditCardBubbleController>& controller); const base::WeakPtr<GeneratedCreditCardBubbleController>& controller);
// Releases focus capture (which is assumed on Show()).
void ReleaseCapture();
// Controller that drives this bubble. May be invalid when hiding. // Controller that drives this bubble. May be invalid when hiding.
base::WeakPtr<GeneratedCreditCardBubbleController> controller_; base::WeakPtr<GeneratedCreditCardBubbleController> controller_;
base::WeakPtrFactory<GeneratedCreditCardBubbleView> weak_ptr_factory_; // A timer used for releasing focus capture.
base::OneShotTimer<GeneratedCreditCardBubbleViews> capture_timer_;
base::WeakPtrFactory<GeneratedCreditCardBubbleViews> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(GeneratedCreditCardBubbleViews); DISALLOW_COPY_AND_ASSIGN(GeneratedCreditCardBubbleViews);
}; };
......
...@@ -378,6 +378,7 @@ ...@@ -378,6 +378,7 @@
}, { # else: toolkit_views == 0 }, { # else: toolkit_views == 0
'sources/': [ 'sources/': [
['exclude', '^browser/ui/views/'], ['exclude', '^browser/ui/views/'],
['exclude', '^../ui/views/'],
], ],
}], }],
['use_ash==1', { ['use_ash==1', {
...@@ -393,7 +394,6 @@ ...@@ -393,7 +394,6 @@
['use_aura==0 or chromeos==1', { ['use_aura==0 or chromeos==1', {
'sources!': [ 'sources!': [
'../ui/views/corewm/desktop_capture_controller_unittest.cc', '../ui/views/corewm/desktop_capture_controller_unittest.cc',
'../ui/views/widget/widget_interactive_uitest.cc',
], ],
}], }],
['chromeos==1', { ['chromeos==1', {
......
...@@ -29,6 +29,7 @@ MenuHost::MenuHost(SubmenuView* submenu) ...@@ -29,6 +29,7 @@ MenuHost::MenuHost(SubmenuView* submenu)
: submenu_(submenu), : submenu_(submenu),
destroying_(false), destroying_(false),
ignore_capture_lost_(false) { ignore_capture_lost_(false) {
set_auto_release_capture(false);
} }
MenuHost::~MenuHost() { MenuHost::~MenuHost() {
...@@ -109,10 +110,6 @@ internal::RootView* MenuHost::CreateRootView() { ...@@ -109,10 +110,6 @@ internal::RootView* MenuHost::CreateRootView() {
return new MenuHostRootView(this, submenu_); return new MenuHostRootView(this, submenu_);
} }
bool MenuHost::ShouldReleaseCaptureOnMouseReleased() const {
return false;
}
void MenuHost::OnMouseCaptureLost() { void MenuHost::OnMouseCaptureLost() {
if (destroying_ || ignore_capture_lost_) if (destroying_ || ignore_capture_lost_)
return; return;
......
...@@ -57,7 +57,6 @@ class MenuHost : public Widget { ...@@ -57,7 +57,6 @@ class MenuHost : public Widget {
private: private:
// Overridden from Widget: // Overridden from Widget:
virtual internal::RootView* CreateRootView() OVERRIDE; virtual internal::RootView* CreateRootView() OVERRIDE;
virtual bool ShouldReleaseCaptureOnMouseReleased() const OVERRIDE;
virtual void OnMouseCaptureLost() OVERRIDE; virtual void OnMouseCaptureLost() OVERRIDE;
virtual void OnNativeWidgetDestroyed() OVERRIDE; virtual void OnNativeWidgetDestroyed() OVERRIDE;
virtual void OnOwnerClosing() OVERRIDE; virtual void OnOwnerClosing() OVERRIDE;
......
// 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 "ui/views/test/widget_test.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/widget/root_view.h"
namespace views {
namespace test {
// A widget that assumes mouse capture always works. It won't on Aura in
// testing, so we mock it.
#if defined(USE_AURA)
NativeWidgetCapture::NativeWidgetCapture(
internal::NativeWidgetDelegate* delegate)
: NativeWidgetPlatform(delegate),
mouse_capture_(false) {}
NativeWidgetCapture::~NativeWidgetCapture() {}
void NativeWidgetCapture::SetCapture() {
mouse_capture_ = true;
}
void NativeWidgetCapture::ReleaseCapture() {
if (mouse_capture_)
delegate()->OnMouseCaptureLost();
mouse_capture_ = false;
}
bool NativeWidgetCapture::HasCapture() const {
return mouse_capture_;
}
#endif
WidgetTest::WidgetTest() {}
WidgetTest::~WidgetTest() {}
NativeWidget* WidgetTest::CreatePlatformNativeWidget(
internal::NativeWidgetDelegate* delegate) {
return new NativeWidgetPlatformForTest(delegate);
}
Widget* WidgetTest::CreateTopLevelPlatformWidget() {
Widget* toplevel = new Widget;
Widget::InitParams toplevel_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
toplevel_params.native_widget = CreatePlatformNativeWidget(toplevel);
toplevel->Init(toplevel_params);
return toplevel;
}
Widget* WidgetTest::CreateTopLevelFramelessPlatformWidget() {
Widget* toplevel = new Widget;
Widget::InitParams toplevel_params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
toplevel_params.native_widget = CreatePlatformNativeWidget(toplevel);
toplevel->Init(toplevel_params);
return toplevel;
}
Widget* WidgetTest::CreateChildPlatformWidget(
gfx::NativeView parent_native_view) {
Widget* child = new Widget;
Widget::InitParams child_params =
CreateParams(Widget::InitParams::TYPE_CONTROL);
child_params.native_widget = CreatePlatformNativeWidget(child);
child_params.parent = parent_native_view;
child->Init(child_params);
child->SetContentsView(new View);
return child;
}
#if defined(OS_WIN) && !defined(USE_AURA)
// On Windows, it is possible for us to have a child window that is
// TYPE_POPUP.
Widget* WidgetTest::CreateChildPopupPlatformWidget(
gfx::NativeView parent_native_view) {
Widget* child = new Widget;
Widget::InitParams child_params =
CreateParams(Widget::InitParams::TYPE_POPUP);
child_params.child = true;
child_params.native_widget = CreatePlatformNativeWidget(child);
child_params.parent = parent_native_view;
child->Init(child_params);
child->SetContentsView(new View);
return child;
}
#endif
Widget* WidgetTest::CreateTopLevelNativeWidget() {
Widget* toplevel = new Widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
toplevel->Init(params);
return toplevel;
}
Widget* WidgetTest::CreateChildNativeWidgetWithParent(Widget* parent) {
Widget* child = new Widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_CONTROL);
params.parent = parent->GetNativeView();
child->Init(params);
child->SetContentsView(new View);
return child;
}
Widget* WidgetTest::CreateChildNativeWidget() {
return CreateChildNativeWidgetWithParent(NULL);
}
View* WidgetTest::GetMousePressedHandler(internal::RootView* root_view) {
return root_view->mouse_pressed_handler_;
}
View* WidgetTest::GetMouseMoveHandler(internal::RootView* root_view) {
return root_view->mouse_move_handler_;
}
View* WidgetTest::GetGestureHandler(internal::RootView* root_view) {
return root_view->gesture_handler_;
}
} // namespace test
} // namespace views
// 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 UI_VIEWS_TEST_WIDGET_TEST_H_
#define UI_VIEWS_TEST_WIDGET_TEST_H_
#include "ui/gfx/native_widget_types.h"
#include "ui/views/test/views_test_base.h"
#if defined(USE_AURA)
#include "ui/views/widget/native_widget_aura.h"
#elif defined(OS_WIN)
#include "ui/views/widget/native_widget_win.h"
#endif
namespace views {
class NativeWidget;
class Widget;
namespace internal {
class RootView;
} // namespace internal
namespace test {
#if defined(USE_AURA)
// A typedef that inserts our mock-capture NativeWidget implementation for
// relevant platforms.
typedef NativeWidgetAura NativeWidgetPlatform;
// A widget that assumes mouse capture always works. It won't on Aura in
// testing, so we mock it.
class NativeWidgetCapture : public NativeWidgetPlatform {
public:
explicit NativeWidgetCapture(internal::NativeWidgetDelegate* delegate);
virtual ~NativeWidgetCapture();
virtual void SetCapture() OVERRIDE;
virtual void ReleaseCapture() OVERRIDE;
virtual bool HasCapture() const OVERRIDE;
private:
bool mouse_capture_;
DISALLOW_COPY_AND_ASSIGN(NativeWidgetCapture);
};
// A generic typedef to pick up relevant NativeWidget implementations.
typedef NativeWidgetCapture NativeWidgetPlatformForTest;
#elif defined(OS_WIN)
typedef NativeWidgetWin NativeWidgetPlatform;
typedef NativeWidgetWin NativeWidgetPlatformForTest;
#endif
class WidgetTest : public ViewsTestBase {
public:
WidgetTest();
virtual ~WidgetTest();
NativeWidget* CreatePlatformNativeWidget(
internal::NativeWidgetDelegate* delegate);
Widget* CreateTopLevelPlatformWidget();
Widget* CreateTopLevelFramelessPlatformWidget();
Widget* CreateChildPlatformWidget(gfx::NativeView parent_native_view);
#if defined(OS_WIN) && !defined(USE_AURA)
// On Windows, it is possible for us to have a child window that is
// TYPE_POPUP.
Widget* CreateChildPopupPlatformWidget(gfx::NativeView parent_native_view);
#endif
Widget* CreateTopLevelNativeWidget();
Widget* CreateChildNativeWidgetWithParent(Widget* parent);
Widget* CreateChildNativeWidget();
View* GetMousePressedHandler(internal::RootView* root_view);
View* GetMouseMoveHandler(internal::RootView* root_view);
View* GetGestureHandler(internal::RootView* root_view);
private:
DISALLOW_COPY_AND_ASSIGN(WidgetTest);
};
} // namespace test
} // namespace views
#endif // UI_VIEWS_TEST_WIDGET_TEST_H_
...@@ -623,6 +623,8 @@ ...@@ -623,6 +623,8 @@
'test/test_widget_observer.h', 'test/test_widget_observer.h',
'test/views_test_base.cc', 'test/views_test_base.cc',
'test/views_test_base.h', 'test/views_test_base.h',
'test/widget_test.cc',
'test/widget_test.h',
'widget/root_view_test_helper.h', 'widget/root_view_test_helper.h',
], ],
'conditions': [ 'conditions': [
......
...@@ -178,6 +178,7 @@ Widget::Widget() ...@@ -178,6 +178,7 @@ Widget::Widget()
is_mouse_button_pressed_(false), is_mouse_button_pressed_(false),
is_touch_down_(false), is_touch_down_(false),
last_mouse_event_was_move_(false), last_mouse_event_was_move_(false),
auto_release_capture_(true),
root_layers_dirty_(false), root_layers_dirty_(false),
movement_disabled_(false) { movement_disabled_(false) {
} }
...@@ -1165,10 +1166,8 @@ void Widget::OnMouseEvent(ui::MouseEvent* event) { ...@@ -1165,10 +1166,8 @@ void Widget::OnMouseEvent(ui::MouseEvent* event) {
last_mouse_event_was_move_ = false; last_mouse_event_was_move_ = false;
is_mouse_button_pressed_ = false; is_mouse_button_pressed_ = false;
// Release capture first, to avoid confusion if OnMouseReleased blocks. // Release capture first, to avoid confusion if OnMouseReleased blocks.
if (native_widget_->HasCapture() && if (auto_release_capture_ && native_widget_->HasCapture())
ShouldReleaseCaptureOnMouseReleased()) {
native_widget_->ReleaseCapture(); native_widget_->ReleaseCapture();
}
if (root_view) if (root_view)
root_view->OnMouseReleased(*event); root_view->OnMouseReleased(*event);
if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0) if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0)
...@@ -1236,7 +1235,7 @@ void Widget::OnGestureEvent(ui::GestureEvent* event) { ...@@ -1236,7 +1235,7 @@ void Widget::OnGestureEvent(ui::GestureEvent* event) {
case ui::ET_GESTURE_END: case ui::ET_GESTURE_END:
if (event->details().touch_points() == 1) { if (event->details().touch_points() == 1) {
is_touch_down_ = false; is_touch_down_ = false;
if (ShouldReleaseCaptureOnMouseReleased()) if (auto_release_capture_)
ReleaseCapture(); ReleaseCapture();
} }
break; break;
...@@ -1319,10 +1318,6 @@ void Widget::DestroyRootView() { ...@@ -1319,10 +1318,6 @@ void Widget::DestroyRootView() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Widget, private: // Widget, private:
bool Widget::ShouldReleaseCaptureOnMouseReleased() const {
return true;
}
void Widget::SetInactiveRenderingDisabled(bool value) { void Widget::SetInactiveRenderingDisabled(bool value) {
if (value == disable_inactive_rendering_) if (value == disable_inactive_rendering_)
return; return;
......
...@@ -631,7 +631,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, ...@@ -631,7 +631,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
} }
// Sets capture to the specified view. This makes it so that all mouse, touch // Sets capture to the specified view. This makes it so that all mouse, touch
// and gesture events go to |view|. // and gesture events go to |view|. If |view| is NULL, the widget still
// obtains event capture, but the events will go to the view they'd normally
// go to.
void SetCapture(View* view); void SetCapture(View* view);
// Releases capture. // Releases capture.
...@@ -640,6 +642,10 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, ...@@ -640,6 +642,10 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// Returns true if the widget has capture. // Returns true if the widget has capture.
bool HasCapture(); bool HasCapture();
void set_auto_release_capture(bool auto_release_capture) {
auto_release_capture_ = auto_release_capture;
}
// Invoked when the tooltip text changes for the specified views. // Invoked when the tooltip text changes for the specified views.
void TooltipTextChanged(View* view); void TooltipTextChanged(View* view);
...@@ -735,9 +741,6 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, ...@@ -735,9 +741,6 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
friend class NativeTextfieldViewsTest; friend class NativeTextfieldViewsTest;
friend class NativeComboboxViewsTest; friend class NativeComboboxViewsTest;
// Returns whether capture should be released on mouse release.
virtual bool ShouldReleaseCaptureOnMouseReleased() const;
// Sets the value of |disable_inactive_rendering_|. If the value changes, // Sets the value of |disable_inactive_rendering_|. If the value changes,
// both the NonClientView and WidgetDelegate are notified. // both the NonClientView and WidgetDelegate are notified.
void SetInactiveRenderingDisabled(bool value); void SetInactiveRenderingDisabled(bool value);
...@@ -852,6 +855,10 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, ...@@ -852,6 +855,10 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
bool last_mouse_event_was_move_; bool last_mouse_event_was_move_;
gfx::Point last_mouse_event_position_; gfx::Point last_mouse_event_position_;
// True if event capture should be released on a mouse up event. Default is
// true.
bool auto_release_capture_;
// See description in GetRootLayers(). // See description in GetRootLayers().
std::vector<ui::Layer*> root_layers_; std::vector<ui::Layer*> root_layers_;
......
This diff is collapsed.
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