- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / help / version_updater_mac.mm
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/webui/help/version_updater_mac.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "chrome/browser/lifetime/application_lifetime.h"
10 #import "chrome/browser/mac/keystone_glue.h"
11 #include "grit/chromium_strings.h"
12 #include "grit/generated_resources.h"
13 #include "ui/base/l10n/l10n_util.h"
14
15 // KeystoneObserver is a simple notification observer for Keystone status
16 // updates. It will be created and managed by VersionUpdaterMac.
17 @interface KeystoneObserver : NSObject {
18  @private
19   VersionUpdaterMac* versionUpdater_;  // Weak.
20 }
21
22 // Initialize an observer with an updater. The updater owns this object.
23 - (id)initWithUpdater:(VersionUpdaterMac*)updater;
24
25 // Notification callback, called with the status of keystone operations.
26 - (void)handleStatusNotification:(NSNotification*)notification;
27
28 @end  // @interface KeystoneObserver
29
30 @implementation KeystoneObserver
31
32 - (id)initWithUpdater:(VersionUpdaterMac*)updater {
33   if ((self = [super init])) {
34     versionUpdater_ = updater;
35     NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
36     [center addObserver:self
37                selector:@selector(handleStatusNotification:)
38                    name:kAutoupdateStatusNotification
39                  object:nil];
40   }
41   return self;
42 }
43
44 - (void)dealloc {
45   [[NSNotificationCenter defaultCenter] removeObserver:self];
46   [super dealloc];
47 }
48
49 - (void)handleStatusNotification:(NSNotification*)notification {
50   versionUpdater_->UpdateStatus([notification userInfo]);
51 }
52
53 @end  // @implementation KeystoneObserver
54
55
56 VersionUpdater* VersionUpdater::Create() {
57   return new VersionUpdaterMac;
58 }
59
60 VersionUpdaterMac::VersionUpdaterMac() {
61   keystone_observer_.reset([[KeystoneObserver alloc] initWithUpdater:this]);
62 }
63
64 VersionUpdaterMac::~VersionUpdaterMac() {
65 }
66
67 void VersionUpdaterMac::CheckForUpdate(
68     const StatusCallback& status_callback,
69     const PromoteCallback& promote_callback) {
70   // Copy the callbacks, we will re-use this for the remaining lifetime
71   // of this object.
72   status_callback_ = status_callback;
73   promote_callback_ = promote_callback;
74
75   KeystoneGlue* keystone_glue = [KeystoneGlue defaultKeystoneGlue];
76   if (keystone_glue && ![keystone_glue isOnReadOnlyFilesystem]) {
77     AutoupdateStatus recent_status = [keystone_glue recentStatus];
78     if ([keystone_glue asyncOperationPending] ||
79         recent_status == kAutoupdateRegisterFailed ||
80         recent_status == kAutoupdateNeedsPromotion) {
81       // If an asynchronous update operation is currently pending, such as a
82       // check for updates or an update installation attempt, set the status
83       // up correspondingly without launching a new update check.
84       //
85       // If registration failed, no other operations make sense, so just go
86       // straight to the error.
87       UpdateStatus([[keystone_glue recentNotification] userInfo]);
88     } else {
89       // Launch a new update check, even if one was already completed, because
90       // a new update may be available or a new update may have been installed
91       // in the background since the last time the Help page was displayed.
92       [keystone_glue checkForUpdate];
93
94       // Immediately, kAutoupdateStatusNotification will be posted, with status
95       // kAutoupdateChecking.
96       //
97       // Upon completion, kAutoupdateStatusNotification will be posted with a
98       // status indicating the result of the check.
99     }
100
101     UpdateShowPromoteButton();
102   } else {
103     // There is no glue, or the application is on a read-only filesystem.
104     // Updates and promotions are impossible.
105     status_callback_.Run(DISABLED, 0, string16());
106   }
107 }
108
109 void VersionUpdaterMac::PromoteUpdater() const {
110   // Tell Keystone to make software updates available for all users.
111   [[KeystoneGlue defaultKeystoneGlue] promoteTicket];
112
113   // Immediately, kAutoupdateStatusNotification will be posted, and
114   // UpdateStatus() will be called with status kAutoupdatePromoting.
115   //
116   // Upon completion, kAutoupdateStatusNotification will be posted, and
117   // UpdateStatus() will be called with a status indicating a result of the
118   // installation attempt.
119   //
120   // If the promotion was successful, KeystoneGlue will re-register the ticket
121   // and UpdateStatus() will be called again indicating first that
122   // registration is in progress and subsequently that it has completed.
123 }
124
125 void VersionUpdaterMac::RelaunchBrowser() const {
126   // Tell the Broweser to restart if possible.
127   chrome::AttemptRestart();
128 }
129
130 void VersionUpdaterMac::UpdateStatus(NSDictionary* dictionary) {
131   AutoupdateStatus keystone_status = static_cast<AutoupdateStatus>(
132       [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
133
134   bool enable_promote_button = true;
135   string16 message;
136
137   Status status;
138   switch (keystone_status) {
139     case kAutoupdateRegistering:
140     case kAutoupdateChecking:
141       status = CHECKING;
142       enable_promote_button = false;
143       break;
144
145     case kAutoupdateRegistered:
146     case kAutoupdatePromoted:
147       UpdateShowPromoteButton();
148       // Go straight into an update check. Return immediately, this routine
149       // will be re-entered shortly with kAutoupdateChecking.
150       [[KeystoneGlue defaultKeystoneGlue] checkForUpdate];
151       return;
152
153     case kAutoupdateCurrent:
154       status = UPDATED;
155       break;
156
157     case kAutoupdateAvailable:
158       // Install the update automatically. Return immediately, this routine
159       // will be re-entered shortly with kAutoupdateInstalling.
160       [[KeystoneGlue defaultKeystoneGlue] installUpdate];
161       return;
162
163     case kAutoupdateInstalling:
164       status = UPDATING;
165       enable_promote_button = false;
166       break;
167
168     case kAutoupdateInstalled:
169       status = NEARLY_UPDATED;
170       break;
171
172     case kAutoupdatePromoting:
173 #if 1
174       // TODO(mark): KSRegistration currently handles the promotion
175       // synchronously, meaning that the main thread's loop doesn't spin,
176       // meaning that animations and other updates to the window won't occur
177       // until KSRegistration is done with promotion. This looks laggy and bad
178       // and probably qualifies as "jank." For now, there just won't be any
179       // visual feedback while promotion is in progress, but it should complete
180       // (or fail) very quickly.  http://b/2290009.
181       return;
182 #endif
183       status = CHECKING;
184       enable_promote_button = false;
185       break;
186
187     case kAutoupdateRegisterFailed:
188       enable_promote_button = false;
189       // Fall through.
190     case kAutoupdateCheckFailed:
191     case kAutoupdateInstallFailed:
192     case kAutoupdatePromoteFailed:
193       status = FAILED;
194       message = l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR,
195                                               keystone_status);
196       break;
197
198     case kAutoupdateNeedsPromotion:
199       {
200         status = FAILED;
201         string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
202         message = l10n_util:: GetStringFUTF16(IDS_PROMOTE_INFOBAR_TEXT,
203                                               product_name);
204       }
205       break;
206
207     default:
208       NOTREACHED();
209       return;
210   }
211   if (!status_callback_.is_null())
212     status_callback_.Run(status, 0, message);
213
214   if (!promote_callback_.is_null()) {
215     PromotionState promotion_state = PROMOTE_HIDDEN;
216     if (show_promote_button_)
217       promotion_state = enable_promote_button ? PROMOTE_ENABLED
218                                               : PROMOTE_DISABLED;
219     promote_callback_.Run(promotion_state);
220   }
221 }
222
223 void VersionUpdaterMac::UpdateShowPromoteButton() {
224   KeystoneGlue* keystone_glue = [KeystoneGlue defaultKeystoneGlue];
225   AutoupdateStatus recent_status = [keystone_glue recentStatus];
226   if (recent_status == kAutoupdateRegistering ||
227       recent_status == kAutoupdateRegisterFailed ||
228       recent_status == kAutoupdatePromoted) {
229     // Promotion isn't possible at this point.
230     show_promote_button_ = false;
231   } else if (recent_status == kAutoupdatePromoting ||
232              recent_status == kAutoupdatePromoteFailed) {
233     // Show promotion UI because the user either just clicked that button or
234     // because the user should be able to click it again.
235     show_promote_button_ = true;
236   } else {
237     // Show the promote button if promotion is a possibility.
238     show_promote_button_ = [keystone_glue wantsPromotion];
239   }
240 }