OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/chrome/app/safe_mode/safe_mode_view_controller.h" | 5 #import "ios/chrome/app/safe_mode/safe_mode_view_controller.h" |
6 | 6 |
7 #import <QuartzCore/QuartzCore.h> | 7 #import <QuartzCore/QuartzCore.h> |
8 | 8 |
9 #include "base/strings/sys_string_conversions.h" | 9 #include "base/strings/sys_string_conversions.h" |
10 #import "ios/chrome/app/safe_mode_crashing_modules_config.h" | 10 #import "ios/chrome/app/safe_mode_crashing_modules_config.h" |
11 #import "ios/chrome/app/safe_mode_util.h" | 11 #import "ios/chrome/app/safe_mode_util.h" |
12 #include "ios/chrome/browser/crash_report/breakpad_helper.h" | 12 #include "ios/chrome/browser/crash_report/breakpad_helper.h" |
13 #import "ios/chrome/browser/ui/fancy_ui/primary_action_button.h" | 13 #import "ios/chrome/browser/ui/fancy_ui/primary_action_button.h" |
14 #include "ios/chrome/browser/ui/ui_util.h" | 14 #include "ios/chrome/browser/ui/ui_util.h" |
15 #import "ios/chrome/browser/ui/uikit_ui_util.h" | 15 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
16 #include "ios/chrome/grit/ios_chromium_strings.h" | 16 #include "ios/chrome/grit/ios_chromium_strings.h" |
17 #import "ui/gfx/ios/NSString+CrStringDrawing.h" | 17 #import "ui/gfx/ios/NSString+CrStringDrawing.h" |
18 | 18 |
| 19 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 20 #error "This file requires ARC support." |
| 21 #endif |
| 22 |
19 namespace { | 23 namespace { |
20 const CGFloat kVerticalSpacing = 20; | 24 const CGFloat kVerticalSpacing = 20; |
21 const CGFloat kUploadProgressSpacing = 5; | 25 const CGFloat kUploadProgressSpacing = 5; |
22 const NSTimeInterval kUploadPumpInterval = 0.1; | 26 const NSTimeInterval kUploadPumpInterval = 0.1; |
23 const NSTimeInterval kUploadTotalTime = 5; | 27 const NSTimeInterval kUploadTotalTime = 5; |
24 } // anonymous namespace | 28 } // anonymous namespace |
25 | 29 |
26 @interface SafeModeViewController () | 30 @interface SafeModeViewController () |
27 // Returns |YES| if any third-party modifications are detected. | 31 // Returns |YES| if any third-party modifications are detected. |
28 + (BOOL)detectedThirdPartyMods; | 32 + (BOOL)detectedThirdPartyMods; |
29 // Returns |YES| if there are crash reports to upload. | 33 // Returns |YES| if there are crash reports to upload. |
30 + (BOOL)hasReportToUpload; | 34 + (BOOL)hasReportToUpload; |
31 // Returns a message explaining which, if any, 3rd party modules were detected | 35 // Returns a message explaining which, if any, 3rd party modules were detected |
32 // that may cause Chrome to crash. | 36 // that may cause Chrome to crash. |
33 - (NSString*)startupCrashModuleText; | 37 - (NSString*)startupCrashModuleText; |
34 // Starts timer to update progress bar for crash report upload. | 38 // Starts timer to update progress bar for crash report upload. |
35 - (void)startUploadProgress; | 39 - (void)startUploadProgress; |
36 // Updates progress bar for crash report upload. | 40 // Updates progress bar for crash report upload. |
37 - (void)pumpUploadProgress; | 41 - (void)pumpUploadProgress; |
38 // Called when user taps on "Resume Chrome" button. Restores the default | 42 // Called when user taps on "Resume Chrome" button. Restores the default |
39 // Breakpad configuration and notifies the delegate to attempt to start the | 43 // Breakpad configuration and notifies the delegate to attempt to start the |
40 // browser. | 44 // browser. |
41 - (void)startBrowserFromSafeMode; | 45 - (void)startBrowserFromSafeMode; |
42 @end | 46 @end |
43 | 47 |
44 @implementation SafeModeViewController | 48 @implementation SafeModeViewController { |
| 49 __weak id<SafeModeViewControllerDelegate> delegate_; |
| 50 UIView* innerView_; |
| 51 PrimaryActionButton* startButton_; |
| 52 UILabel* uploadDescription_; |
| 53 UIProgressView* uploadProgress_; |
| 54 NSDate* uploadStartTime_; |
| 55 NSTimer* uploadTimer_; |
| 56 } |
45 | 57 |
46 - (id)initWithDelegate:(id<SafeModeViewControllerDelegate>)delegate { | 58 - (id)initWithDelegate:(id<SafeModeViewControllerDelegate>)delegate { |
47 self = [super init]; | 59 self = [super init]; |
48 if (self) { | 60 if (self) { |
49 delegate_.reset(delegate); | 61 delegate_ = delegate; |
50 } | 62 } |
51 return self; | 63 return self; |
52 } | 64 } |
53 | 65 |
54 + (BOOL)hasSuggestions { | 66 + (BOOL)hasSuggestions { |
55 if ([SafeModeViewController detectedThirdPartyMods]) | 67 if ([SafeModeViewController detectedThirdPartyMods]) |
56 return YES; | 68 return YES; |
57 return [SafeModeViewController hasReportToUpload]; | 69 return [SafeModeViewController hasReportToUpload]; |
58 } | 70 } |
59 | 71 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 CGRect mainBounds = [[UIScreen mainScreen] bounds]; | 144 CGRect mainBounds = [[UIScreen mainScreen] bounds]; |
133 // SafeModeViewController only supports portrait orientation (see | 145 // SafeModeViewController only supports portrait orientation (see |
134 // implementation of supportedInterfaceOrientations: below) but if the app is | 146 // implementation of supportedInterfaceOrientations: below) but if the app is |
135 // launched from landscape mode (e.g. iPad or iPhone 6+) then the mainScreen's | 147 // launched from landscape mode (e.g. iPad or iPhone 6+) then the mainScreen's |
136 // bounds will still be landscape at this point. Swap the height and width | 148 // bounds will still be landscape at this point. Swap the height and width |
137 // here so that the dimensions will be correct once the app rotates to | 149 // here so that the dimensions will be correct once the app rotates to |
138 // portrait. | 150 // portrait. |
139 if (IsLandscape()) { | 151 if (IsLandscape()) { |
140 mainBounds.size = CGSizeMake(mainBounds.size.height, mainBounds.size.width); | 152 mainBounds.size = CGSizeMake(mainBounds.size.height, mainBounds.size.width); |
141 } | 153 } |
142 base::scoped_nsobject<UIScrollView> scrollView( | 154 UIScrollView* scrollView = [[UIScrollView alloc] initWithFrame:mainBounds]; |
143 [[UIScrollView alloc] initWithFrame:mainBounds]); | |
144 self.view = scrollView; | 155 self.view = scrollView; |
145 [self.view setBackgroundColor:[UIColor colorWithWhite:0.902 alpha:1.0]]; | 156 [self.view setBackgroundColor:[UIColor colorWithWhite:0.902 alpha:1.0]]; |
146 const CGFloat kIPadInset = | 157 const CGFloat kIPadInset = |
147 (mainBounds.size.width - kIPadWidth - kHorizontalSpacing) / 2; | 158 (mainBounds.size.width - kIPadWidth - kHorizontalSpacing) / 2; |
148 const CGFloat widthInset = IsIPadIdiom() ? kIPadInset : kHorizontalSpacing; | 159 const CGFloat widthInset = IsIPadIdiom() ? kIPadInset : kHorizontalSpacing; |
149 innerView_.reset([[UIView alloc] | 160 innerView_ = [[UIView alloc] |
150 initWithFrame:CGRectInset(mainBounds, widthInset, kVerticalSpacing * 2)]); | 161 initWithFrame:CGRectInset(mainBounds, widthInset, kVerticalSpacing * 2)]; |
151 [innerView_ setBackgroundColor:[UIColor whiteColor]]; | 162 [innerView_ setBackgroundColor:[UIColor whiteColor]]; |
152 [innerView_ layer].cornerRadius = 3; | 163 [innerView_ layer].cornerRadius = 3; |
153 [innerView_ layer].borderWidth = 1; | 164 [innerView_ layer].borderWidth = 1; |
154 [innerView_ layer].borderColor = | 165 [innerView_ layer].borderColor = |
155 [UIColor colorWithWhite:0.851 alpha:1.0].CGColor; | 166 [UIColor colorWithWhite:0.851 alpha:1.0].CGColor; |
156 [innerView_ layer].masksToBounds = YES; | 167 [innerView_ layer].masksToBounds = YES; |
157 [scrollView addSubview:innerView_]; | 168 [scrollView addSubview:innerView_]; |
158 | 169 |
159 UIImage* fatalImage = [UIImage imageNamed:@"fatal_error.png"]; | 170 UIImage* fatalImage = [UIImage imageNamed:@"fatal_error.png"]; |
160 base::scoped_nsobject<UIImageView> imageView( | 171 UIImageView* imageView = [[UIImageView alloc] initWithImage:fatalImage]; |
161 [[UIImageView alloc] initWithImage:fatalImage]); | |
162 // Shift the image down a bit. | 172 // Shift the image down a bit. |
163 CGRect imageFrame = [imageView frame]; | 173 CGRect imageFrame = [imageView frame]; |
164 imageFrame.origin.y = kVerticalSpacing; | 174 imageFrame.origin.y = kVerticalSpacing; |
165 [imageView setFrame:imageFrame]; | 175 [imageView setFrame:imageFrame]; |
166 [self centerView:imageView afterView:nil]; | 176 [self centerView:imageView afterView:nil]; |
167 [innerView_ addSubview:imageView]; | 177 [innerView_ addSubview:imageView]; |
168 | 178 |
169 base::scoped_nsobject<UILabel> awSnap([[UILabel alloc] init]); | 179 UILabel* awSnap = [[UILabel alloc] init]; |
170 [awSnap setText:NSLocalizedString(@"IDS_IOS_SAFE_MODE_AW_SNAP", @"")]; | 180 [awSnap setText:NSLocalizedString(@"IDS_IOS_SAFE_MODE_AW_SNAP", @"")]; |
171 [awSnap setBackgroundColor:[UIColor clearColor]]; | 181 [awSnap setBackgroundColor:[UIColor clearColor]]; |
172 [awSnap setTextColor:[UIColor blackColor]]; | 182 [awSnap setTextColor:[UIColor blackColor]]; |
173 [awSnap setFont:[UIFont boldSystemFontOfSize:21]]; | 183 [awSnap setFont:[UIFont boldSystemFontOfSize:21]]; |
174 [awSnap sizeToFit]; | 184 [awSnap sizeToFit]; |
175 [self centerView:awSnap afterView:imageView]; | 185 [self centerView:awSnap afterView:imageView]; |
176 [innerView_ addSubview:awSnap]; | 186 [innerView_ addSubview:awSnap]; |
177 | 187 |
178 base::scoped_nsobject<UILabel> description([[UILabel alloc] init]); | 188 UILabel* description = [[UILabel alloc] init]; |
179 [description setText:[self startupCrashModuleText]]; | 189 [description setText:[self startupCrashModuleText]]; |
180 [description setBackgroundColor:[UIColor clearColor]]; | 190 [description setBackgroundColor:[UIColor clearColor]]; |
181 [description setTextColor:[UIColor colorWithWhite:0.31 alpha:1.0]]; | 191 [description setTextColor:[UIColor colorWithWhite:0.31 alpha:1.0]]; |
182 [description setTextAlignment:NSTextAlignmentCenter]; | 192 [description setTextAlignment:NSTextAlignmentCenter]; |
183 [description setNumberOfLines:0]; | 193 [description setNumberOfLines:0]; |
184 [description setLineBreakMode:NSLineBreakByWordWrapping]; | 194 [description setLineBreakMode:NSLineBreakByWordWrapping]; |
185 CGRect frame = [description frame]; | 195 CGRect frame = [description frame]; |
186 frame.size.width = IsIPadIdiom() ? kIPadWidth : kIPhoneWidth; | 196 frame.size.width = IsIPadIdiom() ? kIPadWidth : kIPhoneWidth; |
187 CGSize maxSize = CGSizeMake(frame.size.width, 999999.0f); | 197 CGSize maxSize = CGSizeMake(frame.size.width, 999999.0f); |
188 frame.size.height = | 198 frame.size.height = |
189 [[description text] cr_boundingSizeWithSize:maxSize | 199 [[description text] cr_boundingSizeWithSize:maxSize |
190 font:[description font]] | 200 font:[description font]] |
191 .height; | 201 .height; |
192 [description setFrame:frame]; | 202 [description setFrame:frame]; |
193 [self centerView:description afterView:awSnap]; | 203 [self centerView:description afterView:awSnap]; |
194 [innerView_ addSubview:description]; | 204 [innerView_ addSubview:description]; |
195 | 205 |
196 startButton_.reset([[PrimaryActionButton alloc] init]); | 206 startButton_ = [[PrimaryActionButton alloc] init]; |
197 NSString* startText = | 207 NSString* startText = |
198 NSLocalizedString(@"IDS_IOS_SAFE_MODE_RELOAD_CHROME", @""); | 208 NSLocalizedString(@"IDS_IOS_SAFE_MODE_RELOAD_CHROME", @""); |
199 [startButton_ setTitle:startText forState:UIControlStateNormal]; | 209 [startButton_ setTitle:startText forState:UIControlStateNormal]; |
200 [startButton_ titleLabel].textAlignment = NSTextAlignmentCenter; | 210 [startButton_ titleLabel].textAlignment = NSTextAlignmentCenter; |
201 [startButton_ titleLabel].lineBreakMode = NSLineBreakByWordWrapping; | 211 [startButton_ titleLabel].lineBreakMode = NSLineBreakByWordWrapping; |
202 frame = [startButton_ frame]; | 212 frame = [startButton_ frame]; |
203 frame.size.width = IsIPadIdiom() ? kIPadWidth : kIPhoneWidth; | 213 frame.size.width = IsIPadIdiom() ? kIPadWidth : kIPhoneWidth; |
204 maxSize = CGSizeMake(frame.size.width, 999999.0f); | 214 maxSize = CGSizeMake(frame.size.width, 999999.0f); |
205 const CGFloat kButtonBuffer = kVerticalSpacing / 2; | 215 const CGFloat kButtonBuffer = kVerticalSpacing / 2; |
206 CGSize startTextBoundingSize = | 216 CGSize startTextBoundingSize = |
207 [startText cr_boundingSizeWithSize:maxSize | 217 [startText cr_boundingSizeWithSize:maxSize |
208 font:[startButton_ titleLabel].font]; | 218 font:[startButton_ titleLabel].font]; |
209 frame.size.height = startTextBoundingSize.height + kButtonBuffer; | 219 frame.size.height = startTextBoundingSize.height + kButtonBuffer; |
210 [startButton_ setFrame:frame]; | 220 [startButton_ setFrame:frame]; |
211 [startButton_ addTarget:self | 221 [startButton_ addTarget:self |
212 action:@selector(startBrowserFromSafeMode) | 222 action:@selector(startBrowserFromSafeMode) |
213 forControlEvents:UIControlEventTouchUpInside]; | 223 forControlEvents:UIControlEventTouchUpInside]; |
214 [self centerView:startButton_ afterView:description]; | 224 [self centerView:startButton_ afterView:description]; |
215 [innerView_ addSubview:startButton_]; | 225 [innerView_ addSubview:startButton_]; |
216 | 226 |
217 UIView* lastView = startButton_; | 227 UIView* lastView = startButton_; |
218 if ([SafeModeViewController hasReportToUpload]) { | 228 if ([SafeModeViewController hasReportToUpload]) { |
219 breakpad_helper::StartUploadingReportsInRecoveryMode(); | 229 breakpad_helper::StartUploadingReportsInRecoveryMode(); |
220 | 230 |
221 // If there are no jailbreak modifications, then present the "Sending crash | 231 // If there are no jailbreak modifications, then present the "Sending crash |
222 // report..." UI. | 232 // report..." UI. |
223 if (![SafeModeViewController detectedThirdPartyMods]) { | 233 if (![SafeModeViewController detectedThirdPartyMods]) { |
224 [startButton_ setEnabled:NO]; | 234 [startButton_ setEnabled:NO]; |
225 | 235 |
226 uploadDescription_.reset([[UILabel alloc] init]); | 236 uploadDescription_ = [[UILabel alloc] init]; |
227 [uploadDescription_ | 237 [uploadDescription_ |
228 setText:NSLocalizedString(@"IDS_IOS_SAFE_MODE_SENDING_CRASH_REPORT", | 238 setText:NSLocalizedString(@"IDS_IOS_SAFE_MODE_SENDING_CRASH_REPORT", |
229 @"")]; | 239 @"")]; |
230 [uploadDescription_ setBackgroundColor:[UIColor clearColor]]; | 240 [uploadDescription_ setBackgroundColor:[UIColor clearColor]]; |
231 [uploadDescription_ setFont:[UIFont systemFontOfSize:13]]; | 241 [uploadDescription_ setFont:[UIFont systemFontOfSize:13]]; |
232 [uploadDescription_ setTextColor:[UIColor colorWithWhite:0.31 alpha:1.0]]; | 242 [uploadDescription_ setTextColor:[UIColor colorWithWhite:0.31 alpha:1.0]]; |
233 [uploadDescription_ sizeToFit]; | 243 [uploadDescription_ sizeToFit]; |
234 [self centerView:uploadDescription_ afterView:startButton_]; | 244 [self centerView:uploadDescription_ afterView:startButton_]; |
235 [innerView_ addSubview:uploadDescription_]; | 245 [innerView_ addSubview:uploadDescription_]; |
236 | 246 |
237 uploadProgress_.reset([[UIProgressView alloc] | 247 uploadProgress_ = [[UIProgressView alloc] |
238 initWithProgressViewStyle:UIProgressViewStyleDefault]); | 248 initWithProgressViewStyle:UIProgressViewStyleDefault]; |
239 [self centerView:uploadProgress_ afterView:nil]; | 249 [self centerView:uploadProgress_ afterView:nil]; |
240 frame = [uploadProgress_ frame]; | 250 frame = [uploadProgress_ frame]; |
241 frame.origin.y = | 251 frame.origin.y = |
242 CGRectGetMaxY([uploadDescription_ frame]) + kUploadProgressSpacing; | 252 CGRectGetMaxY([uploadDescription_ frame]) + kUploadProgressSpacing; |
243 [uploadProgress_ setFrame:frame]; | 253 [uploadProgress_ setFrame:frame]; |
244 [innerView_ addSubview:uploadProgress_]; | 254 [innerView_ addSubview:uploadProgress_]; |
245 | 255 |
246 lastView = uploadProgress_; | 256 lastView = uploadProgress_; |
247 [self startUploadProgress]; | 257 [self startUploadProgress]; |
248 } | 258 } |
249 } | 259 } |
250 | 260 |
251 CGSize scrollSize = | 261 CGSize scrollSize = |
252 CGSizeMake(mainBounds.size.width, | 262 CGSizeMake(mainBounds.size.width, |
253 CGRectGetMaxY([lastView frame]) + kVerticalSpacing); | 263 CGRectGetMaxY([lastView frame]) + kVerticalSpacing); |
254 frame = [innerView_ frame]; | 264 frame = [innerView_ frame]; |
255 frame.size.height = scrollSize.height; | 265 frame.size.height = scrollSize.height; |
256 [innerView_ setFrame:frame]; | 266 [innerView_ setFrame:frame]; |
257 scrollSize.height += frame.origin.y; | 267 scrollSize.height += frame.origin.y; |
258 [scrollView setContentSize:scrollSize]; | 268 [scrollView setContentSize:scrollSize]; |
259 } | 269 } |
260 | 270 |
261 - (NSUInteger)supportedInterfaceOrientations { | 271 - (NSUInteger)supportedInterfaceOrientations { |
262 return UIInterfaceOrientationMaskPortrait; | 272 return UIInterfaceOrientationMaskPortrait; |
263 } | 273 } |
264 | 274 |
265 #pragma mark - Private | 275 #pragma mark - Private |
266 | 276 |
267 - (void)startUploadProgress { | 277 - (void)startUploadProgress { |
268 uploadStartTime_.reset([[NSDate date] retain]); | 278 uploadStartTime_ = [NSDate date]; |
269 uploadTimer_.reset( | 279 uploadTimer_ = |
270 [[NSTimer scheduledTimerWithTimeInterval:kUploadPumpInterval | 280 [NSTimer scheduledTimerWithTimeInterval:kUploadPumpInterval |
271 target:self | 281 target:self |
272 selector:@selector(pumpUploadProgress) | 282 selector:@selector(pumpUploadProgress) |
273 userInfo:nil | 283 userInfo:nil |
274 repeats:YES] retain]); | 284 repeats:YES]; |
275 } | 285 } |
276 | 286 |
277 - (void)pumpUploadProgress { | 287 - (void)pumpUploadProgress { |
278 NSTimeInterval elapsed = | 288 NSTimeInterval elapsed = |
279 [[NSDate date] timeIntervalSinceDate:uploadStartTime_]; | 289 [[NSDate date] timeIntervalSinceDate:uploadStartTime_]; |
280 // Theoretically we could stop early when the value returned by | 290 // Theoretically we could stop early when the value returned by |
281 // ios_internal::breakpad::GetCrashReportCount() changes, but this is | 291 // ios_internal::breakpad::GetCrashReportCount() changes, but this is |
282 // simpler. If we decide to look for a change in crash report count, then we | 292 // simpler. If we decide to look for a change in crash report count, then we |
283 // also probably want to replace the UIProgressView with a | 293 // also probably want to replace the UIProgressView with a |
284 // UIActivityIndicatorView. | 294 // UIActivityIndicatorView. |
(...skipping 11 matching lines...) Expand all Loading... |
296 [uploadProgress_ setHidden:YES]; | 306 [uploadProgress_ setHidden:YES]; |
297 } | 307 } |
298 } | 308 } |
299 | 309 |
300 - (void)startBrowserFromSafeMode { | 310 - (void)startBrowserFromSafeMode { |
301 breakpad_helper::RestoreDefaultConfiguration(); | 311 breakpad_helper::RestoreDefaultConfiguration(); |
302 [delegate_ startBrowserFromSafeMode]; | 312 [delegate_ startBrowserFromSafeMode]; |
303 } | 313 } |
304 | 314 |
305 @end | 315 @end |
OLD | NEW |