Switch to side-by-side view

--- a
+++ b/compass-app/plugins/org.apache.cordova.splashscreen/src/ios/CDVSplashScreen.m
@@ -0,0 +1,232 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVSplashScreen.h"
+
+#define kSplashScreenDurationDefault 0.25f
+
+@implementation CDVSplashScreen
+
+- (void)pluginInitialize
+{
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad) name:CDVPageDidLoadNotification object:self.webView];
+
+    [self setVisible:YES];
+}
+
+- (void)show:(CDVInvokedUrlCommand*)command
+{
+    [self setVisible:YES];
+}
+
+- (void)hide:(CDVInvokedUrlCommand*)command
+{
+    [self setVisible:NO];
+}
+
+- (void)pageDidLoad
+{
+    id autoHideSplashScreenValue = [self.commandDelegate.settings objectForKey:[@"AutoHideSplashScreen" lowercaseString]];
+
+    // if value is missing, default to yes
+    if ((autoHideSplashScreenValue == nil) || [autoHideSplashScreenValue boolValue]) {
+        [self setVisible:NO];
+    }
+}
+
+- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
+{
+    [self updateImage];
+}
+
+- (void)createViews
+{
+    /*
+     * The Activity View is the top spinning throbber in the status/battery bar. We init it with the default Grey Style.
+     *
+     *     whiteLarge = UIActivityIndicatorViewStyleWhiteLarge
+     *     white      = UIActivityIndicatorViewStyleWhite
+     *     gray       = UIActivityIndicatorViewStyleGray
+     *
+     */
+    NSString* topActivityIndicator = [self.commandDelegate.settings objectForKey:[@"TopActivityIndicator" lowercaseString]];
+    UIActivityIndicatorViewStyle topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
+
+    if ([topActivityIndicator isEqualToString:@"whiteLarge"]) {
+        topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhiteLarge;
+    } else if ([topActivityIndicator isEqualToString:@"white"]) {
+        topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhite;
+    } else if ([topActivityIndicator isEqualToString:@"gray"]) {
+        topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
+    }
+
+    UIView* parentView = self.viewController.view;
+    parentView.userInteractionEnabled = NO;  // disable user interaction while splashscreen is shown
+    _activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:topActivityIndicatorStyle];
+    _activityView.center = CGPointMake(parentView.bounds.size.width / 2, parentView.bounds.size.height / 2);
+    _activityView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin
+        | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin;
+    [_activityView startAnimating];
+
+    // Set the frame & image later.
+    _imageView = [[UIImageView alloc] init];
+    [parentView addSubview:_imageView];
+
+    id showSplashScreenSpinnerValue = [self.commandDelegate.settings objectForKey:[@"ShowSplashScreenSpinner" lowercaseString]];
+    // backwards compatibility - if key is missing, default to true
+    if ((showSplashScreenSpinnerValue == nil) || [showSplashScreenSpinnerValue boolValue]) {
+        [parentView addSubview:_activityView];
+    }
+
+    // Frame is required when launching in portrait mode.
+    // Bounds for landscape since it captures the rotation.
+    [parentView addObserver:self forKeyPath:@"frame" options:0 context:nil];
+    [parentView addObserver:self forKeyPath:@"bounds" options:0 context:nil];
+
+    [self updateImage];
+}
+
+- (void)destroyViews
+{
+    [_imageView removeFromSuperview];
+    [_activityView removeFromSuperview];
+    _imageView = nil;
+    _activityView = nil;
+    _curImageName = nil;
+
+    self.viewController.view.userInteractionEnabled = YES;  // re-enable user interaction upon completion
+    [self.viewController.view removeObserver:self forKeyPath:@"frame"];
+    [self.viewController.view removeObserver:self forKeyPath:@"bounds"];
+}
+
+// Sets the view's frame and image.
+- (void)updateImage
+{
+    UIInterfaceOrientation orientation = self.viewController.interfaceOrientation;
+
+    // Use UILaunchImageFile if specified in plist.  Otherwise, use Default.
+    NSString* imageName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchImageFile"];
+
+    if (imageName) {
+        imageName = [imageName stringByDeletingPathExtension];
+    } else {
+        imageName = @"Default";
+    }
+
+    if (CDV_IsIPhone5()) {
+        imageName = [imageName stringByAppendingString:@"-568h"];
+    } else if (CDV_IsIPad()) {
+        switch (orientation) {
+            case UIInterfaceOrientationLandscapeLeft:
+            case UIInterfaceOrientationLandscapeRight:
+                imageName = [imageName stringByAppendingString:@"-Landscape"];
+                break;
+
+            case UIInterfaceOrientationPortrait:
+            case UIInterfaceOrientationPortraitUpsideDown:
+            default:
+                imageName = [imageName stringByAppendingString:@"-Portrait"];
+                break;
+        }
+    }
+
+    if (![imageName isEqualToString:_curImageName]) {
+        UIImage* img = [UIImage imageNamed:imageName];
+        _imageView.image = img;
+        _curImageName = imageName;
+    }
+
+    // Check that splash screen's image exists before updating bounds
+    if (_imageView.image) {
+        [self updateBounds];
+    } else {
+        NSLog(@"WARNING: The splashscreen image named %@ was not found", imageName);
+    }
+}
+
+- (void)updateBounds
+{
+    UIImage* img = _imageView.image;
+    CGRect imgBounds = (img) ? CGRectMake(0, 0, img.size.width, img.size.height) : CGRectZero;
+
+    CGSize screenSize = [self.viewController.view convertRect:[UIScreen mainScreen].bounds fromView:nil].size;
+
+    // There's a special case when the image is the size of the screen.
+    if (CGSizeEqualToSize(screenSize, imgBounds.size)) {
+        CGRect statusFrame = [self.viewController.view convertRect:[UIApplication sharedApplication].statusBarFrame fromView:nil];
+        if (!(IsAtLeastiOSVersion(@"7.0"))) {
+            imgBounds.origin.y -= statusFrame.size.height;
+        }
+    } else if (imgBounds.size.width > 0) {
+        CGRect viewBounds = self.viewController.view.bounds;
+        CGFloat imgAspect = imgBounds.size.width / imgBounds.size.height;
+        CGFloat viewAspect = viewBounds.size.width / viewBounds.size.height;
+        // This matches the behaviour of the native splash screen.
+        CGFloat ratio;
+        if (viewAspect > imgAspect) {
+            ratio = viewBounds.size.width / imgBounds.size.width;
+        } else {
+            ratio = viewBounds.size.height / imgBounds.size.height;
+        }
+        imgBounds.size.height *= ratio;
+        imgBounds.size.width *= ratio;
+    }
+
+    _imageView.frame = imgBounds;
+}
+
+- (void)setVisible:(BOOL)visible
+{
+    if (visible == _visible) {
+        return;
+    }
+    _visible = visible;
+
+    id fadeSplashScreenValue = [self.commandDelegate.settings objectForKey:[@"FadeSplashScreen" lowercaseString]];
+    id fadeSplashScreenDuration = [self.commandDelegate.settings objectForKey:[@"FadeSplashScreenDuration" lowercaseString]];
+
+    float fadeDuration = fadeSplashScreenDuration == nil ? kSplashScreenDurationDefault : [fadeSplashScreenDuration floatValue];
+
+    if ((fadeSplashScreenValue == nil) || ![fadeSplashScreenValue boolValue]) {
+        fadeDuration = 0;
+    }
+
+    // Never animate the showing of the splash screen.
+    if (visible) {
+        if (_imageView == nil) {
+            [self createViews];
+        }
+    } else if (fadeDuration == 0) {
+        [self destroyViews];
+    } else {
+        [UIView transitionWithView:self.viewController.view
+                          duration:fadeDuration
+                           options:UIViewAnimationOptionTransitionNone
+                        animations:^(void) {
+            [_imageView setAlpha:0];
+            [_activityView setAlpha:0];
+        }
+
+                        completion:^(BOOL finished) {
+            [self destroyViews];
+        }];
+    }
+}
+
+@end