Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9174c97 authored by Hasib Prince's avatar Hasib Prince
Browse files

refactor: validation age limit

parent e2dfd09e
Loading
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -222,8 +222,8 @@ class MainActivity : AppCompatActivity() {
            it is AppEvent.AgeLimitRestrictionEvent
        }.collectLatest {
            ApplicationDialogFragment(
                getString(R.string.unknown_error),
                getString(R.string.age_rate_limit_message),
                getString(R.string.restricted_app, it.data as String),
                getString(R.string.age_rate_limit_message, it.data as String),
                positiveButtonText = getString(R.string.ok),
            ).show(supportFragmentManager, TAG)
        }
+89 −0
Original line number Diff line number Diff line
/*
 *  Copyright MURENA SAS 2024
 *  Apps  Quickly and easily install Android apps onto your device!
 *
 *  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 <https://www.gnu.org/licenses/>.
 *
 */

package foundation.e.apps.data.blockedApps

import com.google.gson.Gson
import com.google.gson.JsonSyntaxException
import com.google.gson.reflect.TypeToken
import foundation.e.apps.data.install.FileManager
import timber.log.Timber
import java.io.File
import java.io.IOException
import javax.inject.Inject
import javax.inject.Named

class ContentRatingParser @Inject constructor(
    private val gson: Gson,
    @Named("cacheDir") private val cacheDir: String
) {

    companion object {
        private const val CONTENT_RATINGS_FILE_NAME = "content_ratings.json"
    }

    fun parseContentRatingData(): List<ContentRatingGroup> {
        return try {
            val outputPath = moveFile()
            val contentRatingJson = readJsonFromFile(outputPath)
            Timber.d("ContentRatings file contents: $contentRatingJson")
            parseJsonOfContentRatingGroup(contentRatingJson)
        } catch (exception: IOException) {
            handleException(exception)
        } catch (exception: JsonSyntaxException) {
            handleException(exception)
        }
    }

    private fun readJsonFromFile(outputPath: String): String {
        val downloadedFile =
            File(outputPath + CONTENT_RATINGS_FILE_NAME)
        val contentRatingJson = String(downloadedFile.inputStream().readBytes())

        return contentRatingJson
    }

    private fun moveFile(): String {
        val outputPath = "$cacheDir/content_ratings/"
        FileManager.moveFile(
            "$cacheDir/",
            CONTENT_RATINGS_FILE_NAME, outputPath
        )

        return outputPath
    }

    private fun parseJsonOfContentRatingGroup(contentRatingJson: String): List<ContentRatingGroup> {
        val contentRatingsListTypeGroup = object : TypeToken<List<ContentRatingGroup>>() {}.type
        val contentRatingGroups: List<ContentRatingGroup> =
            gson.fromJson(contentRatingJson, contentRatingsListTypeGroup)

        return contentRatingGroups.map {
            it.ratings = it.ratings.map { rating ->
                rating.lowercase()
            }
            it
        }
    }

    private fun handleException(exception: Exception): List<ContentRatingGroup> {
        Timber.e(exception.localizedMessage ?: "", exception)
        return listOf()
    }
}
+2 −38
Original line number Diff line number Diff line
@@ -33,8 +33,7 @@ import javax.inject.Singleton
@Singleton
class ContentRatingsRepository @Inject constructor(
    private val downloadManager: DownloadManager,
    private val gson: Gson,
    @Named("cacheDir") private val cacheDir: String
    private val contentRatingParser: ContentRatingParser
) {

    private var _contentRatingGroups = listOf<ContentRatingGroup>()
@@ -54,43 +53,8 @@ class ContentRatingsRepository @Inject constructor(
            fileName = CONTENT_RATINGS_FILE_NAME
        ) { success, _ ->
            if (success) {
                parseContentRatingData()
                contentRatingParser.parseContentRatingData()
            }
        }
    }

    private fun parseContentRatingData() {
        _contentRatingGroups = try {
            val outputPath = "$cacheDir/warning_list/"
            FileManager.moveFile(
                "$cacheDir/",
                CONTENT_RATINGS_FILE_NAME, outputPath
            )
            val downloadedFile = File(outputPath + CONTENT_RATINGS_FILE_NAME)
            val contentRatingJson = String(downloadedFile.inputStream().readBytes())
            Timber.d("ContentRatings file contents: $contentRatingJson")

            parseJsonOfContentRatingGroup(contentRatingJson)
        } catch (exception: JsonSyntaxException) {
            handleException(exception)
        }
    }

    private fun parseJsonOfContentRatingGroup(contentRatingJson: String): List<ContentRatingGroup> {
        val contentRatingsListTypeGroup = object : TypeToken<List<ContentRatingGroup>>() {}.type
        val contentRatingGroups: List<ContentRatingGroup> =
            gson.fromJson(contentRatingJson, contentRatingsListTypeGroup)

        return contentRatingGroups.map {
            it.ratings = it.ratings.map { rating ->
                rating.lowercase()
            }
            it
        }
    }

    private fun handleException(exception: Exception): MutableList<ContentRatingGroup> {
        Timber.e(exception.localizedMessage ?: "", exception)
        return mutableListOf()
    }
}
+5 −4
Original line number Diff line number Diff line
@@ -35,25 +35,26 @@ class ParentalControlRepository @Inject constructor(
            "content://foundation.e.parentalcontrol.provider/age"
    }

    fun getSelectedAgeGroup(): Ages? {
    fun getSelectedAgeGroup(): Age {
        val uri = Uri.parse(URI_PARENTAL_CONTROL_PROVIDER)
        val cursor = context.contentResolver.query(uri, null, null, null, null)

        cursor?.use {
            if (it.moveToFirst()) {
                val ageOrdinal = it.getInt(it.getColumnIndexOrThrow("age"))
                return Ages.values()[ageOrdinal]
                return Age.values()[ageOrdinal]
            }
        }

        return null
        return Age.PARENTAL_CONTROL_DISABLED
    }
}

enum class Ages {
enum class Age {
    THREE,
    SIX,
    ELEVEN,
    FIFTEEN,
    SEVENTEEN,
    PARENTAL_CONTROL_DISABLED
}
+12 −9
Original line number Diff line number Diff line
@@ -20,8 +20,9 @@
package foundation.e.apps.domain

import com.aurora.gplayapi.data.models.AuthData
import foundation.e.apps.data.ResultSupreme
import foundation.e.apps.data.application.ApplicationRepository
import foundation.e.apps.data.blockedApps.Ages
import foundation.e.apps.data.blockedApps.Age
import foundation.e.apps.data.blockedApps.ContentRatingGroup
import foundation.e.apps.data.blockedApps.ContentRatingsRepository
import foundation.e.apps.data.blockedApps.ParentalControlRepository
@@ -40,14 +41,17 @@ class ValidateAppAgeLimitUseCase @Inject constructor(
    private val playStoreRepository: PlayStoreRepository
) {

    suspend operator fun invoke(appInstall: AppInstall): Pair<Boolean, ResultStatus> {
    suspend operator fun invoke(appInstall: AppInstall): ResultSupreme<Boolean> {
        val authData = dataStoreManager.getAuthData()
        val selectedAgeGroup = parentalControlRepository.getSelectedAgeGroup()
        if (isParentalControlDisabled(selectedAgeGroup)) {
            return ResultSupreme.Success( true)
        }

        if (!verifyContentRatingExists(appInstall, authData)) {
            return Pair(false, ResultStatus.UNKNOWN)
            return ResultSupreme.Error(false)
        }

        val selectedAgeGroup = parentalControlRepository.getSelectedAgeGroup()
        val allowedContentRating = contentRatingRepository.contentRatingGroups.find {
            it.id == selectedAgeGroup.toString()
        }
@@ -58,9 +62,8 @@ class ValidateAppAgeLimitUseCase @Inject constructor(
                    "Allowed content rating: $allowedContentRating"
        )

        val isAppAgeLimitedValidated = isParentalControlDisabled(selectedAgeGroup)
                || isAppAgeRatingValid(appInstall, allowedContentRating)
        return Pair(isAppAgeLimitedValidated, ResultStatus.OK)
        val isAppAgeLimitValid = isAppAgeRatingValid(appInstall, allowedContentRating)
        return ResultSupreme.Success(isAppAgeLimitValid)
    }

    private fun isAppAgeRatingValid(
@@ -69,8 +72,8 @@ class ValidateAppAgeLimitUseCase @Inject constructor(
    ) = (appInstall.contentRating.id.isNotEmpty()
            && allowedContentRating?.ratings?.contains(appInstall.contentRating.id) == true)

    private fun isParentalControlDisabled(selectedAgeGroup: Ages?) =
        selectedAgeGroup == null
    private fun isParentalControlDisabled(selectedAgeGroup: Age?) =
        selectedAgeGroup == Age.PARENTAL_CONTROL_DISABLED

    private suspend fun verifyContentRatingExists(
        appInstall: AppInstall,
Loading