keystone_infobar_delegate.mm revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
1// Copyright (c) 2012 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/ui/cocoa/keystone_infobar_delegate.h"
6
7#import <AppKit/AppKit.h>
8
9#include <string>
10
11#include "base/bind.h"
12#include "base/command_line.h"
13#include "base/memory/weak_ptr.h"
14#include "base/message_loop.h"
15#include "base/prefs/pref_service.h"
16#include "chrome/browser/first_run/first_run.h"
17#include "chrome/browser/infobars/confirm_infobar_delegate.h"
18#include "chrome/browser/infobars/infobar_service.h"
19#import "chrome/browser/mac/keystone_glue.h"
20#include "chrome/browser/profiles/profile.h"
21#include "chrome/browser/ui/browser.h"
22#include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h"
23#include "chrome/browser/ui/tabs/tab_strip_model.h"
24#include "chrome/common/chrome_switches.h"
25#include "chrome/common/pref_names.h"
26#include "content/public/browser/navigation_details.h"
27#include "content/public/browser/web_contents.h"
28#include "grit/chromium_strings.h"
29#include "grit/generated_resources.h"
30#include "grit/theme_resources.h"
31#include "ui/base/l10n/l10n_util.h"
32#include "ui/base/resource/resource_bundle.h"
33
34class SkBitmap;
35
36namespace {
37
38// KeystonePromotionInfoBarDelegate -------------------------------------------
39
40class KeystonePromotionInfoBarDelegate : public ConfirmInfoBarDelegate {
41 public:
42  // If there's an active tab, creates a keystone promotion delegate and adds it
43  // to the InfoBarService associated with that tab.
44  static void Create();
45
46 private:
47  KeystonePromotionInfoBarDelegate(InfoBarService* infobar_service,
48                                   PrefService* prefs);
49  virtual ~KeystonePromotionInfoBarDelegate();
50
51  // Sets this info bar to be able to expire.  Called a predetermined amount
52  // of time after this object is created.
53  void SetCanExpire() { can_expire_ = true; }
54
55  // ConfirmInfoBarDelegate
56  virtual gfx::Image* GetIcon() const OVERRIDE;
57  virtual string16 GetMessageText() const OVERRIDE;
58  virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
59  virtual bool Accept() OVERRIDE;
60  virtual bool Cancel() OVERRIDE;
61  virtual bool ShouldExpireInternal(
62      const content::LoadCommittedDetails& details) const OVERRIDE;
63
64  // The prefs to use.
65  PrefService* prefs_;  // weak
66
67  // Whether the info bar should be dismissed on the next navigation.
68  bool can_expire_;
69
70  // Used to delay the expiration of the info bar.
71  base::WeakPtrFactory<KeystonePromotionInfoBarDelegate> weak_ptr_factory_;
72
73  DISALLOW_COPY_AND_ASSIGN(KeystonePromotionInfoBarDelegate);
74};
75
76// static
77void KeystonePromotionInfoBarDelegate::Create() {
78  Browser* browser = chrome::GetLastActiveBrowser();
79  if (browser) {
80    content::WebContents* webContents =
81        browser->tab_strip_model()->GetActiveWebContents();
82
83    if (webContents) {
84      InfoBarService* infobar_service =
85          InfoBarService::FromWebContents(webContents);
86      infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
87          new KeystonePromotionInfoBarDelegate(
88              infobar_service,
89              Profile::FromBrowserContext(
90                  webContents->GetBrowserContext())->GetPrefs())));
91    }
92  }
93}
94
95KeystonePromotionInfoBarDelegate::KeystonePromotionInfoBarDelegate(
96    InfoBarService* infobar_service,
97    PrefService* prefs)
98    : ConfirmInfoBarDelegate(infobar_service),
99      prefs_(prefs),
100      can_expire_(false),
101      weak_ptr_factory_(this) {
102  const base::TimeDelta kCanExpireOnNavigationAfterDelay =
103      base::TimeDelta::FromSeconds(8);
104  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
105      base::Bind(&KeystonePromotionInfoBarDelegate::SetCanExpire,
106                 weak_ptr_factory_.GetWeakPtr()),
107      kCanExpireOnNavigationAfterDelay);
108}
109
110KeystonePromotionInfoBarDelegate::~KeystonePromotionInfoBarDelegate() {
111}
112
113gfx::Image* KeystonePromotionInfoBarDelegate::GetIcon() const {
114  return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
115      IDR_PRODUCT_LOGO_32);
116}
117
118string16 KeystonePromotionInfoBarDelegate::GetMessageText() const {
119  return l10n_util::GetStringFUTF16(IDS_PROMOTE_INFOBAR_TEXT,
120      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
121}
122
123string16 KeystonePromotionInfoBarDelegate::GetButtonLabel(
124    InfoBarButton button) const {
125  return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
126      IDS_PROMOTE_INFOBAR_PROMOTE_BUTTON : IDS_PROMOTE_INFOBAR_DONT_ASK_BUTTON);
127}
128
129bool KeystonePromotionInfoBarDelegate::Accept() {
130  [[KeystoneGlue defaultKeystoneGlue] promoteTicket];
131  return true;
132}
133
134bool KeystonePromotionInfoBarDelegate::Cancel() {
135  prefs_->SetBoolean(prefs::kShowUpdatePromotionInfoBar, false);
136  return true;
137}
138
139bool KeystonePromotionInfoBarDelegate::ShouldExpireInternal(
140    const content::LoadCommittedDetails& details) const {
141  return can_expire_;
142}
143
144}  // namespace
145
146
147// KeystonePromotionInfoBar ---------------------------------------------------
148
149@interface KeystonePromotionInfoBar : NSObject
150- (void)checkAndShowInfoBarForProfile:(Profile*)profile;
151- (void)updateStatus:(NSNotification*)notification;
152- (void)removeObserver;
153@end  // @interface KeystonePromotionInfoBar
154
155@implementation KeystonePromotionInfoBar
156
157- (void)dealloc {
158  [self removeObserver];
159  [super dealloc];
160}
161
162- (void)checkAndShowInfoBarForProfile:(Profile*)profile {
163  // If this is the first run, the user clicked the "don't ask again" button
164  // at some point in the past, or if the "don't ask about the default
165  // browser" command-line switch is present, bail out.  That command-line
166  // switch is recycled here because it's likely that the set of users that
167  // don't want to be nagged about the default browser also don't want to be
168  // nagged about the update check.  (Automated testers, I'm thinking of
169  // you...)
170  CommandLine* commandLine = CommandLine::ForCurrentProcess();
171  if (first_run::IsChromeFirstRun() ||
172      !profile->GetPrefs()->GetBoolean(prefs::kShowUpdatePromotionInfoBar) ||
173      commandLine->HasSwitch(switches::kNoDefaultBrowserCheck)) {
174    return;
175  }
176
177  // If there is no Keystone glue (maybe because this application isn't
178  // Keystone-enabled) or the application is on a read-only filesystem,
179  // doing anything related to auto-update is pointless.  Bail out.
180  KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue];
181  if (!keystoneGlue || [keystoneGlue isOnReadOnlyFilesystem]) {
182    return;
183  }
184
185  // Stay alive as long as needed.  This is balanced by a release in
186  // -updateStatus:.
187  [self retain];
188
189  AutoupdateStatus recentStatus = [keystoneGlue recentStatus];
190  if (recentStatus == kAutoupdateNone ||
191      recentStatus == kAutoupdateRegistering) {
192    NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
193    [center addObserver:self
194               selector:@selector(updateStatus:)
195                   name:kAutoupdateStatusNotification
196                 object:nil];
197  } else {
198    [self updateStatus:[keystoneGlue recentNotification]];
199  }
200}
201
202- (void)updateStatus:(NSNotification*)notification {
203  NSDictionary* dictionary = [notification userInfo];
204  AutoupdateStatus status = static_cast<AutoupdateStatus>(
205      [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
206
207  if (status == kAutoupdateNone || status == kAutoupdateRegistering) {
208    return;
209  }
210
211  [self removeObserver];
212
213  if (status != kAutoupdateRegisterFailed &&
214      [[KeystoneGlue defaultKeystoneGlue] needsPromotion]) {
215    KeystonePromotionInfoBarDelegate::Create();
216  }
217
218  [self release];
219}
220
221- (void)removeObserver {
222  [[NSNotificationCenter defaultCenter] removeObserver:self];
223}
224
225@end  // @implementation KeystonePromotionInfoBar
226
227// static
228void KeystoneInfoBar::PromotionInfoBar(Profile* profile) {
229  KeystonePromotionInfoBar* promotionInfoBar =
230      [[[KeystonePromotionInfoBar alloc] init] autorelease];
231
232  [promotionInfoBar checkAndShowInfoBarForProfile:profile];
233}
234