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

Side by Side Diff: ios/chrome/app/safe_mode/safe_mode_view_controller.mm

Issue 2580363002: Upstream Chrome on iOS source code [1/11]. (Closed)
Patch Set: Created 4 years 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "ios/chrome/app/safe_mode/safe_mode_view_controller.h"
6
7 #import <QuartzCore/QuartzCore.h>
8
9 #include "base/strings/sys_string_conversions.h"
10 #import "ios/chrome/app/safe_mode_crashing_modules_config.h"
11 #import "ios/chrome/app/safe_mode_util.h"
12 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
13 #import "ios/chrome/browser/ui/fancy_ui/primary_action_button.h"
14 #include "ios/chrome/browser/ui/ui_util.h"
15 #import "ios/chrome/browser/ui/uikit_ui_util.h"
16 #include "ios/chrome/grit/ios_chromium_strings.h"
17 #import "ui/gfx/ios/NSString+CrStringDrawing.h"
18
19 namespace {
20 const CGFloat kVerticalSpacing = 20;
21 const CGFloat kUploadProgressSpacing = 5;
22 const NSTimeInterval kUploadPumpInterval = 0.1;
23 const NSTimeInterval kUploadTotalTime = 5;
24 } // anonymous namespace
25
26 @interface SafeModeViewController ()
27 // Returns |YES| if any third-party modifications are detected.
28 + (BOOL)detectedThirdPartyMods;
29 // Returns |YES| if there are crash reports to upload.
30 + (BOOL)hasReportToUpload;
31 // Returns a message explaining which, if any, 3rd party modules were detected
32 // that may cause Chrome to crash.
33 - (NSString*)startupCrashModuleText;
34 // Starts timer to update progress bar for crash report upload.
35 - (void)startUploadProgress;
36 // Updates progress bar for crash report upload.
37 - (void)pumpUploadProgress;
38 // Called when user taps on "Resume Chrome" button. Restores the default
39 // Breakpad configuration and notifies the delegate to attempt to start the
40 // browser.
41 - (void)startBrowserFromSafeMode;
42 @end
43
44 @implementation SafeModeViewController
45
46 - (id)initWithDelegate:(id<SafeModeViewControllerDelegate>)delegate {
47 self = [super init];
48 if (self) {
49 delegate_.reset(delegate);
50 }
51 return self;
52 }
53
54 + (BOOL)hasSuggestions {
55 if ([SafeModeViewController detectedThirdPartyMods])
56 return YES;
57 return [SafeModeViewController hasReportToUpload];
58 }
59
60 + (BOOL)detectedThirdPartyMods {
61 std::vector<std::string> thirdPartyMods = safe_mode_util::GetLoadedImages(
62 "/Library/MobileSubstrate/DynamicLibraries/");
63 return (thirdPartyMods.size() > 0);
64 }
65
66 + (BOOL)hasReportToUpload {
67 // If uploading is enabled and more than one report has stacked up, then we
68 // assume that the app may be in a state that is preventing crash report
69 // uploads before crashing again.
70 return breakpad_helper::IsUploadingEnabled() &&
71 breakpad_helper::GetCrashReportCount() > 1;
72 }
73
74 // Return any jailbroken library that appears in SafeModeCrashingModulesConfig.
75 - (NSArray*)startupCrashModules {
76 std::vector<std::string> modules = safe_mode_util::GetLoadedImages(
77 "/Library/MobileSubstrate/DynamicLibraries/");
78 NSMutableArray* array = [NSMutableArray arrayWithCapacity:modules.size()];
79 SafeModeCrashingModulesConfig* config =
80 [SafeModeCrashingModulesConfig sharedInstance];
81 for (size_t i = 0; i < modules.size(); i++) {
82 NSString* path = base::SysUTF8ToNSString(modules[i]);
83 NSString* friendlyName = [config startupCrashModuleFriendlyName:path];
84 if (friendlyName != nil)
85 [array addObject:friendlyName];
86 }
87 return array;
88 }
89
90 // Since we are still supporting iOS5, this is a helper for basic flow layout.
91 - (void)centerView:(UIView*)view afterView:(UIView*)afterView {
92 CGPoint center = [view center];
93 center.x = [innerView_ frame].size.width / 2;
94 [view setCenter:center];
95
96 if (afterView) {
97 CGRect frame = view.frame;
98 frame.origin.y = CGRectGetMaxY(afterView.frame) + kVerticalSpacing;
99 view.frame = frame;
100 }
101 }
102
103 - (NSString*)startupCrashModuleText {
104 NSArray* knownModules = [self startupCrashModules];
105 if ([knownModules count]) {
106 NSString* wrongText =
107 NSLocalizedString(@"IDS_IOS_SAFE_MODE_NAMED_TWEAKS_FOUND", @"");
108 NSMutableString* text = [NSMutableString stringWithString:wrongText];
109 [text appendString:@"\n"];
110 for (NSString* module in knownModules) {
111 [text appendFormat:@"\n %@", module];
112 }
113 return text;
114 } else if ([SafeModeViewController detectedThirdPartyMods]) {
115 return NSLocalizedString(@"IDS_IOS_SAFE_MODE_TWEAKS_FOUND", @"");
116 } else {
117 return NSLocalizedString(@"IDS_IOS_SAFE_MODE_UNKNOWN_CAUSE", @"");
118 }
119 }
120
121 - (void)viewDidLoad {
122 [super viewDidLoad];
123
124 // Width of the inner view on iPhone.
125 const CGFloat kIPhoneWidth = 250;
126 // Width of the inner view on iPad.
127 const CGFloat kIPadWidth = 350;
128 // Horizontal buffer.
129 const CGFloat kHorizontalSpacing = 20;
130
131 self.view.autoresizesSubviews = YES;
132 CGRect mainBounds = [[UIScreen mainScreen] bounds];
133 // SafeModeViewController only supports portrait orientation (see
134 // implementation of supportedInterfaceOrientations: below) but if the app is
135 // 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
137 // here so that the dimensions will be correct once the app rotates to
138 // portrait.
139 if (IsLandscape()) {
140 mainBounds.size = CGSizeMake(mainBounds.size.height, mainBounds.size.width);
141 }
142 base::scoped_nsobject<UIScrollView> scrollView(
143 [[UIScrollView alloc] initWithFrame:mainBounds]);
144 self.view = scrollView;
145 [self.view setBackgroundColor:[UIColor colorWithWhite:0.902 alpha:1.0]];
146 const CGFloat kIPadInset =
147 (mainBounds.size.width - kIPadWidth - kHorizontalSpacing) / 2;
148 const CGFloat widthInset = IsIPadIdiom() ? kIPadInset : kHorizontalSpacing;
149 innerView_.reset([[UIView alloc]
150 initWithFrame:CGRectInset(mainBounds, widthInset, kVerticalSpacing * 2)]);
151 [innerView_ setBackgroundColor:[UIColor whiteColor]];
152 [innerView_ layer].cornerRadius = 3;
153 [innerView_ layer].borderWidth = 1;
154 [innerView_ layer].borderColor =
155 [UIColor colorWithWhite:0.851 alpha:1.0].CGColor;
156 [innerView_ layer].masksToBounds = YES;
157 [scrollView addSubview:innerView_];
158
159 UIImage* fatalImage = [UIImage imageNamed:@"fatal_error.png"];
160 base::scoped_nsobject<UIImageView> imageView(
161 [[UIImageView alloc] initWithImage:fatalImage]);
162 // Shift the image down a bit.
163 CGRect imageFrame = [imageView frame];
164 imageFrame.origin.y = kVerticalSpacing;
165 [imageView setFrame:imageFrame];
166 [self centerView:imageView afterView:nil];
167 [innerView_ addSubview:imageView];
168
169 base::scoped_nsobject<UILabel> awSnap([[UILabel alloc] init]);
170 [awSnap setText:NSLocalizedString(@"IDS_IOS_SAFE_MODE_AW_SNAP", @"")];
171 [awSnap setBackgroundColor:[UIColor clearColor]];
172 [awSnap setTextColor:[UIColor blackColor]];
173 [awSnap setFont:[UIFont boldSystemFontOfSize:21]];
174 [awSnap sizeToFit];
175 [self centerView:awSnap afterView:imageView];
176 [innerView_ addSubview:awSnap];
177
178 base::scoped_nsobject<UILabel> description([[UILabel alloc] init]);
179 [description setText:[self startupCrashModuleText]];
180 [description setBackgroundColor:[UIColor clearColor]];
181 [description setTextColor:[UIColor colorWithWhite:0.31 alpha:1.0]];
182 [description setTextAlignment:NSTextAlignmentCenter];
183 [description setNumberOfLines:0];
184 [description setLineBreakMode:NSLineBreakByWordWrapping];
185 CGRect frame = [description frame];
186 frame.size.width = IsIPadIdiom() ? kIPadWidth : kIPhoneWidth;
187 CGSize maxSize = CGSizeMake(frame.size.width, 999999.0f);
188 frame.size.height =
189 [[description text] cr_boundingSizeWithSize:maxSize
190 font:[description font]]
191 .height;
192 [description setFrame:frame];
193 [self centerView:description afterView:awSnap];
194 [innerView_ addSubview:description];
195
196 startButton_.reset([[PrimaryActionButton alloc] init]);
197 NSString* startText =
198 NSLocalizedString(@"IDS_IOS_SAFE_MODE_RELOAD_CHROME", @"");
199 [startButton_ setTitle:startText forState:UIControlStateNormal];
200 [startButton_ titleLabel].textAlignment = NSTextAlignmentCenter;
201 [startButton_ titleLabel].lineBreakMode = NSLineBreakByWordWrapping;
202 frame = [startButton_ frame];
203 frame.size.width = IsIPadIdiom() ? kIPadWidth : kIPhoneWidth;
204 maxSize = CGSizeMake(frame.size.width, 999999.0f);
205 const CGFloat kButtonBuffer = kVerticalSpacing / 2;
206 CGSize startTextBoundingSize =
207 [startText cr_boundingSizeWithSize:maxSize
208 font:[startButton_ titleLabel].font];
209 frame.size.height = startTextBoundingSize.height + kButtonBuffer;
210 [startButton_ setFrame:frame];
211 [startButton_ addTarget:self
212 action:@selector(startBrowserFromSafeMode)
213 forControlEvents:UIControlEventTouchUpInside];
214 [self centerView:startButton_ afterView:description];
215 [innerView_ addSubview:startButton_];
216
217 UIView* lastView = startButton_;
218 if ([SafeModeViewController hasReportToUpload]) {
219 breakpad_helper::StartUploadingReportsInRecoveryMode();
220
221 // If there are no jailbreak modifications, then present the "Sending crash
222 // report..." UI.
223 if (![SafeModeViewController detectedThirdPartyMods]) {
224 [startButton_ setEnabled:NO];
225
226 uploadDescription_.reset([[UILabel alloc] init]);
227 [uploadDescription_
228 setText:NSLocalizedString(@"IDS_IOS_SAFE_MODE_SENDING_CRASH_REPORT",
229 @"")];
230 [uploadDescription_ setBackgroundColor:[UIColor clearColor]];
231 [uploadDescription_ setFont:[UIFont systemFontOfSize:13]];
232 [uploadDescription_ setTextColor:[UIColor colorWithWhite:0.31 alpha:1.0]];
233 [uploadDescription_ sizeToFit];
234 [self centerView:uploadDescription_ afterView:startButton_];
235 [innerView_ addSubview:uploadDescription_];
236
237 uploadProgress_.reset([[UIProgressView alloc]
238 initWithProgressViewStyle:UIProgressViewStyleDefault]);
239 [self centerView:uploadProgress_ afterView:nil];
240 frame = [uploadProgress_ frame];
241 frame.origin.y =
242 CGRectGetMaxY([uploadDescription_ frame]) + kUploadProgressSpacing;
243 [uploadProgress_ setFrame:frame];
244 [innerView_ addSubview:uploadProgress_];
245
246 lastView = uploadProgress_;
247 [self startUploadProgress];
248 }
249 }
250
251 CGSize scrollSize =
252 CGSizeMake(mainBounds.size.width,
253 CGRectGetMaxY([lastView frame]) + kVerticalSpacing);
254 frame = [innerView_ frame];
255 frame.size.height = scrollSize.height;
256 [innerView_ setFrame:frame];
257 scrollSize.height += frame.origin.y;
258 [scrollView setContentSize:scrollSize];
259 }
260
261 - (NSUInteger)supportedInterfaceOrientations {
262 return UIInterfaceOrientationMaskPortrait;
263 }
264
265 #pragma mark - Private
266
267 - (void)startUploadProgress {
268 uploadStartTime_.reset([[NSDate date] retain]);
269 uploadTimer_.reset(
270 [[NSTimer scheduledTimerWithTimeInterval:kUploadPumpInterval
271 target:self
272 selector:@selector(pumpUploadProgress)
273 userInfo:nil
274 repeats:YES] retain]);
275 }
276
277 - (void)pumpUploadProgress {
278 NSTimeInterval elapsed =
279 [[NSDate date] timeIntervalSinceDate:uploadStartTime_];
280 // Theoretically we could stop early when the value returned by
281 // ios_internal::breakpad::GetCrashReportCount() changes, but this is
282 // 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
284 // UIActivityIndicatorView.
285 if (elapsed <= kUploadTotalTime) {
286 [uploadProgress_ setProgress:elapsed / kUploadTotalTime animated:YES];
287 } else {
288 [uploadTimer_ invalidate];
289
290 [startButton_ setEnabled:YES];
291 [uploadDescription_
292 setText:NSLocalizedString(@"IDS_IOS_SAFE_MODE_CRASH_REPORT_SENT",
293 @"")];
294 [uploadDescription_ sizeToFit];
295 [self centerView:uploadDescription_ afterView:startButton_];
296 [uploadProgress_ setHidden:YES];
297 }
298 }
299
300 - (void)startBrowserFromSafeMode {
301 breakpad_helper::RestoreDefaultConfiguration();
302 [delegate_ startBrowserFromSafeMode];
303 }
304
305 @end
OLDNEW
« no previous file with comments | « ios/chrome/app/safe_mode/safe_mode_view_controller.h ('k') | ios/chrome/app/safe_mode/safe_mode_view_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698