diff --git a/app/src/main/java/foundation/e/apps/AppLoungeApplication.kt b/app/src/main/java/foundation/e/apps/AppLoungeApplication.kt index 368c89a3c97baed45e11851f772c24498fac62b0..2a4ee09891f02fecbfd545080095a7a45ee3fe2b 100644 --- a/app/src/main/java/foundation/e/apps/AppLoungeApplication.kt +++ b/app/src/main/java/foundation/e/apps/AppLoungeApplication.kt @@ -34,6 +34,7 @@ import foundation.e.apps.install.pkg.PkgManagerModule import foundation.e.apps.install.updates.UpdatesWorkManager import foundation.e.apps.install.workmanager.InstallWorkManager import foundation.e.apps.ui.setup.tos.TOS_VERSION +import foundation.e.apps.utils.CustomUncaughtExceptionHandler import foundation.e.lib.telemetry.Telemetry import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.MainScope @@ -59,10 +60,15 @@ class AppLoungeApplication : Application(), Configuration.Provider { @Inject lateinit var preferenceManagerModule: PreferenceManagerModule + @Inject + lateinit var uncaughtExceptionHandler: CustomUncaughtExceptionHandler + @RequiresApi(Build.VERSION_CODES.TIRAMISU) override fun onCreate() { super.onCreate() + Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler) + InstallWorkManager.context = this // Register broadcast receiver for package manager val pkgManagerBR = object : PkgManagerBR() {} diff --git a/app/src/main/java/foundation/e/apps/MainActivity.kt b/app/src/main/java/foundation/e/apps/MainActivity.kt index 5b94937da6fd831fd324523609f4c110a596b53b..a2715a1e8f85e1d3af8c817ceb0be60908207e13 100644 --- a/app/src/main/java/foundation/e/apps/MainActivity.kt +++ b/app/src/main/java/foundation/e/apps/MainActivity.kt @@ -40,8 +40,8 @@ import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.login.AuthObject -import foundation.e.apps.data.login.PlayStoreAuthenticator import foundation.e.apps.data.login.LoginViewModel +import foundation.e.apps.data.login.PlayStoreAuthenticator import foundation.e.apps.data.login.exceptions.GPlayValidationException import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.databinding.ActivityMainBinding diff --git a/app/src/main/java/foundation/e/apps/install/workmanager/InstallAppWorker.kt b/app/src/main/java/foundation/e/apps/install/workmanager/InstallAppWorker.kt index e26c1df66d9f63153b1249ed7529599a2be09818..286c2727d138e28f925f5cb529be7906e7f8666a 100644 --- a/app/src/main/java/foundation/e/apps/install/workmanager/InstallAppWorker.kt +++ b/app/src/main/java/foundation/e/apps/install/workmanager/InstallAppWorker.kt @@ -72,24 +72,26 @@ class InstallAppWorker @AssistedInject constructor( private fun createForegroundInfo(progress: String): ForegroundInfo { val title = applicationContext.getString(R.string.app_name) val cancel = applicationContext.getString(R.string.cancel) + val channelId = context.getString(R.string.basic_notification_channel_id) + // This PendingIntent can be used to cancel the worker val intent = WorkManager.getInstance(applicationContext) - .createCancelPendingIntent(getId()) + .createCancelPendingIntent(id) val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as - NotificationManager + NotificationManager // Create a Notification channel if necessary if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val mChannel = NotificationChannel( - "applounge_notification", + channelId, title, NotificationManager.IMPORTANCE_LOW ) notificationManager.createNotificationChannel(mChannel) } - val notification = NotificationCompat.Builder(applicationContext, "applounge_notification") + val notification = NotificationCompat.Builder(applicationContext, channelId) .setContentTitle(title) .setTicker(title) .setContentText(progress) diff --git a/app/src/main/java/foundation/e/apps/utils/CustomUncaughtExceptionHandler.kt b/app/src/main/java/foundation/e/apps/utils/CustomUncaughtExceptionHandler.kt new file mode 100644 index 0000000000000000000000000000000000000000..b280350f8ba73b00df98dd38650ff17a9175ef46 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/utils/CustomUncaughtExceptionHandler.kt @@ -0,0 +1,97 @@ +/* + * Apps Quickly and easily install Android apps onto your device! + * Copyright (C) 2023 MURENA SAS + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +package foundation.e.apps.utils + +import android.Manifest +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.content.Context +import android.content.pm.PackageManager +import android.database.sqlite.SQLiteFullException +import android.os.Build +import androidx.annotation.StringRes +import androidx.core.app.ActivityCompat +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import dagger.hilt.android.qualifiers.ApplicationContext +import foundation.e.apps.R +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class CustomUncaughtExceptionHandler @Inject constructor( + @ApplicationContext private val context: Context +) : Thread.UncaughtExceptionHandler { + + companion object { + private const val NOTIFICATION_ID = 404 + } + + override fun uncaughtException(thread: Thread, throwable: Throwable) { + Timber.e(throwable, "unhandled exception is caught at thread: ${thread.name}") + + if (throwable is SQLiteFullException || throwable.cause is SQLiteFullException) { + showNotification(R.string.notification_content_full_db) + } + } + + private fun showNotification(@StringRes contentId: Int) { + if (ActivityCompat.checkSelfPermission( + context, Manifest.permission.POST_NOTIFICATIONS + ) != PackageManager.PERMISSION_GRANTED + ) { + return + } + + createNotificationChannel() + + val notification = getNotification(contentId) + NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notification) + } + + private fun getNotification(@StringRes contentId: Int): Notification { + val content = context.getString(contentId) + val channelId = context.getString(R.string.warning_notification_channel_id) + val title = context.getString(R.string.app_name) + + return NotificationCompat.Builder(context, channelId) + .setSmallIcon(R.drawable.app_lounge_notification_icon) + .setContentTitle(title) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setAutoCancel(true) + .setContentText(content).build() + } + + private fun createNotificationChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val id = context.getString(R.string.warning_notification_channel_id) + val title = context.getString(R.string.warning_notification_channel_title) + + val channel = NotificationChannel( + id, title, NotificationManager.IMPORTANCE_DEFAULT + ) + + val notificationManager: NotificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.createNotificationChannel(channel) + } + } +} diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index aafa2cb17d8e926650d38f08b02d34bf1909485d..4f17154f8f3a179de425a9316cede279cd053789 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -169,4 +169,6 @@ Aktualisierungen werden überprüft … Das anonyme Konto, das von Ihnen genutzt wird, ist nicht verfügbar. Bitte erneuern (refresh) Sie die Sitzung, um ein neues anonymes Konto zu erhalten. SITZUNG ERNEUERN + + Bitte etwas Platz auf dem Telefon freimachen, damit die App Lounge ordnungsgemäß funktionieren kann. \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index ac0af2df98976529b486815962fef5fca1274939..6ed760d132b78a7877560ceccc93de7799a9da41 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -155,4 +155,6 @@ PWA y aplicaciones de código abierto O mostrar sólo Libera %1$s en tu teléfono para recibir las últimas actualizaciones. + + Por favor, libera algo de espacio en tu teléfono para que App Lounge funcione correctamente. \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 7ec04744cb76218a6088e045d9eb7a38b43afb12..fcb3a6babbd97a9243e4f5c52587c11f9c32d2c5 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -166,4 +166,6 @@ \n\t• limiter le micro-ciblage \n\t• limiter les impacts au cas où ce compte serait restreint par Google Libérez %1$s sur votre téléphone afin de bénéficier des dernières mises à jour. + + Merci de libérer de l\'espace sur votre téléphone pour qu\'App Lounge puisse fonctionner correctement. \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 537c56f538459b9d299cc21a6cb519913afaf0fe..21908d07f4ad9c8a601f311f4c1190644d774b87 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -166,4 +166,6 @@ \n\t• ridurre il micro-targeting \n\t• limitare l\'impatto nel caso in cui l\'account venga bloccato da Google Per scaricare l\'aggiornamento, devi liberare %1$s di spazio sullo smartphone. + + Ti invitiamo a liberare un pò di spazio sul telefono in modo che App Lounge possa funzionare correttamente. \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c404c57a8a2786baf15288be3751a73491c97e4b..3b2fd32fa11dc16e4192ba675cb597343560f15d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,6 +20,11 @@ App Lounge + applounge_notification + + applounge_warning_notification + Warning + Home Categories @@ -234,4 +239,6 @@ Clicking on \"%1$s\" will open a tab in your browser with the app\'s package name prefilled.<br /><br />Click on \"Perform analysis\" to start the analysis by Exodus.<br /><br />When the button \"See the report\" is displayed (it can take a while depending on the app) you can close the tab and go back to the app description in %2$s where you should see the Privacy Score. Sometimes Exodus can fail to analyze the app.<br /><br />NB: it can take up to 10 min for the score to be displayed in the app description. 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.