Loading app/build.gradle +1 −1 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ plugins { def versionMajor = 2 def versionMinor = 6 def versionPatch = 0 def versionPatch = 1 def getGitHash = { -> def stdOut = new ByteArrayOutputStream() Loading app/src/main/AndroidManifest.xml +9 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,15 @@ </intent-filter> </receiver> <receiver android:name=".receivers.DumpAuthData" android:enabled="true" android:exported="true" tools:ignore="ExportedReceiver"> <intent-filter> <action android:name="foundation.e.apps.action.DUMP_GACCOUNT_INFO"/> </intent-filter> </receiver> <!-- TODO: ExportedReceiver, suppressing because changes are needed in other apps --> <receiver android:name=".install.receiver.PWAPlayerStatusReceiver" tools:ignore="ExportedReceiver" Loading app/src/main/java/foundation/e/apps/MainActivity.kt +37 −3 Original line number Diff line number Diff line Loading @@ -40,8 +40,10 @@ 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.LoginSourceGPlay import foundation.e.apps.data.login.LoginViewModel import foundation.e.apps.data.login.exceptions.GPlayValidationException import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.databinding.ActivityMainBinding import foundation.e.apps.install.updates.UpdatesNotifier import foundation.e.apps.ui.MainActivityViewModel Loading @@ -56,6 +58,8 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject @AndroidEntryPoint class MainActivity : AppCompatActivity() { Loading @@ -65,6 +69,9 @@ class MainActivity : AppCompatActivity() { private val TAG = MainActivity::class.java.simpleName private lateinit var viewModel: MainActivityViewModel @Inject lateinit var preferenceManagerModule: PreferenceManagerModule override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Loading Loading @@ -130,6 +137,13 @@ class MainActivity : AppCompatActivity() { email, SystemInfoProvider.getAppBuildInfo() ) } else if (exception != null) { Timber.e(exception, "Login failed! message: ${exception?.localizedMessage}") ApplicationDialogFragment( title = getString(R.string.sign_in_failed_title), message = getString(R.string.sign_in_failed_desc), positiveButtonText = getString(R.string.ok) ).show(supportFragmentManager, TAG) } } } Loading Loading @@ -207,6 +221,10 @@ class MainActivity : AppCompatActivity() { observeInvalidAuth() } launch { observeTooManyRequests() } launch { observeSignatureMissMatchError() } Loading Loading @@ -277,11 +295,27 @@ class MainActivity : AppCompatActivity() { }.distinctUntilChanged { old, new -> ((old.data is String) && (new.data is String) && old.data == new.data) }.collectLatest { val data = it.data as String validatedAuthObject(it) } } private fun validatedAuthObject(appEvent: AppEvent) { val data = appEvent.data as String if (data.isNotBlank()) { loginViewModel.markInvalidAuthObject(data) } } private suspend fun observeTooManyRequests() { EventBus.events.filter { appEvent -> appEvent is AppEvent.TooManyRequests }.collectLatest { binding.sessionErrorLayout.visibility = View.VISIBLE binding.retrySessionButton.setOnClickListener { binding.sessionErrorLayout.visibility = View.GONE loginViewModel.startLoginFlow(listOf(LoginSourceGPlay::class.java.simpleName)) } } } private fun setupBottomNavItemSelectedListener( Loading app/src/main/java/foundation/e/apps/data/Constants.kt +3 −0 Original line number Diff line number Diff line Loading @@ -6,4 +6,7 @@ object Constants { const val PREFERENCE_SHOW_FOSS = "showFOSSApplications" const val PREFERENCE_SHOW_PWA = "showPWAApplications" const val PREFERENCE_SHOW_GPLAY = "showAllApplications" const val ACTION_AUTHDATA_DUMP = "foundation.e.apps.action.DUMP_GACCOUNT_INFO" const val TAG_AUTHDATA_DUMP = "AUTHDATA_DUMP" } app/src/main/java/foundation/e/apps/data/blockedApps/BlockedAppRepository.kt +27 −24 Original line number Diff line number Diff line Loading @@ -20,20 +20,19 @@ package foundation.e.apps.data.blockedApps import com.google.gson.Gson import foundation.e.apps.data.DownloadManager import foundation.e.apps.data.fusedDownload.FileManager import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import timber.log.Timber import java.io.File import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton import kotlin.coroutines.resume @Singleton class BlockedAppRepository @Inject constructor( private val downloadManager: DownloadManager, private val gson: Gson, @Named("cacheDir") private val cacheDir: String, @Named("ioCoroutineScope") private val coroutineScope: CoroutineScope ) { companion object { Loading @@ -48,7 +47,11 @@ class BlockedAppRepository @Inject constructor( return blockedAppInfoList?.notWorkingApps ?: listOf() } fun fetchUpdateOfAppWarningList() { fun isBlockedApp(packageName: String) = blockedAppInfoList?.notWorkingApps?.contains(packageName) ?: false suspend fun fetchUpdateOfAppWarningList(): Boolean = suspendCancellableCoroutine { continuation -> downloadManager.downloadFileInCache( APP_WARNING_LIST_FILE_URL, fileName = WARNING_LIST_FILE_NAME Loading @@ -56,18 +59,19 @@ class BlockedAppRepository @Inject constructor( if (success) { parseBlockedAppDataFromFile() } continuation.resume(true) } } private fun parseBlockedAppDataFromFile() { coroutineScope.launch { blockedAppInfoList = try { val outputPath = "$cacheDir/warning_list/" FileManager.moveFile("$cacheDir/", WARNING_LIST_FILE_NAME, outputPath) val downloadedFile = File(outputPath + WARNING_LIST_FILE_NAME) Timber.i("Blocked list file exists: ${downloadedFile.exists()}") Timber.d("Blocked list file exists: ${downloadedFile.exists()}") val blockedAppInfoJson = String(downloadedFile.inputStream().readBytes()) Timber.i("Blocked list file contents: $blockedAppInfoJson") Timber.d("Blocked list file contents: $blockedAppInfoJson") gson.fromJson(blockedAppInfoJson, AppWarningInfo::class.java) } catch (exception: Exception) { Timber.e(exception.localizedMessage ?: "", exception) Loading @@ -75,4 +79,3 @@ class BlockedAppRepository @Inject constructor( } } } } Loading
app/build.gradle +1 −1 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ plugins { def versionMajor = 2 def versionMinor = 6 def versionPatch = 0 def versionPatch = 1 def getGitHash = { -> def stdOut = new ByteArrayOutputStream() Loading
app/src/main/AndroidManifest.xml +9 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,15 @@ </intent-filter> </receiver> <receiver android:name=".receivers.DumpAuthData" android:enabled="true" android:exported="true" tools:ignore="ExportedReceiver"> <intent-filter> <action android:name="foundation.e.apps.action.DUMP_GACCOUNT_INFO"/> </intent-filter> </receiver> <!-- TODO: ExportedReceiver, suppressing because changes are needed in other apps --> <receiver android:name=".install.receiver.PWAPlayerStatusReceiver" tools:ignore="ExportedReceiver" Loading
app/src/main/java/foundation/e/apps/MainActivity.kt +37 −3 Original line number Diff line number Diff line Loading @@ -40,8 +40,10 @@ 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.LoginSourceGPlay import foundation.e.apps.data.login.LoginViewModel import foundation.e.apps.data.login.exceptions.GPlayValidationException import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.databinding.ActivityMainBinding import foundation.e.apps.install.updates.UpdatesNotifier import foundation.e.apps.ui.MainActivityViewModel Loading @@ -56,6 +58,8 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject @AndroidEntryPoint class MainActivity : AppCompatActivity() { Loading @@ -65,6 +69,9 @@ class MainActivity : AppCompatActivity() { private val TAG = MainActivity::class.java.simpleName private lateinit var viewModel: MainActivityViewModel @Inject lateinit var preferenceManagerModule: PreferenceManagerModule override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Loading Loading @@ -130,6 +137,13 @@ class MainActivity : AppCompatActivity() { email, SystemInfoProvider.getAppBuildInfo() ) } else if (exception != null) { Timber.e(exception, "Login failed! message: ${exception?.localizedMessage}") ApplicationDialogFragment( title = getString(R.string.sign_in_failed_title), message = getString(R.string.sign_in_failed_desc), positiveButtonText = getString(R.string.ok) ).show(supportFragmentManager, TAG) } } } Loading Loading @@ -207,6 +221,10 @@ class MainActivity : AppCompatActivity() { observeInvalidAuth() } launch { observeTooManyRequests() } launch { observeSignatureMissMatchError() } Loading Loading @@ -277,11 +295,27 @@ class MainActivity : AppCompatActivity() { }.distinctUntilChanged { old, new -> ((old.data is String) && (new.data is String) && old.data == new.data) }.collectLatest { val data = it.data as String validatedAuthObject(it) } } private fun validatedAuthObject(appEvent: AppEvent) { val data = appEvent.data as String if (data.isNotBlank()) { loginViewModel.markInvalidAuthObject(data) } } private suspend fun observeTooManyRequests() { EventBus.events.filter { appEvent -> appEvent is AppEvent.TooManyRequests }.collectLatest { binding.sessionErrorLayout.visibility = View.VISIBLE binding.retrySessionButton.setOnClickListener { binding.sessionErrorLayout.visibility = View.GONE loginViewModel.startLoginFlow(listOf(LoginSourceGPlay::class.java.simpleName)) } } } private fun setupBottomNavItemSelectedListener( Loading
app/src/main/java/foundation/e/apps/data/Constants.kt +3 −0 Original line number Diff line number Diff line Loading @@ -6,4 +6,7 @@ object Constants { const val PREFERENCE_SHOW_FOSS = "showFOSSApplications" const val PREFERENCE_SHOW_PWA = "showPWAApplications" const val PREFERENCE_SHOW_GPLAY = "showAllApplications" const val ACTION_AUTHDATA_DUMP = "foundation.e.apps.action.DUMP_GACCOUNT_INFO" const val TAG_AUTHDATA_DUMP = "AUTHDATA_DUMP" }
app/src/main/java/foundation/e/apps/data/blockedApps/BlockedAppRepository.kt +27 −24 Original line number Diff line number Diff line Loading @@ -20,20 +20,19 @@ package foundation.e.apps.data.blockedApps import com.google.gson.Gson import foundation.e.apps.data.DownloadManager import foundation.e.apps.data.fusedDownload.FileManager import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import timber.log.Timber import java.io.File import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton import kotlin.coroutines.resume @Singleton class BlockedAppRepository @Inject constructor( private val downloadManager: DownloadManager, private val gson: Gson, @Named("cacheDir") private val cacheDir: String, @Named("ioCoroutineScope") private val coroutineScope: CoroutineScope ) { companion object { Loading @@ -48,7 +47,11 @@ class BlockedAppRepository @Inject constructor( return blockedAppInfoList?.notWorkingApps ?: listOf() } fun fetchUpdateOfAppWarningList() { fun isBlockedApp(packageName: String) = blockedAppInfoList?.notWorkingApps?.contains(packageName) ?: false suspend fun fetchUpdateOfAppWarningList(): Boolean = suspendCancellableCoroutine { continuation -> downloadManager.downloadFileInCache( APP_WARNING_LIST_FILE_URL, fileName = WARNING_LIST_FILE_NAME Loading @@ -56,18 +59,19 @@ class BlockedAppRepository @Inject constructor( if (success) { parseBlockedAppDataFromFile() } continuation.resume(true) } } private fun parseBlockedAppDataFromFile() { coroutineScope.launch { blockedAppInfoList = try { val outputPath = "$cacheDir/warning_list/" FileManager.moveFile("$cacheDir/", WARNING_LIST_FILE_NAME, outputPath) val downloadedFile = File(outputPath + WARNING_LIST_FILE_NAME) Timber.i("Blocked list file exists: ${downloadedFile.exists()}") Timber.d("Blocked list file exists: ${downloadedFile.exists()}") val blockedAppInfoJson = String(downloadedFile.inputStream().readBytes()) Timber.i("Blocked list file contents: $blockedAppInfoJson") Timber.d("Blocked list file contents: $blockedAppInfoJson") gson.fromJson(blockedAppInfoJson, AppWarningInfo::class.java) } catch (exception: Exception) { Timber.e(exception.localizedMessage ?: "", exception) Loading @@ -75,4 +79,3 @@ class BlockedAppRepository @Inject constructor( } } } }