From 8d64282ce8bc34916fb63de2fc6280533183f4a9 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Tue, 26 Jul 2022 08:41:30 +0200 Subject: [PATCH] MOBILE-4113 geolocation: Fix screen locked before allowing --- src/core/services/geolocation.ts | 23 ++++++++++++++++++- src/core/services/utils/dom.ts | 6 ++--- src/core/singletons/subscriptions.ts | 9 +++++++- .../singletons/tests/subscriptions.test.ts | 14 +++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/core/services/geolocation.ts b/src/core/services/geolocation.ts index 61f34d953..428726df1 100644 --- a/src/core/services/geolocation.ts +++ b/src/core/services/geolocation.ts @@ -19,6 +19,9 @@ import { CoreApp } from '@services/app'; import { CoreAnyError, CoreError } from '@classes/errors/error'; import { Geolocation, Diagnostic, makeSingleton } from '@singletons'; import { CoreUtils } from './utils/utils'; +import { CorePlatform } from './platform'; +import { CoreSilentError } from '@classes/errors/silenterror'; +import { CoreSubscriptions } from '@singletons/subscriptions'; @Injectable({ providedIn: 'root' }) export class CoreGeolocationProvider { @@ -97,7 +100,7 @@ export class CoreGeolocationProvider { } // Fall through. case Diagnostic.permissionStatus.NOT_REQUESTED: - await Diagnostic.requestLocationAuthorization(); + await this.requestLocationAuthorization(); await CoreApp.waitForResume(500); await this.doAuthorizeLocation(true); @@ -133,6 +136,24 @@ export class CoreGeolocationProvider { return CoreUtils.promiseWorks(Diagnostic.getLocationAuthorizationStatus()); } + /** + * Request and return the location authorization status for the application. + */ + protected async requestLocationAuthorization(): Promise { + if (!CoreApp.isIOS()) { + await Diagnostic.requestLocationAuthorization(); + + return; + } + + // In iOS, the modal disappears when the screen is locked and the promise never ends. Treat that case. + return new Promise((resolve, reject) => { + // Don't display an error if app is sent to the background, just finish the process. + const unsubscribe = CoreSubscriptions.once(CorePlatform.pause, () => reject(new CoreSilentError())); + Diagnostic.requestLocationAuthorization().then(() => resolve(), reject).finally(() => unsubscribe()); + }); + } + } export const CoreGeolocation = makeSingleton(CoreGeolocationProvider); diff --git a/src/core/services/utils/dom.ts b/src/core/services/utils/dom.ts index 3ee12557a..eb0289307 100644 --- a/src/core/services/utils/dom.ts +++ b/src/core/services/utils/dom.ts @@ -670,7 +670,7 @@ export class CoreDomUtilsProvider { * @param error Error to check. * @return Whether it's a canceled error. */ - isSilentError(error: CoreError | CoreTextErrorObject | string): boolean { + isSilentError(error: CoreAnyError): boolean { return error instanceof CoreSilentError; } @@ -1378,8 +1378,8 @@ export class CoreDomUtilsProvider { needsTranslate = false, autocloseTime?: number, ): Promise { - if (this.isCanceledError(error)) { - // It's a canceled error, don't display an error. + if (this.isCanceledError(error) || this.isSilentError(error)) { + // It's a canceled or a silent error, don't display an error. return null; } diff --git a/src/core/singletons/subscriptions.ts b/src/core/singletons/subscriptions.ts index e65b862d5..88e9dc1dd 100644 --- a/src/core/singletons/subscriptions.ts +++ b/src/core/singletons/subscriptions.ts @@ -31,8 +31,13 @@ export class CoreSubscriptions { * @param subscribable Subscribable to listen to. * @param onSuccess Callback to run when the subscription is updated. * @param onError Callback to run when the an error happens. + * @return A function to unsubscribe. */ - static once(subscribable: Subscribable, onSuccess: (value: T) => unknown, onError?: (error: unknown) => unknown): void { + static once( + subscribable: Subscribable, + onSuccess: (value: T) => unknown, + onError?: (error: unknown) => unknown, + ): () => void { let unsubscribe = false; let subscription: Subscription | null = null; @@ -56,6 +61,8 @@ export class CoreSubscriptions { if (unsubscribe) { subscription.unsubscribe(); } + + return () => subscription?.unsubscribe(); } } diff --git a/src/core/singletons/tests/subscriptions.test.ts b/src/core/singletons/tests/subscriptions.test.ts index 7c7a08412..5ea863a8a 100644 --- a/src/core/singletons/tests/subscriptions.test.ts +++ b/src/core/singletons/tests/subscriptions.test.ts @@ -59,4 +59,18 @@ describe('CoreSubscriptions singleton', () => { expect(error).not.toHaveBeenCalled(); }); + it('allows unsubscribing from outside the once function', async () => { + const subject = new Subject(); + const success = jest.fn(); + const error = jest.fn(); + + const unsubscribe = CoreSubscriptions.once(subject, success, error); + unsubscribe(); + + subject.next('foo'); + subject.error('bar'); + expect(success).not.toHaveBeenCalled(); + expect(error).not.toHaveBeenCalled(); + }); + });