Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: ui/progress_wnd.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/progress_wnd.h ('k') | ui/progress_wnd_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2007-2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16
17 #include "omaha/ui/progress_wnd.h"
18 #include "base/basictypes.h"
19 #include "omaha/base/constants.h"
20 #include "omaha/base/debug.h"
21 #include "omaha/base/error.h"
22 #include "omaha/base/logging.h"
23 #include "omaha/base/system_info.h"
24 #include "omaha/base/utils.h"
25 #include "omaha/common/goopdate_utils.h"
26 #include "omaha/ui/ui_ctls.h"
27 #include "omaha/ui/ui_metrics.h"
28
29 namespace omaha {
30
31 namespace {
32
33 // The current UI is only able to show one completion type. If apps in the
34 // bundle have different completion type, then we need to decide which
35 // one should be shown to the user. The following array lists the types
36 // from low priority to high priority. The completion type with highest
37 // priority will be shown to the user.
38 const CompletionCodes kCompletionCodesActionPriority[] = {
39 COMPLETION_CODE_EXIT_SILENTLY,
40 COMPLETION_CODE_EXIT_SILENTLY_ON_LAUNCH_COMMAND,
41 COMPLETION_CODE_SUCCESS,
42 COMPLETION_CODE_LAUNCH_COMMAND,
43 COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY,
44 COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY,
45 COMPLETION_CODE_RESTART_BROWSER,
46 COMPLETION_CODE_RESTART_ALL_BROWSERS,
47 COMPLETION_CODE_REBOOT_NOTICE_ONLY,
48 COMPLETION_CODE_REBOOT,
49 COMPLETION_CODE_ERROR,
50 COMPLETION_CODE_INSTALL_FINISHED_BEFORE_CANCEL,
51 };
52
53 // kCompletionCodesActionPriority should have all the values in enumeration
54 // CompletionCodes. The enumeration value starts from 1 so the array size
55 // should match the last value in the enumeration.
56 COMPILE_ASSERT(arraysize(kCompletionCodesActionPriority) ==
57 COMPLETION_CODE_INSTALL_FINISHED_BEFORE_CANCEL,
58 CompletionCodesActionPriority_missing_completion_code);
59
60 int GetActionPriority(CompletionCodes code) {
61 for (int i = 0; i < arraysize(kCompletionCodesActionPriority); ++i) {
62 if (kCompletionCodesActionPriority[i] == code) {
63 return i;
64 }
65 }
66
67 ASSERT1(false);
68 return -1;
69 }
70
71 bool AreAllAppsCanceled(const std::vector<AppCompletionInfo>& apps_info) {
72 for (size_t i = 0; i < apps_info.size(); ++i) {
73 if (!apps_info[i].is_canceled) {
74 return false;
75 }
76 }
77
78 return true;
79 }
80
81 } // namespace
82
83 InstallStoppedWnd::InstallStoppedWnd(CMessageLoop* message_loop, HWND parent)
84 : message_loop_(message_loop),
85 parent_(parent) {
86 CORE_LOG(L3, (_T("[InstallStoppedWnd::InstallStoppedWnd]")));
87 ASSERT1(message_loop);
88 ASSERT1(::IsWindow(parent));
89 }
90
91 InstallStoppedWnd::~InstallStoppedWnd() {
92 CORE_LOG(L3, (_T("[InstallStoppedWnd::~InstallStoppedWnd]")));
93 if (IsWindow()) {
94 VERIFY1(SUCCEEDED(CloseWindow()));
95 }
96 }
97
98 // Enables the parent window and destroys this window.
99 // Enabling the parent window before destroying this one causes the parent
100 // window to get the focus and avoids a visible momentary lack of focus if we
101 // instead call SetFocus for the parent after the window is destroyed.
102 HRESULT InstallStoppedWnd::CloseWindow() {
103 ASSERT1(IsWindow());
104 VERIFY1(::EnableWindow(parent_, true));
105
106 return DestroyWindow() ? S_OK : HRESULTFromLastError();
107 }
108
109 // Disables the parent window.
110 LRESULT InstallStoppedWnd::OnInitDialog(UINT,
111 WPARAM,
112 LPARAM,
113 BOOL& handled) { // NOLINT
114 VERIFY1(!::EnableWindow(parent_, false));
115 VERIFY1(message_loop_->AddMessageFilter(this));
116 handled = true;
117 return 1;
118 }
119
120 // By letting the parent destroy this window, the parent to manage the entire
121 // lifetime of this window and avoid creating a synchronization problem by
122 // changing the value of IsInstallStoppedWindowPresent() during the middle of
123 // one of the parent's methods.
124 LRESULT InstallStoppedWnd::OnClickButton(WORD,
125 WORD id,
126 HWND,
127 BOOL& handled) { // NOLINT
128 CORE_LOG(L3, (_T("[InstallStoppedWnd::OnClickButton]")));
129 ASSERT1(id == IDOK || id == IDCANCEL);
130 VERIFY1(::PostMessage(parent_, WM_INSTALL_STOPPED, id, 0));
131 handled = true;
132 return 0;
133 }
134
135 LRESULT InstallStoppedWnd::OnDestroy(UINT,
136 WPARAM,
137 LPARAM,
138 BOOL& handled) { // NOLINT
139 VERIFY1(message_loop_->RemoveMessageFilter(this));
140 handled = true;
141 return 0;
142 }
143
144 ProgressWnd::ProgressWnd(CMessageLoop* message_loop, HWND parent)
145 : CompleteWnd(IDD_PROGRESS,
146 ICC_STANDARD_CLASSES | ICC_PROGRESS_CLASS,
147 message_loop,
148 parent),
149 cur_state_(STATE_INIT),
150 events_sink_(NULL),
151 is_canceled_(false) {
152 CORE_LOG(L3, (_T("[ProgressWnd::ProgressWnd]")));
153 }
154
155 ProgressWnd::~ProgressWnd() {
156 CORE_LOG(L3, (_T("[ProgressWnd::~ProgressWnd]")));
157 ASSERT1(!IsWindow());
158 cur_state_ = STATE_END;
159 }
160
161 void ProgressWnd::SetEventSink(ProgressWndEvents* ev) {
162 events_sink_ = ev;
163 CompleteWnd::SetEventSink(events_sink_);
164 }
165
166 LRESULT ProgressWnd::OnInitDialog(UINT message,
167 WPARAM w_param,
168 LPARAM l_param,
169 BOOL& handled) { // NOLINT
170 CORE_LOG(L3, (_T("[ProgressWnd::OnInitDialog]")));
171 UNREFERENCED_PARAMETER(message);
172 UNREFERENCED_PARAMETER(w_param);
173 UNREFERENCED_PARAMETER(l_param);
174 UNREFERENCED_PARAMETER(handled);
175
176 InitializeDialog();
177
178 pause_resume_text_.reset(new StaticEx);
179 pause_resume_text_->SubclassWindow(GetDlgItem(IDC_PAUSE_RESUME_TEXT));
180
181 CString state_text;
182 VERIFY1(state_text.LoadString(IDS_INITIALIZING));
183 VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), state_text));
184 VERIFY1(SUCCEEDED(SetMarqueeMode(true)));
185 VERIFY1(SUCCEEDED(ChangeControlState()));
186
187 metrics_timer_.reset(new HighresTimer);
188
189 return 1; // Let the system set the focus.
190 }
191
192 // If closing is disabled, does not close the window.
193 // If in a completion state, the window is closed.
194 // Otherwise, the InstallStoppedWnd is displayed and the window is closed only
195 // if the user decides to cancel.
196 bool ProgressWnd::MaybeCloseWindow() {
197 if (!is_close_enabled()) {
198 return false;
199 }
200
201 if (cur_state_ != STATE_COMPLETE_SUCCESS &&
202 cur_state_ != STATE_COMPLETE_ERROR &&
203 cur_state_ != STATE_COMPLETE_RESTART_BROWSER &&
204 cur_state_ != STATE_COMPLETE_RESTART_ALL_BROWSERS &&
205 cur_state_ != STATE_COMPLETE_REBOOT) {
206 // The UI is not in final state: ask the user to proceed with closing it.
207 // A modal dialog opens and sends a message back to this window to
208 // communicate the user decision.
209 install_stopped_wnd_.reset(new InstallStoppedWnd(message_loop(), *this));
210 HWND hwnd = install_stopped_wnd_->Create(*this);
211 ASSERT1(hwnd);
212 if (hwnd) {
213 CString title;
214 VERIFY1(title.LoadString(IDS_INSTALLATION_STOPPED_WINDOW_TITLE));
215 VERIFY1(install_stopped_wnd_->SetWindowText(title));
216
217 CString button_text;
218 VERIFY1(button_text.LoadString(IDS_RESUME_INSTALLATION));
219 VERIFY1(::SetWindowText(
220 install_stopped_wnd_->GetDlgItem(IDOK), button_text));
221
222 VERIFY1(button_text.LoadString(IDS_CANCEL_INSTALLATION));
223 VERIFY1(::SetWindowText(
224 install_stopped_wnd_->GetDlgItem(IDCANCEL), button_text));
225
226 CString s;
227 s.FormatMessage(IDS_INSTALL_STOPPED, bundle_name());
228 VERIFY1(::SetWindowText(
229 install_stopped_wnd_->GetDlgItem(IDC_INSTALL_STOPPED_TEXT), s));
230
231 VERIFY1(install_stopped_wnd_->CenterWindow(*this));
232 VERIFY1(!install_stopped_wnd_->ShowWindow(SW_SHOWDEFAULT));
233 return false;
234 }
235 }
236
237 VERIFY1(SUCCEEDED(CloseWindow()));
238 return true;
239 }
240
241 LRESULT ProgressWnd::OnClickedButton(WORD notify_code,
242 WORD id,
243 HWND wnd_ctl,
244 BOOL& handled) { // NOLINT
245 CORE_LOG(L3, (_T("[ProgressWnd::OnClickedButton]")));
246 ASSERT1(id == IDC_BUTTON1 || id == IDC_BUTTON2 || id == IDC_CLOSE);
247 ASSERT1(events_sink_);
248
249 #pragma warning(push)
250 // C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by
251 // a case label.
252 #pragma warning(disable : 4061)
253
254 switch (id) {
255 case IDC_BUTTON1:
256 // TODO(omaha): Consider doing something if the callbacks fail.
257 switch (cur_state_) {
258 case STATE_COMPLETE_RESTART_BROWSER:
259 ++metric_worker_ui_restart_browser_now_click;
260 VERIFY1(events_sink_->DoRestartBrowser(false, post_install_urls_));
261 break;
262 case STATE_COMPLETE_RESTART_ALL_BROWSERS:
263 ++metric_worker_ui_restart_all_browsers_now_click;
264 VERIFY1(events_sink_->DoRestartBrowser(true, post_install_urls_));
265 break;
266 case STATE_COMPLETE_REBOOT:
267 ++metric_worker_ui_reboot_now_click;
268 VERIFY1(events_sink_->DoReboot());
269 break;
270 default:
271 ASSERT1(false);
272 }
273 break;
274 case IDC_BUTTON2:
275 switch (cur_state_) {
276 case STATE_COMPLETE_RESTART_BROWSER:
277 case STATE_COMPLETE_RESTART_ALL_BROWSERS:
278 case STATE_COMPLETE_REBOOT:
279 break;
280 default:
281 ASSERT1(false);
282 }
283 break;
284 case IDC_CLOSE:
285 switch (cur_state_) {
286 case STATE_COMPLETE_SUCCESS:
287 case STATE_COMPLETE_ERROR:
288 return CompleteWnd::OnClickedButton(notify_code,
289 id,
290 wnd_ctl,
291 handled);
292 break;
293 default:
294 ASSERT1(false);
295 }
296 break;
297 default:
298 ASSERT1(false);
299 }
300 #pragma warning(pop)
301
302 // TODO(omaha3): In closing the Window here, we assume that none of the above
303 // code does anything that might delay the UI response. This should be true
304 // since we won't actually be restarting browsers, etc. from the UI.
305 handled = true;
306 VERIFY1(SUCCEEDED(CloseWindow()));
307
308 return 0;
309 }
310
311 LRESULT ProgressWnd::OnInstallStopped(UINT msg,
312 WPARAM wparam,
313 LPARAM,
314 BOOL& handled) { // NOLINT
315 CORE_LOG(L3, (_T("[ProgressWnd::OnInstallStopped]")));
316 UNREFERENCED_PARAMETER(msg);
317
318 install_stopped_wnd_.reset();
319
320 ASSERT1(msg == WM_INSTALL_STOPPED);
321 ASSERT1(wparam == IDOK || wparam == IDCANCEL);
322 // TODO(omaha): Swap the meaning of IDOK and IDCANCEL. IDCANCEL gets passed
323 // when the user hits the esc key. Successive esc presses result in the window
324 // disappearing. Instead, we would like the default (set in the .rc files) and
325 // esc key option to both resume. Changing this requires swapping all uses
326 // in this file as well as in the IDD_INSTALL_STOPPED definition.
327 // Maybe use different constants internally too since these values are used
328 // by different classes and ProgressWnd should not need to know how
329 // InstallStoppedWnd is implemented.
330 // It's possible this will also fix arrow key problem (http://b/1338787).
331 switch (wparam) {
332 case IDOK:
333 // TODO(omaha): Implement "Resume" here.
334 break;
335 case IDCANCEL:
336 HandleCancelRequest();
337 break;
338 default:
339 ASSERT1(false);
340 break;
341 }
342
343 handled = true;
344 return 0;
345 }
346
347 void ProgressWnd::HandleCancelRequest() {
348 CString s;
349 VERIFY1(s.LoadString(IDS_CANCELING));
350 VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
351
352 if (is_canceled_) {
353 return;
354 }
355 is_canceled_ = true;
356
357 // The user has decided to cancel.
358 metric_worker_ui_cancel_ms.AddSample(metrics_timer_->GetElapsedMs());
359 ++metric_worker_ui_cancels;
360
361 if (events_sink_) {
362 events_sink_->DoCancel();
363 }
364 }
365
366 void ProgressWnd::OnCheckingForUpdate() {
367 CORE_LOG(L3, (_T("[ProgressWnd::OnCheckingForUpdate]")));
368 ASSERT1(thread_id() == ::GetCurrentThreadId());
369 if (!IsWindow()) {
370 return;
371 }
372
373 cur_state_ = STATE_CHECKING_FOR_UPDATE;
374
375 CString s;
376 VERIFY1(s.LoadString(IDS_WAITING_TO_CONNECT));
377 VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
378
379 VERIFY1(SUCCEEDED(SetMarqueeMode(true)));
380 VERIFY1(SUCCEEDED(ChangeControlState()));
381 }
382
383 void ProgressWnd::OnUpdateAvailable(const CString& app_name,
384 const CString& version_string) {
385 CORE_LOG(L3, (_T("[ProgressWnd::OnUpdateAvailable][%s][%s]"),
386 app_name, version_string));
387 UNREFERENCED_PARAMETER(app_name);
388 UNREFERENCED_PARAMETER(version_string);
389
390 ASSERT1(thread_id() == ::GetCurrentThreadId());
391 if (!IsWindow()) {
392 return;
393 }
394 }
395
396 void ProgressWnd::OnWaitingToDownload(const CString& app_name) {
397 CORE_LOG(L3, (_T("[ProgressWnd::OnWaitingToDownload][%s]"), app_name));
398 ASSERT1(thread_id() == ::GetCurrentThreadId());
399 if (!IsWindow()) {
400 return;
401 }
402
403 cur_state_ = STATE_WAITING_TO_DOWNLOAD;
404
405 CString s;
406 s.FormatMessage(IDS_WAITING_TO_DOWNLOAD, app_name);
407 VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
408
409 VERIFY1(SUCCEEDED(SetMarqueeMode(true)));
410 VERIFY1(SUCCEEDED(ChangeControlState()));
411 }
412
413 // May be called repeatedly during download.
414 void ProgressWnd::OnDownloading(const CString& app_name,
415 int time_remaining_ms,
416 int pos) {
417 CORE_LOG(L5, (_T("[ProgressWnd::OnDownloading][%s][remaining ms=%d][pos=%d]"),
418 app_name, time_remaining_ms, pos));
419 ASSERT1(thread_id() == ::GetCurrentThreadId());
420 if (!IsWindow()) {
421 return;
422 }
423
424 ASSERT1(0 <= pos && pos <= 100);
425
426 cur_state_ = STATE_DOWNLOADING;
427
428 // This resource is not included in the resource files since it's not used.
429 #if 0
430 VERIFY1(s.LoadString(IDS_PAUSE));
431 VERIFY1(::SetWindowText(GetDlgItem(IDC_PAUSE_RESUME_TEXT), s));
432 #endif
433
434 CString s;
435
436 int time_remaining_sec = CeilingDivide(time_remaining_ms, kMsPerSec);
437 if (time_remaining_ms < 0) {
438 s.FormatMessage(IDS_WAITING_TO_DOWNLOAD, app_name);
439 } else if (time_remaining_ms == 0) {
440 s.FormatMessage(IDS_DOWNLOADING_COMPLETED, app_name);
441 } else if (time_remaining_sec < kSecPerMin) {
442 // Less than one minute remaining.
443 s.FormatMessage(IDS_DOWNLOADING_SHORT, app_name, time_remaining_sec);
444 } else if (time_remaining_sec < kSecondsPerHour) {
445 // Less than one hour remaining.
446 int time_remaining_minute = CeilingDivide(time_remaining_sec, kSecPerMin);
447 s.FormatMessage(IDS_DOWNLOADING_LONG, app_name, time_remaining_minute);
448 } else {
449 int time_remaining_hour = CeilingDivide(time_remaining_sec,
450 kSecondsPerHour);
451 s.FormatMessage(IDS_DOWNLOADING_VERY_LONG, app_name, time_remaining_hour);
452 }
453
454 VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
455 VERIFY1(SUCCEEDED(ChangeControlState()));
456
457 // When the network is connecting keep the marquee moving, otherwise
458 // the user has no indication something is still going on.
459 // TODO(omaha): when resuming an incomplete download this will not work.
460 VERIFY1(SUCCEEDED(SetMarqueeMode(pos == 0)));
461 ::SendMessage(GetDlgItem(IDC_PROGRESS), PBM_SETPOS, pos, 0);
462 }
463
464 void ProgressWnd::OnWaitingRetryDownload(const CString& app_name,
465 time64 next_retry_time) {
466 CORE_LOG(L5, (_T("[ProgressWnd::OnWaitingRetryDownload][%s][retry at:%llu]"),
467 app_name, next_retry_time));
468 ASSERT1(thread_id() == ::GetCurrentThreadId());
469 if (!IsWindow()) {
470 return;
471 }
472
473 time64 now = GetCurrent100NSTime();
474 if (now < next_retry_time) {
475 CString s;
476 int retry_time_in_sec =
477 static_cast<int>(CeilingDivide(next_retry_time - now, kSecsTo100ns));
478 s.FormatMessage(IDS_DOWNLOAD_RETRY, app_name, retry_time_in_sec);
479 VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
480 VERIFY1(SUCCEEDED(ChangeControlState()));
481 }
482 }
483
484 void ProgressWnd::OnWaitingToInstall(const CString& app_name,
485 bool* can_start_install) {
486 CORE_LOG(L3, (_T("[ProgressWnd::OnWaitingToInstall][%s]"), app_name));
487 ASSERT1(thread_id() == ::GetCurrentThreadId());
488 ASSERT1(can_start_install);
489 if (!IsWindow()) {
490 return;
491 }
492
493 if (STATE_WAITING_TO_INSTALL != cur_state_) {
494 cur_state_ = STATE_WAITING_TO_INSTALL;
495
496 CString s;
497 s.FormatMessage(IDS_WAITING_TO_INSTALL, app_name);
498 VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
499
500 VERIFY1(SUCCEEDED(SetMarqueeMode(true)));
501 VERIFY1(SUCCEEDED(ChangeControlState()));
502 }
503
504 // If we want to instead close the window and start install, call
505 // CloseInstallStoppedWindow() and return *can_start_install = true.
506 *can_start_install = !IsInstallStoppedWindowPresent();
507 }
508
509 // May be called repeatedly during install.
510 void ProgressWnd::OnInstalling(const CString& app_name) {
511 CORE_LOG(L5, (_T("[ProgressWnd::OnInstalling][%s]"), app_name));
512 ASSERT1(thread_id() == ::GetCurrentThreadId());
513 if (!IsWindow()) {
514 return;
515 }
516
517 // TODO(omaha3): This can now occur because installs are not gated.
518 // ASSERT1(!IsInstallStoppedWindowPresent());
519
520 if (STATE_INSTALLING != cur_state_) {
521 cur_state_ = STATE_INSTALLING;
522
523 CString s;
524 s.FormatMessage(IDS_INSTALLING, app_name);
525 VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
526
527 VERIFY1(SUCCEEDED(SetMarqueeMode(true)));
528 VERIFY1(SUCCEEDED(ChangeControlState()));
529 }
530 }
531
532 // TODO(omaha): Should this message display the app name or bundle name? Is the
533 // entire bundle paused?
534 void ProgressWnd::OnPause() {
535 CORE_LOG(L3, (_T("[ProgressWnd::OnPause]")));
536 ASSERT(false, (_T("These strings are not in the .rc files.")));
537 ASSERT1(thread_id() == ::GetCurrentThreadId());
538 if (!IsWindow()) {
539 return;
540 }
541
542 cur_state_ = STATE_PAUSED;
543
544 // These resources are not included in resource files since they are not used.
545 #if 0
546 CString s;
547 s.FormatMessage(IDS_DOWNLOAD_PAUSED, bundle_name());
548 VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
549
550 VERIFY1(s.LoadString(IDS_RESUME));
551 VERIFY1(::SetWindowText(GetDlgItem(IDC_PAUSE_RESUME_TEXT), s));
552 #endif
553
554 // TODO(omaha): implement time left.
555
556 VERIFY1(SUCCEEDED(ChangeControlState()));
557 }
558
559 void ProgressWnd::DeterminePostInstallUrls(const ObserverCompletionInfo& info) {
560 ASSERT1(post_install_urls_.empty());
561 post_install_urls_.clear();
562
563 for (size_t i = 0; i < info.apps_info.size(); ++i) {
564 const AppCompletionInfo& app_info = info.apps_info[i];
565 if (!app_info.post_install_url.IsEmpty() &&
566 (app_info.completion_code == COMPLETION_CODE_RESTART_ALL_BROWSERS ||
567 app_info.completion_code == COMPLETION_CODE_RESTART_BROWSER)) {
568 post_install_urls_.push_back(app_info.post_install_url);
569 }
570 }
571 ASSERT1(!post_install_urls_.empty());
572 }
573
574 // TODO(omaha): We can eliminate this function is we have a better UI that can
575 // show compeltion status for each app in the bundle.
576 //
577 // Overall completion code is determined by apps' completion codes and bundle
578 // completion code. If bundle installation fails or installation completed after
579 // a cancel is attempted, returns bundle completion code.
580 // Otherwise the app's completion code that has the greatest priority is
581 // returned.
582 CompletionCodes ProgressWnd::GetBundleOverallCompletionCode(
583 const ObserverCompletionInfo& info) const {
584 if (info.completion_code == COMPLETION_CODE_ERROR ||
585 info.completion_code == COMPLETION_CODE_INSTALL_FINISHED_BEFORE_CANCEL) {
586 return info.completion_code;
587 }
588
589 ASSERT1(info.completion_code == COMPLETION_CODE_SUCCESS);
590
591 CompletionCodes overall_completion_code =
592 kCompletionCodesActionPriority[0];
593 for (size_t i = 0; i < info.apps_info.size(); ++i) {
594 if (GetActionPriority(overall_completion_code) <
595 GetActionPriority(info.apps_info[i].completion_code)) {
596 overall_completion_code = info.apps_info[i].completion_code;
597 }
598 }
599
600 return overall_completion_code;
601 }
602
603 // TODO(omaha3): How should we display the restart browser and reboot messages
604 // when multiple apps are being installed, some of which may have failed? Should
605 // we use the app name or bundle name?
606 void ProgressWnd::OnComplete(const ObserverCompletionInfo& observer_info) {
607 CORE_LOG(L3, (_T("[ProgressWnd::OnComplete][%s]"), observer_info.ToString()));
608 ASSERT1(thread_id() == ::GetCurrentThreadId());
609
610 if (!CompleteWnd::OnComplete()) {
611 return;
612 }
613
614 // Close the 'Install Stop' window if it is on the screen.
615 // TODO(omaha3): This had been before all main dialog UI. Make sure looks OK.
616 CloseInstallStoppedWindow();
617
618 // TODO(omaha3): Do we want to avoid launching commands during an interactive
619 // /ua update? If so, we'll need to handle that somehow. Using the observer
620 // handles the silent update and install cases as well as the OnDemand case.
621 bool launch_commands_succeeded = LaunchCmdLines(observer_info);
622
623 CString s;
624 CompletionCodes overall_completion_code =
625 GetBundleOverallCompletionCode(observer_info);
626 CORE_LOG(L3, (_T("[overall completion code: %d]"), overall_completion_code));
627 switch (overall_completion_code) {
628 case COMPLETION_CODE_SUCCESS:
629 case COMPLETION_CODE_LAUNCH_COMMAND:
630 case COMPLETION_CODE_INSTALL_FINISHED_BEFORE_CANCEL:
631 cur_state_ = STATE_COMPLETE_SUCCESS;
632
633 // TODO(omaha): Do not inherit from CompleteWnd once we have the new
634 // bundle-supporting UI. Among other things, calling
635 // DisplayCompletionDialog causes second call to OmahaWnd::OnComplete().
636 CompleteWnd::DisplayCompletionDialog(true,
637 observer_info.completion_text,
638 observer_info.help_url);
639 break;
640 case COMPLETION_CODE_ERROR:
641 // If all apps are canceled, no need to display any dialog.
642 if (AreAllAppsCanceled(observer_info.apps_info)) {
643 VERIFY1(SUCCEEDED(CloseWindow()));
644 return;
645 } else {
646 cur_state_ = STATE_COMPLETE_ERROR;
647 CompleteWnd::DisplayCompletionDialog(false,
648 observer_info.completion_text,
649 observer_info.help_url);
650 }
651 break;
652 case COMPLETION_CODE_RESTART_ALL_BROWSERS:
653 cur_state_ = STATE_COMPLETE_RESTART_ALL_BROWSERS;
654 VERIFY1(s.LoadString(IDS_RESTART_NOW));
655 VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON1), s));
656 VERIFY1(s.LoadString(IDS_RESTART_LATER));
657 VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON2), s));
658 s.FormatMessage(IDS_TEXT_RESTART_ALL_BROWSERS, bundle_name());
659 VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));
660 DeterminePostInstallUrls(observer_info);
661 ++metric_worker_ui_restart_all_browsers_buttons_displayed;
662 break;
663 case COMPLETION_CODE_RESTART_BROWSER:
664 cur_state_ = STATE_COMPLETE_RESTART_BROWSER;
665 VERIFY1(s.LoadString(IDS_RESTART_NOW));
666 VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON1), s));
667 VERIFY1(s.LoadString(IDS_RESTART_LATER));
668 VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON2), s));
669 s.FormatMessage(IDS_TEXT_RESTART_BROWSER, bundle_name());
670 VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));
671 DeterminePostInstallUrls(observer_info);
672 ++metric_worker_ui_restart_browser_buttons_displayed;
673 break;
674 case COMPLETION_CODE_REBOOT:
675 ASSERT(false, (_T("The button actions are not implemented.")));
676 cur_state_ = STATE_COMPLETE_REBOOT;
677 VERIFY1(s.LoadString(IDS_RESTART_NOW));
678 VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON1), s));
679 VERIFY1(s.LoadString(IDS_RESTART_LATER));
680 VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON2), s));
681 s.FormatMessage(IDS_TEXT_RESTART_COMPUTER, bundle_name());
682 VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));
683 ++metric_worker_ui_reboot_buttons_displayed;
684 break;
685 // TODO(omaha3): We may be able to eliminate these by having the caller
686 // specify the appropriate success text. That is the only difference from
687 // the COMPLETION_CODE_SUCCESS case. Alternatively, we can make a decision
688 // in this class based on, for example, whether the browser is supported.
689 case COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY:
690 cur_state_ = STATE_COMPLETE_SUCCESS;
691 s.FormatMessage(IDS_TEXT_RESTART_ALL_BROWSERS, bundle_name());
692 CompleteWnd::DisplayCompletionDialog(true, s, observer_info.help_url);
693 break;
694 case COMPLETION_CODE_REBOOT_NOTICE_ONLY:
695 cur_state_ = STATE_COMPLETE_SUCCESS;
696 s.FormatMessage(IDS_TEXT_RESTART_COMPUTER, bundle_name());
697 CompleteWnd::DisplayCompletionDialog(true, s, observer_info.help_url);
698 break;
699 case COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY:
700 cur_state_ = STATE_COMPLETE_SUCCESS;
701 s.FormatMessage(IDS_TEXT_RESTART_BROWSER, bundle_name());
702 CompleteWnd::DisplayCompletionDialog(true, s, observer_info.help_url);
703 break;
704 case COMPLETION_CODE_EXIT_SILENTLY_ON_LAUNCH_COMMAND:
705 cur_state_ = STATE_COMPLETE_SUCCESS;
706 if (launch_commands_succeeded) {
707 VERIFY1(SUCCEEDED(CloseWindow()));
708 return;
709 }
710
711 CompleteWnd::DisplayCompletionDialog(true,
712 observer_info.completion_text,
713 observer_info.help_url);
714 break;
715 case COMPLETION_CODE_EXIT_SILENTLY:
716 cur_state_ = STATE_COMPLETE_SUCCESS;
717 VERIFY1(SUCCEEDED(CloseWindow()));
718 return;
719 default:
720 ASSERT1(false);
721 break;
722 }
723
724 VERIFY1(SUCCEEDED(ChangeControlState()));
725 }
726
727 HRESULT ProgressWnd::LaunchCmdLine(const AppCompletionInfo& app_info) {
728 CORE_LOG(L3, (_T("[ProgressWnd::LaunchCmdLine][%s]"),
729 app_info.post_install_launch_command_line));
730 if (app_info.post_install_launch_command_line.IsEmpty()) {
731 return S_OK;
732 }
733
734 if (app_info.completion_code != COMPLETION_CODE_LAUNCH_COMMAND &&
735 app_info.completion_code !=
736 COMPLETION_CODE_EXIT_SILENTLY_ON_LAUNCH_COMMAND) {
737 CORE_LOG(LW, (_T("Launch command line [%s] is not empty but completion ")
738 _T("code [%d] doesn't require a launch"),
739 app_info.post_install_launch_command_line.GetString(),
740 app_info.completion_code));
741 return S_OK;
742 }
743
744 ASSERT1(SUCCEEDED(app_info.error_code));
745 ASSERT1(!app_info.is_noupdate);
746
747 HRESULT hr = goopdate_utils::LaunchCmdLine(
748 is_machine(), app_info.post_install_launch_command_line);
749 if (FAILED(hr)) {
750 CORE_LOG(LE, (_T("[goopdate_utils::LaunchCmdLine failed][0x%x]"), hr));
751 return hr;
752 }
753
754 return S_OK;
755 }
756
757 bool ProgressWnd::LaunchCmdLines(const ObserverCompletionInfo& info) {
758 bool result = true;
759
760 CORE_LOG(L3, (_T("[ProgressWnd::LaunchCmdLines]")));
761 for (size_t i = 0; i < info.apps_info.size(); ++i) {
762 const AppCompletionInfo& app_info = info.apps_info[i];
763 if (FAILED(app_info.error_code)) {
764 continue;
765 }
766 result &= SUCCEEDED(LaunchCmdLine(app_info));
767 VERIFY1(result);
768 }
769
770 return result;
771 }
772
773 HRESULT ProgressWnd::ChangeControlState() {
774 for (size_t i = 0; i != arraysize(ctls_); ++i) {
775 const ControlState& ctl_state = ctls_[i];
776 SetControlAttributes(ctl_state.id_, ctl_state.attr_[cur_state_]);
777 }
778 return S_OK;
779 }
780
781 HRESULT ProgressWnd::SetMarqueeMode(bool is_marquee) {
782 if (!SystemInfo::IsRunningOnXPOrLater()) {
783 // Marquee is not supported on OSes below XP.
784 return S_OK;
785 }
786
787 HWND progress_bar = GetDlgItem(IDC_PROGRESS);
788 if (!progress_bar) {
789 return GOOPDATE_E_UI_INTERNAL_ERROR;
790 }
791
792 LONG style = ::GetWindowLong(progress_bar, GWL_STYLE);
793 if (!style) {
794 return HRESULTFromLastError();
795 }
796
797 if (is_marquee) {
798 if (style & PBS_MARQUEE) {
799 return S_OK;
800 }
801
802 style |= PBS_MARQUEE;
803 style = ::SetWindowLong(progress_bar, GWL_STYLE, style);
804 if (!style) {
805 return HRESULTFromLastError();
806 }
807
808 bool result = ::SendMessage(progress_bar, PBM_SETMARQUEE,
809 is_marquee, kMarqueeModeUpdatesMs) != 0;
810 return result ? S_OK : GOOPDATE_E_UI_INTERNAL_ERROR;
811 } else {
812 if (!(style & PBS_MARQUEE)) {
813 return S_OK;
814 }
815
816 style &= ~PBS_MARQUEE;
817 style = ::SetWindowLong(progress_bar, GWL_STYLE, style);
818 if (!style) {
819 return HRESULTFromLastError();
820 }
821 return S_OK;
822 }
823 }
824
825 bool ProgressWnd::IsInstallStoppedWindowPresent() {
826 return install_stopped_wnd_.get() && install_stopped_wnd_->IsWindow();
827 }
828
829 bool ProgressWnd::CloseInstallStoppedWindow() {
830 if (IsInstallStoppedWindowPresent()) {
831 VERIFY1(SUCCEEDED(install_stopped_wnd_->CloseWindow()));
832 install_stopped_wnd_.reset();
833 return true;
834 } else {
835 return false;
836 }
837 }
838
839 } // namespace omaha
840
OLDNEW
« no previous file with comments | « ui/progress_wnd.h ('k') | ui/progress_wnd_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698