linphone-ios/Classes/PhoneMainView.m
2012-06-18 15:18:00 +02:00

498 lines
No EOL
20 KiB
Objective-C

/* PhoneMainView.m
*
* Copyright (C) 2012 Belledonne Comunications, Grenoble, France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#import "PhoneMainView.h"
#import "DialerViewController.h"
#import "HistoryViewController.h"
#import "ContactsViewController.h"
#import "InCallViewController.h"
@implementation ViewsDescription
-(id) copy {
ViewsDescription *copy = [ViewsDescription alloc];
copy->content = self->content;
copy->tabBar = self->tabBar;
copy->tabBarEnabled = self->tabBarEnabled;
copy->statusEnabled = self->statusEnabled;
copy->fullscreen = self->fullscreen;
return copy;
}
@end
@implementation PhoneMainView
@synthesize stateBarView;
@synthesize contentView;
@synthesize tabBarView;
@synthesize stateBarController;
@synthesize callTabBarController;
@synthesize mainTabBarController;
@synthesize incomingCallTabBarController;
- (void)changeView: (NSNotification*) notif {
NSNumber *viewId = [notif.userInfo objectForKey: @"view"];
NSNumber *tabBar = [notif.userInfo objectForKey: @"tabBar"];
NSNumber *fullscreen = [notif.userInfo objectForKey: @"fullscreen"];
if(viewId != nil) {
PhoneView view = [viewId intValue];
currentViewDescription = [[viewDescriptions objectForKey:[NSNumber numberWithInt: view]] copy];
}
ViewsDescription *description = currentViewDescription;
if(description == nil) {
return;
}
UIView *innerView = description->content.view;
// Change view
if(viewId != nil) {
for (UIView *view in contentView.subviews) {
[view removeFromSuperview];
}
for (UIView *view in tabBarView.subviews) {
[view removeFromSuperview];
}
[contentView addSubview: innerView];
[tabBarView addSubview: description->tabBar.view];
}
if(tabBar != nil) {
description->tabBarEnabled = [tabBar boolValue];
}
if(fullscreen != nil) {
description->fullscreen = [fullscreen boolValue];
}
CGRect contentFrame = contentView.frame;
// Resize StateBar
CGRect stateBarFrame = stateBarView.frame;
if(description->fullscreen)
stateBarFrame.origin.y = -20;
else
stateBarFrame.origin.y = 0;
if(description->statusEnabled) {
stateBarView.hidden = false;
[stateBarView setFrame: stateBarFrame];
contentFrame.origin.y = stateBarFrame.size.height + stateBarFrame.origin.y;
} else {
stateBarView.hidden = true;
contentFrame.origin.y = stateBarFrame.origin.y;
}
// Resize TabBar
CGRect tabFrame = tabBarView.frame;
if(description->tabBar != nil && description->tabBarEnabled) {
tabBarView.hidden = false;
tabFrame.origin.y += tabFrame.size.height;
tabFrame.origin.x += tabFrame.size.width;
tabFrame.size.height = description->tabBar.view.frame.size.height;
tabFrame.size.width = description->tabBar.view.frame.size.width;
tabFrame.origin.y -= tabFrame.size.height;
tabFrame.origin.x -= tabFrame.size.width;
[tabBarView setFrame: tabFrame];
contentFrame.size.height = tabFrame.origin.y - contentFrame.origin.y;
for (UIView *view in description->tabBar.view.subviews) {
if(view.tag == -1) {
contentFrame.size.height += view.frame.origin.y;
break;
}
}
} else {
tabBarView.hidden = true;
contentFrame.size.height = tabFrame.origin.y + tabFrame.size.height;
if(description->fullscreen)
contentFrame.size.height += 20;
}
// Resize innerView
[contentView setFrame: contentFrame];
CGRect innerContentFrame = innerView.frame;
innerContentFrame.size = contentFrame.size;
[innerView setFrame: innerContentFrame];
// Call abstractCall
NSDictionary *dict = [notif.userInfo objectForKey: @"args"];
if(dict != nil)
[LinphoneManager abstractCall:description->content dict:dict];
}
- (void)viewDidLoad {
[super viewDidLoad];
UIView *dumb;
// Init view descriptions
viewDescriptions = [[NSMutableDictionary alloc] init];
// Load Bars
dumb = mainTabBarController.view;
// Status Bar
[stateBarView addSubview: stateBarController.view];
//
// Main View
//
DialerViewController* myDialerViewController = [[DialerViewController alloc]
initWithNibName:@"DialerViewController"
bundle:[NSBundle mainBundle]];
//[myPhoneViewController loadView];
ViewsDescription *dialerDescription = [ViewsDescription alloc];
dialerDescription->content = myDialerViewController;
dialerDescription->tabBar = mainTabBarController;
dialerDescription->statusEnabled = true;
dialerDescription->fullscreen = false;
dialerDescription->tabBarEnabled = true;
[viewDescriptions setObject:dialerDescription forKey:[NSNumber numberWithInt: PhoneView_Dialer]];
//
// Contacts View
//
ContactsViewController* myContactsController = [[ContactsViewController alloc]
initWithNibName:@"ContactsViewController"
bundle:[NSBundle mainBundle]];
//[myContactsController loadView];
ViewsDescription *contactsDescription = [ViewsDescription alloc];
contactsDescription->content = myContactsController;
contactsDescription->tabBar = mainTabBarController;
contactsDescription->statusEnabled = false;
contactsDescription->fullscreen = false;
contactsDescription->tabBarEnabled = true;
[viewDescriptions setObject:contactsDescription forKey:[NSNumber numberWithInt: PhoneView_Contacts]];
//
// Call History View
//
HistoryViewController* myHistoryController = [[HistoryViewController alloc]
initWithNibName:@"HistoryViewController"
bundle:[NSBundle mainBundle]];
//[myHistoryController loadView];
ViewsDescription *historyDescription = [ViewsDescription alloc];
historyDescription->content = myHistoryController;
historyDescription->tabBar = mainTabBarController;
historyDescription->statusEnabled = false;
historyDescription->fullscreen = false;
historyDescription->tabBarEnabled = true;
[viewDescriptions setObject:historyDescription forKey:[NSNumber numberWithInt: PhoneView_History]];
//
// InCall View
//
InCallViewController* myInCallController = [[InCallViewController alloc]
initWithNibName:@"InCallViewController"
bundle:[NSBundle mainBundle]];
//[myHistoryController loadView];
ViewsDescription *inCallDescription = [ViewsDescription alloc];
inCallDescription->content = myInCallController;
inCallDescription->tabBar = callTabBarController;
inCallDescription->statusEnabled = true;
inCallDescription->fullscreen = false;
inCallDescription->tabBarEnabled = true;
[viewDescriptions setObject:inCallDescription forKey:[NSNumber numberWithInt: PhoneView_InCall]];
// Set observers
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(changeView:)
name:@"LinphoneMainViewChange"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(callUpdate:)
name:@"LinphoneCallUpdate"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(batteryLevelChanged:)
name:UIDeviceBatteryLevelDidChangeNotification
object:nil];
}
- (void)viewDidUnload {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)callUpdate: (NSNotification*) notif {
LinphoneCallWrapper *callWrapper = [notif.userInfo objectForKey: @"call"];
LinphoneCall *call = callWrapper->call;
LinphoneCallState state = [[notif.userInfo objectForKey: @"state"] intValue];
NSString *message = [notif.userInfo objectForKey: @"message"];
bool canHideInCallView = (linphone_core_get_calls([LinphoneManager getLc]) == NULL);
switch (state) {
case LinphoneCallIncomingReceived:
{
[self displayIncomingCall:call];
break;
}
case LinphoneCallOutgoingInit:
case LinphoneCallPausedByRemote:
case LinphoneCallConnected:
case LinphoneCallUpdated:
{
if ([[LinphoneManager instance] currentView] != PhoneView_InCall) {
[[LinphoneManager instance] changeView:PhoneView_InCall];
}
break;
}
case LinphoneCallUpdatedByRemote:
{
const LinphoneCallParams* current = linphone_call_get_current_params(call);
const LinphoneCallParams* remote = linphone_call_get_remote_params(call);
/* remote wants to add video */
if (!linphone_call_params_video_enabled(current) &&
linphone_call_params_video_enabled(remote) &&
!linphone_core_get_video_policy([LinphoneManager getLc])->automatically_accept) {
linphone_core_defer_call_update([LinphoneManager getLc], call);
//TODO
//[self displayAskToEnableVideoCall:call forUser:lUserName withDisplayName:lDisplayName];
} else if (linphone_call_params_video_enabled(current) && !linphone_call_params_video_enabled(remote)) {
if ([[LinphoneManager instance] currentView] != PhoneView_InCall) {
[[LinphoneManager instance] changeView:PhoneView_InCall];
}
}
break;
}
case LinphoneCallError:
{
[self displayCallError:call message: message];
}
case LinphoneCallEnd:
{
[self dismissIncomingCall];
if (canHideInCallView) {
if ([[LinphoneManager instance] currentView] != PhoneView_Dialer) {
// Go to dialer view
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:
[[NSArray alloc] initWithObjects: @"", nil]
, @"setAddress:",
nil];
[[LinphoneManager instance] changeView:PhoneView_Dialer dict:dict];
}
} else {
if ([[LinphoneManager instance] currentView] != PhoneView_InCall) {
[[LinphoneManager instance] changeView:PhoneView_InCall];
}
}
break;
}
case LinphoneCallStreamsRunning:
{
if ([[LinphoneManager instance] currentView] != PhoneView_InCall) {
[[LinphoneManager instance] changeView:PhoneView_InCall];
}
break;
}
default:
break;
}
}
- (void)displayCallError:(LinphoneCall*) call message:(NSString*) message {
const char* lUserNameChars=linphone_address_get_username(linphone_call_get_remote_address(call));
NSString* lUserName = lUserNameChars?[[[NSString alloc] initWithUTF8String:lUserNameChars] autorelease]:NSLocalizedString(@"Unknown",nil);
NSString* lMessage;
NSString* lTitle;
//get default proxy
LinphoneProxyConfig* proxyCfg;
linphone_core_get_default_proxy([LinphoneManager getLc],&proxyCfg);
if (proxyCfg == nil) {
lMessage = NSLocalizedString(@"Please make sure your device is connected to the internet and double check your SIP account configuration in the settings.", nil);
} else {
lMessage = [NSString stringWithFormat : NSLocalizedString(@"Cannot call %@", nil), lUserName];
}
if (linphone_call_get_reason(call) == LinphoneReasonNotFound) {
lMessage = [NSString stringWithFormat : NSLocalizedString(@"'%@' not registered to Service", nil), lUserName];
} else {
if (message != nil) {
lMessage = [NSString stringWithFormat : NSLocalizedString(@"%@\nReason was: %@", nil), lMessage, message];
}
}
lTitle = NSLocalizedString(@"Call failed",nil);
UIAlertView* error = [[UIAlertView alloc] initWithTitle:lTitle
message:lMessage
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Dismiss",nil)
otherButtonTitles:nil];
[error show];
[error release];
}
- (void)dismissIncomingCall {
//cancel local notification, just in case
if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)]
&& [UIApplication sharedApplication].applicationState == UIApplicationStateBackground ) {
// cancel local notif if needed
[[UIApplication sharedApplication] cancelAllLocalNotifications];
} else {
if (incomingCallActionSheet) {
[incomingCallActionSheet dismissWithClickedButtonIndex:1 animated:true];
incomingCallActionSheet = nil;
}
}
//TODO
/*
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"firstlogindone_preference" ] == true) {
//first login case, dismmis first login view
[self dismissModalViewControllerAnimated:true];
}; */
}
- (void)displayIncomingCall:(LinphoneCall*) call{
const char* userNameChars=linphone_address_get_username(linphone_call_get_remote_address(call));
NSString* userName = userNameChars?[[[NSString alloc] initWithUTF8String:userNameChars] autorelease]:NSLocalizedString(@"Unknown",nil);
const char* displayNameChars = linphone_address_get_display_name(linphone_call_get_remote_address(call));
NSString* displayName = [displayNameChars?[[NSString alloc] initWithUTF8String:displayNameChars]:@"" autorelease];
//TODO
//[mMainScreenWithVideoPreview showPreview:NO];
if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)]
&& [UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
// Create a new notification
UILocalNotification* notif = [[[UILocalNotification alloc] init] autorelease];
if (notif)
{
notif.repeatInterval = 0;
notif.alertBody =[NSString stringWithFormat:NSLocalizedString(@" %@ is calling you",nil),[displayName length]>0?displayName:userName];
notif.alertAction = @"Answer";
notif.soundName = @"oldphone-mono-30s.caf";
NSData *callData = [NSData dataWithBytes:&call length:sizeof(call)];
notif.userInfo = [NSDictionary dictionaryWithObject:callData forKey:@"call"];
[[UIApplication sharedApplication] presentLocalNotificationNow:notif];
}
} else {
CallDelegate* cd = [[CallDelegate alloc] init];
cd.eventType = CD_NEW_CALL;
cd.delegate = self;
cd.call = call;
incomingCallActionSheet = [[UIActionSheet alloc] initWithTitle:[NSString stringWithFormat:NSLocalizedString(@" %@ is calling you",nil),[displayName length]>0?displayName:userName]
delegate:cd
cancelButtonTitle:nil
destructiveButtonTitle:NSLocalizedString(@"Answer",nil)
otherButtonTitles:NSLocalizedString(@"Decline",nil),nil];
incomingCallActionSheet.actionSheetStyle = UIActionSheetStyleDefault;
//TODO
/*if ([LinphoneManager runningOnIpad]) {
if (self.modalViewController != nil)
[incomingCallActionSheet showInView:[self.modalViewController view]];
else
[incomingCallActionSheet showInView:self.parentViewController.view];
} else */{
[incomingCallActionSheet showInView: self.view];
}
[incomingCallActionSheet release];
}
}
- (void)batteryLevelChanged: (NSNotification*) notif {
LinphoneCall* call = linphone_core_get_current_call([LinphoneManager getLc]);
if (!call || !linphone_call_params_video_enabled(linphone_call_get_current_params(call)))
return;
LinphoneCallAppData* appData = (LinphoneCallAppData*) linphone_call_get_user_pointer(call);
if ([UIDevice currentDevice].batteryState == UIDeviceBatteryStateUnplugged) {
float level = [UIDevice currentDevice].batteryLevel;
ms_message("Video call is running. Battery level: %.2f", level);
if (level < 0.1 && !appData->batteryWarningShown) {
// notify user
CallDelegate* cd = [[CallDelegate alloc] init];
cd.eventType = CD_STOP_VIDEO_ON_LOW_BATTERY;
cd.delegate = self;
cd.call = call;
if (batteryActionSheet != nil) {
[batteryActionSheet dismissWithClickedButtonIndex:batteryActionSheet.cancelButtonIndex animated:TRUE];
}
NSString* title = NSLocalizedString(@"Battery is running low. Stop video ?",nil);
batteryActionSheet = [[UIActionSheet alloc] initWithTitle:title
delegate:cd
cancelButtonTitle:NSLocalizedString(@"Continue video",nil)
destructiveButtonTitle:NSLocalizedString(@"Stop video",nil)
otherButtonTitles:nil];
batteryActionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[batteryActionSheet showInView: self.view];
[batteryActionSheet release];
appData->batteryWarningShown = TRUE;
}
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet ofType:(enum CallDelegateType)type
clickedButtonAtIndex:(NSInteger)buttonIndex
withUserDatas:(void *)datas {
switch(type) {
case CD_NEW_CALL:
{
LinphoneCall* call = (LinphoneCall*)datas;
if (buttonIndex == actionSheet.destructiveButtonIndex) {
linphone_core_accept_call([LinphoneManager getLc], call);
} else {
linphone_core_terminate_call([LinphoneManager getLc], call);
}
incomingCallActionSheet = nil;
break;
}
case CD_STOP_VIDEO_ON_LOW_BATTERY:
{
LinphoneCall* call = (LinphoneCall*)datas;
LinphoneCallParams* paramsCopy = linphone_call_params_copy(linphone_call_get_current_params(call));
if ([batteryActionSheet destructiveButtonIndex] == buttonIndex) {
// stop video
linphone_call_params_enable_video(paramsCopy, FALSE);
linphone_core_update_call([LinphoneManager getLc], call, paramsCopy);
}
break;
}
default:
break;
}
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[viewDescriptions release];
[stateBarView release];
[stateBarController release];
[mainTabBarController release];
[super dealloc];
}
@end