diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5af65e1d6..e7d15f5ec 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -119,6 +119,13 @@ android:exported="false" android:theme="@style/AppTheme.Translucent" /> + + ) { + val uris = files.map { file -> + val uri = FileProvider.getUriForFile( + context, + "${BuildConfig.APPLICATION_ID}.fileProvider", + file + ) + + context.grantUriPermission( + PACKAGE_NAME_PLAY_STORE, + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION + ) + + uri + } + + val intent = Intent(context, MicroGInstallerActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + putExtra(EXTRA_PACKAGE_NAME, packageName) + putExtra(EXTRA_FILES, ArrayList(uris)) + } + + context.startActivity(intent) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val files: ArrayList? = if (isTAndAbove) { + intent.getParcelableArrayListExtra(EXTRA_FILES, Uri::class.java) + } else { + intent.getParcelableArrayListExtra(EXTRA_FILES) + } + + if (files.isNullOrEmpty()) { + Log.e(TAG, "No files provided, cannot proceed with MicroG installation") + return finish() + } + + startActivityForResult( + buildMicroGInstallIntent(files), + REQUEST_CODE + ) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + // TODO: Handle result if needed + finish() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt index f3884f05e..91105ec67 100644 --- a/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt @@ -35,6 +35,7 @@ import com.aurora.store.data.installer.base.IInstaller import com.aurora.store.data.model.Installer import com.aurora.store.data.model.InstallerInfo import com.aurora.store.util.PackageUtil +import com.aurora.store.util.PackageUtil.hasMicroGCompanion import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID import com.topjohnwu.superuser.Shell @@ -52,7 +53,8 @@ class AppInstaller @Inject constructor( private val rootInstaller: RootInstaller, private val serviceInstaller: ServiceInstaller, private val amInstaller: AMInstaller, - private val shizukuInstaller: ShizukuInstaller + private val shizukuInstaller: ShizukuInstaller, + private val microGInstaller: MicroGInstaller ) { companion object { @@ -73,7 +75,8 @@ class AppInstaller @Inject constructor( if (hasRootAccess()) RootInstaller.installerInfo else null, if (hasAuroraService(context)) ServiceInstaller.installerInfo else null, if (hasAppManager(context)) AMInstaller.installerInfo else null, - if (hasShizukuOrSui(context)) ShizukuInstaller.installerInfo else null + if (hasShizukuOrSui(context)) ShizukuInstaller.installerInfo else null, + if (hasMicroGCompanion(context)) MicroGInstaller.installerInfo else null ) } @@ -106,6 +109,7 @@ class AppInstaller @Inject constructor( Installer.SERVICE -> hasAuroraService(context) Installer.AM -> false // We cannot check if AppManager has ability to auto-update Installer.SHIZUKU -> isOAndAbove && hasShizukuOrSui(context) && hasShizukuPerm() + Installer.MICROG -> false } } @@ -176,6 +180,7 @@ class AppInstaller @Inject constructor( defaultInstaller } } + Installer.MICROG -> if(hasMicroGCompanion(context)) microGInstaller else defaultInstaller } } } diff --git a/app/src/main/java/com/aurora/store/data/installer/MicroGInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/MicroGInstaller.kt new file mode 100644 index 000000000..03424bd2d --- /dev/null +++ b/app/src/main/java/com/aurora/store/data/installer/MicroGInstaller.kt @@ -0,0 +1,92 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.data.installer + +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.util.Log +import com.aurora.Constants.PACKAGE_NAME_PLAY_STORE +import com.aurora.store.R +import com.aurora.store.data.activity.MicroGInstallerActivity +import com.aurora.store.data.installer.base.InstallerBase +import com.aurora.store.data.model.Installer +import com.aurora.store.data.model.InstallerInfo +import com.aurora.store.data.room.download.Download +import com.aurora.store.util.PackageUtil.hasMicroGCompanion +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class MicroGInstaller @Inject constructor( + @ApplicationContext private val context: Context +) : InstallerBase(context) { + + companion object { + val installerInfo: InstallerInfo + get() = InstallerInfo( + id = 6, + installer = Installer.MICROG, + packageNames = listOf(PACKAGE_NAME_PLAY_STORE), + installerPackageNames = listOf(PACKAGE_NAME_PLAY_STORE), + title = R.string.pref_install_mode_microg, + subtitle = R.string.microg_installer_subtitle, + description = R.string.microg_installer_desc + ) + + fun buildMicroGInstallIntent(uris: ArrayList): Intent { + return Intent("org.microg.vending.action.INSTALL_PACKAGE").apply { + setPackage(PACKAGE_NAME_PLAY_STORE) + setType("application/vnd.android.package-archive") + putExtra(Intent.EXTRA_STREAM, uris) + } + } + } + + private val TAG = MicroGInstaller::class.java.simpleName + + override fun install(download: Download) { + super.install(download) + + when { + isAlreadyQueued(download.packageName) -> { + Log.i(TAG, "${download.packageName} already queued") + } + + hasMicroGCompanion(context) -> { + Log.i(TAG, "Received microG install request for ${download.packageName}") + + val files = getFiles(download.packageName, download.versionCode) + MicroGInstallerActivity.launch(context, download.packageName, files) + + Log.i(TAG, "Sent install request to microG installer for ${download.packageName}") + } + + else -> { + postError( + download.packageName, + context.getString(R.string.installer_status_failure), + context.getString(R.string.installer_microg_misconfigured) + ) + } + } + } +} diff --git a/app/src/main/java/com/aurora/store/data/model/Installer.kt b/app/src/main/java/com/aurora/store/data/model/Installer.kt index 7efa730b1..59366452f 100644 --- a/app/src/main/java/com/aurora/store/data/model/Installer.kt +++ b/app/src/main/java/com/aurora/store/data/model/Installer.kt @@ -9,5 +9,6 @@ enum class Installer { ROOT, SERVICE, AM, - SHIZUKU + SHIZUKU, + MICROG } diff --git a/app/src/main/java/com/aurora/store/util/PackageUtil.kt b/app/src/main/java/com/aurora/store/util/PackageUtil.kt index 0eeda6428..70370ff9c 100644 --- a/app/src/main/java/com/aurora/store/util/PackageUtil.kt +++ b/app/src/main/java/com/aurora/store/util/PackageUtil.kt @@ -55,6 +55,8 @@ object PackageUtil { private const val VERSION_CODE_MICRO_G: Long = 240913402 private const val VERSION_CODE_MICRO_G_HUAWEI: Long = 240913007 + private const val VERSION_CODE_MICROG_COMPANION_MIN: Long = 84022620 + private const val MICROG_INSTALL_ACTIVITY = "org.microg.vending.installer.AppInstallActivity" fun getAllValidPackages(context: Context): List { return context.packageManager.getInstalledPackages(PackageManager.GET_META_DATA) @@ -109,6 +111,26 @@ object PackageUtil { } } + fun hasActivity(context: Context, packageName: String, activityName: String): Boolean { + val intent = Intent() + intent.setClassName(packageName, activityName) + + val resolveInfo = context.packageManager.resolveActivity(intent, 0) + return resolveInfo != null + } + + fun hasMicroGCompanion(context: Context): Boolean { + return isInstalled( + context, + PACKAGE_NAME_PLAY_STORE, + VERSION_CODE_MICROG_COMPANION_MIN + ) && hasActivity( + context, + PACKAGE_NAME_PLAY_STORE, + MICROG_INSTALL_ACTIVITY + ) + } + fun isInstalled(context: Context, packageName: String, versionCode: Long? = null): Boolean { return try { val packageInfo = getPackageInfo(context, packageName, PackageManager.GET_META_DATA) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 04b3e9fa1..3c564a9dc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -178,6 +178,7 @@ "Aurora Services is available and ready to install." Install Aurora Services 1.0.9 or above, or change the installer. Set up Aurora Services and grant all permissions first. + MicroG installer failed to install app, likely due to misconfiguration. "Installer failed" "Installation was blocked" "Could not create session" @@ -211,6 +212,7 @@ "Root installer" "Aurora Services (Deprecated)" "Session installer" + "MicroG installer" "Select mode of APK installation" "Installation method" Google Play version @@ -387,6 +389,8 @@ Best suited for devices running below Android 4.4 Installer for background installations Requires Aurora Services to be installed as a privileged-system app + Requires microG companion app to be installed + Helps you bypass App Integrity (installer only) check Full-featured open source package manager Requires App Manager, need adb/root mode to install when miui optimization is on Using system APIs directly with adb/root privileges