summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkerz@chromium.org <kerz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-08 00:26:47 +0000
committerkerz@chromium.org <kerz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-08 00:26:47 +0000
commit336dc50b8ec727d43ce7f10123659bf9322bdcdd (patch)
treee7ebde3fbdd79a7ee48b51ca80f8a43b4af198f0
parent127374758dbf0b548b697b429b88fb8434b99f30 (diff)
downloadchromium_src-336dc50b8ec727d43ce7f10123659bf9322bdcdd.zip
chromium_src-336dc50b8ec727d43ce7f10123659bf9322bdcdd.tar.gz
chromium_src-336dc50b8ec727d43ce7f10123659bf9322bdcdd.tar.bz2
Merge 113149 - Reland 112770, but with test disabled.
Prevent a crash in the first run search engine selector. It is possible to try and close the window now before the TemplateURLService is loaded. In this case we will not have a fallback search engine to select by default. So we will just reject attempts to close the window in this circumstance until it is loaded and a fallback choice has been set. It should be an edge case. BUG=106078 TEST=unit test Review URL: http://codereview.chromium.org/8771018 TBR=ben@chromium.org Review URL: http://codereview.chromium.org/8870007 git-svn-id: svn://svn.chromium.org/chrome/branches/963/src@113514 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/ui/views/first_run_search_engine_view.cc29
-rw-r--r--chrome/browser/ui/views/first_run_search_engine_view.h14
-rw-r--r--chrome/browser/ui/views/first_run_search_engine_view_unittest.cc58
-rw-r--r--ui/views/test/views_test_base.h2
4 files changed, 98 insertions, 5 deletions
diff --git a/chrome/browser/ui/views/first_run_search_engine_view.cc b/chrome/browser/ui/views/first_run_search_engine_view.cc
index 1f1e13f..665189f 100644
--- a/chrome/browser/ui/views/first_run_search_engine_view.cc
+++ b/chrome/browser/ui/views/first_run_search_engine_view.cc
@@ -140,7 +140,8 @@ void SearchEngineChoice::SetChoiceViewBounds(int x, int y, int width,
FirstRunSearchEngineView::FirstRunSearchEngineView(Profile* profile,
bool randomize)
- : background_image_(NULL),
+ : views::ClientView(NULL, NULL),
+ background_image_(NULL),
template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)),
text_direction_is_rtl_(base::i18n::IsRTL()),
added_to_view_hierarchy_(false),
@@ -169,6 +170,15 @@ string16 FirstRunSearchEngineView::GetWindowTitle() const {
return l10n_util::GetStringUTF16(IDS_FIRSTRUN_DLG_TITLE);
}
+views::View* FirstRunSearchEngineView::GetContentsView() {
+ return this;
+}
+
+views::ClientView* FirstRunSearchEngineView::CreateClientView(
+ views::Widget* widget) {
+ return this;
+}
+
void FirstRunSearchEngineView::WindowClosing() {
// If the window is closed by clicking the close button, we default to the
// engine in the first slot.
@@ -178,6 +188,21 @@ void FirstRunSearchEngineView::WindowClosing() {
MessageLoop::current()->Quit();
}
+views::Widget* FirstRunSearchEngineView::GetWidget() {
+ return View::GetWidget();
+}
+
+const views::Widget* FirstRunSearchEngineView::GetWidget() const {
+ return View::GetWidget();
+}
+
+bool FirstRunSearchEngineView::CanClose() {
+ // We need a valid search engine to set as default, so if the user tries to
+ // close the window before the template URL service is loaded, we must prevent
+ // this from happening.
+ return fallback_choice_ != NULL;
+}
+
void FirstRunSearchEngineView::ButtonPressed(views::Button* sender,
const views::Event& event) {
ChooseSearchEngine(static_cast<SearchEngineChoice*>(sender));
@@ -477,7 +502,7 @@ void FirstRunSearchEngineView::AddSearchEnginesIfPossible() {
void FirstRunSearchEngineView::ChooseSearchEngine(SearchEngineChoice* choice) {
user_chosen_engine_ = true;
- DCHECK(template_url_service_);
+ DCHECK(choice && template_url_service_);
template_url_service_->SetSearchEngineDialogSlot(choice->slot());
const TemplateURL* default_search = choice->GetSearchEngine();
if (default_search)
diff --git a/chrome/browser/ui/views/first_run_search_engine_view.h b/chrome/browser/ui/views/first_run_search_engine_view.h
index 28ef439..841c2e5 100644
--- a/chrome/browser/ui/views/first_run_search_engine_view.h
+++ b/chrome/browser/ui/views/first_run_search_engine_view.h
@@ -13,6 +13,7 @@
#include "ui/views/controls/button/text_button.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/window/client_view.h"
class Profile;
class TemplateURL;
@@ -74,7 +75,8 @@ class SearchEngineChoice : public views::NativeTextButton {
// This class displays a large search engine choice dialog view during
// initial first run import.
-class FirstRunSearchEngineView : public views::WidgetDelegateView,
+class FirstRunSearchEngineView : public views::ClientView,
+ public views::WidgetDelegate,
public views::ButtonListener,
public TemplateURLServiceObserver {
public:
@@ -84,10 +86,16 @@ class FirstRunSearchEngineView : public views::WidgetDelegateView,
virtual ~FirstRunSearchEngineView();
- // Overridden from views::WidgetDelegateView:
+ // Overridden from views::WidgetDelegate:
virtual string16 GetWindowTitle() const OVERRIDE;
- virtual views::View* GetContentsView() OVERRIDE { return this; }
+ virtual views::View* GetContentsView() OVERRIDE;
+ virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
virtual void WindowClosing() OVERRIDE;
+ virtual views::Widget* GetWidget() OVERRIDE;
+ virtual const views::Widget* GetWidget() const OVERRIDE;
+
+ // Overridden from views::ClientView:
+ virtual bool CanClose() OVERRIDE;
// Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* sender,
diff --git a/chrome/browser/ui/views/first_run_search_engine_view_unittest.cc b/chrome/browser/ui/views/first_run_search_engine_view_unittest.cc
index f0e191f..8d47890 100644
--- a/chrome/browser/ui/views/first_run_search_engine_view_unittest.cc
+++ b/chrome/browser/ui/views/first_run_search_engine_view_unittest.cc
@@ -7,7 +7,12 @@
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/common/chrome_notification_types.h"
#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/browser/browser_process_sub_thread.h"
+#include "content/public/browser/notification_service.h"
+#include "content/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/focus/accelerator_handler.h"
#include "ui/views/test/views_test_base.h"
@@ -49,3 +54,56 @@ TEST_F(FirstRunSearchEngineViewTest, ClosingSelectsFirstEngine) {
ASSERT_TRUE(!template_urls.empty());
EXPECT_EQ(template_urls.front(), service->GetDefaultSearchProvider());
}
+
+TEST_F(FirstRunSearchEngineViewTest, ClosingBeforeServiceLoadedAbortsClose) {
+ // This ensures the current thread is named the UI thread, so code that checks
+ // that this is the UI thread doesn't assert.
+ content::TestBrowserThread ui_thread(content::BrowserThread::UI,
+ message_loop());
+ content::BrowserProcessSubThread db_thread(content::BrowserThread::DB);
+ db_thread.StartWithOptions(base::Thread::Options());
+
+ TestingProfile profile;
+ // We need to initialize the web database before accessing the template url
+ // service otherwise the template url service will init itself synchronously
+ // and appear to be loaded.
+ profile.CreateWebDataService(false);
+ profile.CreateTemplateURLService();
+
+ // Instead of giving the template url service a chance to load, try and close
+ // the window immediately.
+ FirstRunSearchEngineView* contents =
+ new FirstRunSearchEngineView(&profile, false);
+ contents->set_quit_on_closing(false);
+ views::Widget* window = views::Widget::CreateWindow(contents);
+ window->Show();
+ EXPECT_TRUE(window->IsVisible());
+ window->Close();
+ // The window wouldn't actually be closed until a return to the message loop,
+ // which we don't want to spin here because the window shouldn't have closed
+ // in the correct case. The window is however actually hidden immediately when
+ // the window is allowed to close, so we can test for visibility to make sure
+ // it hasn't.
+ EXPECT_TRUE(window->IsVisible());
+
+ // Now let the template url service a chance to load.
+ ui_test_utils::WindowedNotificationObserver service_load_observer(
+ chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED,
+ content::NotificationService::AllSources());
+ service_load_observer.Wait();
+
+ // .. and try and close the window. It should be allowed to now.
+ window->Close();
+ EXPECT_FALSE(window->IsVisible());
+
+ // Allow the window to actually close.
+ RunPendingMessages();
+
+ // Verify goodness. Because we actually went to the trouble of starting the
+ // WebDB, we will have real data in the model, so we can verify a choice was
+ // made without having to seed the model with dummy data.
+ TemplateURLService* service =
+ TemplateURLServiceFactory::GetForProfile(&profile);
+ ASSERT_TRUE(service != NULL);
+ EXPECT_TRUE(service->GetDefaultSearchProvider() != NULL);
+}
diff --git a/ui/views/test/views_test_base.h b/ui/views/test/views_test_base.h
index 51a9df6..eed6889 100644
--- a/ui/views/test/views_test_base.h
+++ b/ui/views/test/views_test_base.h
@@ -35,6 +35,8 @@ class ViewsTestBase : public testing::Test {
views_delegate_.reset(views_delegate);
}
+ MessageLoop* message_loop() { return &message_loop_; }
+
private:
MessageLoopForUI message_loop_;
scoped_ptr<TestViewsDelegate> views_delegate_;