Home | History | Annotate | Download | only in login
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/login/eula_view.h"
      6 
      7 #include <signal.h>
      8 #include <sys/types.h>
      9 #include <string>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/message_loop.h"
     13 #include "base/task.h"
     14 #include "base/utf_string_conversions.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/browser_process.h"
     17 #include "chrome/browser/chromeos/cros/cros_library.h"
     18 #include "chrome/browser/chromeos/cros/cryptohome_library.h"
     19 #include "chrome/browser/chromeos/customization_document.h"
     20 #include "chrome/browser/chromeos/login/background_view.h"
     21 #include "chrome/browser/chromeos/login/help_app_launcher.h"
     22 #include "chrome/browser/chromeos/login/helper.h"
     23 #include "chrome/browser/chromeos/login/login_utils.h"
     24 #include "chrome/browser/chromeos/login/network_screen_delegate.h"
     25 #include "chrome/browser/chromeos/login/rounded_rect_painter.h"
     26 #include "chrome/browser/chromeos/login/wizard_controller.h"
     27 #include "chrome/browser/profiles/profile_manager.h"
     28 #include "chrome/browser/ui/views/dom_view.h"
     29 #include "chrome/browser/ui/views/window.h"
     30 #include "chrome/common/url_constants.h"
     31 #include "content/browser/site_instance.h"
     32 #include "content/browser/tab_contents/tab_contents.h"
     33 #include "content/common/native_web_keyboard_event.h"
     34 #include "grit/chromium_strings.h"
     35 #include "grit/generated_resources.h"
     36 #include "grit/locale_settings.h"
     37 #include "grit/theme_resources.h"
     38 #include "ui/base/l10n/l10n_util.h"
     39 #include "ui/base/resource/resource_bundle.h"
     40 #include "views/controls/button/checkbox.h"
     41 #include "views/controls/button/native_button_gtk.h"
     42 #include "views/controls/label.h"
     43 #include "views/controls/throbber.h"
     44 #include "views/events/event.h"
     45 #include "views/layout/grid_layout.h"
     46 #include "views/layout/layout_constants.h"
     47 #include "views/layout/layout_manager.h"
     48 #include "views/widget/widget_gtk.h"
     49 #include "views/window/dialog_delegate.h"
     50 #include "views/window/window.h"
     51 
     52 using views::WidgetGtk;
     53 
     54 namespace {
     55 
     56 const int kBorderSize = 10;
     57 const int kCheckboxWidth = 26;
     58 const int kLastButtonHorizontalMargin = 10;
     59 const int kMargin = 20;
     60 const int kTextMargin = 10;
     61 const int kTpmCheckIntervalMs = 500;
     62 
     63 // TODO(glotov): this URL should be changed to actual Google ChromeOS EULA.
     64 // See crbug.com/4647
     65 const char kGoogleEulaUrl[] = "about:terms";
     66 
     67 enum kLayoutColumnsets {
     68   SINGLE_CONTROL_ROW,
     69   SINGLE_CONTROL_WITH_SHIFT_ROW,
     70   SINGLE_LINK_WITH_SHIFT_ROW,
     71   LAST_ROW
     72 };
     73 
     74 // Helper class that disables using native label for subclassed GTK control.
     75 class EULANativeCheckboxGtk : public views::NativeCheckboxGtk {
     76  public:
     77   explicit EULANativeCheckboxGtk(views::Checkbox* checkbox)
     78       : views::NativeCheckboxGtk(checkbox) {
     79     set_fast_resize(true);
     80   }
     81   virtual ~EULANativeCheckboxGtk() { }
     82   virtual bool UsesNativeLabel() const { return false; }
     83   virtual void UpdateLabel() { }
     84 };
     85 
     86 // views::Checkbox specialization that uses its internal views::Label
     87 // instead of native one. We need this because native label does not
     88 // support multiline property and we need it for certain languages.
     89 class EULACheckbox : public views::Checkbox {
     90  public:
     91   EULACheckbox() { }
     92   virtual ~EULACheckbox() { }
     93 
     94  protected:
     95   virtual views::NativeButtonWrapper* CreateWrapper() {
     96     views::NativeButtonWrapper* native_wrapper =
     97         new EULANativeCheckboxGtk(this);
     98     native_wrapper->UpdateChecked();
     99     return native_wrapper;
    100   }
    101 };
    102 
    103 // A simple LayoutManager that causes the associated view's one child to be
    104 // sized to match the bounds of its parent except the bounds, if set.
    105 struct FillLayoutWithBorder : public views::LayoutManager {
    106   // Overridden from LayoutManager:
    107   virtual void Layout(views::View* host) {
    108     DCHECK(host->has_children());
    109     host->GetChildViewAt(0)->SetBoundsRect(host->GetContentsBounds());
    110   }
    111   virtual gfx::Size GetPreferredSize(views::View* host) {
    112     return gfx::Size(host->width(), host->height());
    113   }
    114 };
    115 
    116 // System security setting dialog.
    117 class TpmInfoView : public views::View,
    118                     public views::DialogDelegate {
    119  public:
    120   explicit TpmInfoView(std::string* password)
    121       : ALLOW_THIS_IN_INITIALIZER_LIST(runnable_method_factory_(this)),
    122         password_(password) {
    123     DCHECK(password_);
    124   }
    125 
    126   void Init();
    127 
    128  protected:
    129   // views::DialogDelegate overrides:
    130   virtual bool Accept() { return true; }
    131   virtual bool IsModal() const { return true; }
    132   virtual views::View* GetContentsView() { return this; }
    133   virtual int GetDialogButtons() const {
    134     return MessageBoxFlags::DIALOGBUTTON_OK;
    135   }
    136 
    137   // views::View overrides:
    138   virtual std::wstring GetWindowTitle() const {
    139     return UTF16ToWide(
    140         l10n_util::GetStringUTF16(IDS_EULA_SYSTEM_SECURITY_SETTING));
    141   }
    142 
    143   gfx::Size GetPreferredSize() {
    144     return gfx::Size(views::Window::GetLocalizedContentsSize(
    145         IDS_TPM_INFO_DIALOG_WIDTH_CHARS,
    146         IDS_TPM_INFO_DIALOG_HEIGHT_LINES));
    147   }
    148 
    149  private:
    150   void PullPassword();
    151 
    152   ScopedRunnableMethodFactory<TpmInfoView> runnable_method_factory_;
    153 
    154   // Holds pointer to the password storage.
    155   std::string* password_;
    156 
    157   views::Label* busy_label_;
    158   views::Label* password_label_;
    159   views::Throbber* throbber_;
    160 
    161   DISALLOW_COPY_AND_ASSIGN(TpmInfoView);
    162 };
    163 
    164 void TpmInfoView::Init() {
    165   views::GridLayout* layout = views::GridLayout::CreatePanel(this);
    166   SetLayoutManager(layout);
    167   views::ColumnSet* column_set = layout->AddColumnSet(0);
    168   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
    169                         views::GridLayout::USE_PREF, 0, 0);
    170   layout->StartRow(0, 0);
    171   views::Label* label = new views::Label(UTF16ToWide(
    172       l10n_util::GetStringUTF16(IDS_EULA_SYSTEM_SECURITY_SETTING_DESCRIPTION)));
    173   label->SetMultiLine(true);
    174   label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    175   layout->AddView(label);
    176   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    177 
    178   layout->StartRow(0, 0);
    179   label = new views::Label(UTF16ToWide(l10n_util::GetStringUTF16(
    180       IDS_EULA_SYSTEM_SECURITY_SETTING_DESCRIPTION_KEY)));
    181   label->SetMultiLine(true);
    182   label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    183   layout->AddView(label);
    184   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    185 
    186   column_set = layout->AddColumnSet(1);
    187   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
    188                         views::GridLayout::USE_PREF, 0, 0);
    189   layout->StartRow(0, 1);
    190   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    191   gfx::Font password_font =
    192       rb.GetFont(ResourceBundle::MediumFont).DeriveFont(0, gfx::Font::BOLD);
    193   // Password will be set later.
    194   password_label_ = new views::Label(L"", password_font);
    195   password_label_->SetVisible(false);
    196   layout->AddView(password_label_);
    197   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    198 
    199   column_set = layout->AddColumnSet(2);
    200   column_set->AddPaddingColumn(1, 0);
    201   // Resize of the throbber and label is not allowed, since we want they to be
    202   // placed in the center.
    203   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
    204                         views::GridLayout::USE_PREF, 0, 0);
    205   column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
    206   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
    207                         views::GridLayout::USE_PREF, 0, 0);
    208   column_set->AddPaddingColumn(1, 0);
    209   // Border padding columns should have the same width. It guaranties that
    210   // throbber and label will be placed in the center.
    211   column_set->LinkColumnSizes(0, 4, -1);
    212 
    213   layout->StartRow(0, 2);
    214   throbber_ = chromeos::CreateDefaultThrobber();
    215   throbber_->Start();
    216   layout->AddView(throbber_);
    217   busy_label_ = new views::Label(
    218       UTF16ToWide(l10n_util::GetStringUTF16(IDS_EULA_TPM_BUSY)));
    219   layout->AddView(busy_label_);
    220   layout->AddPaddingRow(0, views::kRelatedControlHorizontalSpacing);
    221 
    222   PullPassword();
    223 }
    224 
    225 void TpmInfoView::PullPassword() {
    226   // Since this method is also called directly.
    227   runnable_method_factory_.RevokeAll();
    228 
    229   chromeos::CryptohomeLibrary* cryptohome =
    230       chromeos::CrosLibrary::Get()->GetCryptohomeLibrary();
    231 
    232   bool password_acquired = false;
    233   if (password_->empty() && cryptohome->TpmIsReady()) {
    234     password_acquired = cryptohome->TpmGetPassword(password_);
    235     if (!password_acquired) {
    236       password_->clear();
    237     } else if (password_->empty()) {
    238       // For a fresh OOBE flow TPM is uninitialized,
    239       // ownership process is started at the EULA screen,
    240       // password is cleared after EULA is accepted.
    241       LOG(ERROR) << "TPM returned an empty password.";
    242     }
    243   }
    244   if (password_->empty() && !password_acquired) {
    245     // Password hasn't been acquired, reschedule pulling.
    246     MessageLoop::current()->PostDelayedTask(
    247         FROM_HERE,
    248         runnable_method_factory_.NewRunnableMethod(&TpmInfoView::PullPassword),
    249         kTpmCheckIntervalMs);
    250   } else {
    251     password_label_->SetText(ASCIIToWide(*password_));
    252     password_label_->SetVisible(true);
    253     busy_label_->SetVisible(false);
    254     throbber_->Stop();
    255     throbber_->SetVisible(false);
    256   }
    257 }
    258 
    259 }  // namespace
    260 
    261 namespace chromeos {
    262 
    263 ////////////////////////////////////////////////////////////////////////////////
    264 // EulaView, public:
    265 
    266 EulaView::EulaView(chromeos::ScreenObserver* observer)
    267     : google_eula_label_(NULL),
    268       google_eula_view_(NULL),
    269       usage_statistics_checkbox_(NULL),
    270       learn_more_link_(NULL),
    271       oem_eula_label_(NULL),
    272       oem_eula_view_(NULL),
    273       system_security_settings_link_(NULL),
    274       back_button_(NULL),
    275       continue_button_(NULL),
    276       observer_(observer),
    277       bubble_(NULL) {
    278 }
    279 
    280 EulaView::~EulaView() {
    281   // bubble_ will be set to NULL in callback.
    282   if (bubble_)
    283     bubble_->Close();
    284 }
    285 
    286 // Convenience function to set layout's columnsets for this screen.
    287 static void SetUpGridLayout(views::GridLayout* layout) {
    288   static const int kPadding = kBorderSize + kMargin;
    289   views::ColumnSet* column_set = layout->AddColumnSet(SINGLE_CONTROL_ROW);
    290   column_set->AddPaddingColumn(0, kPadding);
    291   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
    292                         views::GridLayout::USE_PREF, 0, 0);
    293   column_set->AddPaddingColumn(0, kPadding);
    294 
    295   column_set = layout->AddColumnSet(SINGLE_CONTROL_WITH_SHIFT_ROW);
    296   column_set->AddPaddingColumn(0, kPadding + kTextMargin);
    297   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
    298                         views::GridLayout::USE_PREF, 0, 0);
    299   column_set->AddPaddingColumn(0, kPadding);
    300 
    301   column_set = layout->AddColumnSet(SINGLE_LINK_WITH_SHIFT_ROW);
    302   column_set->AddPaddingColumn(0, kPadding + kTextMargin + kCheckboxWidth);
    303   column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
    304                         views::GridLayout::USE_PREF, 0, 0);
    305   column_set->AddPaddingColumn(0, kPadding);
    306 
    307   column_set = layout->AddColumnSet(LAST_ROW);
    308   column_set->AddPaddingColumn(0, kPadding + kTextMargin);
    309   column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
    310                         views::GridLayout::USE_PREF, 0, 0);
    311   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
    312                         views::GridLayout::USE_PREF, 0, 0);
    313   column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
    314   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
    315                         views::GridLayout::USE_PREF, 0, 0);
    316   column_set->AddPaddingColumn(0, kLastButtonHorizontalMargin + kBorderSize);
    317 }
    318 
    319 // Convenience function. Returns URL of the OEM EULA page that should be
    320 // displayed using current locale and manifest. Returns empty URL otherwise.
    321 static GURL GetOemEulaPagePath() {
    322   const StartupCustomizationDocument* customization =
    323       StartupCustomizationDocument::GetInstance();
    324   if (customization->IsReady()) {
    325     std::string locale = customization->initial_locale();
    326     std::string eula_page = customization->GetEULAPage(locale);
    327     if (!eula_page.empty())
    328       return GURL(eula_page);
    329 
    330     VLOG(1) << "No eula found for locale: " << locale;
    331   } else {
    332     LOG(ERROR) << "No manifest found.";
    333   }
    334   return GURL();
    335 }
    336 
    337 void EulaView::Init() {
    338   // First, command to own the TPM.
    339   if (chromeos::CrosLibrary::Get()->EnsureLoaded()) {
    340     chromeos::CrosLibrary::Get()->
    341         GetCryptohomeLibrary()->TpmCanAttemptOwnership();
    342   } else {
    343     LOG(ERROR) << "Cros library not loaded. "
    344                << "We must have disabled the link that led here.";
    345   }
    346 
    347   // Use rounded rect background.
    348   views::Painter* painter = CreateWizardPainter(
    349       &BorderDefinition::kScreenBorder);
    350   set_background(
    351       views::Background::CreateBackgroundPainter(true, painter));
    352 
    353   // Layout created controls.
    354   views::GridLayout* layout = new views::GridLayout(this);
    355   SetLayoutManager(layout);
    356   SetUpGridLayout(layout);
    357 
    358   static const int kPadding = kBorderSize + kMargin;
    359   layout->AddPaddingRow(0, kPadding);
    360   layout->StartRow(0, SINGLE_CONTROL_ROW);
    361   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    362   gfx::Font label_font =
    363       rb.GetFont(ResourceBundle::MediumFont).DeriveFont(0, gfx::Font::NORMAL);
    364   google_eula_label_ = new views::Label(std::wstring(), label_font);
    365   layout->AddView(google_eula_label_, 1, 1,
    366                   views::GridLayout::LEADING, views::GridLayout::FILL);
    367 
    368   layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
    369   layout->StartRow(1, SINGLE_CONTROL_ROW);
    370   views::View* box_view = new views::View();
    371   box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
    372   box_view->SetLayoutManager(new FillLayoutWithBorder());
    373   layout->AddView(box_view);
    374 
    375   google_eula_view_ = new DOMView();
    376   box_view->AddChildView(google_eula_view_);
    377 
    378   layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
    379   layout->StartRow(0, SINGLE_CONTROL_WITH_SHIFT_ROW);
    380   usage_statistics_checkbox_ = new EULACheckbox();
    381   usage_statistics_checkbox_->SetMultiLine(true);
    382   usage_statistics_checkbox_->SetChecked(
    383       observer_->usage_statistics_reporting());
    384   layout->AddView(usage_statistics_checkbox_);
    385 
    386   layout->StartRow(0, SINGLE_LINK_WITH_SHIFT_ROW);
    387   learn_more_link_ = new views::Link();
    388   learn_more_link_->SetController(this);
    389   layout->AddView(learn_more_link_);
    390 
    391   layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
    392   layout->StartRow(0, SINGLE_CONTROL_ROW);
    393   oem_eula_label_ = new views::Label(std::wstring(), label_font);
    394   layout->AddView(oem_eula_label_, 1, 1,
    395                   views::GridLayout::LEADING, views::GridLayout::FILL);
    396 
    397   oem_eula_page_ = GetOemEulaPagePath();
    398   if (!oem_eula_page_.is_empty()) {
    399     layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
    400     layout->StartRow(1, SINGLE_CONTROL_ROW);
    401     box_view = new views::View();
    402     box_view->SetLayoutManager(new FillLayoutWithBorder());
    403     box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
    404     layout->AddView(box_view);
    405 
    406     oem_eula_view_ = new DOMView();
    407     box_view->AddChildView(oem_eula_view_);
    408   }
    409 
    410   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    411   layout->StartRow(0, LAST_ROW);
    412   system_security_settings_link_ = new views::Link();
    413   system_security_settings_link_->SetController(this);
    414 
    415   if (!chromeos::CrosLibrary::Get()->EnsureLoaded() ||
    416       !chromeos::CrosLibrary::Get()->GetCryptohomeLibrary()->
    417           TpmIsEnabled()) {
    418     system_security_settings_link_->SetEnabled(false);
    419   }
    420 
    421   layout->AddView(system_security_settings_link_);
    422 
    423   back_button_ = new login::WideButton(this, std::wstring());
    424   layout->AddView(back_button_);
    425 
    426   continue_button_ = new login::WideButton(this, std::wstring());
    427   layout->AddView(continue_button_);
    428   layout->AddPaddingRow(0, kPadding);
    429 
    430   UpdateLocalizedStrings();
    431 }
    432 
    433 void EulaView::UpdateLocalizedStrings() {
    434   // Load Google EULA and its title.
    435   LoadEulaView(google_eula_view_, google_eula_label_, GURL(kGoogleEulaUrl));
    436 
    437   // Load OEM EULA and its title.
    438   if (!oem_eula_page_.is_empty())
    439     LoadEulaView(oem_eula_view_, oem_eula_label_, oem_eula_page_);
    440 
    441   // Set tooltip for usage statistics checkbox if the metric is unmanaged.
    442   if (!usage_statistics_checkbox_->IsEnabled()) {
    443     usage_statistics_checkbox_->SetTooltipText(
    444         UTF16ToWide(l10n_util::GetStringUTF16(IDS_OPTION_DISABLED_BY_POLICY)));
    445   }
    446 
    447   // Set tooltip for system security settings link if TPM is disabled.
    448   if (!system_security_settings_link_->IsEnabled()) {
    449     system_security_settings_link_->SetTooltipText(
    450         UTF16ToWide(l10n_util::GetStringUTF16(IDS_EULA_TPM_DISABLED)));
    451   }
    452 
    453   // Load other labels from resources.
    454   usage_statistics_checkbox_->SetLabel(
    455       UTF16ToWide(l10n_util::GetStringUTF16(IDS_EULA_CHECKBOX_ENABLE_LOGGING)));
    456   learn_more_link_->SetText(
    457       UTF16ToWide(l10n_util::GetStringUTF16(IDS_LEARN_MORE)));
    458   system_security_settings_link_->SetText(
    459       UTF16ToWide(l10n_util::GetStringUTF16(IDS_EULA_SYSTEM_SECURITY_SETTING)));
    460   continue_button_->SetLabel(UTF16ToWide(
    461       l10n_util::GetStringUTF16(IDS_EULA_ACCEPT_AND_CONTINUE_BUTTON)));
    462   back_button_->SetLabel(
    463       UTF16ToWide(l10n_util::GetStringUTF16(IDS_EULA_BACK_BUTTON)));
    464 }
    465 
    466 ////////////////////////////////////////////////////////////////////////////////
    467 // EulaView, protected, views::View implementation:
    468 
    469 void EulaView::OnLocaleChanged() {
    470   UpdateLocalizedStrings();
    471   Layout();
    472 }
    473 
    474 ////////////////////////////////////////////////////////////////////////////////
    475 // views::ButtonListener implementation:
    476 
    477 void EulaView::ButtonPressed(views::Button* sender, const views::Event& event) {
    478   if (usage_statistics_checkbox_) {
    479     observer_->set_usage_statistics_reporting(
    480         usage_statistics_checkbox_->checked());
    481   }
    482   if (sender == continue_button_) {
    483     observer_->OnExit(ScreenObserver::EULA_ACCEPTED);
    484   } else if (sender == back_button_) {
    485     observer_->OnExit(ScreenObserver::EULA_BACK);
    486   }
    487 }
    488 
    489 ////////////////////////////////////////////////////////////////////////////////
    490 // views::LinkController implementation:
    491 
    492 void EulaView::LinkActivated(views::Link* source, int event_flags) {
    493   gfx::NativeWindow parent_window =
    494       LoginUtils::Get()->GetBackgroundView()->GetNativeWindow();
    495   if (source == learn_more_link_) {
    496     if (!help_app_.get())
    497       help_app_ = new HelpAppLauncher(parent_window);
    498     help_app_->ShowHelpTopic(HelpAppLauncher::HELP_STATS_USAGE);
    499   } else if (source == system_security_settings_link_) {
    500     TpmInfoView* view = new TpmInfoView(&tpm_password_);
    501     view->Init();
    502     views::Window* window = browser::CreateViewsWindow(parent_window,
    503                                                        gfx::Rect(),
    504                                                        view);
    505     window->SetIsAlwaysOnTop(true);
    506     window->Show();
    507   }
    508 }
    509 
    510 ////////////////////////////////////////////////////////////////////////////////
    511 // TabContentsDelegate implementation:
    512 
    513 // Convenience function. Queries |eula_view| for HTML title and, if it
    514 // is ready, assigns it to |eula_label| and returns true so the caller
    515 // view calls Layout().
    516 static bool PublishTitleIfReady(const TabContents* contents,
    517                                 DOMView* eula_view,
    518                                 views::Label* eula_label) {
    519   if (contents != eula_view->tab_contents())
    520     return false;
    521   eula_label->SetText(UTF16ToWide(eula_view->tab_contents()->GetTitle()));
    522   return true;
    523 }
    524 
    525 void EulaView::NavigationStateChanged(const TabContents* contents,
    526                                       unsigned changed_flags) {
    527   if (changed_flags & TabContents::INVALIDATE_TITLE) {
    528     if (PublishTitleIfReady(contents, google_eula_view_, google_eula_label_) ||
    529         PublishTitleIfReady(contents, oem_eula_view_, oem_eula_label_)) {
    530       Layout();
    531     }
    532   }
    533 }
    534 
    535 void EulaView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
    536   views::Widget* widget = GetWidget();
    537   if (widget && event.os_event && !event.skip_in_browser) {
    538     views::KeyEvent views_event(reinterpret_cast<GdkEvent*>(event.os_event));
    539     static_cast<views::WidgetGtk*>(widget)->HandleKeyboardEvent(views_event);
    540   }
    541 }
    542 
    543 ////////////////////////////////////////////////////////////////////////////////
    544 // EulaView, private:
    545 
    546 void EulaView::LoadEulaView(DOMView* eula_view,
    547                             views::Label* eula_label,
    548                             const GURL& eula_url) {
    549   Profile* profile = ProfileManager::GetDefaultProfile();
    550   eula_view->Init(profile,
    551                   SiteInstance::CreateSiteInstanceForURL(profile, eula_url));
    552   eula_view->LoadURL(eula_url);
    553   eula_view->tab_contents()->set_delegate(this);
    554 }
    555 
    556 ////////////////////////////////////////////////////////////////////////////////
    557 // EulaView, private, views::View implementation:
    558 
    559 bool EulaView::OnKeyPressed(const views::KeyEvent&) {
    560   // Close message bubble if shown. bubble_ will be set to NULL in callback.
    561   if (bubble_) {
    562     bubble_->Close();
    563     return true;
    564   }
    565   return false;
    566 }
    567 
    568 }  // namespace chromeos
    569