DVDCodecs: Amlogic: Handle conditions in which amcodec should be opened during Open()
[vuplus_xbmc] / xbmc / osx / ios / XBMCController.mm
1 /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 //hack around problem with xbmc's typedef int BOOL
22 // and obj-c's typedef unsigned char BOOL
23 #define BOOL XBMC_BOOL 
24 #include <sys/resource.h>
25 #include <signal.h>
26
27 #include "system.h"
28 #include "settings/AdvancedSettings.h"
29 #include "settings/Settings.h"
30 #include "FileItem.h"
31 #include "MusicInfoTag.h"
32 #include "SpecialProtocol.h"
33 #include "PlayList.h"
34 #include "ApplicationMessenger.h"
35 #include "Application.h"
36 #include "interfaces/AnnouncementManager.h"
37 #include "input/touch/generic/GenericTouchActionHandler.h"
38 #include "guilib/GUIControl.h"
39 #include "guilib/Key.h"
40 #include "windowing/WindowingFactory.h"
41 #include "video/VideoReferenceClock.h"
42 #include "utils/log.h"
43 #include "utils/TimeUtils.h"
44 #include "utils/Variant.h"
45 #include "Util.h"
46 #include "threads/Event.h"
47 #define id _id
48 #include "TextureCache.h"
49 #undef id
50 #include <math.h>
51
52 #ifndef M_PI
53 #define M_PI 3.1415926535897932384626433832795028842
54 #endif
55 #define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI))
56
57 #undef BOOL
58
59 #import <AVFoundation/AVAudioSession.h>
60 #import <MediaPlayer/MPMediaItem.h>
61 #ifdef __IPHONE_5_0
62 #import <MediaPlayer/MPNowPlayingInfoCenter.h>
63 #else
64 const NSString *MPNowPlayingInfoPropertyElapsedPlaybackTime = @"MPNowPlayingInfoPropertyElapsedPlaybackTime";
65 const NSString *MPNowPlayingInfoPropertyPlaybackRate = @"MPNowPlayingInfoPropertyPlaybackRate";
66 const NSString *MPNowPlayingInfoPropertyPlaybackQueueIndex = @"MPNowPlayingInfoPropertyPlaybackQueueIndex";
67 const NSString *MPNowPlayingInfoPropertyPlaybackQueueCount = @"MPNowPlayingInfoPropertyPlaybackQueueCount";
68 #endif
69 #import "IOSEAGLView.h"
70
71 #import "XBMCController.h"
72 #import "IOSScreenManager.h"
73 #import "XBMCApplication.h"
74 #import "XBMCDebugHelpers.h"
75 #import "AutoPool.h"
76
77 XBMCController *g_xbmcController;
78 static CEvent screenChangeEvent;
79
80
81 // notification messages
82 extern NSString* kBRScreenSaverActivated;
83 extern NSString* kBRScreenSaverDismissed;
84
85 id objectFromVariant(const CVariant &data);
86
87 NSArray *arrayFromVariantArray(const CVariant &data)
88 {
89   if (!data.isArray())
90     return nil;
91   NSMutableArray *array = [[[NSMutableArray alloc] initWithCapacity:data.size()] autorelease];
92   for (CVariant::const_iterator_array itr = data.begin_array(); itr != data.end_array(); ++itr)
93   {
94     [array addObject:objectFromVariant(*itr)];
95   }
96   return array;
97 }
98
99 NSDictionary *dictionaryFromVariantMap(const CVariant &data)
100 {
101   if (!data.isObject())
102     return nil;
103   NSMutableDictionary *dict = [[[NSMutableDictionary alloc] initWithCapacity:data.size()] autorelease];
104   for (CVariant::const_iterator_map itr = data.begin_map(); itr != data.end_map(); ++itr)
105   {
106     [dict setValue:objectFromVariant(itr->second) forKey:[NSString stringWithUTF8String:itr->first.c_str()]];
107   }
108   return dict;
109 }
110
111 id objectFromVariant(const CVariant &data)
112 {
113   if (data.isNull())
114     return nil;
115   if (data.isString())
116     return [NSString stringWithUTF8String:data.asString().c_str()];
117   if (data.isWideString())
118     return [NSString stringWithCString:(const char *)data.asWideString().c_str() encoding:NSUnicodeStringEncoding];
119   if (data.isInteger())
120     return [NSNumber numberWithLongLong:data.asInteger()];
121   if (data.isUnsignedInteger())
122     return [NSNumber numberWithUnsignedLongLong:data.asUnsignedInteger()];
123   if (data.isBoolean())
124     return [NSNumber numberWithInt:data.asBoolean()?1:0];
125   if (data.isDouble())
126     return [NSNumber numberWithDouble:data.asDouble()];
127   if (data.isArray())
128     return arrayFromVariantArray(data);
129   if (data.isObject())
130     return dictionaryFromVariantMap(data);
131   return nil;
132 }
133
134 void AnnounceBridge(ANNOUNCEMENT::AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
135 {
136   LOG(@"AnnounceBridge: [%s], [%s], [%s]", ANNOUNCEMENT::AnnouncementFlagToString(flag), sender, message);
137   NSDictionary *dict = dictionaryFromVariantMap(data);
138   LOG(@"data: %@", dict.description);
139   const std::string msg(message);
140   if (msg == "OnPlay")
141   {
142     NSDictionary *item = [dict valueForKey:@"item"];
143     NSDictionary *player = [dict valueForKey:@"player"];
144     [item setValue:[player valueForKey:@"speed"] forKey:@"speed"];
145     std::string thumb = g_application.CurrentFileItem().GetArt("thumb");
146     if (!thumb.empty())
147     {
148       bool needsRecaching;
149       CStdString cachedThumb(CTextureCache::Get().CheckCachedImage(thumb, false, needsRecaching));
150       LOG("thumb: %s, %s", thumb.c_str(), cachedThumb.c_str());
151       if (!cachedThumb.empty())
152       {
153         CStdString thumbRealPath = CSpecialProtocol::TranslatePath(cachedThumb);
154         [item setValue:[NSString stringWithUTF8String:thumbRealPath.c_str()] forKey:@"thumb"];
155       }
156     }
157     double duration = g_application.GetTotalTime();
158     if (duration > 0)
159       [item setValue:[NSNumber numberWithDouble:duration] forKey:@"duration"];
160     [item setValue:[NSNumber numberWithDouble:g_application.GetTime()] forKey:@"elapsed"];
161     int current = g_playlistPlayer.GetCurrentSong();
162     if (current >= 0)
163     {
164       [item setValue:[NSNumber numberWithInt:current] forKey:@"current"];
165       [item setValue:[NSNumber numberWithInt:g_playlistPlayer.GetPlaylist(g_playlistPlayer.GetCurrentPlaylist()).size()] forKey:@"total"];
166     }
167     if (g_application.CurrentFileItem().HasMusicInfoTag())
168     {
169       const std::vector<std::string> &genre = g_application.CurrentFileItem().GetMusicInfoTag()->GetGenre();
170       if (!genre.empty())
171       {
172         NSMutableArray *genreArray = [[NSMutableArray alloc] initWithCapacity:genre.size()];
173         for(std::vector<std::string>::const_iterator it = genre.begin(); it != genre.end(); ++it)
174         {
175           [genreArray addObject:[NSString stringWithUTF8String:it->c_str()]];
176         }
177         [item setValue:genreArray forKey:@"genre"];
178       }
179     }
180     LOG(@"item: %@", item.description);
181     [g_xbmcController performSelectorOnMainThread:@selector(onPlay:) withObject:item  waitUntilDone:NO];
182   }
183   else if (msg == "OnSpeedChanged")
184   {
185     NSDictionary *item = [dict valueForKey:@"item"];
186     NSDictionary *player = [dict valueForKey:@"player"];
187     [item setValue:[player valueForKey:@"speed"] forKey:@"speed"];
188     [item setValue:[NSNumber numberWithDouble:g_application.GetTime()] forKey:@"elapsed"];
189     LOG(@"item: %@", item.description);
190     [g_xbmcController performSelectorOnMainThread:@selector(OnSpeedChanged:) withObject:item  waitUntilDone:NO];
191   }
192   else if (msg == "OnPause")
193   {
194     [g_xbmcController performSelectorOnMainThread:@selector(onPause:) withObject:[dict valueForKey:@"item"]  waitUntilDone:NO];
195   }
196   else if (msg == "OnStop")
197   {
198     [g_xbmcController performSelectorOnMainThread:@selector(onStop:) withObject:[dict valueForKey:@"item"]  waitUntilDone:NO];
199   }
200 }
201
202 class AnnounceReceiver : public ANNOUNCEMENT::IAnnouncer
203 {
204 public:
205   virtual void Announce(ANNOUNCEMENT::AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
206   {
207     // not all Announce called from xbmc main thread, we need an auto poll here.
208     CCocoaAutoPool pool;
209     AnnounceBridge(flag, sender, message, data);
210   }
211   virtual ~AnnounceReceiver() {}
212   static void init()
213   {
214     if (NULL==g_announceReceiver) {
215       g_announceReceiver = new AnnounceReceiver();
216       ANNOUNCEMENT::CAnnouncementManager::AddAnnouncer(g_announceReceiver);
217     }
218   }
219   static void dealloc()
220   {
221     ANNOUNCEMENT::CAnnouncementManager::RemoveAnnouncer(g_announceReceiver);
222     delete g_announceReceiver;
223   }
224 private:
225   AnnounceReceiver() {}
226   static AnnounceReceiver *g_announceReceiver;
227 };
228
229 AnnounceReceiver *AnnounceReceiver::g_announceReceiver = NULL;
230
231 //--------------------------------------------------------------
232 //
233
234 @interface XBMCController ()
235 - (void)rescheduleNetworkAutoSuspend;
236 @end
237
238 @interface UIApplication (extended)
239 -(void) terminateWithSuccess;
240 @end
241
242 @implementation XBMCController
243 @synthesize animating;
244 @synthesize lastGesturePoint;
245 @synthesize screenScale;
246 @synthesize touchBeginSignaled;
247 @synthesize m_screenIdx;
248 @synthesize screensize;
249 @synthesize m_networkAutoSuspendTimer;
250 @synthesize nowPlayingInfo;
251 //--------------------------------------------------------------
252 - (void) sendKeypressEvent: (XBMC_Event) event
253 {
254   event.type = XBMC_KEYDOWN;
255   CWinEvents::MessagePush(&event);
256
257   event.type = XBMC_KEYUP;
258   CWinEvents::MessagePush(&event);
259 }
260
261 // START OF UIKeyInput protocol
262 - (BOOL)hasText
263 {
264   return NO;
265 }
266
267 - (void)insertText:(NSString *)text
268 {
269   XBMC_Event newEvent;
270   memset(&newEvent, 0, sizeof(newEvent));
271   unichar currentKey = [text characterAtIndex:0];
272
273   // handle upper case letters
274   if (currentKey >= 'A' && currentKey <= 'Z')
275   {
276     newEvent.key.keysym.mod = XBMCKMOD_LSHIFT;
277     currentKey += 0x20;// convert to lower case
278   }
279
280   // handle return
281   if (currentKey == '\n' || currentKey == '\r')
282     currentKey = XBMCK_RETURN;
283
284   newEvent.key.keysym.sym = (XBMCKey)currentKey;
285   newEvent.key.keysym.unicode = currentKey;
286
287   [self sendKeypressEvent:newEvent];
288 }
289
290 - (void)deleteBackward
291 {
292   [self sendKey:XBMCK_BACKSPACE];
293 }
294 // END OF UIKeyInput protocol
295
296 // - iOS6 rotation API - will be called on iOS7 runtime!--------
297 - (NSUInteger)supportedInterfaceOrientations
298 {
299   //mask defines available as of ios6 sdk
300   //return UIInterfaceOrientationMaskLandscape;
301   return (1 << UIInterfaceOrientationLandscapeLeft) | (1 << UIInterfaceOrientationLandscapeRight);
302 }
303 // - old rotation API will be called on iOS6 and lower - removed in iOS7
304 -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
305 {  
306   //on external screens somehow the logic is rotated by 90°
307   //so we have to do this with our supported orientations then aswell
308   if([[IOSScreenManager sharedInstance] isExternalScreen])
309   {
310     if(interfaceOrientation == UIInterfaceOrientationPortrait) 
311     {
312       return YES;
313     }
314   }
315   else//internal screen
316   {
317     if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft) 
318     {
319       return YES;
320     }
321     else if(interfaceOrientation == UIInterfaceOrientationLandscapeRight)
322     {
323       return YES;
324     }
325   }
326   return NO;
327 }
328 //--------------------------------------------------------------
329 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
330 {
331   orientation = toInterfaceOrientation;
332   CGRect srect = [IOSScreenManager getLandscapeResolution: [m_glView getCurrentScreen]];
333   CGRect rect = srect;;
334   
335
336   switch(toInterfaceOrientation)
337   {
338     case UIInterfaceOrientationPortrait:  
339     case UIInterfaceOrientationPortraitUpsideDown:
340       if(![[IOSScreenManager sharedInstance] isExternalScreen]) 
341       {
342         rect.size = CGSizeMake( srect.size.height, srect.size.width );    
343       }
344       break;
345     case UIInterfaceOrientationLandscapeLeft:
346     case UIInterfaceOrientationLandscapeRight:
347       break;//just leave the rect as is
348   }  
349         m_glView.frame = rect;
350 }
351
352 - (UIInterfaceOrientation) getOrientation
353 {
354         return orientation;
355 }
356
357 -(void)sendKey:(XBMCKey) key
358 {
359   XBMC_Event newEvent;
360   memset(&newEvent, 0, sizeof(newEvent));
361   
362   //newEvent.key.keysym.unicode = key;
363   newEvent.key.keysym.sym = key;
364   [self sendKeypressEvent:newEvent];
365   
366 }
367 //--------------------------------------------------------------
368 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
369 {
370   if ([gestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
371     return YES;
372   }
373
374   if ([gestureRecognizer isKindOfClass:[UISwipeGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
375     return YES;
376   }
377
378   
379   return NO;
380 }
381 //--------------------------------------------------------------
382 - (void)createGestureRecognizers 
383 {
384   //1 finger single tab
385   UITapGestureRecognizer *singleFingerSingleTap = [[UITapGestureRecognizer alloc]
386                                                    initWithTarget:self action:@selector(handleSingleFingerSingleTap:)];
387
388   singleFingerSingleTap.delaysTouchesBegan = NO;
389   singleFingerSingleTap.numberOfTapsRequired = 1;
390   singleFingerSingleTap.numberOfTouchesRequired = 1;
391
392   [m_glView addGestureRecognizer:singleFingerSingleTap];
393   [singleFingerSingleTap release];
394
395   //2 finger single tab - right mouse
396   //single finger double tab delays single finger single tab - so we
397   //go for 2 fingers here - so single finger single tap is instant
398   UITapGestureRecognizer *doubleFingerSingleTap = [[UITapGestureRecognizer alloc]
399     initWithTarget:self action:@selector(handleDoubleFingerSingleTap:)];  
400
401   doubleFingerSingleTap.delaysTouchesBegan = NO;
402   doubleFingerSingleTap.numberOfTapsRequired = 1;
403   doubleFingerSingleTap.numberOfTouchesRequired = 2;
404   [m_glView addGestureRecognizer:doubleFingerSingleTap];
405   [doubleFingerSingleTap release];
406
407   //1 finger single long tab - right mouse - alernative
408   UILongPressGestureRecognizer *singleFingerSingleLongTap = [[UILongPressGestureRecognizer alloc]
409     initWithTarget:self action:@selector(handleSingleFingerSingleLongTap:)];  
410
411   singleFingerSingleLongTap.delaysTouchesBegan = NO;
412   singleFingerSingleLongTap.delaysTouchesEnded = NO;
413   [m_glView addGestureRecognizer:singleFingerSingleLongTap];
414   [singleFingerSingleLongTap release];
415
416   //double finger swipe left for backspace ... i like this fast backspace feature ;)
417   UISwipeGestureRecognizer *swipeLeft2 = [[UISwipeGestureRecognizer alloc]
418                                             initWithTarget:self action:@selector(handleSwipe:)];
419
420   swipeLeft2.delaysTouchesBegan = NO;
421   swipeLeft2.numberOfTouchesRequired = 2;
422   swipeLeft2.direction = UISwipeGestureRecognizerDirectionLeft;
423   swipeLeft2.delegate = self;
424   [m_glView addGestureRecognizer:swipeLeft2];
425   [swipeLeft2 release];
426
427   //single finger swipe left
428   UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc]
429                                           initWithTarget:self action:@selector(handleSwipe:)];
430
431   swipeLeft.delaysTouchesBegan = NO;
432   swipeLeft.numberOfTouchesRequired = 1;
433   swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
434   swipeLeft.delegate = self;
435   [m_glView addGestureRecognizer:swipeLeft];
436   [swipeLeft release];
437   
438   //single finger swipe right
439   UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc]
440                                          initWithTarget:self action:@selector(handleSwipe:)];
441   
442   swipeRight.delaysTouchesBegan = NO;
443   swipeRight.numberOfTouchesRequired = 1;
444   swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
445   swipeRight.delegate = self;
446   [m_glView addGestureRecognizer:swipeRight];
447   [swipeRight release];
448   
449   //single finger swipe up
450   UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc]
451                                          initWithTarget:self action:@selector(handleSwipe:)];
452   
453   swipeUp.delaysTouchesBegan = NO;
454   swipeUp.numberOfTouchesRequired = 1;
455   swipeUp.direction = UISwipeGestureRecognizerDirectionUp;
456   swipeUp.delegate = self;
457   [m_glView addGestureRecognizer:swipeUp];
458   [swipeUp release];
459
460   //single finger swipe down
461   UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc]
462                                          initWithTarget:self action:@selector(handleSwipe:)];
463   
464   swipeDown.delaysTouchesBegan = NO;
465   swipeDown.numberOfTouchesRequired = 1;
466   swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
467   swipeDown.delegate = self;
468   [m_glView addGestureRecognizer:swipeDown];
469   [swipeDown release];
470   
471   //for pan gestures with one finger
472   UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]
473     initWithTarget:self action:@selector(handlePan:)];
474
475   pan.delaysTouchesBegan = NO;
476   pan.maximumNumberOfTouches = 1;
477   [m_glView addGestureRecognizer:pan];
478   [pan release];
479
480   //for zoom gesture
481   UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]
482     initWithTarget:self action:@selector(handlePinch:)];
483
484   pinch.delaysTouchesBegan = NO;
485   pinch.delegate = self;
486   [m_glView addGestureRecognizer:pinch];
487   [pinch release];
488
489   //for rotate gesture
490   UIRotationGestureRecognizer *rotate = [[UIRotationGestureRecognizer alloc]
491                                          initWithTarget:self action:@selector(handleRotate:)];
492
493   rotate.delaysTouchesBegan = NO;
494   rotate.delegate = self;
495   [m_glView addGestureRecognizer:rotate];
496   [rotate release];
497 }
498 //--------------------------------------------------------------
499 - (void) activateKeyboard:(UIView *)view
500 {
501   [self.view addSubview:view];
502   m_glView.userInteractionEnabled = NO;
503 }
504 //--------------------------------------------------------------
505 - (void) deactivateKeyboard:(UIView *)view
506 {
507   [view removeFromSuperview];
508   m_glView.userInteractionEnabled = YES; 
509   [self becomeFirstResponder];
510 }
511 //--------------------------------------------------------------
512 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
513 {
514   if( [m_glView isXBMCAlive] )//NO GESTURES BEFORE WE ARE UP AND RUNNING
515   {
516     UITouch *touch = (UITouch *)[[touches allObjects] objectAtIndex:0];
517     CGPoint point = [touch locationInView:m_glView];
518     point.x *= screenScale;
519     point.y *= screenScale;
520     CGenericTouchActionHandler::Get().OnSingleTouchStart(point.x, point.y);
521   }
522 }
523 //--------------------------------------------------------------
524 -(void)handlePinch:(UIPinchGestureRecognizer*)sender
525 {
526   if( [m_glView isXBMCAlive] )//NO GESTURES BEFORE WE ARE UP AND RUNNING
527   {
528     CGPoint point = [sender locationOfTouch:0 inView:m_glView];  
529     point.x *= screenScale;
530     point.y *= screenScale;
531
532     switch(sender.state)
533     {
534       case UIGestureRecognizerStateBegan:
535         CGenericTouchActionHandler::Get().OnTouchGestureStart(point.x, point.y);
536         break;
537       case UIGestureRecognizerStateChanged:
538         CGenericTouchActionHandler::Get().OnZoomPinch(point.x, point.y, [sender scale]);
539         break;
540       case UIGestureRecognizerStateEnded:
541       case UIGestureRecognizerStateCancelled:
542         CGenericTouchActionHandler::Get().OnTouchGestureEnd(point.x, point.y, 0, 0, 0, 0);
543         break;
544       default:
545         break;
546     }
547   }
548 }
549 //--------------------------------------------------------------
550 -(void)handleRotate:(UIRotationGestureRecognizer*)sender
551 {
552   if( [m_glView isXBMCAlive] )//NO GESTURES BEFORE WE ARE UP AND RUNNING
553   {
554     CGPoint point = [sender locationOfTouch:0 inView:m_glView];
555     point.x *= screenScale;
556     point.y *= screenScale;
557
558     switch(sender.state)
559     {
560       case UIGestureRecognizerStateBegan:
561         CGenericTouchActionHandler::Get().OnTouchGestureStart(point.x, point.y);
562         break;
563       case UIGestureRecognizerStateChanged:
564         CGenericTouchActionHandler::Get().OnRotate(point.x, point.y, RADIANS_TO_DEGREES([sender rotation]));
565         break;
566       case UIGestureRecognizerStateEnded:
567         CGenericTouchActionHandler::Get().OnTouchGestureEnd(point.x, point.y, 0, 0, 0, 0);
568         break;
569       default:
570         break;
571     }
572   }
573 }
574 //--------------------------------------------------------------
575 - (IBAction)handlePan:(UIPanGestureRecognizer *)sender 
576 {
577   if( [m_glView isXBMCAlive] )//NO GESTURES BEFORE WE ARE UP AND RUNNING
578   { 
579     CGPoint velocity = [sender velocityInView:m_glView];
580
581     if( [sender state] == UIGestureRecognizerStateBegan )
582     {
583       CGPoint point = [sender locationOfTouch:0 inView:m_glView];
584       point.x *= screenScale;
585       point.y *= screenScale;
586       touchBeginSignaled = false;
587       lastGesturePoint = point;
588     }
589
590     if( [sender state] == UIGestureRecognizerStateChanged )
591     {
592       CGPoint point = [sender locationOfTouch:0 inView:m_glView];
593       point.x *= screenScale;
594       point.y *= screenScale;
595       bool bNotify = false;
596       CGFloat yMovement=point.y - lastGesturePoint.y;
597       CGFloat xMovement=point.x - lastGesturePoint.x;
598       
599       if( xMovement )
600       {
601         bNotify = true;
602       }
603       
604       if( yMovement )
605       {
606         bNotify = true;
607       }
608       
609       if( bNotify )
610       {
611         if( !touchBeginSignaled )
612         {
613           CGenericTouchActionHandler::Get().OnTouchGestureStart((float)point.x, (float)point.y);
614           touchBeginSignaled = true;
615         }
616
617         CGenericTouchActionHandler::Get().OnTouchGesturePan((float)point.x, (float)point.y,
618                                                             (float)xMovement, (float)yMovement, 
619                                                             (float)velocity.x, (float)velocity.y);
620         lastGesturePoint = point;
621       }
622     }
623     
624     if( touchBeginSignaled && ([sender state] == UIGestureRecognizerStateEnded || [sender state] == UIGestureRecognizerStateCancelled))
625     {
626       //signal end of pan - this will start inertial scrolling with deacceleration in CApplication
627       CGenericTouchActionHandler::Get().OnTouchGestureEnd((float)lastGesturePoint.x, (float)lastGesturePoint.y,
628                                                              (float)0.0, (float)0.0, 
629                                                              (float)velocity.x, (float)velocity.y);
630
631       touchBeginSignaled = false;
632     }
633   }
634 }
635 //--------------------------------------------------------------
636 - (IBAction)handleSwipe:(UISwipeGestureRecognizer *)sender
637 {
638   if( [m_glView isXBMCAlive] )//NO GESTURES BEFORE WE ARE UP AND RUNNING
639   {
640     
641     
642     if (sender.state == UIGestureRecognizerStateRecognized)
643     {
644       CGPoint point = [sender locationOfTouch:0 inView:m_glView];
645       point.x *= screenScale;
646       point.y *= screenScale;
647
648       TouchMoveDirection direction = TouchMoveDirectionNone;
649       switch ([sender direction])
650       {
651         case UISwipeGestureRecognizerDirectionRight:
652           direction = TouchMoveDirectionRight;
653           break;
654         case UISwipeGestureRecognizerDirectionLeft:
655           direction = TouchMoveDirectionLeft;
656           break;
657         case UISwipeGestureRecognizerDirectionUp:
658           direction = TouchMoveDirectionUp;
659           break;
660         case UISwipeGestureRecognizerDirectionDown:
661           direction = TouchMoveDirectionDown;
662           break;
663       }
664       CGenericTouchActionHandler::Get().OnSwipe(direction,
665                                                 0.0, 0.0,
666                                                 point.x, point.y, 0, 0,
667                                                 [sender numberOfTouches]);
668     }
669   }
670 }
671 //--------------------------------------------------------------
672 - (IBAction)handleSingleFingerSingleTap:(UIGestureRecognizer *)sender 
673 {
674   if( [m_glView isXBMCAlive] )//NO GESTURES BEFORE WE ARE UP AND RUNNING
675   {
676     CGPoint point = [sender locationOfTouch:0 inView:m_glView];
677     point.x *= screenScale;
678     point.y *= screenScale;
679     //NSLog(@"%s singleTap", __PRETTY_FUNCTION__);
680     CGenericTouchActionHandler::Get().OnTap((float)point.x, (float)point.y, [sender numberOfTouches]);
681   }
682 }
683 //--------------------------------------------------------------
684 - (IBAction)handleDoubleFingerSingleTap:(UIGestureRecognizer *)sender
685 {
686   if( [m_glView isXBMCAlive] )//NO GESTURES BEFORE WE ARE UP AND RUNNING
687   {
688     CGPoint point = [sender locationOfTouch:0 inView:m_glView];
689     point.x *= screenScale;
690     point.y *= screenScale;
691     //NSLog(@"%s toubleTap", __PRETTY_FUNCTION__);
692     CGenericTouchActionHandler::Get().OnTap((float)point.x, (float)point.y, [sender numberOfTouches]);
693   }
694 }
695 //--------------------------------------------------------------
696 - (IBAction)handleSingleFingerSingleLongTap:(UIGestureRecognizer *)sender
697 {
698   if( [m_glView isXBMCAlive] )//NO GESTURES BEFORE WE ARE UP AND RUNNING
699   {
700     CGPoint point = [sender locationOfTouch:0 inView:m_glView];
701     point.x *= screenScale;
702     point.y *= screenScale;
703
704     if (sender.state == UIGestureRecognizerStateBegan)
705     {
706       lastGesturePoint = point;
707       // mark the control
708       //CGenericTouchActionHandler::Get().OnSingleTouchStart((float)point.x, (float)point.y);
709     }
710
711     if (sender.state == UIGestureRecognizerStateEnded)
712     {
713       CGenericTouchActionHandler::Get().OnSingleTouchMove((float)point.x, (float)point.y, point.x - lastGesturePoint.x, point.y - lastGesturePoint.y, 0, 0);
714     }
715     
716     if (sender.state == UIGestureRecognizerStateEnded)
717     {   
718       CGenericTouchActionHandler::Get().OnLongPress((float)point.x, (float)point.y);
719     }
720   }
721 }
722 //--------------------------------------------------------------
723 - (id)initWithFrame:(CGRect)frame withScreen:(UIScreen *)screen
724
725   PRINT_SIGNATURE();
726   m_screenIdx = 0;
727   self = [super init];
728   if ( !self )
729     return ( nil );
730
731   m_isPlayingBeforeInactive = NO;
732   m_bgTask = UIBackgroundTaskInvalid;
733   m_playbackState = IOS_PLAYBACK_STOPPED;
734
735   m_window = [[UIWindow alloc] initWithFrame:frame];
736   [m_window setRootViewController:self];  
737   m_window.screen = screen;
738   /* Turn off autoresizing */
739   m_window.autoresizingMask = 0;
740   m_window.autoresizesSubviews = NO;
741   
742   NSNotificationCenter *center;
743   center = [NSNotificationCenter defaultCenter];
744   [center addObserver: self
745              selector: @selector(observeDefaultCenterStuff:)
746                  name: nil
747                object: nil];
748
749   /* We start in landscape mode */
750   CGRect srect = frame;
751   srect.size = CGSizeMake( frame.size.height, frame.size.width );
752   orientation = UIInterfaceOrientationLandscapeLeft;
753   
754   m_glView = [[IOSEAGLView alloc] initWithFrame: srect withScreen:screen];
755   [[IOSScreenManager sharedInstance] setView:m_glView];  
756   [m_glView setMultipleTouchEnabled:YES];
757   
758   /* Check if screen is Retina */
759   screenScale = [m_glView getScreenScale:screen];
760
761   [self.view addSubview: m_glView];
762   
763   [self createGestureRecognizers];
764   [m_window addSubview: self.view];
765   [m_window makeKeyAndVisible];
766   g_xbmcController = self;  
767   
768   AnnounceReceiver::init();
769
770   return self;
771 }
772 //--------------------------------------------------------------
773 -(void)viewDidLoad
774 {
775   [super viewDidLoad];
776 }
777 //--------------------------------------------------------------
778 - (void)dealloc
779 {
780   // stop background task
781   [m_networkAutoSuspendTimer invalidate];
782   [self enableNetworkAutoSuspend:nil];
783
784   AnnounceReceiver::dealloc();
785   [m_glView stopAnimation];
786   [m_glView release];
787   [m_window release];
788
789   NSNotificationCenter *center;
790   // take us off the default center for our app
791   center = [NSNotificationCenter defaultCenter];
792   [center removeObserver: self];
793   
794   [super dealloc];
795 }
796 //--------------------------------------------------------------
797 - (void)viewWillAppear:(BOOL)animated
798 {
799   PRINT_SIGNATURE();
800   
801   // move this later into CocoaPowerSyscall
802   [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
803   
804   [self resumeAnimation];
805   
806   [super viewWillAppear:animated];
807 }
808 //--------------------------------------------------------------
809 -(void) viewDidAppear:(BOOL)animated
810 {
811   [super viewDidAppear:animated];
812
813   [self becomeFirstResponder];
814   [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
815 }
816 //--------------------------------------------------------------
817 - (void)viewWillDisappear:(BOOL)animated
818 {  
819   PRINT_SIGNATURE();
820   
821   [self pauseAnimation];
822   
823   // move this later into CocoaPowerSyscall
824   [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
825         
826   [super viewWillDisappear:animated];
827 }
828 //--------------------------------------------------------------
829 -(UIView *)inputView
830 {
831   // override our input view to an empty view
832   // this prevents the on screen keyboard
833   // which would be shown whenever this UIResponder
834   // becomes the first responder (which is always the case!)
835   // caused by implementing the UIKeyInput protocol
836   return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
837 }
838 //--------------------------------------------------------------
839 - (BOOL) canBecomeFirstResponder
840 {
841   return YES;
842 }
843 //--------------------------------------------------------------
844 - (void)viewDidUnload
845 {
846   [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
847   [self resignFirstResponder];
848
849         [super viewDidUnload];  
850 }
851 //--------------------------------------------------------------
852 - (void) initDisplayLink
853 {
854         [m_glView initDisplayLink];
855 }
856 //--------------------------------------------------------------
857 - (void) deinitDisplayLink
858 {
859   [m_glView deinitDisplayLink];
860 }
861 //--------------------------------------------------------------
862 - (double) getDisplayLinkFPS;
863 {
864   return [m_glView getDisplayLinkFPS];
865 }
866 //--------------------------------------------------------------
867 - (void) setFramebuffer
868 {
869   [m_glView setFramebuffer];
870 }
871 //--------------------------------------------------------------
872 - (bool) presentFramebuffer
873 {
874   return [m_glView presentFramebuffer];
875 }
876 //--------------------------------------------------------------
877 - (CGSize) getScreenSize
878 {
879   screensize.width  = m_glView.bounds.size.width * screenScale;
880   screensize.height = m_glView.bounds.size.height * screenScale;  
881   return screensize;
882 }
883 //--------------------------------------------------------------
884 - (CGFloat) getScreenScale:(UIScreen *)screen;
885 {
886   return [m_glView getScreenScale:screen];
887 }
888 //--------------------------------------------------------------
889 //--------------------------------------------------------------
890 - (BOOL) recreateOnReselect
891
892   PRINT_SIGNATURE();
893   return YES;
894 }
895 //--------------------------------------------------------------
896 - (void)didReceiveMemoryWarning
897 {
898   // Releases the view if it doesn't have a superview.
899   [super didReceiveMemoryWarning];
900   
901   // Release any cached data, images, etc. that aren't in use.
902 }
903 //--------------------------------------------------------------
904 - (void)disableNetworkAutoSuspend
905 {
906   PRINT_SIGNATURE();
907   if (m_bgTask != UIBackgroundTaskInvalid)
908   {
909     [[UIApplication sharedApplication] endBackgroundTask: m_bgTask];
910     m_bgTask = UIBackgroundTaskInvalid;
911   }
912   // we have to alloc the background task for keep network working after screen lock and dark.
913   UIBackgroundTaskIdentifier newTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
914   m_bgTask = newTask;
915
916   if (m_networkAutoSuspendTimer)
917   {
918     [m_networkAutoSuspendTimer invalidate];
919     self.m_networkAutoSuspendTimer = nil;
920   }
921 }
922 //--------------------------------------------------------------
923 - (void)enableNetworkAutoSuspend:(id)obj
924 {
925   PRINT_SIGNATURE();
926   if (m_bgTask != UIBackgroundTaskInvalid)
927   {
928     [[UIApplication sharedApplication] endBackgroundTask: m_bgTask];
929     m_bgTask = UIBackgroundTaskInvalid;
930   }
931 }
932 //--------------------------------------------------------------
933 - (void) disableSystemSleep
934 {
935 }
936 //--------------------------------------------------------------
937 - (void) enableSystemSleep
938 {
939 }
940 //--------------------------------------------------------------
941 - (void) disableScreenSaver
942 {
943 }
944 //--------------------------------------------------------------
945 - (void) enableScreenSaver
946 {
947 }
948 //--------------------------------------------------------------
949 - (bool) changeScreen: (unsigned int)screenIdx withMode:(UIScreenMode *)mode
950 {
951   bool ret = false;
952
953   ret = [[IOSScreenManager sharedInstance] changeScreen:screenIdx withMode:mode];
954
955   return ret;
956 }
957 //--------------------------------------------------------------
958 - (void) activateScreen: (UIScreen *)screen  withOrientation:(UIInterfaceOrientation)newOrientation
959 {
960   // Since ios7 we have to handle the orientation manually
961   // it differs by 90 degree between internal and external screen
962   float   angle = 0;
963   UIView *view = [m_window.subviews objectAtIndex:0];
964   switch(newOrientation)
965   {
966     case UIInterfaceOrientationPortrait:
967       angle = 0;
968       break;
969     case UIInterfaceOrientationPortraitUpsideDown:
970       angle = M_PI;
971       break;
972     case UIInterfaceOrientationLandscapeLeft:
973       angle = -M_PI_2;
974       break;
975     case UIInterfaceOrientationLandscapeRight:
976       angle = M_PI_2;
977       break;
978   }
979   // reset the rotation of the view
980   view.layer.transform = CATransform3DMakeRotation(angle, 0, 0.0, 1.0);
981   [view setFrame:m_window.frame];
982   m_window.screen = screen;
983 }
984 //--------------------------------------------------------------
985 - (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {
986   LOG(@"%s: type %d, subtype: %d", __PRETTY_FUNCTION__, receivedEvent.type, receivedEvent.subtype);
987   if (receivedEvent.type == UIEventTypeRemoteControl)
988   {
989     [self disableNetworkAutoSuspend];
990     switch (receivedEvent.subtype)
991     {
992       case UIEventSubtypeRemoteControlTogglePlayPause:
993         CApplicationMessenger::Get().SendAction(ACTION_PLAYER_PLAYPAUSE);
994         break;
995       case UIEventSubtypeRemoteControlPlay:
996         CApplicationMessenger::Get().SendAction(ACTION_PLAYER_PLAY);
997         break;
998       case UIEventSubtypeRemoteControlPause:
999         // ACTION_PAUSE sometimes cause unpause, use MediaPauseIfPlaying to make sure pause only
1000         CApplicationMessenger::Get().MediaPauseIfPlaying();
1001         break;
1002       case UIEventSubtypeRemoteControlNextTrack:
1003         CApplicationMessenger::Get().SendAction(ACTION_NEXT_ITEM);
1004         break;
1005       case UIEventSubtypeRemoteControlPreviousTrack:
1006         CApplicationMessenger::Get().SendAction(ACTION_PREV_ITEM);
1007         break;
1008       case UIEventSubtypeRemoteControlBeginSeekingForward:
1009         // use 4X speed forward.
1010         CApplicationMessenger::Get().SendAction(ACTION_PLAYER_FORWARD);
1011         CApplicationMessenger::Get().SendAction(ACTION_PLAYER_FORWARD);
1012         break;
1013       case UIEventSubtypeRemoteControlBeginSeekingBackward:
1014         // use 4X speed rewind.
1015         CApplicationMessenger::Get().SendAction(ACTION_PLAYER_REWIND);
1016         CApplicationMessenger::Get().SendAction(ACTION_PLAYER_REWIND);
1017         break;
1018       case UIEventSubtypeRemoteControlEndSeekingForward:
1019       case UIEventSubtypeRemoteControlEndSeekingBackward:
1020         // restore to normal playback speed.
1021         if (g_application.m_pPlayer->IsPlaying() && !g_application.m_pPlayer->IsPaused())
1022           CApplicationMessenger::Get().SendAction(ACTION_PLAYER_PLAY);
1023         break;
1024       default:
1025         LOG(@"unhandled subtype: %d", receivedEvent.subtype);
1026         break;
1027     }
1028     [self rescheduleNetworkAutoSuspend];
1029   }
1030 }
1031 //--------------------------------------------------------------
1032 - (void)enterBackground
1033 {
1034   PRINT_SIGNATURE();
1035   if (g_application.m_pPlayer->IsPlaying() && !g_application.m_pPlayer->IsPaused())
1036   {
1037     m_isPlayingBeforeInactive = YES;
1038     CApplicationMessenger::Get().MediaPauseIfPlaying();
1039   }
1040 }
1041
1042 - (void)enterForeground
1043 {
1044   PRINT_SIGNATURE();
1045   // when we come back, restore playing if we were.
1046   if (m_isPlayingBeforeInactive)
1047   {
1048     CApplicationMessenger::Get().MediaUnPause();
1049     m_isPlayingBeforeInactive = NO;
1050   }
1051 }
1052
1053 - (void)becomeInactive
1054 {
1055   // if we were interrupted, already paused here
1056   // else if user background us or lock screen, only pause video here, audio keep playing.
1057   if (g_application.m_pPlayer->IsPlayingVideo() && !g_application.m_pPlayer->IsPaused())
1058   {
1059     m_isPlayingBeforeInactive = YES;
1060     CApplicationMessenger::Get().MediaPauseIfPlaying();
1061   }
1062   // check whether we need disable network auto suspend.
1063   [self rescheduleNetworkAutoSuspend];
1064 }
1065 //--------------------------------------------------------------
1066 - (void)pauseAnimation
1067 {
1068   PRINT_SIGNATURE();
1069   
1070   [m_glView pauseAnimation];
1071 }
1072 //--------------------------------------------------------------
1073 - (void)resumeAnimation
1074 {  
1075   PRINT_SIGNATURE();
1076
1077   [m_glView resumeAnimation];
1078 }
1079 //--------------------------------------------------------------
1080 - (void)startAnimation
1081 {
1082   PRINT_SIGNATURE();
1083
1084   [m_glView startAnimation];
1085 }
1086 //--------------------------------------------------------------
1087 - (void)stopAnimation
1088 {
1089   PRINT_SIGNATURE();
1090
1091   [m_glView stopAnimation];
1092 }
1093 //--------------------------------------------------------------
1094 - (void)setIOSNowPlayingInfo:(NSDictionary *)info
1095 {
1096   self.nowPlayingInfo = info;
1097   // MPNowPlayingInfoCenter is an ios5+ class, following code will work on ios5 even if compiled by xcode3
1098   Class NowPlayingInfoCenter = NSClassFromString(@"MPNowPlayingInfoCenter");
1099   if (NowPlayingInfoCenter)
1100     [[NowPlayingInfoCenter defaultCenter] setNowPlayingInfo:self.nowPlayingInfo];
1101 }
1102 //--------------------------------------------------------------
1103 - (void)onPlay:(NSDictionary *)item
1104 {
1105   PRINT_SIGNATURE();
1106   NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
1107
1108   NSString *title = [item objectForKey:@"title"];
1109   if (title && title.length > 0)
1110     [dict setObject:title forKey:MPMediaItemPropertyTitle];
1111   NSString *album = [item objectForKey:@"album"];
1112   if (album && album.length > 0)
1113     [dict setObject:album forKey:MPMediaItemPropertyAlbumTitle];
1114   NSArray *artists = [item objectForKey:@"artist"];
1115   if (artists && artists.count > 0)
1116     [dict setObject:[artists componentsJoinedByString:@" "] forKey:MPMediaItemPropertyArtist];
1117   NSNumber *track = [item objectForKey:@"track"];
1118   if (track)
1119     [dict setObject:track forKey:MPMediaItemPropertyAlbumTrackNumber];
1120   NSNumber *duration = [item objectForKey:@"duration"];
1121   if (duration)
1122     [dict setObject:duration forKey:MPMediaItemPropertyPlaybackDuration];
1123   NSArray *genres = [item objectForKey:@"genre"];
1124   if (genres && genres.count > 0)
1125     [dict setObject:[genres componentsJoinedByString:@" "] forKey:MPMediaItemPropertyGenre];
1126
1127   if (NSClassFromString(@"MPNowPlayingInfoCenter"))
1128   {
1129     NSString *thumb = [item objectForKey:@"thumb"];
1130     if (thumb && thumb.length > 0)
1131     {
1132       UIImage *image = [UIImage imageWithContentsOfFile:thumb];
1133       if (image)
1134       {
1135         MPMediaItemArtwork *mArt = [[MPMediaItemArtwork alloc] initWithImage:image];
1136         if (mArt)
1137         {
1138           [dict setObject:mArt forKey:MPMediaItemPropertyArtwork];
1139           [mArt release];
1140         }
1141       }
1142     }
1143     // these proprity keys are ios5+ only
1144     NSNumber *elapsed = [item objectForKey:@"elapsed"];
1145     if (elapsed)
1146       [dict setObject:elapsed forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
1147     NSNumber *speed = [item objectForKey:@"speed"];
1148     if (speed)
1149       [dict setObject:speed forKey:MPNowPlayingInfoPropertyPlaybackRate];
1150     NSNumber *current = [item objectForKey:@"current"];
1151     if (current)
1152       [dict setObject:current forKey:MPNowPlayingInfoPropertyPlaybackQueueIndex];
1153     NSNumber *total = [item objectForKey:@"total"];
1154     if (total)
1155       [dict setObject:total forKey:MPNowPlayingInfoPropertyPlaybackQueueCount];
1156   }
1157   /*
1158    other properities can be set:
1159    MPMediaItemPropertyAlbumTrackCount
1160    MPMediaItemPropertyComposer
1161    MPMediaItemPropertyDiscCount
1162    MPMediaItemPropertyDiscNumber
1163    MPMediaItemPropertyPersistentID
1164
1165    Additional metadata properties:
1166    MPNowPlayingInfoPropertyChapterNumber;
1167    MPNowPlayingInfoPropertyChapterCount;
1168    */
1169
1170   [self setIOSNowPlayingInfo:dict];
1171   [dict release];
1172
1173   m_playbackState = IOS_PLAYBACK_PLAYING;
1174   [self disableNetworkAutoSuspend];
1175 }
1176 //--------------------------------------------------------------
1177 - (void)OnSpeedChanged:(NSDictionary *)item
1178 {
1179   PRINT_SIGNATURE();
1180   if (NSClassFromString(@"MPNowPlayingInfoCenter"))
1181   {
1182     NSMutableDictionary *info = [self.nowPlayingInfo mutableCopy];
1183     NSNumber *elapsed = [item objectForKey:@"elapsed"];
1184     if (elapsed)
1185       [info setObject:elapsed forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
1186     NSNumber *speed = [item objectForKey:@"speed"];
1187     if (speed)
1188       [info setObject:speed forKey:MPNowPlayingInfoPropertyPlaybackRate];
1189
1190     [self setIOSNowPlayingInfo:info];
1191   }
1192 }
1193 //--------------------------------------------------------------
1194 - (void)onPause:(NSDictionary *)item
1195 {
1196   PRINT_SIGNATURE();
1197   m_playbackState = IOS_PLAYBACK_PAUSED;
1198   // schedule set network auto suspend state for save power if idle.
1199   [self rescheduleNetworkAutoSuspend];
1200 }
1201 //--------------------------------------------------------------
1202 - (void)onStop:(NSDictionary *)item
1203 {
1204   PRINT_SIGNATURE();
1205   [self setIOSNowPlayingInfo:nil];
1206
1207   m_playbackState = IOS_PLAYBACK_STOPPED;
1208   // delay set network auto suspend state in case we are switching playing item.
1209   [self rescheduleNetworkAutoSuspend];
1210 }
1211 //--------------------------------------------------------------
1212 - (void)rescheduleNetworkAutoSuspend
1213 {
1214   LOG(@"%s: playback state: %d", __PRETTY_FUNCTION__,  m_playbackState);
1215   if (m_playbackState == IOS_PLAYBACK_PLAYING)
1216   {
1217     [self disableNetworkAutoSuspend];
1218     return;
1219   }
1220   if (m_networkAutoSuspendTimer)
1221     [m_networkAutoSuspendTimer invalidate];
1222
1223   int delay = m_playbackState == IOS_PLAYBACK_PAUSED ? 60 : 30;  // wait longer if paused than stopped
1224   self.m_networkAutoSuspendTimer = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:@selector(enableNetworkAutoSuspend:) userInfo:nil repeats:NO];
1225 }
1226
1227 #pragma mark -
1228 #pragma mark private helper methods
1229 //
1230 - (void)observeDefaultCenterStuff: (NSNotification *) notification
1231 {
1232 //  LOG(@"default: %@", [notification name]);
1233 //  LOG(@"userInfo: %@", [notification userInfo]);
1234 }
1235
1236 @end