1/* 2 * Copyright (C) 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "config.h" 27#import "WKAirPlayRoutePicker.h" 28 29#if PLATFORM(IOS) 30 31#import "WKContentView.h" 32#import "WKContentViewInteraction.h" 33#import "WebPageProxy.h" 34#import <MediaPlayer/MPAVItem.h> 35#import <MediaPlayer/MPAVRoutingController.h> 36#import <MediaPlayer/MPAudioVideoRoutingPopoverController.h> 37#import <MediaPlayer/MPAudioVideoRoutingActionSheet.h> 38#import <WebCore/SoftLinking.h> 39#import <UIKit/UIApplication_Private.h> 40#import <UIKit/UIWindow_Private.h> 41#import <wtf/RetainPtr.h> 42 43SOFT_LINK_FRAMEWORK(MediaPlayer) 44SOFT_LINK_CLASS(MediaPlayer, MPAVRoutingController) 45SOFT_LINK_CLASS(MediaPlayer, MPAudioVideoRoutingPopoverController) 46SOFT_LINK_CLASS(MediaPlayer, MPAudioVideoRoutingActionSheet) 47 48using namespace WebKit; 49 50@implementation WKAirPlayRoutePicker { 51 RetainPtr<MPAVRoutingController> _routingController; 52 RetainPtr<MPAudioVideoRoutingPopoverController> _popoverController; // iPad 53 RetainPtr<MPAudioVideoRoutingActionSheet> _actionSheet; // iPhone 54 __weak WKContentView* _view; // Weak reference. 55} 56 57- (instancetype)initWithView:(WKContentView *)view 58{ 59 if (!(self = [super init])) 60 return nil; 61 62 _view = view; 63 return self; 64} 65 66- (void)dealloc 67{ 68 // The ActionSheet's completion handler will release and clear the ActionSheet. 69 [_actionSheet dismissWithClickedButtonIndex:[_actionSheet cancelButtonIndex] animated:YES]; 70 [self _dismissAirPlayRoutePickerIPad]; 71 72 [super dealloc]; 73} 74 75- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController 76{ 77 if (popoverController != _popoverController) 78 return; 79 80 [self _dismissAirPlayRoutePickerIPad]; 81} 82 83- (void)_presentAirPlayPopoverAnimated:(BOOL)animated fromRect:(CGRect)elementRect 84{ 85 [_popoverController presentPopoverFromRect:elementRect inView:_view permittedArrowDirections:UIPopoverArrowDirectionAny animated:animated]; 86} 87 88- (void)_windowWillRotate:(NSNotification *)notification 89{ 90 [_popoverController dismissPopoverAnimated:NO]; 91} 92 93- (void)_windowDidRotate:(NSNotification *)notification 94{ 95 [self _dismissAirPlayRoutePickerIPad]; 96} 97 98- (void)_dismissAirPlayRoutePickerIPad 99{ 100 _routingController = nil; 101 102 if (!_popoverController) 103 return; 104 105 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; 106 [center removeObserver:self name:UIWindowWillRotateNotification object:nil]; 107 [center removeObserver:self name:UIWindowDidRotateNotification object:nil]; 108 109 [_popoverController dismissPopoverAnimated:NO]; 110 [_popoverController setDelegate:nil]; 111 _popoverController = nil; 112} 113 114- (void)showAirPlayPickerIPad:(MPAVItemType)itemType fromRect:(CGRect)elementRect 115{ 116 if (_popoverController) 117 return; 118 119 _popoverController = adoptNS([[getMPAudioVideoRoutingPopoverControllerClass() alloc] initWithType:itemType]); 120 [_popoverController setDelegate:self]; 121 122 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; 123 [center addObserver:self selector:@selector(_windowWillRotate:) name:UIWindowWillRotateNotification object:nil]; 124 [center addObserver:self selector:@selector(_windowDidRotate:) name:UIWindowDidRotateNotification object:nil]; 125 126 [self _presentAirPlayPopoverAnimated:YES fromRect:elementRect]; 127} 128 129- (void)showAirPlayPickerIPhone:(MPAVItemType)itemType 130{ 131 if (_actionSheet) 132 return; 133 134 _actionSheet = adoptNS([[getMPAudioVideoRoutingActionSheetClass() alloc] initWithType:itemType]); 135 136 [_actionSheet 137 showWithValidInterfaceOrientationMaskBlock:^UIInterfaceOrientationMask { 138 return UIInterfaceOrientationMaskPortrait; 139 } 140 completionHandler:^{ 141 _routingController = nil; 142 _actionSheet = nil; 143 } 144 ]; 145} 146 147- (void)show:(BOOL)hasVideo fromRect:(CGRect)elementRect 148{ 149 _routingController = adoptNS([[getMPAVRoutingControllerClass() alloc] initWithName:@"WebKit2 - HTML media element showing AirPlay route picker"]); 150 [_routingController setDiscoveryMode:MPRouteDiscoveryModeDetailed]; 151 152 MPAVItemType itemType = hasVideo ? MPAVItemTypeVideo : MPAVItemTypeAudio; 153 if (UICurrentUserInterfaceIdiomIsPad()) 154 [self showAirPlayPickerIPad:itemType fromRect:elementRect]; 155 else 156 [self showAirPlayPickerIPhone:itemType]; 157} 158 159@end 160 161#endif // PLATFORM(IOS) 162