From 8c0527b79d7858b58664aed024526e2c972fcdb3 Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Thu, 23 Nov 2023 12:49:36 +0100 Subject: [PATCH] Split install improvements --- app/libs/splitinstall-lib.jar | Bin 4689 -> 8421 bytes .../ISplitInstallServiceCallback.aidl | 29 ++++ .../ISplitInstallServiceCallback.aidl | 48 ++++++ .../e/apps/ISplitInstallService.aidl | 21 ++- .../e/apps/ISplitInstallServiceCallback.aidl | 26 +++ .../splitinstall/SplitInstallBinder.kt | 156 +++++++++++++++--- .../splitinstall/SplitInstallService.kt | 5 +- app/src/main/res/values/strings.xml | 5 + 8 files changed, 267 insertions(+), 23 deletions(-) create mode 100644 app/src/main/aidl/com/android/vending/splitinstall/ISplitInstallServiceCallback.aidl create mode 100644 app/src/main/aidl/com/google/android/play/core/splitinstall/protocol/ISplitInstallServiceCallback.aidl create mode 100644 app/src/main/aidl/foundation/e/apps/ISplitInstallServiceCallback.aidl diff --git a/app/libs/splitinstall-lib.jar b/app/libs/splitinstall-lib.jar index a18b464e1ce836e121e24e1be57a9fbdbd5a9c43..bcfa5e5c9a1fae760affdddfbfe7051e16dea0ce 100644 GIT binary patch literal 8421 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 delta 3503 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 list); + + void onDeferredUninstall(in Bundle bundle); + + void onDeferredInstall(in Bundle bundle); + + void onGetSplitsForAppUpdate(int i, in Bundle bundle); + + void onCompleteInstallForAppUpdate(); + + void onDeferredLanguageInstall(int i); +} diff --git a/app/src/main/aidl/foundation/e/apps/ISplitInstallService.aidl b/app/src/main/aidl/foundation/e/apps/ISplitInstallService.aidl index bf327d45d..6e759db98 100644 --- a/app/src/main/aidl/foundation/e/apps/ISplitInstallService.aidl +++ b/app/src/main/aidl/foundation/e/apps/ISplitInstallService.aidl @@ -1,6 +1,25 @@ +/* + * Copyright Murena SAS 2023 + * Copyright 2013-2022 microG Project Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package foundation.e.apps; +import com.android.vending.splitinstall.ISplitInstallServiceCallback; + interface ISplitInstallService { - void installSplitModule(String packageName, String moduleName); + void installSplitModule(String packageName, String moduleName, ISplitInstallServiceCallback callback); } \ No newline at end of file diff --git a/app/src/main/aidl/foundation/e/apps/ISplitInstallServiceCallback.aidl b/app/src/main/aidl/foundation/e/apps/ISplitInstallServiceCallback.aidl new file mode 100644 index 000000000..21f38abe3 --- /dev/null +++ b/app/src/main/aidl/foundation/e/apps/ISplitInstallServiceCallback.aidl @@ -0,0 +1,26 @@ +/* + * Copyright Murena SAS 2023 + * Copyright 2013-2022 microG Project Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package foundation.e.apps; + +interface ISplitInstallServiceCallback { + + void onStartInstall(int sessionId); + + void onInstalled(int sessionId); + + void onError(int errorCode); +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/install/splitinstall/SplitInstallBinder.kt b/app/src/main/java/foundation/e/apps/install/splitinstall/SplitInstallBinder.kt index fcd7528b2..ce9f8e322 100644 --- a/app/src/main/java/foundation/e/apps/install/splitinstall/SplitInstallBinder.kt +++ b/app/src/main/java/foundation/e/apps/install/splitinstall/SplitInstallBinder.kt @@ -18,12 +18,30 @@ package foundation.e.apps.install.splitinstall +import android.Manifest +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build.VERSION +import android.os.Build.VERSION_CODES +import androidx.annotation.RequiresApi +import androidx.core.app.ActivityCompat +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat import androidx.core.content.pm.PackageInfoCompat -import com.aurora.gplayapi.data.models.AuthData -import foundation.e.apps.ISplitInstallService +import com.android.vending.splitinstall.ISplitInstallServiceCallback +import foundation.e.apps.MainActivity +import foundation.e.apps.R import foundation.e.apps.data.DownloadManager import foundation.e.apps.data.application.ApplicationRepository +import foundation.e.apps.data.login.AuthenticatorRepository +import foundation.e.apps.data.login.exceptions.GPlayLoginException +import foundation.e.apps.ISplitInstallService as ISplitInstallAppLoungeService +import foundation.e.splitinstall.ISplitInstallService as ISplitInstallSystemService +import foundation.e.splitinstall.ISplitInstallSystemServiceCallback import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -35,53 +53,149 @@ class SplitInstallBinder( private val coroutineScope: CoroutineScope, val applicationRepository: ApplicationRepository, val downloadManager: DownloadManager, - val authData: AuthData?, - private var splitInstallSystemService: foundation.e.splitinstall.ISplitInstallService? -) : ISplitInstallService.Stub() { + val authenticatorRepository: AuthenticatorRepository, + private var splitInstallSystemService: ISplitInstallSystemService? +) : ISplitInstallAppLoungeService.Stub() { private val modulesToInstall = HashMap() + private val callbacks = HashMap() companion object { const val TAG = "SplitInstallerBinder" + const val NOTIFICATION_ID = 667 + const val NOTIFICATION_CHANNEL = "AuthToken" + const val PLAY_STORE_NOT_FOUND_ERROR = -14 } - override fun installSplitModule(packageName: String, moduleName: String) { - if (authData == null) { - Timber.i("No authentication data. Could not install on demand module") + fun setService(service: foundation.e.splitinstall.ISplitInstallService) { + splitInstallSystemService = service + installPendingModules() + } + + override fun installSplitModule( + packageName: String, + moduleName: String, + callback: ISplitInstallServiceCallback + ) { + try { + if (authenticatorRepository.gplayAuth == null) { + handleError(packageName, callback) + return + } + + coroutineScope.launch { + downloadModule(packageName, moduleName, callback) + } + } catch (exception: GPlayLoginException) { + Timber.w(TAG, "Could not get auth data", exception) + handleError(packageName, callback) return } + } - coroutineScope.launch { - downloadModule(packageName, moduleName) + private fun handleError(packageName: String, callback: ISplitInstallServiceCallback) { + if (VERSION.SDK_INT < VERSION_CODES.O) { + return } + + createNotificationChannel(context) + showNotification(context, packageName) + callback.onError(PLAY_STORE_NOT_FOUND_ERROR) } - fun setService(service: foundation.e.splitinstall.ISplitInstallService) { - splitInstallSystemService = service - installPendingModules() + @RequiresApi(VERSION_CODES.O) + private fun createNotificationChannel(context: Context) { + val descriptionText = context.getString(R.string.notification_channel_desc) + val notificationChannel = NotificationChannel( + NOTIFICATION_CHANNEL, + NOTIFICATION_CHANNEL, + NotificationManager.IMPORTANCE_DEFAULT + ).apply { + description = descriptionText + } + + val notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + notificationManager.createNotificationChannel(notificationChannel) } - private suspend fun downloadModule(packageName: String, moduleName: String) { + private fun showNotification(context: Context, packageName: String) { + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) + != PackageManager.PERMISSION_GRANTED + ) { + return + } + + val intent = Intent(context, MainActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK + val pendingIntent = PendingIntent.getActivity( + context, + 0, + intent, + PendingIntent.FLAG_IMMUTABLE + ) + + val notificationBuilder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL) + .setSmallIcon(R.drawable.app_lounge_notification_icon) + .setContentTitle(context.getString(R.string.split_install_warning_title, packageName)) + .setContentText(context.getString(R.string.split_install_warning_text)) + .setPriority(NotificationManager.IMPORTANCE_DEFAULT) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + + with(NotificationManagerCompat.from(context)) { + notify(NOTIFICATION_ID, notificationBuilder.build()) + } + } + + private suspend fun downloadModule( + packageName: String, + moduleName: String, + callback: ISplitInstallServiceCallback + ) { withContext(Dispatchers.IO) { val versionCode = getPackageVersionCode(packageName) val url = fetchModuleUrl(packageName, moduleName, versionCode) if (url == null) { Timber.e("Could not find split module named $moduleName for $packageName package") + callback.onError(PLAY_STORE_NOT_FOUND_ERROR) return@withContext } downloadManager.downloadFileInExternalStorage( url, packageName, "$packageName.split.$moduleName.apk" ) { success, path -> - if (success) { - Timber.i("Split module has been downloaded: $path") - if (splitInstallSystemService == null) { - Timber.i("Not connected to system service now. Adding $path to the list.") - modulesToInstall[path] = packageName + if (!success) { + return@downloadFileInExternalStorage + } + + Timber.i("Split module has been downloaded: $path") + if (splitInstallSystemService == null) { + Timber.i("Not connected to system service now. Adding $path to the list.") + modulesToInstall[path] = packageName + } + + callbacks[moduleName] = object : ISplitInstallSystemServiceCallback.Stub() { + override fun onStartInstall(sessionId: Int) { + callback.onStartInstall(sessionId) + } + + override fun onInstalled(sessionId: Int) { + callback.onInstalled(sessionId) + } + + override fun onError(errorCode: Int) { + callback.onError(errorCode) } - splitInstallSystemService?.installSplitModule(packageName, path) } + + splitInstallSystemService?.installSplitModule( + packageName, + path, + callbacks[moduleName] + ) } } } @@ -114,7 +228,7 @@ class SplitInstallBinder( private fun installPendingModules() { for (module in modulesToInstall.keys) { val packageName = modulesToInstall[module] - splitInstallSystemService?.installSplitModule(packageName, module) + splitInstallSystemService?.installSplitModule(packageName, module, callbacks[module]) } } } diff --git a/app/src/main/java/foundation/e/apps/install/splitinstall/SplitInstallService.kt b/app/src/main/java/foundation/e/apps/install/splitinstall/SplitInstallService.kt index 133509242..c56448a0f 100644 --- a/app/src/main/java/foundation/e/apps/install/splitinstall/SplitInstallService.kt +++ b/app/src/main/java/foundation/e/apps/install/splitinstall/SplitInstallService.kt @@ -29,6 +29,7 @@ import com.google.gson.Gson import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.data.DownloadManager import foundation.e.apps.data.application.ApplicationRepository +import foundation.e.apps.data.login.AuthenticatorRepository import foundation.e.apps.data.preference.DataStoreModule import foundation.e.splitinstall.ISplitInstallService import foundation.e.splitinstall.SplitInstall @@ -46,6 +47,7 @@ class SplitInstallService : LifecycleService() { @Inject lateinit var applicationRepository: ApplicationRepository @Inject lateinit var downloadManager: DownloadManager @Inject lateinit var gson: Gson + @Inject lateinit var authenticatorRepository: AuthenticatorRepository private lateinit var binder: SplitInstallBinder private var authData: AuthData? = null private var splitInstallSystemService: ISplitInstallService? = null @@ -67,6 +69,7 @@ class SplitInstallService : LifecycleService() { val intent = Intent().apply { component = SplitInstall.SPLIT_INSTALL_SYSTEM_SERVICE } + bindService(intent, serviceConnection, BIND_AUTO_CREATE) lifecycleScope.launch { @@ -94,7 +97,7 @@ class SplitInstallService : LifecycleService() { lifecycleScope, applicationRepository, downloadManager, - authData, + authenticatorRepository, splitInstallSystemService ) return binder diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3b2fd32fa..3888fc3a2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -241,4 +241,9 @@ Free up %1$s on your phone to get the latest updates. Please free up some space on your phone so App Lounge can work properly. + + + Split install warning: %s + Please reconnect in AppLounge (either Anonymously or with a Google account). + Authentication token channel -- GitLab