Loading app/build.gradle +20 −19 Original line number Diff line number Diff line Loading @@ -5,13 +5,13 @@ plugins { id 'kotlin-kapt' id 'org.jlleitschuh.gradle.ktlint' version '10.2.0' id 'androidx.navigation.safeargs.kotlin' id 'dagger.hilt.android.plugin' id 'com.google.dagger.hilt.android' id 'kotlin-allopen' } def versionMajor = 2 def versionMinor = 4 def versionPatch = 7 def versionPatch = 9 def getGitHash = { -> def stdOut = new ByteArrayOutputStream() Loading Loading @@ -42,7 +42,7 @@ def getSentryDsn = { -> } android { compileSdk 31 compileSdk 33 defaultConfig { applicationId "foundation.e.apps" Loading Loading @@ -149,11 +149,12 @@ dependencies { // TODO: Add splitinstall-lib to a repo https://gitlab.e.foundation/e/os/backlog/-/issues/628 api files('libs/splitinstall-lib.jar') implementation 'foundation.e.lib:telemetry:0.0.4-alpha' implementation 'foundation.e.lib:telemetry:0.0.7-alpha' implementation 'foundation.e:gplayapi:3.0.1' implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.fragment:fragment-ktx:1.5.6' implementation 'com.google.android.material:material:1.5.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' implementation 'androidx.legacy:legacy-support-v4:1.0.0' Loading @@ -164,16 +165,16 @@ dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' testImplementation "com.google.truth:truth:1.1.3" testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' // Optional -- Robolectric environment testImplementation "androidx.test:core:1.4.0" testImplementation "androidx.test:core:1.5.0" // Optional -- Mockito framework testImplementation "org.mockito:mockito-core:4.6.1" testImplementation "org.mockito:mockito-core:5.0.0" // Optional -- mockito-kotlin testImplementation "org.mockito.kotlin:mockito-kotlin:3.2.0" testImplementation 'org.mockito:mockito-inline:2.13.0' testImplementation "androidx.arch.core:core-testing:2.1.0" testImplementation "org.mockito.kotlin:mockito-kotlin:4.1.0" testImplementation 'org.mockito:mockito-inline:5.0.0' testImplementation "androidx.arch.core:core-testing:2.2.0" testImplementation "io.mockk:mockk:1.12.3" Loading @@ -182,8 +183,8 @@ dependencies { implementation 'com.github.Baseflow:PhotoView:2.3.0' //Protobuf and Gson implementation 'com.google.code.gson:gson:2.8.9' implementation "com.google.protobuf:protobuf-java:3.14.0" implementation 'com.google.code.gson:gson:2.9.0' implementation "com.google.protobuf:protobuf-java:3.17.2" // ViewPager2 and RecyclerView implementation "androidx.viewpager2:viewpager2:1.0.0" Loading Loading @@ -211,19 +212,19 @@ dependencies { implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.11.2" // Navigation Components def navigation_version = "2.3.5" def navigation_version = "2.5.3" implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version" implementation "androidx.navigation:navigation-ui-ktx:$navigation_version" // Hilt def hilt_version = '2.40.5' kapt "com.google.dagger:hilt-compiler:$hilt_version" implementation "com.google.dagger:hilt-android:$hilt_version" kapt "com.google.dagger:hilt-compiler:2.44.2" implementation "com.google.dagger:hilt-android:2.44.2" implementation 'androidx.hilt:hilt-work:1.0.0' kapt 'androidx.hilt:hilt-compiler:1.0.0' // Lifecycle Components def lifecycle_version = "2.4.0" def lifecycle_version = "2.6.1" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" implementation "android.arch.lifecycle:extensions:1.1.1" Loading app/src/main/java/foundation/e/apps/AppLoungeApplication.kt +14 −3 Original line number Diff line number Diff line Loading @@ -22,12 +22,17 @@ import android.app.Application import android.util.Log import androidx.hilt.work.HiltWorkerFactory import androidx.work.Configuration import androidx.work.ExistingPeriodicWorkPolicy import dagger.hilt.android.HiltAndroidApp import foundation.e.apps.login.LoginDataStore import foundation.e.apps.manager.pkg.PkgManagerBR import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.manager.workmanager.InstallWorkManager import foundation.e.apps.setup.tos.TOS_VERSION import foundation.e.apps.updates.manager.UpdatesWorkManager import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.modules.DataStoreModule import foundation.e.apps.utils.modules.PreferenceManagerModule import foundation.e.lib.telemetry.Telemetry import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.MainScope Loading @@ -50,6 +55,9 @@ class AppLoungeApplication : Application(), Configuration.Provider { @Inject lateinit var dataStoreModule: DataStoreModule @Inject lateinit var preferenceManagerModule: PreferenceManagerModule override fun onCreate() { super.onCreate() Loading @@ -75,13 +83,16 @@ class AppLoungeApplication : Application(), Configuration.Provider { if (priority < Log.WARN) { return } if (priority == Log.ERROR) { Telemetry.reportMessage("$tag: $message") } Log.println(priority, tag, message) } }) } UpdatesWorkManager.enqueueWork( this, preferenceManagerModule.getUpdateInterval(), ExistingPeriodicWorkPolicy.KEEP ) } override fun getWorkManagerConfiguration() = Loading app/src/main/java/foundation/e/apps/MainActivity.kt +20 −1 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.exceptions.GPlayValidationException import foundation.e.apps.utils.modules.CommonUtilsFunctions import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import timber.log.Timber Loading Loading @@ -130,7 +131,10 @@ class MainActivity : AppCompatActivity() { viewModel.gPlayAuthData = data as AuthData } else if (exception is GPlayValidationException) { val email = otherPayload.toString() viewModel.uploadFaultyTokenToEcloud(email, CommonUtilsFunctions.getAppBuildInfo()) viewModel.uploadFaultyTokenToEcloud( email, CommonUtilsFunctions.getAppBuildInfo() ) } } } Loading Loading @@ -213,6 +217,8 @@ class MainActivity : AppCompatActivity() { viewModel.updateAppWarningList() lifecycleScope.launchWhenResumed { observeInvalidAuth() EventBus.events.filter { appEvent -> appEvent is AppEvent.SignatureMissMatchError }.collectLatest { Loading @@ -226,6 +232,19 @@ class MainActivity : AppCompatActivity() { } } private suspend fun observeInvalidAuth() { EventBus.events.filter { appEvent -> appEvent is AppEvent.InvalidAuthEvent }.distinctUntilChanged { old, new -> ((old.data is String) && (new.data is String) && old.data == new.data) }.collectLatest { val data = it.data as String if (data.isNotBlank()) { loginViewModel.markInvalidAuthObject(data) } } } private fun setupBottomNavItemSelectedListener( bottomNavigationView: BottomNavigationView, navHostFragment: NavHostFragment, Loading app/src/main/java/foundation/e/apps/api/DownloadManager.kt +18 −31 Original line number Diff line number Diff line Loading @@ -96,10 +96,18 @@ class DownloadManager @Inject constructor( downloadFile: File, downloadCompleted: ((Boolean, String) -> Unit)? ): Long { var downloadId = -1L try { val request = DownloadManager.Request(Uri.parse(url)) .setTitle(context.getString(R.string.downloading)) .setDestinationUri(Uri.fromFile(downloadFile)) val downloadId = downloadManager.enqueue(request) downloadId = downloadManager.enqueue(request) } catch (e: java.lang.NullPointerException) { Timber.e(e, "Url: $url; downloadFilePath: ${downloadFile.absolutePath}") downloadCompleted?.invoke(false, e.localizedMessage ?: "No message found!") return downloadId } downloadsMaps[downloadId] = true tickerFlow(downloadId, .5.seconds).onEach { checkDownloadProgress(downloadId, downloadFile.absolutePath, downloadCompleted) Loading @@ -107,7 +115,7 @@ class DownloadManager @Inject constructor( return downloadId } private fun checkDownloadProgress( fun checkDownloadProgress( downloadId: Long, filePath: String = "", downloadCompleted: ((Boolean, String) -> Unit)? Loading Loading @@ -154,6 +162,10 @@ class DownloadManager @Inject constructor( return getDownloadStatus(downloadId) == DownloadManager.STATUS_SUCCESSFUL } fun hasDownloadFailed(downloadId: Long): Boolean { return getDownloadStatus(downloadId) == DownloadManager.STATUS_FAILED } private fun getDownloadStatus(downloadId: Long): Int { try { downloadManager.query(downloadManagerQuery.setFilterById(downloadId)) Loading @@ -161,7 +173,7 @@ class DownloadManager @Inject constructor( if (cursor.moveToFirst()) { val status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) Timber.d("Download Failed: downloadId: $downloadId $status") Timber.d("Download Status: downloadId: $downloadId $status") return status } } Loading @@ -170,29 +182,4 @@ class DownloadManager @Inject constructor( } return DownloadManager.STATUS_FAILED } suspend fun checkDownloadProcess(downloadingIds: LongArray, handleFailed: suspend () -> Unit) { try { downloadManager.query(downloadManagerQuery.setFilterById(*downloadingIds)) .use { cursor -> if (!cursor.moveToFirst()) { return@use } while (!cursor.isAfterLast) { val status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) if (status == DownloadManager.STATUS_FAILED) { handleFailed() } cursor.moveToNext() } } } catch (e: Exception) { Timber.e(e) } } } app/src/main/java/foundation/e/apps/api/exodus/ExodusTrackerApi.kt +8 −5 Original line number Diff line number Diff line Loading @@ -3,17 +3,20 @@ package foundation.e.apps.api.exodus import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query interface ExodusTrackerApi { companion object { const val BASE_URL = "https://exodus.ecloud.global/api/" const val VERSION = "190239" } @GET("trackers?v=$VERSION") suspend fun getTrackerList(): Response<Trackers> @GET("trackers?v={date}") suspend fun getTrackerList(@Path("date") date: String): Response<Trackers> @GET("search/{appHandle}/details?v=$VERSION") suspend fun getTrackerInfoOfApp(@Path("appHandle") appHandle: String): Response<List<Report>> @GET("search/{appHandle}/details") suspend fun getTrackerInfoOfApp( @Path("appHandle") appHandle: String, @Query("v") versionCode: Int, ): Response<List<Report>> } Loading
app/build.gradle +20 −19 Original line number Diff line number Diff line Loading @@ -5,13 +5,13 @@ plugins { id 'kotlin-kapt' id 'org.jlleitschuh.gradle.ktlint' version '10.2.0' id 'androidx.navigation.safeargs.kotlin' id 'dagger.hilt.android.plugin' id 'com.google.dagger.hilt.android' id 'kotlin-allopen' } def versionMajor = 2 def versionMinor = 4 def versionPatch = 7 def versionPatch = 9 def getGitHash = { -> def stdOut = new ByteArrayOutputStream() Loading Loading @@ -42,7 +42,7 @@ def getSentryDsn = { -> } android { compileSdk 31 compileSdk 33 defaultConfig { applicationId "foundation.e.apps" Loading Loading @@ -149,11 +149,12 @@ dependencies { // TODO: Add splitinstall-lib to a repo https://gitlab.e.foundation/e/os/backlog/-/issues/628 api files('libs/splitinstall-lib.jar') implementation 'foundation.e.lib:telemetry:0.0.4-alpha' implementation 'foundation.e.lib:telemetry:0.0.7-alpha' implementation 'foundation.e:gplayapi:3.0.1' implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.fragment:fragment-ktx:1.5.6' implementation 'com.google.android.material:material:1.5.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' implementation 'androidx.legacy:legacy-support-v4:1.0.0' Loading @@ -164,16 +165,16 @@ dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' testImplementation "com.google.truth:truth:1.1.3" testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' // Optional -- Robolectric environment testImplementation "androidx.test:core:1.4.0" testImplementation "androidx.test:core:1.5.0" // Optional -- Mockito framework testImplementation "org.mockito:mockito-core:4.6.1" testImplementation "org.mockito:mockito-core:5.0.0" // Optional -- mockito-kotlin testImplementation "org.mockito.kotlin:mockito-kotlin:3.2.0" testImplementation 'org.mockito:mockito-inline:2.13.0' testImplementation "androidx.arch.core:core-testing:2.1.0" testImplementation "org.mockito.kotlin:mockito-kotlin:4.1.0" testImplementation 'org.mockito:mockito-inline:5.0.0' testImplementation "androidx.arch.core:core-testing:2.2.0" testImplementation "io.mockk:mockk:1.12.3" Loading @@ -182,8 +183,8 @@ dependencies { implementation 'com.github.Baseflow:PhotoView:2.3.0' //Protobuf and Gson implementation 'com.google.code.gson:gson:2.8.9' implementation "com.google.protobuf:protobuf-java:3.14.0" implementation 'com.google.code.gson:gson:2.9.0' implementation "com.google.protobuf:protobuf-java:3.17.2" // ViewPager2 and RecyclerView implementation "androidx.viewpager2:viewpager2:1.0.0" Loading Loading @@ -211,19 +212,19 @@ dependencies { implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.11.2" // Navigation Components def navigation_version = "2.3.5" def navigation_version = "2.5.3" implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version" implementation "androidx.navigation:navigation-ui-ktx:$navigation_version" // Hilt def hilt_version = '2.40.5' kapt "com.google.dagger:hilt-compiler:$hilt_version" implementation "com.google.dagger:hilt-android:$hilt_version" kapt "com.google.dagger:hilt-compiler:2.44.2" implementation "com.google.dagger:hilt-android:2.44.2" implementation 'androidx.hilt:hilt-work:1.0.0' kapt 'androidx.hilt:hilt-compiler:1.0.0' // Lifecycle Components def lifecycle_version = "2.4.0" def lifecycle_version = "2.6.1" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" implementation "android.arch.lifecycle:extensions:1.1.1" Loading
app/src/main/java/foundation/e/apps/AppLoungeApplication.kt +14 −3 Original line number Diff line number Diff line Loading @@ -22,12 +22,17 @@ import android.app.Application import android.util.Log import androidx.hilt.work.HiltWorkerFactory import androidx.work.Configuration import androidx.work.ExistingPeriodicWorkPolicy import dagger.hilt.android.HiltAndroidApp import foundation.e.apps.login.LoginDataStore import foundation.e.apps.manager.pkg.PkgManagerBR import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.manager.workmanager.InstallWorkManager import foundation.e.apps.setup.tos.TOS_VERSION import foundation.e.apps.updates.manager.UpdatesWorkManager import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.modules.DataStoreModule import foundation.e.apps.utils.modules.PreferenceManagerModule import foundation.e.lib.telemetry.Telemetry import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.MainScope Loading @@ -50,6 +55,9 @@ class AppLoungeApplication : Application(), Configuration.Provider { @Inject lateinit var dataStoreModule: DataStoreModule @Inject lateinit var preferenceManagerModule: PreferenceManagerModule override fun onCreate() { super.onCreate() Loading @@ -75,13 +83,16 @@ class AppLoungeApplication : Application(), Configuration.Provider { if (priority < Log.WARN) { return } if (priority == Log.ERROR) { Telemetry.reportMessage("$tag: $message") } Log.println(priority, tag, message) } }) } UpdatesWorkManager.enqueueWork( this, preferenceManagerModule.getUpdateInterval(), ExistingPeriodicWorkPolicy.KEEP ) } override fun getWorkManagerConfiguration() = Loading
app/src/main/java/foundation/e/apps/MainActivity.kt +20 −1 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.exceptions.GPlayValidationException import foundation.e.apps.utils.modules.CommonUtilsFunctions import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import timber.log.Timber Loading Loading @@ -130,7 +131,10 @@ class MainActivity : AppCompatActivity() { viewModel.gPlayAuthData = data as AuthData } else if (exception is GPlayValidationException) { val email = otherPayload.toString() viewModel.uploadFaultyTokenToEcloud(email, CommonUtilsFunctions.getAppBuildInfo()) viewModel.uploadFaultyTokenToEcloud( email, CommonUtilsFunctions.getAppBuildInfo() ) } } } Loading Loading @@ -213,6 +217,8 @@ class MainActivity : AppCompatActivity() { viewModel.updateAppWarningList() lifecycleScope.launchWhenResumed { observeInvalidAuth() EventBus.events.filter { appEvent -> appEvent is AppEvent.SignatureMissMatchError }.collectLatest { Loading @@ -226,6 +232,19 @@ class MainActivity : AppCompatActivity() { } } private suspend fun observeInvalidAuth() { EventBus.events.filter { appEvent -> appEvent is AppEvent.InvalidAuthEvent }.distinctUntilChanged { old, new -> ((old.data is String) && (new.data is String) && old.data == new.data) }.collectLatest { val data = it.data as String if (data.isNotBlank()) { loginViewModel.markInvalidAuthObject(data) } } } private fun setupBottomNavItemSelectedListener( bottomNavigationView: BottomNavigationView, navHostFragment: NavHostFragment, Loading
app/src/main/java/foundation/e/apps/api/DownloadManager.kt +18 −31 Original line number Diff line number Diff line Loading @@ -96,10 +96,18 @@ class DownloadManager @Inject constructor( downloadFile: File, downloadCompleted: ((Boolean, String) -> Unit)? ): Long { var downloadId = -1L try { val request = DownloadManager.Request(Uri.parse(url)) .setTitle(context.getString(R.string.downloading)) .setDestinationUri(Uri.fromFile(downloadFile)) val downloadId = downloadManager.enqueue(request) downloadId = downloadManager.enqueue(request) } catch (e: java.lang.NullPointerException) { Timber.e(e, "Url: $url; downloadFilePath: ${downloadFile.absolutePath}") downloadCompleted?.invoke(false, e.localizedMessage ?: "No message found!") return downloadId } downloadsMaps[downloadId] = true tickerFlow(downloadId, .5.seconds).onEach { checkDownloadProgress(downloadId, downloadFile.absolutePath, downloadCompleted) Loading @@ -107,7 +115,7 @@ class DownloadManager @Inject constructor( return downloadId } private fun checkDownloadProgress( fun checkDownloadProgress( downloadId: Long, filePath: String = "", downloadCompleted: ((Boolean, String) -> Unit)? Loading Loading @@ -154,6 +162,10 @@ class DownloadManager @Inject constructor( return getDownloadStatus(downloadId) == DownloadManager.STATUS_SUCCESSFUL } fun hasDownloadFailed(downloadId: Long): Boolean { return getDownloadStatus(downloadId) == DownloadManager.STATUS_FAILED } private fun getDownloadStatus(downloadId: Long): Int { try { downloadManager.query(downloadManagerQuery.setFilterById(downloadId)) Loading @@ -161,7 +173,7 @@ class DownloadManager @Inject constructor( if (cursor.moveToFirst()) { val status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) Timber.d("Download Failed: downloadId: $downloadId $status") Timber.d("Download Status: downloadId: $downloadId $status") return status } } Loading @@ -170,29 +182,4 @@ class DownloadManager @Inject constructor( } return DownloadManager.STATUS_FAILED } suspend fun checkDownloadProcess(downloadingIds: LongArray, handleFailed: suspend () -> Unit) { try { downloadManager.query(downloadManagerQuery.setFilterById(*downloadingIds)) .use { cursor -> if (!cursor.moveToFirst()) { return@use } while (!cursor.isAfterLast) { val status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) if (status == DownloadManager.STATUS_FAILED) { handleFailed() } cursor.moveToNext() } } } catch (e: Exception) { Timber.e(e) } } }
app/src/main/java/foundation/e/apps/api/exodus/ExodusTrackerApi.kt +8 −5 Original line number Diff line number Diff line Loading @@ -3,17 +3,20 @@ package foundation.e.apps.api.exodus import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query interface ExodusTrackerApi { companion object { const val BASE_URL = "https://exodus.ecloud.global/api/" const val VERSION = "190239" } @GET("trackers?v=$VERSION") suspend fun getTrackerList(): Response<Trackers> @GET("trackers?v={date}") suspend fun getTrackerList(@Path("date") date: String): Response<Trackers> @GET("search/{appHandle}/details?v=$VERSION") suspend fun getTrackerInfoOfApp(@Path("appHandle") appHandle: String): Response<List<Report>> @GET("search/{appHandle}/details") suspend fun getTrackerInfoOfApp( @Path("appHandle") appHandle: String, @Query("v") versionCode: Int, ): Response<List<Report>> }