| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/browser/shared/ui/util/keyboard_observer_helper.h" |
| |
| #import "base/check.h" |
| #import "base/check_op.h" |
| #import "ios/chrome/common/ui/util/constraints_ui_util.h" |
| #import "ios/chrome/common/ui/util/ui_util.h" |
| #import "ui/base/device_form_factor.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| @interface KeyboardObserverHelper () |
| |
| // Flag that indicates if the keyboard is on screen. |
| @property(nonatomic, readwrite, getter=isKeyboardVisible) BOOL keyboardVisible; |
| |
| @end |
| |
| @implementation KeyboardObserverHelper |
| |
| #pragma mark - Public class methods |
| |
| + (instancetype)sharedKeyboardObserver { |
| static KeyboardObserverHelper* sharedInstance; |
| static dispatch_once_t onceToken; |
| dispatch_once(&onceToken, ^{ |
| sharedInstance = [[KeyboardObserverHelper alloc] init]; |
| }); |
| return sharedInstance; |
| } |
| |
| + (CGFloat)keyboardHeightInWindow:(UIWindow*)window { |
| if (!window) { |
| return 0; |
| } |
| UIView* keyboardView = [KeyboardObserverHelper keyboardViewInWindow:window]; |
| CGRect keyboardFrame = keyboardView.frame; |
| BOOL keyboardCoversFullWidth = |
| CGRectGetWidth(keyboardFrame) >= CGRectGetWidth(window.bounds); |
| BOOL isDocked = CGRectGetMaxY(keyboardFrame) >= CGRectGetMaxY(window.bounds); |
| if (!keyboardCoversFullWidth || !isDocked) { |
| return 0; |
| } |
| CGRect intersection = CGRectIntersection(keyboardFrame, window.bounds); |
| return CGRectGetHeight(intersection); |
| } |
| |
| #pragma mark - Private instance methods |
| |
| - (instancetype)init { |
| self = [super init]; |
| if (self) { |
| [[NSNotificationCenter defaultCenter] |
| addObserver:self |
| selector:@selector(keyboardWillShow:) |
| name:UIKeyboardWillShowNotification |
| object:nil]; |
| [[NSNotificationCenter defaultCenter] |
| addObserver:self |
| selector:@selector(keyboardWillHide:) |
| name:UIKeyboardWillHideNotification |
| object:nil]; |
| _keyboardVisible = NO; |
| } |
| return self; |
| } |
| |
| #pragma mark - Private class methods |
| |
| // Returns the keyboard view in `window`. |
| // keyboard view coordinates {x: keyboard x in window coordinate, |
| // y: keyboard y in window coordinate} |
| // When the keyboard is docked and software (the keyboard spans across the full |
| // width of the screen): |
| // - Fixed window (full screen, split screen): |
| // keyboard size is {width: screen width, |
| // height: keyboard height} |
| // - Floating window (slide over, stage manager): |
| // keyboard size is {width: window width, |
| // height: keyboard and window intersection height} |
| // When the keyboard is hardware: |
| // - Fixed window (full screen, split screen): |
| // keyboard view size is {width: screen width, |
| // height: accessory height} |
| // - Slide over: |
| // keyboard view size is {width: window width, |
| // height: accessory and window intersection height} |
| // - Stage manager: |
| // keyboard view size is {width: window width, height: 0} |
| + (UIView*)keyboardViewInWindow:(UIWindow*)window { |
| if (!window || !window.windowScene || !window.windowScene.windows.count) { |
| return nil; |
| } |
| |
| // Iterate windows in reverse order from frontmost to back. |
| for (UIWindow* w in window.windowScene.windows.reverseObjectEnumerator) { |
| for (UIView* subview in w.subviews) { |
| if ([NSStringFromClass([subview class]) rangeOfString:@"PeripheralHost"] |
| .location != NSNotFound) { |
| return subview; |
| } |
| if ([NSStringFromClass([subview class]) rangeOfString:@"SetContainer"] |
| .location != NSNotFound) { |
| for (UIView* subsubview in subview.subviews) { |
| if ([NSStringFromClass([subsubview class]) rangeOfString:@"SetHost"] |
| .location != NSNotFound) { |
| return subsubview; |
| } |
| } |
| } |
| } |
| } |
| |
| return nil; |
| } |
| |
| #pragma mark - Keyboard Notifications |
| |
| - (void)keyboardWillShow:(NSNotification*)notification { |
| self.keyboardVisible = YES; |
| } |
| |
| - (void)keyboardWillHide:(NSNotification*)notification { |
| self.keyboardVisible = NO; |
| } |
| |
| @end |