MOBILE-4113 geolocation: Fix screen locked before allowing

main
Dani Palou 2022-07-26 08:41:30 +02:00
parent aaa98793aa
commit 8d64282ce8
4 changed files with 47 additions and 5 deletions

View File

@ -19,6 +19,9 @@ import { CoreApp } from '@services/app';
import { CoreAnyError, CoreError } from '@classes/errors/error'; import { CoreAnyError, CoreError } from '@classes/errors/error';
import { Geolocation, Diagnostic, makeSingleton } from '@singletons'; import { Geolocation, Diagnostic, makeSingleton } from '@singletons';
import { CoreUtils } from './utils/utils'; import { CoreUtils } from './utils/utils';
import { CorePlatform } from './platform';
import { CoreSilentError } from '@classes/errors/silenterror';
import { CoreSubscriptions } from '@singletons/subscriptions';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class CoreGeolocationProvider { export class CoreGeolocationProvider {
@ -97,7 +100,7 @@ export class CoreGeolocationProvider {
} }
// Fall through. // Fall through.
case Diagnostic.permissionStatus.NOT_REQUESTED: case Diagnostic.permissionStatus.NOT_REQUESTED:
await Diagnostic.requestLocationAuthorization(); await this.requestLocationAuthorization();
await CoreApp.waitForResume(500); await CoreApp.waitForResume(500);
await this.doAuthorizeLocation(true); await this.doAuthorizeLocation(true);
@ -133,6 +136,24 @@ export class CoreGeolocationProvider {
return CoreUtils.promiseWorks(Diagnostic.getLocationAuthorizationStatus()); return CoreUtils.promiseWorks(Diagnostic.getLocationAuthorizationStatus());
} }
/**
* Request and return the location authorization status for the application.
*/
protected async requestLocationAuthorization(): Promise<void> {
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); export const CoreGeolocation = makeSingleton(CoreGeolocationProvider);

View File

@ -670,7 +670,7 @@ export class CoreDomUtilsProvider {
* @param error Error to check. * @param error Error to check.
* @return Whether it's a canceled error. * @return Whether it's a canceled error.
*/ */
isSilentError(error: CoreError | CoreTextErrorObject | string): boolean { isSilentError(error: CoreAnyError): boolean {
return error instanceof CoreSilentError; return error instanceof CoreSilentError;
} }
@ -1378,8 +1378,8 @@ export class CoreDomUtilsProvider {
needsTranslate = false, needsTranslate = false,
autocloseTime?: number, autocloseTime?: number,
): Promise<HTMLIonAlertElement | null> { ): Promise<HTMLIonAlertElement | null> {
if (this.isCanceledError(error)) { if (this.isCanceledError(error) || this.isSilentError(error)) {
// It's a canceled error, don't display an error. // It's a canceled or a silent error, don't display an error.
return null; return null;
} }

View File

@ -31,8 +31,13 @@ export class CoreSubscriptions {
* @param subscribable Subscribable to listen to. * @param subscribable Subscribable to listen to.
* @param onSuccess Callback to run when the subscription is updated. * @param onSuccess Callback to run when the subscription is updated.
* @param onError Callback to run when the an error happens. * @param onError Callback to run when the an error happens.
* @return A function to unsubscribe.
*/ */
static once<T>(subscribable: Subscribable<T>, onSuccess: (value: T) => unknown, onError?: (error: unknown) => unknown): void { static once<T>(
subscribable: Subscribable<T>,
onSuccess: (value: T) => unknown,
onError?: (error: unknown) => unknown,
): () => void {
let unsubscribe = false; let unsubscribe = false;
let subscription: Subscription | null = null; let subscription: Subscription | null = null;
@ -56,6 +61,8 @@ export class CoreSubscriptions {
if (unsubscribe) { if (unsubscribe) {
subscription.unsubscribe(); subscription.unsubscribe();
} }
return () => subscription?.unsubscribe();
} }
} }

View File

@ -59,4 +59,18 @@ describe('CoreSubscriptions singleton', () => {
expect(error).not.toHaveBeenCalled(); 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();
});
}); });