Merge branch 'bugfix/session_timer_bkg_reset' into 'develop'
Fix the session timer ### Summary Fixes an issue with the session timer resetting without a session update when the app returns from the background. ### JIRA Ticket https://onejira.verizon.com/browse/PRODDEF-1509 See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/246
This commit is contained in:
commit
08a1718f11
@ -22,6 +22,7 @@
|
||||
@property (nullable, strong, nonatomic) MVMCoreLoadObject *loadObject;
|
||||
@property (nullable, strong, nonatomic) NSDictionary *dataForPage;
|
||||
@property (nullable, strong, nonatomic) DelegateObject *delegateObject;
|
||||
@property (nullable, nonatomic, readonly) NSString *finalLoadSource;
|
||||
@property (nonatomic) BOOL backgroundLoad;
|
||||
@property (nonatomic, getter=areDependenciesAdded) BOOL dependenciesAdded;
|
||||
|
||||
|
||||
@ -77,6 +77,10 @@
|
||||
[super start];
|
||||
}
|
||||
|
||||
- (NSString *)finalLoadSource {
|
||||
return _sessionTask.currentRequest.URL.absoluteString;
|
||||
}
|
||||
|
||||
- (void)markAsFinished {
|
||||
|
||||
// stop any loading animation we may have started
|
||||
|
||||
@ -13,50 +13,56 @@
|
||||
|
||||
@interface MVMCoreSessionTimeHandler : NSObject
|
||||
|
||||
// The time that we started the last session timer.
|
||||
@property (assign, nonatomic, readonly) NSTimeInterval timeTimerStarted;
|
||||
/// The number of seconds ago that we started the last session timer. A value of -1 will be returned for sessions not started.
|
||||
@property (nonatomic, readonly) NSTimeInterval timeSinceStart;
|
||||
|
||||
// Keeps track of if the session is currently being timed. Used for entering from the background.
|
||||
/// The number of seconds remaining until a warning will occur. A value of 0 will be returned for sessions not started or warning tracking is not enabled.
|
||||
@property (nonatomic, readonly) NSTimeInterval remainingTimeUntilWarning;
|
||||
|
||||
/// The number of seconds remaining until a timeout will occur. A value of 0 will be returned for sessions not started or timeout tracking is not enabled.
|
||||
@property (nonatomic, readonly) NSTimeInterval remainingTimeUntiTimeout;
|
||||
|
||||
/// Keeps track of if the session is currently being timed. Used for entering from the background.
|
||||
@property (assign, nonatomic, readonly) BOOL sessionBeingTimed;
|
||||
|
||||
// Keeps track of if the session has already timed out.
|
||||
/// Keeps track of if the session has already timed out.
|
||||
@property (assign, nonatomic, readonly) BOOL sessionTimedOut;
|
||||
|
||||
#pragma mark - functions to override
|
||||
|
||||
// Can override to provide a time until the warning shows in seconds. Set to 0 if there should be no warning. Default is 0
|
||||
/// Can override to provide a time until the warning shows in seconds. Set to 0 if there should be no warning. Default is 0.
|
||||
- (NSTimeInterval)timeUntilWarning;
|
||||
|
||||
// Can override to provide a time until the timeout happens in seconds. If there is a warning, then this value is used after the warning happens. Set to 0 if there should be no timeout. Default is 0.
|
||||
/// Can override to provide a time until the timeout happens in seconds. If there is a warning, then this value is used after the warning happens. Set to 0 if there should be no timeout. Default is 0.
|
||||
- (NSTimeInterval)timeUntilTimeout;
|
||||
|
||||
// Starts the timeout timer. Override to handle what happens on timeout warning. Should call super if want the timeout timer going.
|
||||
/// Starts the timeout timer. Override to handle what happens on timeout warning. Should call super if want the timeout timer going.
|
||||
- (void)sessionTimeoutWarning NS_REQUIRES_SUPER;
|
||||
|
||||
// Called when the session has timed out. Override to handle what happens on timeout. Should call super. Can be called to force timeout... should never need to call unless simulating timout.
|
||||
/// Called when the session has timed out. Override to handle what happens on timeout. Should call super. Can be called to force timeout... should never need to call unless simulating timout.
|
||||
- (void)sessionTimeout:(BOOL)whileInBackground NS_REQUIRES_SUPER;
|
||||
|
||||
// Keeps the session alive. A boolean for if we should show the alert if there is an error. Does nothing by default. Can override to do something.
|
||||
/// Keeps the session alive. A boolean for if we should show the alert if there is an error. Does nothing by default. Can override to do something.
|
||||
- (void)sendKeepAliveToServer:(BOOL)notifyUserIfError;
|
||||
|
||||
// Invalidates the server session and then calls the completion handler. Error may or may not populate. By default this only calls the completion handler, override to invalidate your server session as you see fit then call completion.
|
||||
/// Invalidates the server session and then calls the completion handler. Error may or may not populate. By default this only calls the completion handler, override to invalidate your server session as you see fit then call completion.
|
||||
- (void)invalidateSession:(void (^ __nullable)(MVMCoreErrorObject * _Nullable error))completion;
|
||||
|
||||
#pragma mark - Session timer functions
|
||||
|
||||
// Returns the shared instance of this singleton
|
||||
/// Returns the shared instance of this singleton
|
||||
+ (nullable instancetype)sharedSessionHandler;
|
||||
|
||||
// Starts the session timer. Should be called after every response from the server. Happens on the main thread.
|
||||
/// Starts the session timer. Should be called after every response from the server. Happens on the main thread.
|
||||
- (void)startSessionTimer;
|
||||
|
||||
// Should only be used in rare occassions, like on the original wifi screen.
|
||||
/// Completely stop the session timer. Should only be used in rare occassions, like on the original wifi screen.
|
||||
- (void)stopSessionTimer;
|
||||
|
||||
// Returns whether the app is in session.
|
||||
/// Returns whether the app is in session.
|
||||
- (BOOL)isAppInSession;
|
||||
|
||||
// Resets everything.
|
||||
/// Resets everything.
|
||||
- (void)resetState;
|
||||
|
||||
@end
|
||||
|
||||
@ -24,22 +24,22 @@
|
||||
@property (strong, nonatomic) NSTimer *sessionWarningTimer;
|
||||
@property (strong, nonatomic) NSTimer *sessionTimer;
|
||||
|
||||
// The time that we started the last session timer.
|
||||
/// The time that we started the last session timer.
|
||||
@property (assign, nonatomic, readwrite) NSTimeInterval timeTimerStarted;
|
||||
|
||||
// Keeps track of if the session is currently being timed. Used for entering from the background.
|
||||
/// Keeps track of if the session is currently being timed. Used for entering from the background.
|
||||
@property (assign, nonatomic, readwrite) BOOL sessionBeingTimed;
|
||||
|
||||
// Keeps track of if the session has already timed out.
|
||||
/// Keeps track of if the session has already timed out.
|
||||
@property (assign, nonatomic, readwrite) BOOL sessionTimedOut;
|
||||
|
||||
@property (assign, nonatomic) NSTimeInterval secondsUntilWarning;
|
||||
@property (assign, nonatomic) NSTimeInterval secondsUntilTimeout;
|
||||
|
||||
// Should be called when the app enters the background.
|
||||
/// Should be called when the app enters the background.
|
||||
- (void)appEnteredBackground;
|
||||
|
||||
// Should be called when the app enters the foreground.
|
||||
/// Should be called when the app enters the foreground.
|
||||
- (void)appEnteredForeground;
|
||||
|
||||
@end
|
||||
@ -55,6 +55,7 @@
|
||||
// Adds notifications for if the app entered the background/foreground.
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnteredBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnteredForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
|
||||
[self resetStartTime];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -85,6 +86,45 @@
|
||||
- (void)sendKeepAliveToServer:(BOOL)notifyUserIfError {
|
||||
}
|
||||
|
||||
#pragma mark - State
|
||||
|
||||
- (void)markStartTime {
|
||||
self.timeTimerStarted = [NSDate timeIntervalSinceReferenceDate];
|
||||
}
|
||||
|
||||
- (void)resetStartTime {
|
||||
self.timeTimerStarted = -1;
|
||||
}
|
||||
|
||||
- (NSTimeInterval)timeSinceStart {
|
||||
if (self.timeTimerStarted < 0) {
|
||||
return -1;
|
||||
}
|
||||
return [NSDate timeIntervalSinceReferenceDate] - self.timeTimerStarted;
|
||||
}
|
||||
|
||||
- (BOOL)isWarningEnabled {
|
||||
return [self isTimeoutEnabled] && !fequal(0, self.secondsUntilWarning);
|
||||
}
|
||||
|
||||
- (BOOL)isTimeoutEnabled {
|
||||
return !fequal(0, self.secondsUntilTimeout);
|
||||
}
|
||||
|
||||
- (NSTimeInterval)remainingTimeUntilWarning {
|
||||
if (self.timeTimerStarted < 0 || ![self isWarningEnabled]) {
|
||||
return 0;
|
||||
}
|
||||
return self.secondsUntilWarning - self.timeSinceStart;
|
||||
}
|
||||
|
||||
- (NSTimeInterval)remainingTimeUntiTimeout {
|
||||
if (self.timeTimerStarted < 0 || ![self isTimeoutEnabled]) {
|
||||
return 0;
|
||||
}
|
||||
return self.secondsUntilTimeout - self.timeSinceStart;
|
||||
}
|
||||
|
||||
#pragma mark - Session timer functions
|
||||
|
||||
- (void)startSessionTimer {
|
||||
@ -97,17 +137,33 @@
|
||||
|
||||
self.secondsUntilWarning = [self timeUntilWarning];
|
||||
self.secondsUntilTimeout = [self timeUntilTimeout];
|
||||
if (!fequal(0, self.secondsUntilTimeout)) {
|
||||
|
||||
if (self.isTimeoutEnabled) {
|
||||
self.sessionBeingTimed = YES;
|
||||
self.timeTimerStarted = [NSDate timeIntervalSinceReferenceDate];
|
||||
[self markStartTime];
|
||||
[self resumeSessionTimer];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Only start physical timer if active, otherwise will begin once entering foreground.
|
||||
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive && !fequal(0, self.secondsUntilTimeout)) {
|
||||
if (!fequal(0, self.secondsUntilWarning)) {
|
||||
self.sessionWarningTimer = [NSTimer scheduledTimerWithTimeInterval:self.secondsUntilWarning target:self selector:@selector(sessionTimeoutWarning) userInfo:nil repeats:NO];
|
||||
}
|
||||
self.sessionTimer = [NSTimer scheduledTimerWithTimeInterval:self.secondsUntilTimeout target:self selector:@selector(sessionTimeout:) userInfo:nil repeats:NO];
|
||||
/// Resume the session timers if they are stopped.
|
||||
- (void)resumeSessionTimer {
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void) {
|
||||
// Only start physical timer if active, otherwise will begin once entering foreground. FaceId prompt is considered UIApplicationStateInactive.
|
||||
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.isTimeoutEnabled && ![self.sessionTimer isValid]) {
|
||||
// Session timeout, implicitly whileInBackround as no. Note based on scheduledTimerWithTimeInterval, if the remaining time < 0, this will fire near immediately.
|
||||
self.sessionTimer = [NSTimer scheduledTimerWithTimeInterval:[self remainingTimeUntiTimeout] target:self selector:@selector(sessionTimeout:) userInfo:nil repeats:NO];
|
||||
MVMCoreLog(@"Session timeout will fire at: %@", self.sessionTimer.fireDate);
|
||||
|
||||
// Only setup a warning timer if there is a timeout timer. Note based on scheduledTimerWithTimeInterval, if the remaining time < 0, this will fire near immediately.
|
||||
if (self.isWarningEnabled && ![self.sessionWarningTimer isValid]) {
|
||||
self.sessionWarningTimer = [NSTimer scheduledTimerWithTimeInterval:[self remainingTimeUntilWarning] target:self selector:@selector(sessionTimeoutWarning) userInfo:nil repeats:NO];
|
||||
MVMCoreLog(@"Session warning will fire at: %@", self.sessionWarningTimer.fireDate);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -137,31 +193,14 @@
|
||||
}
|
||||
|
||||
- (void)appEnteredForeground {
|
||||
|
||||
if (self.sessionBeingTimed || self.sessionTimedOut) {
|
||||
|
||||
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
|
||||
if ((!fequal(0, self.secondsUntilWarning) && now > self.timeTimerStarted + self.secondsUntilWarning) || (!fequal(0, self.secondsUntilTimeout) && now > self.timeTimerStarted + self.secondsUntilTimeout)) {
|
||||
|
||||
// Timeout if we are passed the warning.
|
||||
[self sessionTimeout:YES];
|
||||
} else {
|
||||
if (!fequal(0, self.secondsUntilWarning)) {
|
||||
|
||||
// Restart the warning timer!
|
||||
NSTimeInterval timeLeftTillWarning = self.timeTimerStarted + self.secondsUntilWarning - now;
|
||||
[self.sessionWarningTimer invalidate];
|
||||
self.sessionWarningTimer = [NSTimer scheduledTimerWithTimeInterval:timeLeftTillWarning target:self selector:@selector(sessionTimeoutWarning) userInfo:nil repeats:NO];
|
||||
}
|
||||
if (!fequal(0, self.secondsUntilTimeout)) {
|
||||
|
||||
// Restart the timeout timer!
|
||||
NSTimeInterval timeLeftTillTimeout = self.timeTimerStarted + self.secondsUntilTimeout - now;
|
||||
[self.sessionTimer invalidate];
|
||||
self.sessionTimer = [NSTimer scheduledTimerWithTimeInterval:timeLeftTillTimeout target:self selector:@selector(sessionTimeout:) userInfo:nil repeats:NO];
|
||||
}
|
||||
}
|
||||
// Special return logic to cancel when returning in warning track. This is not in the revalidateSessionTimestamp in order to prevent API checks to isAppInSession from timing out the session from under the user warning period.
|
||||
if (self.isWarningEnabled && self.remainingTimeUntilWarning < 0) {
|
||||
[self sessionTimeout:YES];
|
||||
}
|
||||
|
||||
// Revalidate first to check if we should be in the timeout state.
|
||||
[self revalidateSessionTimestamp];
|
||||
[self sendKeepAliveToServer:NO];
|
||||
}
|
||||
|
||||
- (void)invalidateSession:(void (^ __nullable)(MVMCoreErrorObject * _Nullable error))completion {
|
||||
@ -170,24 +209,18 @@
|
||||
|
||||
// Checks to make sure session is still valid and that the timer is running.
|
||||
- (void)revalidateSessionTimestamp {
|
||||
if (self.sessionBeingTimed && !self.sessionTimedOut) {
|
||||
|
||||
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
|
||||
if ((!fequal(0, self.secondsUntilWarning) && now > self.timeTimerStarted + self.secondsUntilWarning) || (!fequal(0, self.secondsUntilTimeout) && now > self.timeTimerStarted + self.secondsUntilTimeout)) {
|
||||
self.sessionTimedOut = YES;
|
||||
[self.sessionWarningTimer invalidate];
|
||||
self.sessionWarningTimer = nil;
|
||||
[self.sessionTimer invalidate];
|
||||
self.sessionTimer = nil;
|
||||
} else if (![self.sessionTimer isValid]) {
|
||||
// Restart the session timer!
|
||||
[self startSessionTimer];
|
||||
if (self.sessionBeingTimed || self.sessionTimedOut) {
|
||||
if (self.isTimeoutEnabled && self.remainingTimeUntiTimeout < 0) {
|
||||
// Force a timeout if we are passed the timeout interval.
|
||||
[self sessionTimeout:YES];
|
||||
} else {
|
||||
[self resumeSessionTimer];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isAppInSession {
|
||||
[self revalidateSessionTimestamp];
|
||||
[self revalidateSessionTimestamp]; // Possible race condition hazard. Session timeouts will happen as if they are in background. If isAppInSession is called right before foreground trigger, it could potentially suppress the dialog.
|
||||
return self.sessionBeingTimed && !self.sessionTimedOut;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user