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.