summaryrefslogtreecommitdiffstats
path: root/chrome/app/keystone_glue.m
diff options
context:
space:
mode:
authorjrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-20 21:23:58 +0000
committerjrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-20 21:23:58 +0000
commite2a9027c5bc0f0fa895ec0f42837a73d19b21ce0 (patch)
tree3dbf2d105d9f44093b07038a0c5f151ec6a3d6ab /chrome/app/keystone_glue.m
parent89b0600da74755aa3e19255177eb48287f4377b7 (diff)
downloadchromium_src-e2a9027c5bc0f0fa895ec0f42837a73d19b21ce0.zip
chromium_src-e2a9027c5bc0f0fa895ec0f42837a73d19b21ce0.tar.gz
chromium_src-e2a9027c5bc0f0fa895ec0f42837a73d19b21ce0.tar.bz2
Development of keystone glue.
BUG=http://codereview.chromium.org/112044 chrome.gyp caught in a different CL but here is the relevant part of the diff: --- chrome.gyp (revision 16158) +++ chrome.gyp (working copy) @@ -2679,6 +2682,11 @@ ], 'sources': [ 'app/breakpad_mac_stubs.mm', + # *NO* files in chrome/app have unit tests (except keystone_glue)!!! + # It seems a waste to have an app_unittests target, so for now + # I add keystone_glue.m explicitly to this target. + 'app/keystone_glue.m', + 'app/keystone_glue_unittest.mm', # All unittests in browser, common, and renderer. 'browser/autocomplete/autocomplete_unittest.cc', 'browser/autocomplete/autocomplete_popup_view_mac_unittest.mm', Review URL: http://codereview.chromium.org/113613 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16540 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/app/keystone_glue.m')
-rw-r--r--chrome/app/keystone_glue.m180
1 files changed, 149 insertions, 31 deletions
diff --git a/chrome/app/keystone_glue.m b/chrome/app/keystone_glue.m
index 0a01374..56a8e5f 100644
--- a/chrome/app/keystone_glue.m
+++ b/chrome/app/keystone_glue.m
@@ -4,9 +4,28 @@
#import "keystone_glue.h"
+@interface KeystoneGlue(Private)
+
+// Called periodically to announce activity by pinging the Keystone server.
+- (void)markActive:(NSTimer*)timer;
+
+@end
+
+
// Provide declarations of the Keystone registration bits needed here. From
// KSRegistration.h.
typedef enum { kKSPathExistenceChecker } KSExistenceCheckerType;
+
+NSString *KSRegistrationCheckForUpdateNotification =
+ @"KSRegistrationCheckForUpdateNotification";
+NSString *KSRegistrationStatusKey = @"Status";
+NSString *KSRegistrationVersionKey = @"Version";
+
+NSString *KSRegistrationStartUpdateNotification =
+ @"KSRegistrationStartUpdateNotification";
+NSString *KSUpdateCheckSuccessfulKey = @"CheckSuccessful";
+NSString *KSUpdateCheckSuccessfullyInstalledKey = @"SuccessfullyInstalled";
+
@interface KSRegistration : NSObject
+ (id)registrationWithProductID:(NSString*)productID;
- (BOOL)registerWithVersion:(NSString*)version
@@ -14,28 +33,65 @@ typedef enum { kKSPathExistenceChecker } KSExistenceCheckerType;
existenceCheckerString:(NSString*)xc
serverURLString:(NSString*)serverURLString;
- (void)setActive;
+- (void)checkForUpdate;
+- (void)startUpdate;
@end
+
@implementation KeystoneGlue
-// TODO(mmentovai): Determine if the app is writable, and don't register for
-// updates if not - but keep the periodic activity pings.
-+ (void)registerWithKeystone {
- // Figure out who we are.
- NSBundle* mainBundle = [NSBundle mainBundle];
- NSDictionary* infoDictionary = [mainBundle infoDictionary];
++ (id)defaultKeystoneGlue {
+ // TODO(jrg): rename this file to .mm so I can use C++ and
+ // make this type a base::SingletonObjC<KeystoneGlue>.
+ static KeystoneGlue* sDefaultKeystoneGlue = nil; // leaked
+
+ if (sDefaultKeystoneGlue == nil) {
+ sDefaultKeystoneGlue = [[KeystoneGlue alloc] init];
+ [sDefaultKeystoneGlue loadParameters];
+ if (![sDefaultKeystoneGlue loadKeystoneRegistration]) {
+ [sDefaultKeystoneGlue release];
+ sDefaultKeystoneGlue = nil;
+ }
+ }
+ return sDefaultKeystoneGlue;
+}
+
+- (void)dealloc {
+ [url_ release];
+ [productID_ release];
+ [version_ release];
+ [registration_ release];
+ [super dealloc];
+}
+
+- (NSDictionary*)infoDictionary {
+ return [[NSBundle mainBundle] infoDictionary];
+}
+
+- (void)loadParameters {
+ NSDictionary* infoDictionary = [self infoDictionary];
NSString* url = [infoDictionary objectForKey:@"KSUpdateURL"];
- NSString* bundleIdentifier = [infoDictionary objectForKey:@"KSProductID"];
- if (bundleIdentifier == nil) {
- bundleIdentifier = [mainBundle bundleIdentifier];
+ NSString* product = [infoDictionary objectForKey:@"KSProductID"];
+ if (product == nil) {
+ product = [[NSBundle mainBundle] bundleIdentifier];
}
NSString* version = [infoDictionary objectForKey:@"KSVersion"];
- if (!bundleIdentifier || !url || !version) {
+ if (!product || !url || !version) {
// If parameters required for Keystone are missing, don't use it.
return;
}
+ url_ = [url retain];
+ productID_ = [product retain];
+ version_ = [version retain];
+}
+
+- (BOOL)loadKeystoneRegistration {
+ if (!productID_ || !url_ || !version_)
+ return NO;
+
// Load the KeystoneRegistration framework bundle.
+ NSBundle* mainBundle = [NSBundle mainBundle];
NSString* ksrPath =
[[mainBundle privateFrameworksPath]
stringByAppendingPathComponent:@"KeystoneRegistration.framework"];
@@ -44,36 +100,98 @@ typedef enum { kKSPathExistenceChecker } KSExistenceCheckerType;
// Harness the KSRegistration class.
Class ksrClass = [ksrBundle classNamed:@"KSRegistration"];
- KSRegistration* ksr = [ksrClass registrationWithProductID:bundleIdentifier];
- if (!ksr) {
- // Strictly speaking, this isn't necessary, because it's harmless to send
- // messages to nil. However, if there really isn't a
- // KeystoneRegistration.framework or KSRegistration class, bailing out here
- // avoids setting up the timer that will only be able to perform no-ops.
- return;
- }
+ KSRegistration* ksr = [ksrClass registrationWithProductID:productID_];
+ if (!ksr)
+ return NO;
+
+ registration_ = [ksr retain];
+ return YES;
+}
- // Keystone will asynchronously handle installation and registration as
- // needed.
- [ksr registerWithVersion:version
- existenceCheckerType:kKSPathExistenceChecker
- existenceCheckerString:[mainBundle bundlePath]
- serverURLString:url];
+- (void)registerWithKeystone {
+ [registration_ registerWithVersion:version_
+ existenceCheckerType:kKSPathExistenceChecker
+ existenceCheckerString:[[NSBundle mainBundle] bundlePath]
+ serverURLString:url_];
// Mark an active RIGHT NOW; don't wait an hour for the first one.
- [ksr setActive];
+ [registration_ setActive];
// Set up hourly activity pings.
- [NSTimer scheduledTimerWithTimeInterval:60 * 60 // One hour
- target:self
- selector:@selector(markActive:)
- userInfo:ksr
- repeats:YES];
+ timer_ = [NSTimer scheduledTimerWithTimeInterval:60 * 60 // One hour
+ target:self
+ selector:@selector(markActive:)
+ userInfo:registration_
+ repeats:YES];
+}
+
+- (void)stopTimer {
+ [timer_ invalidate];
}
-+ (void)markActive:(NSTimer*)timer {
+- (void)markActive:(NSTimer*)timer {
KSRegistration* ksr = [timer userInfo];
[ksr setActive];
}
+- (void)checkComplete:(NSNotification *)notification {
+ NSDictionary *userInfo = [notification userInfo];
+ BOOL updatesAvailable = [[userInfo objectForKey:KSRegistrationStatusKey]
+ boolValue];
+ NSString *latestVersion = [userInfo objectForKey:KSRegistrationVersionKey];
+
+ [checkTarget_ upToDateCheckCompleted:updatesAvailable
+ latestVersion:latestVersion];
+ [checkTarget_ release];
+ checkTarget_ = nil;
+
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center removeObserver:self
+ name:KSRegistrationCheckForUpdateNotification
+ object:nil];
+}
+
+- (BOOL)checkForUpdate:(NSObject<KeystoneGlueCallbacks>*)target {
+ if (registration_ == nil)
+ return NO;
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(checkComplete:)
+ name:KSRegistrationCheckForUpdateNotification
+ object:nil];
+ checkTarget_ = [target retain];
+ [registration_ checkForUpdate];
+ return YES;
+}
+
+- (void)startUpdateComplete:(NSNotification *)notification {
+ NSDictionary *userInfo = [notification userInfo];
+ BOOL checkSuccessful = [[userInfo objectForKey:KSUpdateCheckSuccessfulKey]
+ boolValue];
+ int installs = [[userInfo objectForKey:KSUpdateCheckSuccessfullyInstalledKey]
+ intValue];
+
+ [startTarget_ updateCompleted:checkSuccessful installs:installs];
+ [startTarget_ release];
+ startTarget_ = nil;
+
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center removeObserver:self
+ name:KSRegistrationStartUpdateNotification
+ object:nil];
+}
+
+- (BOOL)startUpdate:(NSObject<KeystoneGlueCallbacks>*)target {
+ if (registration_ == nil)
+ return NO;
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(startUpdateComplete:)
+ name:KSRegistrationStartUpdateNotification
+ object:nil];
+ startTarget_ = [target retain];
+ [registration_ startUpdate];
+ return YES;
+}
+
@end