| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 #import "AppDelegate.h" | |
| 6 | |
| 7 #import "Downloader.h" | |
| 8 #import "InstallerWindowController.h" | |
| 9 #import "NSError+ChromeInstallerAdditions.h" | |
| 10 #import "NSAlert+ChromeInstallerAdditions.h" | |
| 11 #import "OmahaCommunication.h" | |
| 12 #import "Unpacker.h" | |
| 13 | |
| 14 @interface NSAlert () | |
| 15 - (void)beginSheetModalForWindow:(NSWindow*)sheetWindow | |
| 16 completionHandler: | |
| 17 (void (^__nullable)(NSModalResponse returnCode))handler; | |
| 18 @end | |
| 19 | |
| 20 @interface AppDelegate ()<NSWindowDelegate, | |
| 21 OmahaCommunicationDelegate, | |
| 22 DownloaderDelegate, | |
| 23 UnpackDelegate> { | |
| 24 InstallerWindowController* installerWindowController_; | |
| 25 BOOL preventTermination_; | |
| 26 } | |
| 27 @property(strong) NSWindow* window; | |
| 28 - (void)exit; | |
| 29 @end | |
| 30 | |
| 31 @implementation AppDelegate | |
| 32 @synthesize window = window_; | |
| 33 | |
| 34 // Sets up the main window and begins the downloading process. | |
| 35 - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { | |
| 36 window_.delegate = self; | |
| 37 installerWindowController_ = | |
| 38 [[InstallerWindowController alloc] initWithWindow:window_]; | |
| 39 | |
| 40 [self startDownload]; | |
| 41 } | |
| 42 | |
| 43 - (void)applicationWillTerminate:(NSNotification*)aNotification { | |
| 44 } | |
| 45 | |
| 46 // This function effectively takes the place of | |
| 47 // applicationShouldTerminateAfterLastWindowClosed: to make sure that the | |
| 48 // application does correctly terminate after closing the installer, but does | |
| 49 // not terminate when we call orderOut: to hide the installer during its | |
| 50 // tear-down steps. | |
| 51 - (BOOL)windowShouldClose:(id)sender { | |
| 52 [self exit]; | |
| 53 return YES; | |
| 54 } | |
| 55 | |
| 56 - (NSApplicationTerminateReply)applicationShouldTerminate: | |
| 57 (NSApplication*)sender { | |
| 58 return preventTermination_ ? NSTerminateCancel : NSTerminateNow; | |
| 59 } | |
| 60 | |
| 61 - (void)exit { | |
| 62 preventTermination_ = NO; | |
| 63 [NSApp terminate:nil]; | |
| 64 } | |
| 65 | |
| 66 - (void)startDownload { | |
| 67 [installerWindowController_ updateStatusDescription:@"Initializing..."]; | |
| 68 | |
| 69 OmahaCommunication* omahaMessenger = [[OmahaCommunication alloc] init]; | |
| 70 omahaMessenger.delegate = self; | |
| 71 [omahaMessenger fetchDownloadURLs]; | |
| 72 } | |
| 73 | |
| 74 - (void)omahaCommunication:(OmahaCommunication*)messenger | |
| 75 onSuccess:(NSArray*)URLs { | |
| 76 [installerWindowController_ updateStatusDescription:@"Downloading..."]; | |
| 77 | |
| 78 Downloader* download = [[Downloader alloc] init]; | |
| 79 download.delegate = self; | |
| 80 [download downloadChromeImageFrom:[URLs firstObject]]; | |
| 81 } | |
| 82 | |
| 83 - (void)omahaCommunication:(OmahaCommunication*)messenger | |
| 84 onFailure:(NSError*)error { | |
| 85 NSError* networkError = | |
| 86 [NSError errorForAlerts:@"Network Error" | |
| 87 withDescription:@"Could not connect to Chrome server." | |
| 88 isRecoverable:YES]; | |
| 89 [self displayError:networkError]; | |
| 90 } | |
| 91 | |
| 92 // Bridge method from Downloader to InstallerWindowController. Allows Downloader | |
| 93 // to update the progressbar without having direct access to any UI obejcts. | |
| 94 - (void)downloader:(Downloader*)download percentProgress:(double)percentage { | |
| 95 [installerWindowController_ updateDownloadProgress:(double)percentage]; | |
| 96 } | |
| 97 | |
| 98 - (void)downloader:(Downloader*)download onSuccess:(NSURL*)diskImageURL { | |
| 99 [installerWindowController_ updateStatusDescription:@"Installing..."]; | |
| 100 | |
| 101 Unpacker* unpacker = [[Unpacker alloc] init]; | |
| 102 unpacker.delegate = self; | |
| 103 [unpacker mountDMGFromURL:diskImageURL]; | |
| 104 } | |
| 105 | |
| 106 - (void)downloader:(Downloader*)download onFailure:(NSError*)error { | |
| 107 NSError* downloadError = | |
| 108 [NSError errorForAlerts:@"Download Failure" | |
| 109 withDescription:@"Unable to download Google Chrome." | |
| 110 isRecoverable:NO]; | |
| 111 [self displayError:downloadError]; | |
| 112 } | |
| 113 | |
| 114 - (void)unpacker:(Unpacker*)unpacker onMountSuccess:(NSString*)tempAppPath { | |
| 115 // Calling this function will change the progress bar into an indeterminate | |
| 116 // one. We won't need to update the progress bar any more after this point. | |
| 117 [installerWindowController_ updateDownloadProgress:-1.0]; | |
| 118 // By disabling closing the window or quitting, we can tell the user that | |
| 119 // closing the application at this point is not a good idea. | |
| 120 window_.styleMask &= ~NSClosableWindowMask; | |
| 121 preventTermination_ = YES; | |
| 122 | |
| 123 // TODO: move the below code into AuthorizedInstall | |
| 124 | |
| 125 NSError* error = nil; | |
| 126 if ([[NSFileManager defaultManager] | |
| 127 fileExistsAtPath:@"/Applications/Google Chromo.app"]) { | |
| 128 [[NSFileManager defaultManager] | |
| 129 removeItemAtPath:@"/Applications/Google Chromo.app" | |
| 130 error:nil]; | |
| 131 } | |
| 132 if (![[NSFileManager defaultManager] | |
| 133 moveItemAtPath:tempAppPath | |
| 134 toPath:@"/Applications/Google Chromo.app" | |
| 135 error:&error]) { | |
| 136 NSLog(@"%@", error); | |
| 137 } | |
| 138 | |
| 139 // TODO: edit the below code to feed in command line arguments | |
| 140 | |
| 141 [[NSWorkspace sharedWorkspace] | |
| 142 launchApplicationAtURL: | |
| 143 [NSURL fileURLWithPath:@"/Applications/Google Chromo.app" | |
| 144 isDirectory:NO] | |
| 145 options:NSWorkspaceLaunchDefault | |
| 146 configuration:@{} | |
| 147 error:&error]; | |
| 148 if (error) { | |
| 149 NSLog(@"Chromo failed to launch: %@", error); | |
| 150 } | |
| 151 | |
| 152 // Begin teardown stuff! | |
| 153 dispatch_async(dispatch_get_main_queue(), ^{ | |
| 154 [window_ orderOut:nil]; | |
| 155 }); | |
| 156 | |
| 157 [unpacker unmountDMG]; | |
| 158 } | |
| 159 | |
| 160 - (void)unpacker:(Unpacker*)unpacker onMountFailure:(NSError*)error { | |
| 161 NSError* extractError = | |
| 162 [NSError errorForAlerts:@"Install Failure" | |
| 163 withDescription:@"Unable to add Google Chrome to Applications." | |
| 164 isRecoverable:NO]; | |
| 165 [self displayError:extractError]; | |
| 166 } | |
| 167 | |
| 168 - (void)unpacker:(Unpacker*)unpacker onUnmountSuccess:(NSString*)mountpath { | |
| 169 NSLog(@"we're done here!"); | |
| 170 [self exit]; | |
| 171 } | |
| 172 | |
| 173 - (void)unpacker:(Unpacker*)unpacker onUnmountFailure:(NSError*)error { | |
| 174 NSLog(@"error unmounting"); | |
| 175 // NOTE: since we are not deleting the temporary folder if the unmount fails, | |
| 176 // we'll just leave it up to the computer to delete the temporary folder on | |
| 177 // its own time, and to unmount the disk during a restart at some point. There | |
| 178 // is no other work to be done in the mean time. | |
| 179 [self exit]; | |
| 180 } | |
| 181 | |
| 182 // Displays an alert on the main window using the contents of the passed in | |
| 183 // error. | |
| 184 - (void)displayError:(NSError*)error { | |
| 185 NSAlert* alertForUser = [NSAlert alertWithError:error]; | |
| 186 dispatch_async(dispatch_get_main_queue(), ^{ | |
| 187 [alertForUser beginSheetModalForWindow:window_ | |
| 188 completionHandler:^(NSModalResponse returnCode) { | |
| 189 if (returnCode != [alertForUser quitResponse]) { | |
| 190 [self startDownload]; | |
| 191 } else { | |
| 192 [NSApp terminate:nil]; | |
| 193 } | |
| 194 }]; | |
| 195 }); | |
| 196 } | |
| 197 | |
| 198 @end | |
| OLD | NEW |