Suppress home bar hiding when user is interacting

This commit is contained in:
Cameron Gutman 2019-11-02 15:17:52 -07:00
parent 9f19f5da27
commit 18e2d67f6b
4 changed files with 84 additions and 6 deletions

View File

@ -15,11 +15,18 @@
@end
@protocol UserInteractionDelegate <NSObject>
- (void) userInteractionBegan;
- (void) userInteractionEnded;
@end
@interface StreamView : OSView <UITextFieldDelegate>
@property (nonatomic, retain) IBOutlet UITextField* keyInputField;
- (void) setupStreamView:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate;
- (void) setupStreamView:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate interactionDelegate:(id<UserInteractionDelegate>)interactionDelegate;
- (void) showOnScreenControls;
- (void) setMouseDeltaFactors:(float)x y:(float)y;
- (OnScreenControlsLevel) getCurrentOscState;

View File

@ -30,6 +30,10 @@
UIGestureRecognizer* remoteLongPressRecognizer;
#endif
id<UserInteractionDelegate> interactionDelegate;
NSTimer* interactionTimer;
BOOL hasUserInteracted;
NSDictionary<NSString *, NSNumber *> *dictCodes;
}
@ -46,7 +50,8 @@
#endif
}
- (void) setupStreamView:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate {
- (void) setupStreamView:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate interactionDelegate:(id<UserInteractionDelegate>)interactionDelegate {
self->interactionDelegate = interactionDelegate;
#if TARGET_OS_TV
remotePressRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(remoteButtonPressed:)];
remotePressRecognizer.allowedPressTypes = @[@(UIPressTypeSelect)];
@ -70,6 +75,38 @@
#endif
}
- (void)startInteractionTimer {
// Restart user interaction tracking
hasUserInteracted = NO;
BOOL timerAlreadyRunning = interactionTimer != nil;
// Start/restart the timer
[interactionTimer invalidate];
interactionTimer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(interactionTimerExpired:)
userInfo:nil
repeats:NO];
// Notify the delegate if this was a new user interaction
if (!timerAlreadyRunning) {
[interactionDelegate userInteractionBegan];
}
}
- (void)interactionTimerExpired:(NSTimer *)timer {
if (!hasUserInteracted) {
// User has finished touching the screen
interactionTimer = nil;
[interactionDelegate userInteractionEnded];
}
else {
// User is still touching the screen. Restart the timer.
[self startInteractionTimer];
}
}
- (void) showOnScreenControls {
#if !TARGET_OS_TV
[onScreenControls show];
@ -93,6 +130,10 @@
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
Log(LOG_D, @"Touch down");
// Notify of user interaction and start expiration timer
[self startInteractionTimer];
if (![onScreenControls handleTouchDownEvent:touches]) {
UITouch *touch = [[event allTouches] anyObject];
originalLocation = touchLocation = [touch locationInView:self];
@ -115,6 +156,8 @@
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
hasUserInteracted = YES;
if (![onScreenControls handleTouchMovedEvent:touches]) {
if ([[event allTouches] count] == 1) {
UITouch *touch = [[event allTouches] anyObject];
@ -163,6 +206,9 @@
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
Log(LOG_D, @"Touch up");
hasUserInteracted = YES;
if (![onScreenControls handleTouchUpEvent:touches]) {
[dragTimer invalidate];
dragTimer = nil;

View File

@ -15,9 +15,9 @@
#if TARGET_OS_TV
@import GameController;
@interface StreamFrameViewController : GCEventViewController <ConnectionCallbacks, EdgeDetectionDelegate, GamepadPresenceDelegate>
@interface StreamFrameViewController : GCEventViewController <ConnectionCallbacks, EdgeDetectionDelegate, GamepadPresenceDelegate, UserInteractionDelegate>
#else
@interface StreamFrameViewController : UIViewController <ConnectionCallbacks, EdgeDetectionDelegate, GamepadPresenceDelegate>
@interface StreamFrameViewController : UIViewController <ConnectionCallbacks, EdgeDetectionDelegate, GamepadPresenceDelegate, UserInteractionDelegate>
#endif
@property (strong, nonatomic) IBOutlet UILabel *stageLabel;
@property (strong, nonatomic) IBOutlet UILabel *tipLabel;

View File

@ -25,6 +25,7 @@
UITapGestureRecognizer *_menuDoubleTapGestureRecognizer;
UITextView *_overlayView;
StreamView *_streamView;
BOOL _userIsInteracting;
}
- (void)viewDidAppear:(BOOL)animated
@ -62,7 +63,7 @@
_inactivityTimer = nil;
_streamView = (StreamView*)self.view;
[_streamView setupStreamView:_controllerSupport swipeDelegate:self];
[_streamView setupStreamView:_controllerSupport swipeDelegate:self interactionDelegate:self];
#if TARGET_OS_TV
if (!_menuGestureRecognizer || !_menuDoubleTapGestureRecognizer) {
@ -343,6 +344,29 @@
#endif
}
- (void)userInteractionBegan {
// Disable hiding home bar when user is interacting.
// iOS will force it to be shown anyway, but it will
// also discard our edges deferring system gestures unless
// we willingly give up home bar hiding preference.
_userIsInteracting = YES;
#if !TARGET_OS_TV
if (@available(iOS 11.0, *)) {
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
}
#endif
}
- (void)userInteractionEnded {
// Enable home bar hiding again if conditions allow
_userIsInteracting = NO;
#if !TARGET_OS_TV
if (@available(iOS 11.0, *)) {
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
}
#endif
}
#if !TARGET_OS_TV
// Require a confirmation when streaming to activate a system gesture
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
@ -351,7 +375,8 @@
- (BOOL)prefersHomeIndicatorAutoHidden {
if ([_controllerSupport getConnectedGamepadCount] > 0 &&
[_streamView getCurrentOscState] == OnScreenControlsLevelOff) {
[_streamView getCurrentOscState] == OnScreenControlsLevelOff &&
_userIsInteracting == NO) {
// Autohide the home bar when a gamepad is connected
// and the on-screen controls are disabled. We can't
// do this all the time because any touch on the display