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