diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index d00076841d..00e9dd6c8f 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -47,9 +47,7 @@ } - (NSString *)activityTitle { - NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; - if (!appName) - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyFeedbackActivityAppPlaceholder"); + NSString *appName = bit_appName(); return [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackActivityButtonTitle"), appName]; } diff --git a/Classes/BITHockeyHelper.h b/Classes/BITHockeyHelper.h index 6121ea409b..a8ff3e3da0 100644 --- a/Classes/BITHockeyHelper.h +++ b/Classes/BITHockeyHelper.h @@ -34,6 +34,7 @@ NSString *bit_URLEncodedString(NSString *inputString); NSString *bit_URLDecodedString(NSString *inputString); NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB); NSString *bit_encodeAppIdentifier(NSString *inputString); +NSString *bit_appName(void); /* UIImage helpers */ UIImage *bit_roundedCornerImage(UIImage *inputImage, NSInteger cornerSize, NSInteger borderSize); @@ -43,3 +44,5 @@ UIImage *bit_reflectedImageWithHeight(UIImage *inputImage, NSUInteger height, fl UIImage *bit_newWithContentsOfResolutionIndependentFile(NSString * path); UIImage *bit_imageWithContentsOfResolutionIndependentFile(NSString * path); UIImage *bit_imageNamed(NSString *imageName, NSString *bundleName); +UIImage *bit_screenshot(void); +UIImage *bit_appIcon(void); diff --git a/Classes/BITHockeyHelper.m b/Classes/BITHockeyHelper.m index 73193d0d6a..e866ca6e1a 100644 --- a/Classes/BITHockeyHelper.m +++ b/Classes/BITHockeyHelper.m @@ -29,6 +29,8 @@ #import "BITHockeyHelper.h" #import "HockeySDK.h" +#import "HockeySDKPrivate.h" +#import #pragma mark NSString helpers @@ -80,6 +82,13 @@ NSString *bit_encodeAppIdentifier(NSString *inputString) { return (inputString ? bit_URLEncodedString(inputString) : bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"])); } +NSString *bit_appName(void) { + NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; + if (!appName) + appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyFeedbackActivityAppPlaceholder"); + + return appName; +} #pragma mark UIImage private helpers @@ -89,6 +98,7 @@ static CGContextRef bit_MyOpenBitmapContext(int pixelsWide, int pixelsHigh); static CGImageRef bit_CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha, float toAlpha); static BOOL bit_hasAlpha(UIImage *inputImage); UIImage *bit_imageWithAlpha(UIImage *inputImage); +UIImage *bit_addGlossToImage(UIImage *inputImage); // Adds a rectangular path to the given context and rounds its corners by the given extents // Original author: Björn Sållarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/ @@ -148,12 +158,7 @@ CGImageRef bit_CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlp CGContextRef bit_MyOpenBitmapContext(int pixelsWide, int pixelsHigh) { CGSize size = CGSizeMake(pixelsWide, pixelsHigh); - if (UIGraphicsBeginImageContextWithOptions != NULL) { - UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); - } - else { - UIGraphicsBeginImageContext(size); - } + UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); return UIGraphicsGetCurrentContext(); } @@ -199,6 +204,18 @@ UIImage *bit_imageWithAlpha(UIImage *inputImage) { return imageWithAlpha; } +UIImage *bit_addGlossToImage(UIImage *inputImage) { + UIGraphicsBeginImageContextWithOptions(inputImage.size, NO, 0.0); + + [inputImage drawAtPoint:CGPointZero]; + UIImage *iconGradient = bit_imageNamed(@"IconGradient.png", BITHOCKEYSDK_BUNDLE); + [iconGradient drawInRect:CGRectMake(0, 0, inputImage.size.width, inputImage.size.height) blendMode:kCGBlendModeNormal alpha:0.5]; + + UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return result; +} #pragma mark UIImage helpers @@ -387,3 +404,115 @@ UIImage *bit_roundedCornerImage(UIImage *inputImage, NSInteger cornerSize, NSInt return roundedImage; } + +UIImage *bit_appIcon() { + NSString *iconString = nil; + NSArray *icons = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFiles"]; + if (!icons) { + icons = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIcons"]; + if ((icons) && ([icons isKindOfClass:[NSDictionary class]])) { + icons = [icons valueForKeyPath:@"CFBundlePrimaryIcon.CFBundleIconFiles"]; + } + + if (!icons) { + iconString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFile"]; + if (!iconString) { + iconString = @"Icon.png"; + } + } + } + + if (icons) { + BOOL useHighResIcon = NO; + if ([UIScreen mainScreen].scale == 2.0f) useHighResIcon = YES; + + for(NSString *icon in icons) { + iconString = icon; + UIImage *iconImage = [UIImage imageNamed:icon]; + + if (iconImage.size.height == 57 && !useHighResIcon) { + // found! + break; + } + if (iconImage.size.height == 114 && useHighResIcon) { + // found! + break; + } + } + } + + BOOL addGloss = YES; + NSNumber *prerendered = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIPrerenderedIcon"]; + if (prerendered) { + addGloss = ![prerendered boolValue]; + } + + if (addGloss) { + return bit_addGlossToImage([UIImage imageNamed:iconString]); + } else { + return [UIImage imageNamed:iconString]; + } +} + +UIImage *bit_screenshot() { + // Create a graphics context with the target size + CGSize imageSize = [[UIScreen mainScreen] bounds].size; + BOOL isLandscapeLeft = [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft; + BOOL isLandscapeRight = [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight; + BOOL isUpsideDown = [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown; + + if (isLandscapeLeft ||isLandscapeRight) { + CGFloat temp = imageSize.width; + imageSize.width = imageSize.height; + imageSize.height = temp; + } + + UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0); + + CGContextRef context = UIGraphicsGetCurrentContext(); + + // Iterate over every window from back to front + //NSInteger count = 0; + for (UIWindow *window in [[UIApplication sharedApplication] windows]) { + if (![window respondsToSelector:@selector(screen)] || [window screen] == [UIScreen mainScreen]) { + // -renderInContext: renders in the coordinate space of the layer, + // so we must first apply the layer's geometry to the graphics context + CGContextSaveGState(context); + + // Center the context around the window's anchor point + CGContextTranslateCTM(context, [window center].x, [window center].y); + + // Apply the window's transform about the anchor point + CGContextConcatCTM(context, [window transform]); + + // Y-offset for the status bar (if it's showing) + NSInteger yOffset = [UIApplication sharedApplication].statusBarHidden ? 0 : -20; + + // Offset by the portion of the bounds left of and above the anchor point + CGContextTranslateCTM(context, + -[window bounds].size.width * [[window layer] anchorPoint].x, + -[window bounds].size.height * [[window layer] anchorPoint].y + yOffset); + + if (isLandscapeLeft) { + CGContextConcatCTM(context, CGAffineTransformRotate(CGAffineTransformMakeTranslation( imageSize.width, 0), M_PI / 2.0)); + } else if (isLandscapeRight) { + CGContextConcatCTM(context, CGAffineTransformRotate(CGAffineTransformMakeTranslation( 0, imageSize.height), 3 * M_PI / 2.0)); + } else if (isUpsideDown) { + CGContextConcatCTM(context, CGAffineTransformRotate(CGAffineTransformMakeTranslation( imageSize.width, imageSize.height), M_PI)); + } + + // Render the layer hierarchy to the current context + [[window layer] renderInContext:context]; + + // Restore the context + CGContextRestoreGState(context); + } + } + + // Retrieve the screenshot image + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + + UIGraphicsEndImageContext(); + + return image; +} diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index e2fbd9d397..3545cb7ab2 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -138,9 +138,7 @@ } if (shouldShowDefaultAlert) { - NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; - if (!appName) - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyAppNamePlaceholder"); + NSString *appName = bit_appName(); [self showBlockingScreen:[NSString stringWithFormat:BITHockeyLocalizedString(@"UpdateExpired"), appName] image:@"authorize_denied.png"]; if (self.delegate != nil && [self.delegate respondsToSelector:@selector(didDisplayExpiryAlertForUpdateManager:)]) {