Merge pull request #3350 from dpalou/MOBILE-4113

MOBILE-4113 geolocation: Fix screen locked before allowing
main
Noel De Martin 2022-08-03 11:20:37 +02:00 committed by GitHub
commit 31499beec6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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 { 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<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);

View File

@ -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<HTMLIonAlertElement | null> {
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;
}

View File

@ -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<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 subscription: Subscription | null = null;
@ -56,6 +61,8 @@ export class CoreSubscriptions {
if (unsubscribe) {
subscription.unsubscribe();
}
return () => subscription?.unsubscribe();
}
}

View File

@ -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();
});
});