From ae5f9f81594e7f941e332648f13fcd08addc8ad4 Mon Sep 17 00:00:00 2001 From: Worthing ~ <115107835+w-goog@users.noreply.github.com> Date: Thu, 15 Oct 2026 14:01:27 -0700 Subject: [PATCH 1/2] g-orchestrated: inject application and alert presenter into GIDEMMErrorHandler --- GoogleSignIn/Sources/GIDEMMErrorHandler.h | 17 ++++++ GoogleSignIn/Sources/GIDEMMErrorHandler.m | 70 ++++++++--------------- 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/GoogleSignIn/Sources/GIDEMMErrorHandler.h b/GoogleSignIn/Sources/GIDEMMErrorHandler.h index 5051f56e..1d3efbc4 100644 --- a/GoogleSignIn/Sources/GIDEMMErrorHandler.h +++ b/GoogleSignIn/Sources/GIDEMMErrorHandler.h @@ -18,6 +18,10 @@ #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST #import +#import + +#import "GoogleSignIn/Sources/GIDApplication/API/GIDApplication.h" +#import "GoogleSignIn/Sources/GIDEMMAlertPresenter/API/GIDEMMAlertPresenter.h" NS_ASSUME_NONNULL_BEGIN @@ -27,6 +31,19 @@ NS_ASSUME_NONNULL_BEGIN // Retrieve the shared instance of this class. + (instancetype)sharedInstance; +// Creates a handler that finds the key window and opens URLs through `application`, and shows its +// alerts through `alertPresenter`. +- (instancetype)initWithApplication:(id)application + alertPresenter:(id)alertPresenter + NS_DESIGNATED_INITIALIZER; + +// Creates a handler backed by `UIApplication.sharedApplication` and a `GIDEMMAlertWindowPresenter`. +- (instancetype)init; + +// Returns the application's key window, or nil if there is none. +// Exposed for the unit tests. +- (nullable UIWindow *)keyWindow; + // Handles EMM-specific errors in the server |response|. |completion| is always called // exactly once, asynchronously on the main thread, with |YES| if |response| carries an EMM // error and |NO| otherwise. For an EMM error, a remediation dialog is presented and diff --git a/GoogleSignIn/Sources/GIDEMMErrorHandler.m b/GoogleSignIn/Sources/GIDEMMErrorHandler.m index 019d6136..a5b492d3 100644 --- a/GoogleSignIn/Sources/GIDEMMErrorHandler.m +++ b/GoogleSignIn/Sources/GIDEMMErrorHandler.m @@ -19,6 +19,8 @@ #import +#import "GoogleSignIn/Sources/GIDApplication/Implementation/GIDSharedApplication.h" +#import "GoogleSignIn/Sources/GIDEMMAlertPresenter/Implementation/GIDEMMAlertWindowPresenter.h" #import "GoogleSignIn/Sources/GIDSignInStrings.h" NS_ASSUME_NONNULL_BEGIN @@ -43,6 +45,8 @@ } ErrorCode; @implementation GIDEMMErrorHandler { + id _application; + id _alertPresenter; // Whether or not a dialog is pending user interaction. BOOL _pendingDialog; } @@ -56,6 +60,21 @@ + (instancetype)sharedInstance { return sharedInstance; } +- (instancetype)initWithApplication:(id)application + alertPresenter:(id)alertPresenter { + self = [super init]; + if (self) { + _application = application; + _alertPresenter = alertPresenter; + } + return self; +} + +- (instancetype)init { + return [self initWithApplication:[[GIDSharedApplication alloc] init] + alertPresenter:[[GIDEMMAlertWindowPresenter alloc] init]]; +} + - (void)handleErrorFromResponse:(NSDictionary *)response completion:(void (^)(BOOL handled))completion { ErrorCode errorCode = ErrorCodeNone; @@ -119,26 +138,8 @@ - (void)handleErrorFromResponse:(NSDictionary *)response completion(YES); return; } - UIWindow *alertWindow; - if (@available(iOS 13, *)) { - if (keyWindow.windowScene) { - alertWindow = [[UIWindow alloc] initWithWindowScene:keyWindow.windowScene]; - } - } - if (!alertWindow) { - CGRect keyWindowBounds = CGRectIsEmpty(keyWindow.bounds) ? - keyWindow.bounds : [UIScreen mainScreen].bounds; - alertWindow = [[UIWindow alloc] initWithFrame:keyWindowBounds]; - } - alertWindow.backgroundColor = [UIColor clearColor]; - alertWindow.rootViewController = [[UIViewController alloc] init]; - alertWindow.rootViewController.view.backgroundColor = [UIColor clearColor]; - alertWindow.windowLevel = UIWindowLevelAlert; - [alertWindow makeKeyAndVisible]; void (^finish)(void) = ^{ - alertWindow.hidden = YES; - alertWindow.rootViewController = nil; - [keyWindow makeKeyAndVisible]; + [self->_alertPresenter dismissAlert]; clearPendingDialog(); completion(YES); }; @@ -157,7 +158,7 @@ - (void)handleErrorFromResponse:(NSDictionary *)response break; } if (alert) { - [alertWindow.rootViewController presentViewController:alert animated:YES completion:nil]; + [self->_alertPresenter presentAlert:alert overKeyWindow:keyWindow]; } else { // Should not happen but just in case. finish(); @@ -167,32 +168,7 @@ - (void)handleErrorFromResponse:(NSDictionary *)response // This method is exposed to the unit test. - (nullable UIWindow *)keyWindow { -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 - if (@available(iOS 15, *)) { - for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) { - if ([scene isKindOfClass:[UIWindowScene class]] && - scene.activationState == UISceneActivationStateForegroundActive) { - return ((UIWindowScene *)scene).keyWindow; - } - } - } else -#endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 - { -#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_15_0 - if (@available(iOS 13, *)) { - for (UIWindow *window in UIApplication.sharedApplication.windows) { - if (window.isKeyWindow) { - return window; - } - } - } else { -#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_13_0 - return UIApplication.sharedApplication.keyWindow; -#endif // __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_13_0 - } -#endif // __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_15_0 - } - return nil; + return [_application keyWindow]; } #pragma mark - Alerts @@ -286,7 +262,7 @@ - (UIAlertController *)appVerificationRequiredAlertWithURL:(nullable NSURL *)url } - (void)openURL:(NSURL *)url { - [UIApplication.sharedApplication openURL:url options:@{} completionHandler:nil]; + [_application openURL:url]; } #pragma mark - Localization From 64b6bfe67b6deee6df810ab876344575c011b2e7 Mon Sep 17 00:00:00 2001 From: Worthing ~ <115107835+w-goog@users.noreply.github.com> Date: Tue, 27 Oct 2026 11:09:34 -0700 Subject: [PATCH 2/2] g-orchestrated: Follow the Objective-C style guide in GIDEMMErrorHandler --- GoogleSignIn/Sources/GIDEMMErrorHandler.h | 25 ++++++++++++----------- GoogleSignIn/Sources/GIDEMMErrorHandler.m | 2 ++ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/GoogleSignIn/Sources/GIDEMMErrorHandler.h b/GoogleSignIn/Sources/GIDEMMErrorHandler.h index 1d3efbc4..9f7ef71c 100644 --- a/GoogleSignIn/Sources/GIDEMMErrorHandler.h +++ b/GoogleSignIn/Sources/GIDEMMErrorHandler.h @@ -25,30 +25,31 @@ NS_ASSUME_NONNULL_BEGIN -// The handler for displaying EMM-specific errors to users. +/// The handler for displaying EMM-specific errors to users. @interface GIDEMMErrorHandler : NSObject -// Retrieve the shared instance of this class. +/// Returns the shared instance of this class. + (instancetype)sharedInstance; -// Creates a handler that finds the key window and opens URLs through `application`, and shows its -// alerts through `alertPresenter`. +/// Creates a handler that finds the key window and opens URLs through `application`, and shows its +/// alerts through `alertPresenter`. - (instancetype)initWithApplication:(id)application alertPresenter:(id)alertPresenter NS_DESIGNATED_INITIALIZER; -// Creates a handler backed by `UIApplication.sharedApplication` and a `GIDEMMAlertWindowPresenter`. +/// Creates a handler backed by `UIApplication.sharedApplication` and a +/// `GIDEMMAlertWindowPresenter`. - (instancetype)init; -// Returns the application's key window, or nil if there is none. -// Exposed for the unit tests. +/// Returns the application's key window, or nil if there is none. +/// Exposed for the unit tests. - (nullable UIWindow *)keyWindow; -// Handles EMM-specific errors in the server |response|. |completion| is always called -// exactly once, asynchronously on the main thread, with |YES| if |response| carries an EMM -// error and |NO| otherwise. For an EMM error, a remediation dialog is presented and -// |completion| is called after the user dismisses it — unless another EMM dialog is already -// pending or no dialog can be presented, in which case it is called as soon as possible. +/// Handles EMM-specific errors in the server |response|. |completion| is always called +/// exactly once, asynchronously on the main thread, with |YES| if |response| carries an EMM +/// error and |NO| otherwise. For an EMM error, a remediation dialog is presented and +/// |completion| is called after the user dismisses it — unless another EMM dialog is already +/// pending or no dialog can be presented, in which case it is called as soon as possible. - (void)handleErrorFromResponse:(NSDictionary *)response completion:(void (^)(BOOL handled))completion; diff --git a/GoogleSignIn/Sources/GIDEMMErrorHandler.m b/GoogleSignIn/Sources/GIDEMMErrorHandler.m index a5b492d3..f6ef6888 100644 --- a/GoogleSignIn/Sources/GIDEMMErrorHandler.m +++ b/GoogleSignIn/Sources/GIDEMMErrorHandler.m @@ -45,7 +45,9 @@ } ErrorCode; @implementation GIDEMMErrorHandler { + // Finds the key window and opens URLs. id _application; + // Shows and hides the remediation alert. id _alertPresenter; // Whether or not a dialog is pending user interaction. BOOL _pendingDialog;