From 6f86bc95c74bdfa089d4f0a2f3749022cb6d6640 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 12 Aug 2016 16:14:35 +0200 Subject: [PATCH] Shows notification or popup when the account is about to expire. --- Classes/InAppProductsManager.h | 13 +++++ Classes/InAppProductsManager.m | 81 +++++++++++++++++++++++++++--- Classes/LinphoneAppDelegate.m | 18 ++++++- Classes/LinphoneManager.m | 3 +- Classes/RenewalManager.h | 23 --------- Resources/linphonerc-factory | 6 ++- linphone.xcodeproj/project.pbxproj | 2 - 7 files changed, 112 insertions(+), 34 deletions(-) delete mode 100644 Classes/RenewalManager.h diff --git a/Classes/InAppProductsManager.h b/Classes/InAppProductsManager.h index 87bb82a96..6b6fcb539 100644 --- a/Classes/InAppProductsManager.h +++ b/Classes/InAppProductsManager.h @@ -45,6 +45,8 @@ typedef NSString *IAPPurchaseNotificationStatus; // paid_account_id=test.autorenew_7days // receipt_validation_url=https://www.linphone.org/inapp.php // products_list=test.autorenew_7days +// expiry_check_period = 86400 +// warn_before_expiry_period = 604800 // Note: in Sandbox mode (test), autorenewal expire time is speed up (see // http://stackoverflow.com/questions/8815271/what-expiry-date-should-i-see-for-in-app-purchase-in-the-application-sandbox) // so that 7 days renewal is only 3 minutes and: @@ -57,11 +59,19 @@ typedef NSString *IAPPurchaseNotificationStatus; @interface InAppProductsManager : NSObject { NSString *latestReceiptMD5; + time_t lastCheck; + time_t expiryTime; } @property(nonatomic, strong) IAPPurchaseNotificationStatus status; @property(nonatomic, strong) NSMutableArray *productsAvailable; @property(nonatomic, strong) NSMutableArray *productsIDPurchased; +//Period of time between each expiration check. Default value is given in linphonerc. +@property time_t checkPeriod; +//Period of time before expiration during which we warn the user about the need to renew the account. +@property time_t warnBeforeExpiryPeriod; +//The notification category to use for displaying notification related to account expiry. +@property NSString *notificationCategory; // TRUE when in app purchase capability is available - not modified during runtime @property(readonly) BOOL enabled; @@ -92,6 +102,9 @@ typedef NSString *IAPPurchaseNotificationStatus; // Warning: on first run, this will open a popup to user to provide iTunes Store credentials - (BOOL)retrievePurchases; +//Check if account is about to expire, and if yes launch a notification. +- (void)check; + // internal API only due to methods conflict - (void)XMLRPCRequest:(XMLRPCRequest *)request didReceiveResponse:(XMLRPCResponse *)response; // internal API only due to methods conflict diff --git a/Classes/InAppProductsManager.m b/Classes/InAppProductsManager.m index af19ed70b..0cb1cca82 100644 --- a/Classes/InAppProductsManager.m +++ b/Classes/InAppProductsManager.m @@ -18,6 +18,7 @@ */ #import "InAppProductsManager.h" +#import "ShopView.h" // In app purchase are not supported by the Simulator #import @@ -36,8 +37,14 @@ @property(nonatomic, strong) InAppProductsXMLRPCDelegate *xmlrpc; @end + + @implementation InAppProductsManager +@synthesize checkPeriod; +@synthesize warnBeforeExpiryPeriod; +@synthesize notificationCategory; + // LINPHONE_CAPABILITY_INAPP_PURCHASE must be defined in Linphone Build Settings #if 1 @@ -48,6 +55,14 @@ _initialized = false; _available = false; _accountActivationInProgress = false; + checkPeriod = [LinphoneManager.instance lpConfigIntForKey:@"expiry_check_period" inSection:@"in_app_purchase"]; + warnBeforeExpiryPeriod = [LinphoneManager.instance lpConfigIntForKey:@"warn_before_expiry_period" inSection:@"in_app_purchase"]; + lastCheck = 0; + + int testExpiry = [LinphoneManager.instance lpConfigIntForKey:@"expiry_time_test" inSection:@"in_app_purchase"]; + if (testExpiry > 0){ + expiryTime = time(NULL) + testExpiry; + }else expiryTime = 0; if (_enabled) { self.xmlrpc = [[InAppProductsXMLRPCDelegate alloc] init]; _status = kIAPNotReady; @@ -301,13 +316,9 @@ NSString *phoneNumber = @""; LinphoneProxyConfig *config = linphone_core_get_default_proxy_config(LC); if (config) { - const char *identity = linphone_proxy_config_get_identity(config); + const LinphoneAddress *identity = linphone_proxy_config_get_identity_address(config); if (identity) { - LinphoneAddress *addr = linphone_core_interpret_url(LC, identity); - if (addr) { - phoneNumber = [NSString stringWithUTF8String:linphone_address_get_username(addr)]; - linphone_address_destroy(addr); - } + phoneNumber = [NSString stringWithUTF8String:linphone_address_get_username(identity)]; } } return phoneNumber; @@ -476,6 +487,64 @@ NSDictionary *dict = @{ @"error_msg" : errorString }; [self postNotificationforStatus:kIAPReceiptFailed withDict:dict]; } + +- (void) presentNotification:(int64_t) remaining{ + if (notificationCategory == nil) return; + int days = (int)remaining / (3600 * 24); + NSString * expireText; + if (remaining >= 0){ + expireText = [NSString stringWithFormat:NSLocalizedString(@"Your account will expire in %i days.", nil), days]; + }else{ + expireText = [NSString stringWithFormat:NSLocalizedString(@"Your account has expired.", nil), days]; + } + + if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground){ + UILocalNotification *notification = [[UILocalNotification alloc] init]; + if (notification) { + + notification.category = notificationCategory; + notification.repeatInterval = 0; + notification.applicationIconBadgeNumber = 1; + notification.alertBody = expireText; + + [[UIApplication sharedApplication] presentLocalNotificationNow:notification]; + } + + }else{ + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Account expiring" + message:expireText + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* buyAction = [UIAlertAction actionWithTitle:@"Buy" style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + [PhoneMainView.instance changeCurrentView:ShopView.compositeViewDescription]; + }]; + + UIAlertAction* laterAction = [UIAlertAction actionWithTitle:@"Later" style:UIAlertActionStyleCancel + handler:^(UIAlertAction * action) { + // [alert dismissViewControllerAnimated:FALSE]; + }]; + + [alert addAction:buyAction]; + [alert addAction:laterAction]; + [PhoneMainView.instance presentViewController:alert animated:YES completion:nil]; + } +} + +- (void) check{ + if (!_available) return; + if (expiryTime == 0 || checkPeriod == 0) return; + + time_t now = time(NULL); + + if (now < lastCheck + checkPeriod) return; + if (now >= expiryTime - warnBeforeExpiryPeriod){ + lastCheck = now; + int64_t remaining = (int64_t)expiryTime - (int64_t)now; + [self presentNotification: remaining]; + } +} + #else - (void)postNotificationforStatus:(IAPPurchaseNotificationStatus)status { _status = status; diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index 8e9b01daa..aa5e15211 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -18,6 +18,7 @@ */ #import "PhoneMainView.h" +#import "ShopView.h" #import "linphoneAppDelegate.h" #import "AddressBook/ABPerson.h" @@ -99,6 +100,7 @@ [self fixRing]; } } + [LinphoneManager.instance.iapManager check]; } #pragma deploymate push "ignored-api-availability" @@ -170,6 +172,14 @@ return localRingNotifAction; } +- (UIUserNotificationCategory *)getAccountExpiryNotificationCategory { + + UIMutableUserNotificationCategory *expiryNotification = [[UIMutableUserNotificationCategory alloc] init]; + expiryNotification.identifier = @"expiry_notification"; + return expiryNotification; +} + + - (void)registerForNotifications:(UIApplication *)app { LinphoneManager *instance = [LinphoneManager instance]; @@ -179,7 +189,7 @@ UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert; NSSet *categories = - [NSSet setWithObjects:[self getCallNotificationCategory], [self getMessageNotificationCategory], nil]; + [NSSet setWithObjects:[self getCallNotificationCategory], [self getMessageNotificationCategory], [self getAccountExpiryNotificationCategory], nil]; UIUserNotificationSettings *userSettings = [UIUserNotificationSettings settingsForTypes:notifTypes categories:categories]; [app registerUserNotificationSettings:userSettings]; @@ -224,6 +234,7 @@ }]; [LinphoneManager.instance startLinphoneCore]; + LinphoneManager.instance.iapManager.notificationCategory = @"expiry_notification"; // initialize UI [self.window makeKeyAndVisible]; [RootViewManager setupWithPortrait:(PhoneMainView *)self.window.rootViewController]; @@ -357,6 +368,11 @@ - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { LOGI(@"%@ - state = %ld", NSStringFromSelector(_cmd), (long)application.applicationState); + + if ([notification.category isEqual:LinphoneManager.instance.iapManager.notificationCategory]){ + [PhoneMainView.instance changeCurrentView:ShopView.compositeViewDescription]; + return; + } [self fixRing]; diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 7b7b8760b..9e831c331 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -1741,6 +1741,7 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { LOGW(@"It seems that Linphone BG mode was deactivated, just skipping"); return; } + [_iapManager check]; // kick up network cnx, just in case [self refreshRegisters]; linphone_core_iterate(theLinphoneCore); @@ -2396,7 +2397,7 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { - (void)inappReady:(NSNotification *)notif { // Query our in-app server to retrieve InApp purchases - [_iapManager retrievePurchases]; + //[_iapManager retrievePurchases]; } #pragma mark - diff --git a/Classes/RenewalManager.h b/Classes/RenewalManager.h deleted file mode 100644 index 81a01114e..000000000 --- a/Classes/RenewalManager.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// RenewalManager.h -// linphone -// -// Created by Simon Morlat on 11/08/2016. -// -// - -#ifndef RenewalManager_h -#define RenewalManager_h - - -@interface RenewalManager : NSObject { -@protected - -@private - -@public - -} - - -#endif /* RenewalManager_h */ diff --git a/Resources/linphonerc-factory b/Resources/linphonerc-factory index 163adef30..25e45f727 100644 --- a/Resources/linphonerc-factory +++ b/Resources/linphonerc-factory @@ -34,4 +34,8 @@ display_filter_auto_rotate=0 enabled=1 paid_account_id=sipAccount_12m receipt_validation_url=https://www.linphone.org/inapp.php -products_list=sipAccount_12m \ No newline at end of file +products_list=sipAccount_12m +expiry_check_period=30 +warn_before_expiry_period=160 +expiry_time_test=180 + diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 05e3711cd..6367cc89f 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -943,7 +943,6 @@ 570742631D5A1860004B9C84 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ShopView.strings; sourceTree = ""; }; 570742651D5A1868004B9C84 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/ShopView.strings; sourceTree = ""; }; 570742661D5A63DB004B9C84 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; - 570742681D5C852B004B9C84 /* RenewalManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenewalManager.h; sourceTree = ""; }; 630589DE1B4E810900EFAE36 /* ChatTester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatTester.h; sourceTree = ""; }; 630589DF1B4E810900EFAE36 /* ChatTester.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatTester.m; sourceTree = ""; }; 630589E01B4E810900EFAE36 /* ContactsTester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsTester.h; sourceTree = ""; }; @@ -2053,7 +2052,6 @@ D326483415887D4400930C67 /* Utils */, 34216F3E1547EBCD00EA9777 /* VideoZoomHandler.h */, 34216F3F1547EBCD00EA9777 /* VideoZoomHandler.m */, - 570742681D5C852B004B9C84 /* RenewalManager.h */, ); path = Classes; sourceTree = "";