diff options
author | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-28 22:05:11 +0000 |
---|---|---|
committer | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-28 22:05:11 +0000 |
commit | eee9f55299e1223c156f1bcf86f557446009cc5e (patch) | |
tree | 5eb3b23a1754afca47a4a8e5b74078224d0c122e /chrome/browser/cocoa/keystone_infobar.mm | |
parent | 110086c1a303bdcf3829a289efebef7e9378ab7b (diff) | |
download | chromium_src-eee9f55299e1223c156f1bcf86f557446009cc5e.zip chromium_src-eee9f55299e1223c156f1bcf86f557446009cc5e.tar.gz chromium_src-eee9f55299e1223c156f1bcf86f557446009cc5e.tar.bz2 |
In-application Keystone ticket promotion.
The concept of "ticket promotion" is added to the application when Keystone is
in use. Ticket promotion is used to turn a user Keystone ticket, which Chrome
normally establishes when it launches, into a system Keystone ticket, after
successful user authentication and authorization. Having a system Keystone
with a system ticket means that updates are applied with root privileges
instead of user privileges, essentially eliminating the possibility that a
user will fall off of the auto-update train because they can read and execute
but not write the application.
Two principles of promotion apply:
- An application on a user ticket NEEDS promotion if it determines that it
doesn't have permission to write to itself. Being on a user ticket, an
update attempt would fail.
- An application on a user ticket WANTS promotion if it already NEEDS
promotion. Additionally, if it is installed in a system-wide location
such as /Applications, it will WANT promotion, even if it does not NEED it.
If promotion is needed, an info bar will show up on launch requesting it.
This info bar works similarly to the default browser info bar: it has a "don't
bother me again" button, it will only show up after the first launch, it won't
disappear on navigation if the navigation happens very quickly, and it won't
show itself if another info bar is up. This means that if both the default
browser info bar and the promotion info bar have a shot at showing, only one
will win. In my experience, each wins about half of the time.
If promotion is needed, the update UI in the About window will be hidden.
Checking for updates and offering to apply them doesn't make much sense when
the update won't be able to install successfully. All of the auto-update
machinery is still working in the background, but the About window UI is
hidden.
If promotion is wanted, the About window will contain a new button allowing
the user to enter promotion. This gives access to the same promotion routine
as the promotion info bar. It can be used even from an administrative account
that is able to update the application without promotion. It's intended to be
used by the system administrator of the family without requiring them to
switch to one of the kids' accounts.
BUG=16360
TEST=Exhaustively, please.
Review URL: http://codereview.chromium.org/437053
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33241 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa/keystone_infobar.mm')
-rw-r--r-- | chrome/browser/cocoa/keystone_infobar.mm | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/keystone_infobar.mm b/chrome/browser/cocoa/keystone_infobar.mm new file mode 100644 index 0000000..689a1ad --- /dev/null +++ b/chrome/browser/cocoa/keystone_infobar.mm @@ -0,0 +1,211 @@ +// Copyright (c) 2009 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/cocoa/keystone_infobar.h" + +#import <AppKit/AppKit.h> + +#include <string> + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/command_line.h" +#include "base/message_loop.h" +#include "base/task.h" +#import "chrome/browser/cocoa/keystone_glue.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/first_run.h" +#include "chrome/browser/tab_contents/infobar_delegate.h" +#include "chrome/browser/tab_contents/navigation_controller.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/profile.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" + +class SkBitmap; + +namespace { + +class KeystonePromotionInfoBarDelegate : public ConfirmInfoBarDelegate { + public: + KeystonePromotionInfoBarDelegate(TabContents* tab_contents) + : ConfirmInfoBarDelegate(tab_contents), + profile_(tab_contents->profile()), + can_expire_(false), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + const int kCanExpireOnNavigationAfterMilliseconds = 8 * 1000; + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &KeystonePromotionInfoBarDelegate::SetCanExpire), + kCanExpireOnNavigationAfterMilliseconds); + } + + virtual ~KeystonePromotionInfoBarDelegate() {} + + // Inherited from InfoBarDelegate and overridden. + + virtual bool ShouldExpire( + const NavigationController::LoadCommittedDetails& details) { + return can_expire_; + } + + virtual void InfoBarClosed() { + delete this; + } + + // Inherited from AlertInfoBarDelegate and overridden. + + virtual std::wstring GetMessageText() const { + return l10n_util::GetStringF(IDS_PROMOTE_INFOBAR_TEXT, + l10n_util::GetString(IDS_PRODUCT_NAME)); + } + + virtual SkBitmap* GetIcon() const { + return ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_PRODUCT_ICON_32); + } + + // Inherited from ConfirmInfoBarDelegate and overridden. + + virtual int GetButtons() const { + return BUTTON_OK | BUTTON_CANCEL | BUTTON_OK_DEFAULT; + } + + virtual std::wstring GetButtonLabel(InfoBarButton button) const { + return button == BUTTON_OK ? + l10n_util::GetString(IDS_PROMOTE_INFOBAR_PROMOTE_BUTTON) : + l10n_util::GetString(IDS_PROMOTE_INFOBAR_DONT_ASK_BUTTON); + } + + virtual bool Accept() { + [[KeystoneGlue defaultKeystoneGlue] promoteTicket]; + return true; + } + + virtual bool Cancel() { + profile_->GetPrefs()->SetBoolean(prefs::kShowUpdatePromotionInfoBar, false); + return true; + } + + private: + // Sets this info bar to be able to expire. Called a predetermined amount + // of time after this object is created. + void SetCanExpire() { + can_expire_ = true; + } + + // The TabContents' profile. + Profile* profile_; // weak + + // Whether the info bar should be dismissed on the next navigation. + bool can_expire_; + + // Used to delay the expiration of the info bar. + ScopedRunnableMethodFactory<KeystonePromotionInfoBarDelegate> method_factory_; + + DISALLOW_COPY_AND_ASSIGN(KeystonePromotionInfoBarDelegate); +}; + +} // namespace + +@interface KeystonePromotionInfoBar : NSObject +- (void)checkAndShowInfoBarForProfile:(Profile*)profile; +- (void)updateStatus:(NSNotification*)notification; +- (void)removeObserver; +@end // @interface KeystonePromotionInfoBar + +@implementation KeystonePromotionInfoBar + +- (void)dealloc { + [self removeObserver]; + [super dealloc]; +} + +- (void)checkAndShowInfoBarForProfile:(Profile*)profile { + // If this is the first run, the user clicked the "don't ask again" button + // at some point in the past, or if the "don't ask about the default + // browser" command-line switch is present, bail out. That command-line + // switch is recycled here because it's likely that the set of users that + // don't want to be nagged about the default browser also don't want to be + // nagged about the update check. (Automated testers, I'm thinking of + // you...) + CommandLine* commandLine = CommandLine::ForCurrentProcess(); + if (FirstRun::IsChromeFirstRun() || + !profile->GetPrefs()->GetBoolean(prefs::kShowUpdatePromotionInfoBar) || + commandLine->HasSwitch(switches::kNoDefaultBrowserCheck)) { + return; + } + + // If there is no Keystone glue (maybe because this application isn't + // Keystone-enabled) or the application is on a read-only filesystem, + // doing anything related to auto-update is pointless. Bail out. + KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue]; + if (!keystoneGlue || [keystoneGlue isOnReadOnlyFilesystem]) { + return; + } + + // Stay alive as long as needed. This is balanced by a release in + // -updateStatus:. + [self retain]; + + AutoupdateStatus recentStatus = [keystoneGlue recentStatus]; + if (recentStatus == kAutoupdateNone || + recentStatus == kAutoupdateRegistering) { + NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; + [center addObserver:self + selector:@selector(updateStatus:) + name:kAutoupdateStatusNotification + object:nil]; + } else { + [self updateStatus:[keystoneGlue recentNotification]]; + } +} + +- (void)updateStatus:(NSNotification*)notification { + NSDictionary* dictionary = [notification userInfo]; + AutoupdateStatus status = static_cast<AutoupdateStatus>( + [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]); + + if (status == kAutoupdateNone || status == kAutoupdateRegistering) { + return; + } + + [self removeObserver]; + + if (status != kAutoupdateRegisterFailed && + [[KeystoneGlue defaultKeystoneGlue] needsPromotion]) { + Browser* browser = BrowserList::GetLastActive(); + if (browser) { + TabContents* tabContents = browser->GetSelectedTabContents(); + + // Only show if no other info bars are showing, because that's how the + // default browser info bar works. + if (tabContents && tabContents->infobar_delegate_count() == 0) { + tabContents->AddInfoBar( + new KeystonePromotionInfoBarDelegate(tabContents)); + } + } + } + + [self release]; +} + +- (void)removeObserver { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +@end // @implementation KeystonePromotionInfoBar + +// static +void KeystoneInfoBar::PromotionInfoBar(Profile* profile) { + KeystonePromotionInfoBar* promotionInfoBar = + [[[KeystonePromotionInfoBar alloc] init] autorelease]; + + [promotionInfoBar checkAndShowInfoBarForProfile:profile]; +} |