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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: ios/chrome/app/safe_mode/safe_mode_view_controller.mm
diff --git a/ios/chrome/app/safe_mode/safe_mode_view_controller.mm b/ios/chrome/app/safe_mode/safe_mode_view_controller.mm
new file mode 100644
index 0000000000000000000000000000000000000000..fbd921c49e2c743ed3cfe2dd7b2fa3e18de9bb27
--- /dev/null
+++ b/ios/chrome/app/safe_mode/safe_mode_view_controller.mm
@@ -0,0 +1,305 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/app/safe_mode/safe_mode_view_controller.h"
+
+#import <QuartzCore/QuartzCore.h>
+
+#include "base/strings/sys_string_conversions.h"
+#import "ios/chrome/app/safe_mode_crashing_modules_config.h"
+#import "ios/chrome/app/safe_mode_util.h"
+#include "ios/chrome/browser/crash_report/breakpad_helper.h"
+#import "ios/chrome/browser/ui/fancy_ui/primary_action_button.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#include "ios/chrome/grit/ios_chromium_strings.h"
+#import "ui/gfx/ios/NSString+CrStringDrawing.h"
+
+namespace {
+const CGFloat kVerticalSpacing = 20;
+const CGFloat kUploadProgressSpacing = 5;
+const NSTimeInterval kUploadPumpInterval = 0.1;
+const NSTimeInterval kUploadTotalTime = 5;
+} // anonymous namespace
+
+@interface SafeModeViewController ()
+// Returns |YES| if any third-party modifications are detected.
++ (BOOL)detectedThirdPartyMods;
+// Returns |YES| if there are crash reports to upload.
++ (BOOL)hasReportToUpload;
+// Returns a message explaining which, if any, 3rd party modules were detected
+// that may cause Chrome to crash.
+- (NSString*)startupCrashModuleText;
+// Starts timer to update progress bar for crash report upload.
+- (void)startUploadProgress;
+// Updates progress bar for crash report upload.
+- (void)pumpUploadProgress;
+// Called when user taps on "Resume Chrome" button. Restores the default
+// Breakpad configuration and notifies the delegate to attempt to start the
+// browser.
+- (void)startBrowserFromSafeMode;
+@end
+
+@implementation SafeModeViewController
+
+- (id)initWithDelegate:(id<SafeModeViewControllerDelegate>)delegate {
+ self = [super init];
+ if (self) {
+ delegate_.reset(delegate);
+ }
+ return self;
+}
+
++ (BOOL)hasSuggestions {
+ if ([SafeModeViewController detectedThirdPartyMods])
+ return YES;
+ return [SafeModeViewController hasReportToUpload];
+}
+
++ (BOOL)detectedThirdPartyMods {
+ std::vector<std::string> thirdPartyMods = safe_mode_util::GetLoadedImages(
+ "/Library/MobileSubstrate/DynamicLibraries/");
+ return (thirdPartyMods.size() > 0);
+}
+
++ (BOOL)hasReportToUpload {
+ // If uploading is enabled and more than one report has stacked up, then we
+ // assume that the app may be in a state that is preventing crash report
+ // uploads before crashing again.
+ return breakpad_helper::IsUploadingEnabled() &&
+ breakpad_helper::GetCrashReportCount() > 1;
+}
+
+// Return any jailbroken library that appears in SafeModeCrashingModulesConfig.
+- (NSArray*)startupCrashModules {
+ std::vector<std::string> modules = safe_mode_util::GetLoadedImages(
+ "/Library/MobileSubstrate/DynamicLibraries/");
+ NSMutableArray* array = [NSMutableArray arrayWithCapacity:modules.size()];
+ SafeModeCrashingModulesConfig* config =
+ [SafeModeCrashingModulesConfig sharedInstance];
+ for (size_t i = 0; i < modules.size(); i++) {
+ NSString* path = base::SysUTF8ToNSString(modules[i]);
+ NSString* friendlyName = [config startupCrashModuleFriendlyName:path];
+ if (friendlyName != nil)
+ [array addObject:friendlyName];
+ }
+ return array;
+}
+
+// Since we are still supporting iOS5, this is a helper for basic flow layout.
+- (void)centerView:(UIView*)view afterView:(UIView*)afterView {
+ CGPoint center = [view center];
+ center.x = [innerView_ frame].size.width / 2;
+ [view setCenter:center];
+
+ if (afterView) {
+ CGRect frame = view.frame;
+ frame.origin.y = CGRectGetMaxY(afterView.frame) + kVerticalSpacing;
+ view.frame = frame;
+ }
+}
+
+- (NSString*)startupCrashModuleText {
+ NSArray* knownModules = [self startupCrashModules];
+ if ([knownModules count]) {
+ NSString* wrongText =
+ NSLocalizedString(@"IDS_IOS_SAFE_MODE_NAMED_TWEAKS_FOUND", @"");
+ NSMutableString* text = [NSMutableString stringWithString:wrongText];
+ [text appendString:@"\n"];
+ for (NSString* module in knownModules) {
+ [text appendFormat:@"\n %@", module];
+ }
+ return text;
+ } else if ([SafeModeViewController detectedThirdPartyMods]) {
+ return NSLocalizedString(@"IDS_IOS_SAFE_MODE_TWEAKS_FOUND", @"");
+ } else {
+ return NSLocalizedString(@"IDS_IOS_SAFE_MODE_UNKNOWN_CAUSE", @"");
+ }
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ // Width of the inner view on iPhone.
+ const CGFloat kIPhoneWidth = 250;
+ // Width of the inner view on iPad.
+ const CGFloat kIPadWidth = 350;
+ // Horizontal buffer.
+ const CGFloat kHorizontalSpacing = 20;
+
+ self.view.autoresizesSubviews = YES;
+ CGRect mainBounds = [[UIScreen mainScreen] bounds];
+ // SafeModeViewController only supports portrait orientation (see
+ // implementation of supportedInterfaceOrientations: below) but if the app is
+ // launched from landscape mode (e.g. iPad or iPhone 6+) then the mainScreen's
+ // bounds will still be landscape at this point. Swap the height and width
+ // here so that the dimensions will be correct once the app rotates to
+ // portrait.
+ if (IsLandscape()) {
+ mainBounds.size = CGSizeMake(mainBounds.size.height, mainBounds.size.width);
+ }
+ base::scoped_nsobject<UIScrollView> scrollView(
+ [[UIScrollView alloc] initWithFrame:mainBounds]);
+ self.view = scrollView;
+ [self.view setBackgroundColor:[UIColor colorWithWhite:0.902 alpha:1.0]];
+ const CGFloat kIPadInset =
+ (mainBounds.size.width - kIPadWidth - kHorizontalSpacing) / 2;
+ const CGFloat widthInset = IsIPadIdiom() ? kIPadInset : kHorizontalSpacing;
+ innerView_.reset([[UIView alloc]
+ initWithFrame:CGRectInset(mainBounds, widthInset, kVerticalSpacing * 2)]);
+ [innerView_ setBackgroundColor:[UIColor whiteColor]];
+ [innerView_ layer].cornerRadius = 3;
+ [innerView_ layer].borderWidth = 1;
+ [innerView_ layer].borderColor =
+ [UIColor colorWithWhite:0.851 alpha:1.0].CGColor;
+ [innerView_ layer].masksToBounds = YES;
+ [scrollView addSubview:innerView_];
+
+ UIImage* fatalImage = [UIImage imageNamed:@"fatal_error.png"];
+ base::scoped_nsobject<UIImageView> imageView(
+ [[UIImageView alloc] initWithImage:fatalImage]);
+ // Shift the image down a bit.
+ CGRect imageFrame = [imageView frame];
+ imageFrame.origin.y = kVerticalSpacing;
+ [imageView setFrame:imageFrame];
+ [self centerView:imageView afterView:nil];
+ [innerView_ addSubview:imageView];
+
+ base::scoped_nsobject<UILabel> awSnap([[UILabel alloc] init]);
+ [awSnap setText:NSLocalizedString(@"IDS_IOS_SAFE_MODE_AW_SNAP", @"")];
+ [awSnap setBackgroundColor:[UIColor clearColor]];
+ [awSnap setTextColor:[UIColor blackColor]];
+ [awSnap setFont:[UIFont boldSystemFontOfSize:21]];
+ [awSnap sizeToFit];
+ [self centerView:awSnap afterView:imageView];
+ [innerView_ addSubview:awSnap];
+
+ base::scoped_nsobject<UILabel> description([[UILabel alloc] init]);
+ [description setText:[self startupCrashModuleText]];
+ [description setBackgroundColor:[UIColor clearColor]];
+ [description setTextColor:[UIColor colorWithWhite:0.31 alpha:1.0]];
+ [description setTextAlignment:NSTextAlignmentCenter];
+ [description setNumberOfLines:0];
+ [description setLineBreakMode:NSLineBreakByWordWrapping];
+ CGRect frame = [description frame];
+ frame.size.width = IsIPadIdiom() ? kIPadWidth : kIPhoneWidth;
+ CGSize maxSize = CGSizeMake(frame.size.width, 999999.0f);
+ frame.size.height =
+ [[description text] cr_boundingSizeWithSize:maxSize
+ font:[description font]]
+ .height;
+ [description setFrame:frame];
+ [self centerView:description afterView:awSnap];
+ [innerView_ addSubview:description];
+
+ startButton_.reset([[PrimaryActionButton alloc] init]);
+ NSString* startText =
+ NSLocalizedString(@"IDS_IOS_SAFE_MODE_RELOAD_CHROME", @"");
+ [startButton_ setTitle:startText forState:UIControlStateNormal];
+ [startButton_ titleLabel].textAlignment = NSTextAlignmentCenter;
+ [startButton_ titleLabel].lineBreakMode = NSLineBreakByWordWrapping;
+ frame = [startButton_ frame];
+ frame.size.width = IsIPadIdiom() ? kIPadWidth : kIPhoneWidth;
+ maxSize = CGSizeMake(frame.size.width, 999999.0f);
+ const CGFloat kButtonBuffer = kVerticalSpacing / 2;
+ CGSize startTextBoundingSize =
+ [startText cr_boundingSizeWithSize:maxSize
+ font:[startButton_ titleLabel].font];
+ frame.size.height = startTextBoundingSize.height + kButtonBuffer;
+ [startButton_ setFrame:frame];
+ [startButton_ addTarget:self
+ action:@selector(startBrowserFromSafeMode)
+ forControlEvents:UIControlEventTouchUpInside];
+ [self centerView:startButton_ afterView:description];
+ [innerView_ addSubview:startButton_];
+
+ UIView* lastView = startButton_;
+ if ([SafeModeViewController hasReportToUpload]) {
+ breakpad_helper::StartUploadingReportsInRecoveryMode();
+
+ // If there are no jailbreak modifications, then present the "Sending crash
+ // report..." UI.
+ if (![SafeModeViewController detectedThirdPartyMods]) {
+ [startButton_ setEnabled:NO];
+
+ uploadDescription_.reset([[UILabel alloc] init]);
+ [uploadDescription_
+ setText:NSLocalizedString(@"IDS_IOS_SAFE_MODE_SENDING_CRASH_REPORT",
+ @"")];
+ [uploadDescription_ setBackgroundColor:[UIColor clearColor]];
+ [uploadDescription_ setFont:[UIFont systemFontOfSize:13]];
+ [uploadDescription_ setTextColor:[UIColor colorWithWhite:0.31 alpha:1.0]];
+ [uploadDescription_ sizeToFit];
+ [self centerView:uploadDescription_ afterView:startButton_];
+ [innerView_ addSubview:uploadDescription_];
+
+ uploadProgress_.reset([[UIProgressView alloc]
+ initWithProgressViewStyle:UIProgressViewStyleDefault]);
+ [self centerView:uploadProgress_ afterView:nil];
+ frame = [uploadProgress_ frame];
+ frame.origin.y =
+ CGRectGetMaxY([uploadDescription_ frame]) + kUploadProgressSpacing;
+ [uploadProgress_ setFrame:frame];
+ [innerView_ addSubview:uploadProgress_];
+
+ lastView = uploadProgress_;
+ [self startUploadProgress];
+ }
+ }
+
+ CGSize scrollSize =
+ CGSizeMake(mainBounds.size.width,
+ CGRectGetMaxY([lastView frame]) + kVerticalSpacing);
+ frame = [innerView_ frame];
+ frame.size.height = scrollSize.height;
+ [innerView_ setFrame:frame];
+ scrollSize.height += frame.origin.y;
+ [scrollView setContentSize:scrollSize];
+}
+
+- (NSUInteger)supportedInterfaceOrientations {
+ return UIInterfaceOrientationMaskPortrait;
+}
+
+#pragma mark - Private
+
+- (void)startUploadProgress {
+ uploadStartTime_.reset([[NSDate date] retain]);
+ uploadTimer_.reset(
+ [[NSTimer scheduledTimerWithTimeInterval:kUploadPumpInterval
+ target:self
+ selector:@selector(pumpUploadProgress)
+ userInfo:nil
+ repeats:YES] retain]);
+}
+
+- (void)pumpUploadProgress {
+ NSTimeInterval elapsed =
+ [[NSDate date] timeIntervalSinceDate:uploadStartTime_];
+ // Theoretically we could stop early when the value returned by
+ // ios_internal::breakpad::GetCrashReportCount() changes, but this is
+ // simpler. If we decide to look for a change in crash report count, then we
+ // also probably want to replace the UIProgressView with a
+ // UIActivityIndicatorView.
+ if (elapsed <= kUploadTotalTime) {
+ [uploadProgress_ setProgress:elapsed / kUploadTotalTime animated:YES];
+ } else {
+ [uploadTimer_ invalidate];
+
+ [startButton_ setEnabled:YES];
+ [uploadDescription_
+ setText:NSLocalizedString(@"IDS_IOS_SAFE_MODE_CRASH_REPORT_SENT",
+ @"")];
+ [uploadDescription_ sizeToFit];
+ [self centerView:uploadDescription_ afterView:startButton_];
+ [uploadProgress_ setHidden:YES];
+ }
+}
+
+- (void)startBrowserFromSafeMode {
+ breakpad_helper::RestoreDefaultConfiguration();
+ [delegate_ startBrowserFromSafeMode];
+}
+
+@end
« 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