diff --git a/scripts/langindex.json b/scripts/langindex.json index 1ef97ed16..7cd0b2a57 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -1474,6 +1474,7 @@ "core.cannotconnecttrouble": "local_moodlemobileapp", "core.cannotconnectverify": "local_moodlemobileapp", "core.cannotdownloadfiles": "local_moodlemobileapp", + "core.cannotinstallapk": "local_moodlemobileapp", "core.cannotlogoutpageblocks": "local_moodlemobileapp", "core.cannotopeninapp": "local_moodlemobileapp", "core.cannotopeninappdownload": "local_moodlemobileapp", diff --git a/src/core/lang.json b/src/core/lang.json index e61537e0e..bdfd886f4 100644 --- a/src/core/lang.json +++ b/src/core/lang.json @@ -18,6 +18,7 @@ "cannotconnecttrouble": "We're having trouble connecting to your site.", "cannotconnectverify": "Please check the address is correct.", "cannotdownloadfiles": "File downloading is disabled. Please contact your site administrator.", + "cannotinstallapk": "For security reasons, you can't install unknown apps on your device from this app. Please open the file using a browser.", "cannotlogoutpageblocks": "Please save or discard your changes before continuing.", "cannotopeninapp": "This file may not work as expected on this device. Would you like to open it anyway?", "cannotopeninappdownload": "This file may not work as expected on this device. Would you like to download it anyway?", diff --git a/src/core/services/file-helper.ts b/src/core/services/file-helper.ts index 7817c4d7b..cc245e3ef 100644 --- a/src/core/services/file-helper.ts +++ b/src/core/services/file-helper.ts @@ -30,6 +30,7 @@ import { makeSingleton, Translate } from '@singletons'; import { CoreNetworkError } from '@classes/errors/network-error'; import { CoreConfig } from './config'; import { CoreCanceledError } from '@classes/errors/cancelederror'; +import { CoreMimetypeUtils } from '@services/utils/mimetype'; /** * Provider to provide some helper functions regarding files and packages. @@ -306,18 +307,23 @@ export class CoreFileHelperProvider { } /** - * Whether the file has to be opened in browser (external repository). - * The file must have a mimetype attribute. + * Whether the file has to be opened in browser. * * @param file The file to check. * @return Whether the file should be opened in browser. */ shouldOpenInBrowser(file: CoreWSFile): boolean { - if (!file || !('isexternalfile' in file) || !file.isexternalfile || !file.mimetype) { + if (!file.mimetype) { return false; } const mimetype = file.mimetype; + + if (!('isexternalfile' in file) || !file.isexternalfile) { + return mimetype === 'application/vnd.android.package-archive' + || CoreMimetypeUtils.getFileExtension(file.filename ?? '') === 'apk'; + } + if (mimetype.indexOf('application/vnd.google-apps.') != -1) { // Google Docs file, always open in browser. return true; diff --git a/src/core/services/filepool.ts b/src/core/services/filepool.ts index fbe4a2e2b..73c7dd48d 100644 --- a/src/core/services/filepool.ts +++ b/src/core/services/filepool.ts @@ -1410,6 +1410,19 @@ export class CoreFilepoolProvider { return this.getFilePath(siteId, fileId); } + /** + * Get the url of a file form its path. + * + * @param siteId The site ID. + * @param path File path. + * @returns File url. + */ + async getFileUrlByPath(siteId: string, path: string): Promise { + const record = await this.filesTables[siteId].getOne({ path }); + + return record.url; + } + /** * Get site Filepool Folder Path * diff --git a/src/core/services/utils/utils.ts b/src/core/services/utils/utils.ts index 23f51f9e1..1729c27a0 100644 --- a/src/core/services/utils/utils.ts +++ b/src/core/services/utils/utils.ts @@ -36,6 +36,9 @@ import { CoreWindow } from '@singletons/window'; import { CoreColors } from '@singletons/colors'; import { CorePromisedValue } from '@classes/promised-value'; import { CorePlatform } from '@services/platform'; +import { CoreErrorWithOptions } from '@classes/errors/errorwithtitle'; +import { CoreFilepool } from '@services/filepool'; +import { CoreSites } from '@services/sites'; export type TreeNode = T & { children: TreeNode[] }; @@ -970,6 +973,23 @@ export class CoreUtilsProvider { this.openInApp(path); return; + } else if (extension === 'apk' && CoreApp.isAndroid()) { + const url = await CoreUtils.ignoreErrors( + CoreFilepool.getFileUrlByPath(CoreSites.getCurrentSiteId(), CoreFile.removeBasePath(path)), + ); + + // @todo MOBILE-4167: Handle urls with expired tokens. + + throw new CoreErrorWithOptions( + Translate.instant('core.cannotinstallapk'), + undefined, + url + ? [{ + text: Translate.instant('core.openinbrowser'), + handler: () => this.openInBrowser(url), + }] + : undefined, + ); } // Path needs to be decoded, the file won't be opened if the path has %20 instead of spaces and so.