From a2732bc7679e938ae7618381efe57b797a486ea6 Mon Sep 17 00:00:00 2001 From: flyingbird Date: Wed, 18 Dec 2013 16:00:25 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=8A=A0=E5=BC=BA=E4=B8=BA=E7=A9=BA?= =?UTF-8?q?=E5=88=A4=E6=96=AD=EF=BC=8C=E9=81=BF=E5=85=8D=E5=B4=A9=E6=BA=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WhoCall/Src/Telephony/WCAddressBook.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WhoCall/Src/Telephony/WCAddressBook.m b/WhoCall/Src/Telephony/WCAddressBook.m index 30c9130..e288723 100644 --- a/WhoCall/Src/Telephony/WCAddressBook.m +++ b/WhoCall/Src/Telephony/WCAddressBook.m @@ -71,7 +71,8 @@ - (void)reload:(ABAddressBookRef)addressBook for (CFIndex idxNumber = 0; idxNumber < ABMultiValueGetCount(phoneNumbers); idxNumber++) { NSString *phoneNumber = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phoneNumbers, idxNumber); phoneNumber = [phoneNumber normalizedPhoneNumber]; - self.allPhoneNumbers[phoneNumber] = personName; + if(personName!=nil && phoneNumber!=nil) + self.allPhoneNumbers[phoneNumber] = personName; } CFRelease(phoneNumbers); From 6a9d2e6a8592b52b8339e1af41b2b8bb12c88633 Mon Sep 17 00:00:00 2001 From: flyingbird Date: Wed, 18 Dec 2013 16:01:32 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=B8=89=E4=BD=8D?= =?UTF-8?q?=E5=8C=BA=E5=8F=B7=E7=9A=84=E5=88=A4=E6=96=AD=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WhoCall/Src/Telephony/WCPhoneLocator.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WhoCall/Src/Telephony/WCPhoneLocator.m b/WhoCall/Src/Telephony/WCPhoneLocator.m index 365498b..b0850ad 100644 --- a/WhoCall/Src/Telephony/WCPhoneLocator.m +++ b/WhoCall/Src/Telephony/WCPhoneLocator.m @@ -80,8 +80,8 @@ - (NSString *)locationForPhoneNumber:(NSString *)phoneNumber // 国内长途,首位是1、2则区号为两位,否则区号为3位 NSString *areacode; if ( phoneNumber.length > 3 - && [phoneNumber characterAtIndex:1] == '1' - && [phoneNumber characterAtIndex:1] == '2') { + && ([phoneNumber characterAtIndex:1] == '1' + || [phoneNumber characterAtIndex:1] == '2')) { areacode = [phoneNumber substringWithRange:NSMakeRange(1, 2)]; } else if (phoneNumber.length > 4) { areacode = [phoneNumber substringWithRange:NSMakeRange(1, 3)]; From f51a972a2b1124d47551cbb4b519c0219e7aac64 Mon Sep 17 00:00:00 2001 From: flyingbird Date: Wed, 18 Dec 2013 18:49:42 +0800 Subject: [PATCH 3/3] voip & notification & vibrate --- .../MMPDeepSleepPreventer.h | 91 -------- .../MMPDeepSleepPreventer.m | 218 ------------------ .../3rd/MMPDeepSleepPreventer/MMPSilence.wav | Bin 7068 -> 0 bytes WhoCall/Src/Telephony/WCCall.h | 1 + WhoCall/Src/Telephony/WCCallCenter.m | 4 + WhoCall/Src/Telephony/WCCallInspector.m | 5 + WhoCall/Src/WCAppDelegate.h | 12 + WhoCall/Src/WCAppDelegate.m | 150 +++++++++++- WhoCall/Support/WhoCall-Info.plist | 1 + WhoCall/WhoCall.xcodeproj/project.pbxproj | 31 +-- 10 files changed, 169 insertions(+), 344 deletions(-) delete mode 100755 WhoCall/Src/3rd/MMPDeepSleepPreventer/MMPDeepSleepPreventer.h delete mode 100755 WhoCall/Src/3rd/MMPDeepSleepPreventer/MMPDeepSleepPreventer.m delete mode 100755 WhoCall/Src/3rd/MMPDeepSleepPreventer/MMPSilence.wav diff --git a/WhoCall/Src/3rd/MMPDeepSleepPreventer/MMPDeepSleepPreventer.h b/WhoCall/Src/3rd/MMPDeepSleepPreventer/MMPDeepSleepPreventer.h deleted file mode 100755 index bd27e24..0000000 --- a/WhoCall/Src/3rd/MMPDeepSleepPreventer/MMPDeepSleepPreventer.h +++ /dev/null @@ -1,91 +0,0 @@ -// -// MMPDeepSleepPreventer.h -// MMPDeepSleepPreventer -// -// Created by Marco Peluso on 20.08.09. -// Copyright (c) 2009-2010, Marco Peluso - marcopeluso.com -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -#pragma mark - -#pragma mark MMPLog - -// Set up some advanced logging preprocessor macros to replace NSLog. -// I usually have this in an external file (MMPLog.h) which is maintained in its own git repository. -// I add this repository in my other projects as a submodule (via git submodule) and import the MMPLog.h -// in a project's Prefix.pch. -// -// For convenience reasons, I just include these macros here, so other people are not confused by -// git submodule if they are unfamiliar with it or simply don't have to bother and can use MMPDeepSleepPreventer -// as simple drop-in code. - -#ifndef MMPDLog - #ifdef DEBUG - #define MMPDLog(format, ...) NSLog((@"%s [Line %d] " format), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) - #else - #define MMPDLog(...) do { } while (0) - #endif -#endif - -#ifndef MMPALog - #define MMPALog(format, ...) NSLog((@"%s [Line %d] " format), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) -#endif - - -#pragma mark - -#pragma mark Imports and Forward Declarations - -#import - -@class AVAudioPlayer; - - -#pragma mark - -#pragma mark Public Interface - -@interface MMPDeepSleepPreventer : NSObject -{ - -} - - -#pragma mark - -#pragma mark Properties - -@property (nonatomic, retain) AVAudioPlayer *audioPlayer; -@property (nonatomic, retain) NSTimer *preventSleepTimer; - - -#pragma mark - -#pragma mark Public Methods - -- (void)startPreventSleep; -- (void)stopPreventSleep; - -@end diff --git a/WhoCall/Src/3rd/MMPDeepSleepPreventer/MMPDeepSleepPreventer.m b/WhoCall/Src/3rd/MMPDeepSleepPreventer/MMPDeepSleepPreventer.m deleted file mode 100755 index 03808a0..0000000 --- a/WhoCall/Src/3rd/MMPDeepSleepPreventer/MMPDeepSleepPreventer.m +++ /dev/null @@ -1,218 +0,0 @@ -// -// MMPDeepSleepPreventer.m -// MMPDeepSleepPreventer -// -// Created by Marco Peluso on 20.08.09. -// Copyright (c) 2009-2010, Marco Peluso - marcopeluso.com -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -#pragma mark - -#pragma mark Imports - -#import "MMPDeepSleepPreventer.h" -#import -#import - - -#pragma mark - -#pragma mark MMPDeepSleepPreventer Private Interface - -@interface MMPDeepSleepPreventer () - -- (void)mmp_playPreventSleepSound; -- (void)mmp_setUpAudioSession; - -@end - - -@implementation MMPDeepSleepPreventer - - -#pragma mark - -#pragma mark Synthesizes - -@synthesize audioPlayer = audioPlayer_; -@synthesize preventSleepTimer = preventSleepTimer_; - - -#pragma mark - -#pragma mark Creation and Destruction - -- (id)init -{ - if ( !(self = [super init]) ) - return nil; - - [self mmp_setUpAudioSession]; - - // Set up path to sound file - NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"MMPSilence" - ofType:@"wav"]; - - NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:soundFilePath]; - - // Set up audio player with sound file - audioPlayer_ = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL - error:nil]; - - [self.audioPlayer prepareToPlay]; - - self.audioPlayer.volume = 0.1; - - self.audioPlayer.numberOfLoops = -1; - - return self; -} - - -#pragma mark - -#pragma mark Public Methods - -- (void)startPreventSleep -{ - // We need to play a sound at least every 10 seconds to keep the iPhone awake. - // It doesn't seem to affect battery life how often inbetween these 10 seconds the sound file is played. - // To prevent the iPhone from falling asleep due to timing/performance issues, we play a sound file every five seconds. - - // We create a new repeating timer, that begins firing immediately and then every five seconds afterwards. - // Every time it fires, it calls -mmp_playPreventSleepSound. - NSTimer *preventSleepTimer = [[NSTimer alloc] initWithFireDate:[NSDate date] - interval:5.0 - target:self - selector:@selector(mmp_playPreventSleepSound) - userInfo:nil - repeats:YES]; - self.preventSleepTimer = preventSleepTimer; - - // Add the timer to the current run loop. - [[NSRunLoop currentRunLoop] addTimer:self.preventSleepTimer - forMode:NSDefaultRunLoopMode]; -} - - -- (void)stopPreventSleep -{ - [self.preventSleepTimer invalidate]; - self.preventSleepTimer = nil; -} - - -#pragma mark - -#pragma mark Private Methods - -- (void)mmp_playPreventSleepSound -{ - [self.audioPlayer play]; -} - - -- (void)mmp_setUpAudioSession -{ - // AudioSession functions are deprecated from iOS 7.0, so prefer using AVAudioSession - AVAudioSession *audioSession = [AVAudioSession sharedInstance]; - - if ([audioSession respondsToSelector:@selector(setCategory:withOptions:error:)]) { - NSError *activeSetError = nil; - [audioSession setActive:YES - error:&activeSetError]; - - if (activeSetError) { - MMPALog(@"Error activating AVAudioSession: %@", activeSetError); - } - - NSError *categorySetError = nil; - [audioSession setCategory:AVAudioSessionCategoryPlayback - withOptions:AVAudioSessionCategoryOptionMixWithOthers - error:&categorySetError]; - - if (categorySetError) { - MMPALog(@"Error setting AVAudioSession category: %@", categorySetError); - } - } else { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" // supress deprecated warning - - // Initialize audio session - AudioSessionInitialize - ( - NULL, // Use NULL to use the default (main) run loop. - NULL, // Use NULL to use the default run loop mode. - NULL, // A reference to your interruption listener callback function. - // See “Responding to Audio Session Interruptions” in Apple's "Audio Session Programming Guide" for a description of how to write - // and use an interruption callback function. - NULL // Data you intend to be passed to your interruption listener callback function when the audio session object invokes it. - ); - - // Activate audio session - OSStatus activationResult = 0; - activationResult = AudioSessionSetActive(true); - - if (activationResult) - { - MMPDLog(@"AudioSession is active"); - } - - // Set up audio session category to kAudioSessionCategory_MediaPlayback. - // While playing sounds using this session category at least every 10 seconds, the iPhone doesn't go to sleep. - UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback; // Defines a new variable of type UInt32 and initializes it with the identifier - // for the category you want to apply to the audio session. - AudioSessionSetProperty - ( - kAudioSessionProperty_AudioCategory, // The identifier, or key, for the audio session property you want to set. - sizeof(sessionCategory), // The size, in bytes, of the property value that you are applying. - &sessionCategory // The category you want to apply to the audio session. - ); - - // Set up audio session playback mixing behavior. - // kAudioSessionCategory_MediaPlayback usually prevents playback mixing, so we allow it here. This way, we don't get in the way of other sound playback in an application. - // This property has a value of false (0) by default. When the audio session category changes, such as during an interruption, the value of this property reverts to false. - // To regain mixing behavior you must then set this property again. - - // Always check to see if setting this property succeeds or fails, and react appropriately; behavior may change in future releases of iPhone OS. - OSStatus propertySetError = 0; - UInt32 allowMixing = true; - - propertySetError = AudioSessionSetProperty - ( - kAudioSessionProperty_OverrideCategoryMixWithOthers, // The identifier, or key, for the audio session property you want to set. - sizeof(allowMixing), // The size, in bytes, of the property value that you are applying. - &allowMixing // The value to apply to the property. - ); - - if (propertySetError) - { - MMPALog(@"Error setting kAudioSessionProperty_OverrideCategoryMixWithOthers: %ld", (long)propertySetError); - } - -#pragma clang diagnostic pop - } -} - -@end diff --git a/WhoCall/Src/3rd/MMPDeepSleepPreventer/MMPSilence.wav b/WhoCall/Src/3rd/MMPDeepSleepPreventer/MMPSilence.wav deleted file mode 100755 index 9fbce3755ea67ff4d904f34646a39e45faa5251c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7068 zcmeIup$&jA07TIPi=Z9>lMoOzA*reW-Gtz99e^Q_jKolMjW+*Ip1C}~TKja;K5xr; z#lc9bQm0~SnCP? diff --git a/WhoCall/Src/Telephony/WCCall.h b/WhoCall/Src/Telephony/WCCall.h index 5d07e83..7ae96de 100644 --- a/WhoCall/Src/Telephony/WCCall.h +++ b/WhoCall/Src/Telephony/WCCall.h @@ -11,6 +11,7 @@ // private API typedef NS_ENUM(short, CTCallStatus) { + kCTCallStatusConnected = 1, kCTCallStatusCallIn = 4, kCTCallStatusHungUp = 5 }; diff --git a/WhoCall/Src/Telephony/WCCallCenter.m b/WhoCall/Src/Telephony/WCCallCenter.m index 0f01421..79c86f3 100644 --- a/WhoCall/Src/Telephony/WCCallCenter.m +++ b/WhoCall/Src/Telephony/WCCallCenter.m @@ -7,6 +7,7 @@ // #import "WCCallCenter.h" +@import AudioToolbox; // encrypted string's #define ENCSTR_kCTCallStatusChangeNotification [@"n0AHD2SfoSA0LKE1p0AbLJ5aMH5iqTyznJAuqTyiot==" wcDecryptString] @@ -138,6 +139,9 @@ static void callHandler(CFNotificationCenterRef center, NSDictionary *info = (__bridge NSDictionary *)(userInfo); CTCall *call = (CTCall *)info[ENCSTR_kCTCall]; CTCallStatus status = (CTCallStatus)[info[ENCSTR_kCTCallStatus] shortValue]; + if (status == kCTCallStatusConnected) { + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); + } WCCallCenter *wcCenter = (__bridge WCCallCenter*)observer; [wcCenter handleCall:call withStatus:status]; diff --git a/WhoCall/Src/Telephony/WCCallInspector.m b/WhoCall/Src/Telephony/WCCallInspector.m index 89d2af6..148cfe5 100644 --- a/WhoCall/Src/Telephony/WCCallInspector.m +++ b/WhoCall/Src/Telephony/WCCallInspector.m @@ -153,6 +153,11 @@ - (void)notifyMessage:(NSString *)text forPhoneNumber:(NSString *)phoneNumber { } - (void)notifyMessage:(NSString *)text afterDealy:(NSTimeInterval)delay forPhoneNumber:(NSString *)phoneNumber { + UILocalNotification *notification=[[UILocalNotification alloc] init]; + if (notification!=nil) { + notification.alertBody=[NSString stringWithFormat:@"%@-%@",text,phoneNumber]; + [[UIApplication sharedApplication] presentLocalNotificationNow:notification]; + } // 循环提醒,直到电话号码不匹配(来电挂断) dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ diff --git a/WhoCall/Src/WCAppDelegate.h b/WhoCall/Src/WCAppDelegate.h index cbfc8f7..a141dee 100644 --- a/WhoCall/Src/WCAppDelegate.h +++ b/WhoCall/Src/WCAppDelegate.h @@ -8,6 +8,18 @@ #import +#ifndef MMPDLog +#ifdef DEBUG +#define MMPDLog(format, ...) NSLog((@"%s [Line %d] " format), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) +#else +#define MMPDLog(...) do { } while (0) +#endif +#endif + +#ifndef MMPALog +#define MMPALog(format, ...) NSLog((@"%s [Line %d] " format), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) +#endif + @interface WCAppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; diff --git a/WhoCall/Src/WCAppDelegate.m b/WhoCall/Src/WCAppDelegate.m index ca7c802..6639b27 100644 --- a/WhoCall/Src/WCAppDelegate.m +++ b/WhoCall/Src/WCAppDelegate.m @@ -8,28 +8,128 @@ #import "WCAppDelegate.h" #import "WCSettingViewController.h" -#import "MMPDeepSleepPreventer.h" #import "WCCallInspector.h" +@import AVFoundation; @interface WCAppDelegate () -@property (nonatomic, strong) MMPDeepSleepPreventer *sleepPreventer; -@property (nonatomic, assign) UIBackgroundTaskIdentifier bgTaskID; +@property (assign, nonatomic) UIBackgroundTaskIdentifier bgTask; +@property (assign, nonatomic) BOOL background; +@property (strong, nonatomic) dispatch_block_t expirationHandler; +@property (assign, nonatomic) BOOL jobExpired; @end @implementation WCAppDelegate +- (void)mmp_setUpAudioSession +{ + // AudioSession functions are deprecated from iOS 7.0, so prefer using AVAudioSession + AVAudioSession *audioSession = [AVAudioSession sharedInstance]; + + if ([audioSession respondsToSelector:@selector(setCategory:withOptions:error:)]) { + NSError *activeSetError = nil; + [audioSession setActive:YES + error:&activeSetError]; + + if (activeSetError) { + MMPALog(@"Error activating AVAudioSession: %@", activeSetError); + } + + NSError *categorySetError = nil; + [audioSession setCategory:AVAudioSessionCategoryPlayback + withOptions:AVAudioSessionCategoryOptionMixWithOthers + error:&categorySetError]; + + if (categorySetError) { + MMPALog(@"Error setting AVAudioSession category: %@", categorySetError); + } + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // supress deprecated warning + + // Initialize audio session + AudioSessionInitialize + ( + NULL, // Use NULL to use the default (main) run loop. + NULL, // Use NULL to use the default run loop mode. + NULL, // A reference to your interruption listener callback function. + // See “Responding to Audio Session Interruptions” in Apple's "Audio Session Programming Guide" for a description of how to write + // and use an interruption callback function. + NULL // Data you intend to be passed to your interruption listener callback function when the audio session object invokes it. + ); + + // Activate audio session + OSStatus activationResult = 0; + activationResult = AudioSessionSetActive(true); + + if (activationResult) + { + MMPDLog(@"AudioSession is active"); + } + + // Set up audio session category to kAudioSessionCategory_MediaPlayback. + // While playing sounds using this session category at least every 10 seconds, the iPhone doesn't go to sleep. + UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback; // Defines a new variable of type UInt32 and initializes it with the identifier + // for the category you want to apply to the audio session. + AudioSessionSetProperty + ( + kAudioSessionProperty_AudioCategory, // The identifier, or key, for the audio session property you want to set. + sizeof(sessionCategory), // The size, in bytes, of the property value that you are applying. + &sessionCategory // The category you want to apply to the audio session. + ); + + // Set up audio session playback mixing behavior. + // kAudioSessionCategory_MediaPlayback usually prevents playback mixing, so we allow it here. This way, we don't get in the way of other sound playback in an application. + // This property has a value of false (0) by default. When the audio session category changes, such as during an interruption, the value of this property reverts to false. + // To regain mixing behavior you must then set this property again. + + // Always check to see if setting this property succeeds or fails, and react appropriately; behavior may change in future releases of iPhone OS. + OSStatus propertySetError = 0; + UInt32 allowMixing = true; + + propertySetError = AudioSessionSetProperty + ( + kAudioSessionProperty_OverrideCategoryMixWithOthers, // The identifier, or key, for the audio session property you want to set. + sizeof(allowMixing), // The size, in bytes, of the property value that you are applying. + &allowMixing // The value to apply to the property. + ); + + if (propertySetError) + { + MMPALog(@"Error setting kAudioSessionProperty_OverrideCategoryMixWithOthers: %ld", (long)propertySetError); + } + +#pragma clang diagnostic pop + } +} + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - // prevent sleep - self.sleepPreventer = [[MMPDeepSleepPreventer alloc] init]; + [self mmp_setUpAudioSession]; + + UIApplication* app = [UIApplication sharedApplication]; + + __weak WCAppDelegate* selfRef = self; + + self.expirationHandler = ^{ + [app endBackgroundTask:selfRef.bgTask]; + selfRef.bgTask = UIBackgroundTaskInvalid; + selfRef.bgTask = [app beginBackgroundTaskWithExpirationHandler:selfRef.expirationHandler]; + NSLog(@"Expired"); + selfRef.jobExpired = YES; + while(selfRef.jobExpired) { + // spin while we wait for the task to actually end. + [NSThread sleepForTimeInterval:1]; + } + // Restart the background task so we can run forever. + [selfRef startBackgroundTask]; + }; + self.bgTask = [app beginBackgroundTaskWithExpirationHandler:self.expirationHandler]; - // 必须正确处理background task,才能在后台发声 - self.bgTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ - [[UIApplication sharedApplication] endBackgroundTask:self.bgTaskID]; - self.bgTaskID = UIBackgroundTaskInvalid; - }]; + // Assume that we're in background at first since we get no notification from device that we're in background when + // app launches immediately into background (i.e. when powering on the device or when the app is killed and restarted) + [self monitorBatteryStateInBackground]; // call inspector [[WCCallInspector sharedInspector] startInspect]; @@ -49,6 +149,30 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( return YES; } +- (void)monitorBatteryStateInBackground +{ + self.background = YES; + [self startBackgroundTask]; +} + +- (void)startBackgroundTask +{ + NSLog(@"Restarting task"); + // Start the long-running task. + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + // When the job expires it still keeps running since we never exited it. Thus have the expiration handler + // set a flag that the job expired and use that to exit the while loop and end the task. + while(self.background && !self.jobExpired) + { + [NSThread sleepForTimeInterval:1]; + // NSTimeInterval backgroundTimeRemaining = [[UIApplication sharedApplication] backgroundTimeRemaining]; + // NSLog(@"Background Time Remaining = %.02f Seconds",backgroundTimeRemaining); + } + self.jobExpired = NO; + }); +} + + - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. @@ -59,18 +183,20 @@ - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - [self.sleepPreventer startPreventSleep]; + NSLog(@"Entered background"); + [self monitorBatteryStateInBackground]; } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - [self.sleepPreventer stopPreventSleep]; } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + NSLog(@"App is active"); + self.background = NO; } - (void)applicationWillTerminate:(UIApplication *)application diff --git a/WhoCall/Support/WhoCall-Info.plist b/WhoCall/Support/WhoCall-Info.plist index 4a8a7fd..c57f30a 100644 --- a/WhoCall/Support/WhoCall-Info.plist +++ b/WhoCall/Support/WhoCall-Info.plist @@ -27,6 +27,7 @@ UIBackgroundModes audio + voip UIRequiredDeviceCapabilities diff --git a/WhoCall/WhoCall.xcodeproj/project.pbxproj b/WhoCall/WhoCall.xcodeproj/project.pbxproj index db18594..e56223c 100644 --- a/WhoCall/WhoCall.xcodeproj/project.pbxproj +++ b/WhoCall/WhoCall.xcodeproj/project.pbxproj @@ -15,10 +15,7 @@ 461320881838A6A7006634C7 /* WCAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 461320801838A6A7006634C7 /* WCAppDelegate.m */; }; 4613208B1838A788006634C7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 461320841838A6A7006634C7 /* InfoPlist.strings */; }; 466216741838B6A8008DC8FA /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 466216731838B6A8008DC8FA /* AVFoundation.framework */; }; - 466216761838B6AF008DC8FA /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 466216751838B6AF008DC8FA /* AudioToolbox.framework */; }; 466216781838B6B7008DC8FA /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 466216771838B6B7008DC8FA /* CoreTelephony.framework */; }; - 4662167F1838B729008DC8FA /* MMPDeepSleepPreventer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4662167C1838B729008DC8FA /* MMPDeepSleepPreventer.m */; }; - 466216801838B729008DC8FA /* MMPSilence.wav in Resources */ = {isa = PBXBuildFile; fileRef = 4662167D1838B729008DC8FA /* MMPSilence.wav */; }; 466216841838B767008DC8FA /* WCSettingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 466216821838B767008DC8FA /* WCSettingViewController.m */; }; 466216871838B8F2008DC8FA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 466216861838B8F2008DC8FA /* Localizable.strings */; }; 466216891838DEFC008DC8FA /* WCSetting.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 466216881838DEFC008DC8FA /* WCSetting.storyboard */; }; @@ -64,11 +61,7 @@ 461320831838A6A7006634C7 /* WhoCall-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "WhoCall-Info.plist"; sourceTree = ""; }; 461320851838A6A7006634C7 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; 466216731838B6A8008DC8FA /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; - 466216751838B6AF008DC8FA /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 466216771838B6B7008DC8FA /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; - 4662167B1838B729008DC8FA /* MMPDeepSleepPreventer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMPDeepSleepPreventer.h; sourceTree = ""; }; - 4662167C1838B729008DC8FA /* MMPDeepSleepPreventer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMPDeepSleepPreventer.m; sourceTree = ""; }; - 4662167D1838B729008DC8FA /* MMPSilence.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = MMPSilence.wav; sourceTree = ""; }; 466216811838B767008DC8FA /* WCSettingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WCSettingViewController.h; sourceTree = ""; }; 466216821838B767008DC8FA /* WCSettingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WCSettingViewController.m; sourceTree = ""; }; 466216861838B8F2008DC8FA /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = ""; }; @@ -125,7 +118,6 @@ 4662170C183C521F008DC8FA /* libsqlite3.dylib in Frameworks */, 466216EE183BA363008DC8FA /* AddressBook.framework in Frameworks */, 466216781838B6B7008DC8FA /* CoreTelephony.framework in Frameworks */, - 466216761838B6AF008DC8FA /* AudioToolbox.framework in Frameworks */, 466216741838B6A8008DC8FA /* AVFoundation.framework in Frameworks */, 4613204D1838A357006634C7 /* CoreGraphics.framework in Frameworks */, 4613204F1838A357006634C7 /* UIKit.framework in Frameworks */, @@ -162,7 +154,6 @@ 4662170B183C521F008DC8FA /* libsqlite3.dylib */, 466216ED183BA363008DC8FA /* AddressBook.framework */, 466216771838B6B7008DC8FA /* CoreTelephony.framework */, - 466216751838B6AF008DC8FA /* AudioToolbox.framework */, 466216731838B6A8008DC8FA /* AVFoundation.framework */, 4613204A1838A357006634C7 /* Foundation.framework */, 4613204C1838A357006634C7 /* CoreGraphics.framework */, @@ -220,21 +211,10 @@ children = ( 466216F9183C4AFD008DC8FA /* FMDB */, 466216EF183BB2DC008DC8FA /* MKAdditions */, - 4662167A1838B729008DC8FA /* MMPDeepSleepPreventer */, ); path = 3rd; sourceTree = ""; }; - 4662167A1838B729008DC8FA /* MMPDeepSleepPreventer */ = { - isa = PBXGroup; - children = ( - 4662167B1838B729008DC8FA /* MMPDeepSleepPreventer.h */, - 4662167C1838B729008DC8FA /* MMPDeepSleepPreventer.m */, - 4662167D1838B729008DC8FA /* MMPSilence.wav */, - ); - path = MMPDeepSleepPreventer; - sourceTree = ""; - }; 4662167E1838B729008DC8FA /* Controllers */ = { isa = PBXGroup; children = ( @@ -324,11 +304,14 @@ ORGANIZATIONNAME = "Wang Xiaolei"; TargetAttributes = { 461320461838A357006634C7 = { - DevelopmentTeam = CZ2PUS96XT; + DevelopmentTeam = RR5AV4GY8C; SystemCapabilities = { com.apple.BackgroundModes = { enabled = 1; }; + com.apple.InterAppAudio = { + enabled = 0; + }; }; }; }; @@ -367,7 +350,6 @@ 466216901838FF2A008DC8FA /* icon_contact.png in Resources */, 466216F5183C47B6008DC8FA /* telocation.db in Resources */, 461320861838A6A7006634C7 /* AppImages.xcassets in Resources */, - 466216801838B729008DC8FA /* MMPSilence.wav in Resources */, 466216951838FF35008DC8FA /* icon_spam@2x.png in Resources */, 466216991839014A008DC8FA /* icon_nobody@2x.png in Resources */, ); @@ -391,7 +373,6 @@ 466216E0183A6319008DC8FA /* WCCall.m in Sources */, 461320871838A6A7006634C7 /* main.m in Sources */, 466216EC183BA2D2008DC8FA /* WCUtil.m in Sources */, - 4662167F1838B729008DC8FA /* MMPDeepSleepPreventer.m in Sources */, 466216E6183BA292008DC8FA /* WCAddressBook.m in Sources */, 466216841838B767008DC8FA /* WCSettingViewController.m in Sources */, 46621707183C4AFD008DC8FA /* FMDatabasePool.m in Sources */, @@ -493,11 +474,13 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Src/WhoCall-Prefix.pch"; INFOPLIST_FILE = "$(SRCROOT)/Support/WhoCall-Info.plist"; LIBRARY_SEARCH_PATHS = "$(inherited)"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; WRAPPER_EXTENSION = app; }; name = Debug; @@ -508,11 +491,13 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Src/WhoCall-Prefix.pch"; INFOPLIST_FILE = "$(SRCROOT)/Support/WhoCall-Info.plist"; LIBRARY_SEARCH_PATHS = "$(inherited)"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; WRAPPER_EXTENSION = app; }; name = Release;