Add app permission sheet
This commit is contained in:
@@ -40,7 +40,7 @@ fun Context.showDialog(@StringRes titleId: Int, @StringRes messageId: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.showDialog(title: String, message: String) {
|
||||
fun Context.showDialog(title: String?, message: String?) {
|
||||
runOnUiThread {
|
||||
val backgroundColor: Int = getStyledAttributeColor(android.R.attr.colorBackground)
|
||||
val builder = MaterialAlertDialogBuilder(this).apply {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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 Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.model
|
||||
|
||||
data class AppPermission(
|
||||
var name: String,
|
||||
var permission: String,
|
||||
var raw: String,
|
||||
var flags: Int,
|
||||
var icon: Int
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return when (other) {
|
||||
is AppPermission -> other.permission == permission
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return permission.hashCode()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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 Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.aurora.store.view.custom.layouts
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PermissionGroupInfo
|
||||
import android.content.pm.PermissionInfo
|
||||
import android.content.res.Resources.NotFoundException
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.aurora.extensions.showDialog
|
||||
import com.aurora.store.R
|
||||
import java.util.*
|
||||
|
||||
class PermissionGroup : LinearLayout {
|
||||
|
||||
private lateinit var permissionGroupInfo: PermissionGroupInfo
|
||||
private lateinit var packageManager: PackageManager
|
||||
|
||||
private val permissionMap: MutableMap<String, String> = HashMap()
|
||||
|
||||
constructor(context: Context?) : super(context) {
|
||||
init()
|
||||
}
|
||||
|
||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
|
||||
init()
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
) {
|
||||
init()
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
constructor(
|
||||
context: Context?,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||
init()
|
||||
}
|
||||
|
||||
private fun init() {
|
||||
inflate(context, R.layout.view_permission, this)
|
||||
packageManager = context.packageManager
|
||||
}
|
||||
|
||||
fun setPermissionGroupInfo(permissionGroupInfo: PermissionGroupInfo) {
|
||||
this.permissionGroupInfo = permissionGroupInfo
|
||||
val imageView = findViewById<ImageView>(R.id.img)
|
||||
imageView.setImageDrawable(getPermissionGroupIcon(permissionGroupInfo))
|
||||
//imageView.setColorFilter(getContext().getStyledAttributeColor(imageView.getContext(), android.R.attr.colorAccent));
|
||||
}
|
||||
|
||||
fun addPermission(permissionInfo: PermissionInfo) {
|
||||
val title = permissionInfo.loadLabel(packageManager)
|
||||
val description = permissionInfo.loadDescription(packageManager)
|
||||
|
||||
permissionMap[getReadableLabel(title.toString(), permissionInfo.packageName)] =
|
||||
if (description.isNullOrEmpty())
|
||||
"No description"
|
||||
else
|
||||
description.toString()
|
||||
|
||||
val permissionLabels: List<String> = ArrayList(permissionMap.keys)
|
||||
val permissionLabelsView = findViewById<LinearLayout>(R.id.permission_labels)
|
||||
permissionLabelsView.removeAllViews()
|
||||
|
||||
permissionLabels
|
||||
.filter { it.isNotEmpty() }
|
||||
.sortedBy { it }
|
||||
.forEach {
|
||||
addPermissionLabel(
|
||||
permissionLabelsView,
|
||||
it,
|
||||
permissionMap[it]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addPermissionLabel(
|
||||
permissionLabelsView: LinearLayout,
|
||||
label: String,
|
||||
description: String?
|
||||
) {
|
||||
val textView = TextView(context)
|
||||
textView.text = label
|
||||
textView.setOnClickListener {
|
||||
var title: String = permissionGroupInfo.loadLabel(packageManager).toString()
|
||||
|
||||
if (title.contains("UNDEFINED")) {
|
||||
title = "Android"
|
||||
}
|
||||
|
||||
title = title.capitalize(Locale.getDefault())
|
||||
|
||||
context.showDialog(title, description)
|
||||
}
|
||||
|
||||
permissionLabelsView.addView(textView)
|
||||
}
|
||||
|
||||
private fun getPermissionGroupIcon(permissionGroupInfo: PermissionGroupInfo?): Drawable? {
|
||||
return try {
|
||||
ContextCompat.getDrawable(context, permissionGroupInfo!!.icon)
|
||||
} catch (e: NotFoundException) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1)
|
||||
permissionGroupInfo!!.loadUnbadgedIcon(packageManager)
|
||||
else
|
||||
permissionGroupInfo!!.loadIcon(packageManager)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getReadableLabel(label: String, packageName: String): String {
|
||||
val prefixes: MutableList<String> = mutableListOf(
|
||||
"android",
|
||||
packageName
|
||||
)
|
||||
|
||||
if (label.contains("UNDEFINED")) {
|
||||
return "Android"
|
||||
}
|
||||
|
||||
prefixes
|
||||
.map { "$it.permission." }
|
||||
.forEach {
|
||||
if (label.startsWith(it)) {
|
||||
return it.replace(it, "")
|
||||
.replace("_", " ")
|
||||
.toLowerCase(Locale.getDefault())
|
||||
.capitalize(Locale.getDefault())
|
||||
}
|
||||
}
|
||||
|
||||
return label.capitalize(Locale.getDefault())
|
||||
}
|
||||
}
|
||||
@@ -343,6 +343,7 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
||||
inflateAppRatingAndReviews(B.layoutDetailsReview, app)
|
||||
inflateAppDevInfo(B.layoutDetailsDev, app)
|
||||
inflateAppPrivacy(B.layoutDetailsPrivacy, app)
|
||||
inflateAppPermission(B.layoutDetailsPermissions, app)
|
||||
|
||||
if (!authData.isAnonymous) {
|
||||
app.testingProgram?.let {
|
||||
|
||||
@@ -31,6 +31,10 @@ import androidx.core.text.HtmlCompat
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.airbnb.epoxy.EpoxyRecyclerView
|
||||
import com.aurora.Constants
|
||||
import com.aurora.extensions.hide
|
||||
import com.aurora.extensions.load
|
||||
import com.aurora.extensions.show
|
||||
import com.aurora.extensions.toast
|
||||
import com.aurora.gplayapi.data.models.*
|
||||
import com.aurora.gplayapi.helpers.AppDetailsHelper
|
||||
import com.aurora.gplayapi.helpers.ReviewsHelper
|
||||
@@ -43,10 +47,6 @@ import com.aurora.store.data.providers.AuthProvider
|
||||
import com.aurora.store.databinding.*
|
||||
import com.aurora.store.util.CommonUtil
|
||||
import com.aurora.store.util.NavigationUtil
|
||||
import com.aurora.extensions.hide
|
||||
import com.aurora.extensions.load
|
||||
import com.aurora.extensions.show
|
||||
import com.aurora.extensions.toast
|
||||
import com.aurora.store.view.custom.RatingView
|
||||
import com.aurora.store.view.epoxy.controller.DetailsCarouselController
|
||||
import com.aurora.store.view.epoxy.controller.GenericCarouselController
|
||||
@@ -55,6 +55,7 @@ import com.aurora.store.view.epoxy.views.details.ReviewViewModel_
|
||||
import com.aurora.store.view.epoxy.views.details.ScreenshotView
|
||||
import com.aurora.store.view.epoxy.views.details.ScreenshotViewModel_
|
||||
import com.aurora.store.view.ui.commons.BaseActivity
|
||||
import com.aurora.store.view.ui.sheets.PermissionBottomSheet
|
||||
import com.aurora.store.viewmodel.details.DetailsClusterViewModel
|
||||
import nl.komponents.kovenant.task
|
||||
import nl.komponents.kovenant.ui.failUi
|
||||
@@ -339,6 +340,14 @@ abstract class BaseDetailsActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
fun inflateAppPermission(B: LayoutDetailsPermissionsBinding, app: App) {
|
||||
B.headerPermission.addClickListener {
|
||||
PermissionBottomSheet.newInstance(app)
|
||||
.show(supportFragmentManager, PermissionBottomSheet.TAG)
|
||||
}
|
||||
B.txtPermissionCount.text = ("${app.permissions.size} permissions")
|
||||
}
|
||||
|
||||
private fun updateBetaActions(B: LayoutDetailsBetaBinding, isSubscribed: Boolean) {
|
||||
if (isSubscribed) {
|
||||
B.btnBetaAction.text = getString(R.string.action_leave)
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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 Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
package com.aurora.store.view.ui.sheets
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PermissionGroupInfo
|
||||
import android.content.pm.PermissionInfo
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import com.aurora.Constants
|
||||
import com.aurora.extensions.hide
|
||||
import com.aurora.extensions.show
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.databinding.SheetPermissionsBinding
|
||||
import com.aurora.store.view.custom.layouts.PermissionGroup
|
||||
import java.util.*
|
||||
|
||||
class PermissionBottomSheet : BaseBottomSheet() {
|
||||
|
||||
private lateinit var B: SheetPermissionsBinding
|
||||
private lateinit var app: App
|
||||
private lateinit var packageManager: PackageManager
|
||||
|
||||
companion object {
|
||||
|
||||
const val TAG = "PermissionBottomSheet"
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(
|
||||
app: App
|
||||
): PermissionBottomSheet {
|
||||
return PermissionBottomSheet().apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(Constants.STRING_APP, gson.toJson(app))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateContentView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
B = SheetPermissionsBinding.inflate(inflater)
|
||||
return B.root
|
||||
}
|
||||
|
||||
override fun onContentViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val bundle = arguments
|
||||
bundle?.let {
|
||||
val rawApp = bundle.getString(Constants.STRING_APP, "{}")
|
||||
app = gson.fromJson(rawApp, App::class.java)
|
||||
if (app.packageName.isNotEmpty()) {
|
||||
inflateData()
|
||||
} else {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateData() {
|
||||
packageManager = requireContext().packageManager
|
||||
|
||||
val permissionGroupWidgets: MutableMap<String, PermissionGroup?> =
|
||||
HashMap<String, PermissionGroup?>()
|
||||
for (permissionName in app.permissions) {
|
||||
|
||||
val permissionInfo = getPermissionInfo(permissionName) ?: continue
|
||||
val permissionGroupInfo = getPermissionGroupInfo(permissionInfo)
|
||||
var permissionGroup: PermissionGroup?
|
||||
|
||||
if (permissionGroupWidgets.containsKey(permissionGroupInfo.name)) {
|
||||
permissionGroup = permissionGroupWidgets[permissionGroupInfo.name]
|
||||
} else {
|
||||
permissionGroup = PermissionGroup(context)
|
||||
permissionGroup.setPermissionGroupInfo(permissionGroupInfo)
|
||||
permissionGroup.layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
permissionGroupWidgets[permissionGroupInfo.name] = permissionGroup
|
||||
}
|
||||
|
||||
permissionGroup?.addPermission(permissionInfo)
|
||||
}
|
||||
|
||||
B.permissionsContainer.removeAllViews()
|
||||
|
||||
val permissionGroupLabels: List<String> = ArrayList(permissionGroupWidgets.keys)
|
||||
permissionGroupLabels.sortedBy { it }.forEach {
|
||||
B.permissionsContainer.addView(permissionGroupWidgets[it])
|
||||
}
|
||||
|
||||
if (permissionGroupLabels.isEmpty())
|
||||
B.permissionsNone.show()
|
||||
else
|
||||
B.permissionsNone.hide()
|
||||
}
|
||||
|
||||
private fun getPermissionInfo(permissionName: String): PermissionInfo? {
|
||||
return try {
|
||||
packageManager.getPermissionInfo(permissionName, 0)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPermissionGroupInfo(permissionInfo: PermissionInfo): PermissionGroupInfo {
|
||||
val permissionGroupInfo: PermissionGroupInfo = if (null == permissionInfo.group) {
|
||||
getFakePermissionGroupInfo(permissionInfo.packageName)
|
||||
} else {
|
||||
try {
|
||||
packageManager.getPermissionGroupInfo(permissionInfo.group!!, 0)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
getFakePermissionGroupInfo(permissionInfo.packageName)
|
||||
}
|
||||
}
|
||||
if (permissionGroupInfo.icon == 0) {
|
||||
permissionGroupInfo.icon = R.drawable.ic_permission_android
|
||||
}
|
||||
return permissionGroupInfo
|
||||
}
|
||||
|
||||
private fun getFakePermissionGroupInfo(packageName: String): PermissionGroupInfo {
|
||||
val permissionGroupInfo = PermissionGroupInfo()
|
||||
when (packageName) {
|
||||
"android" -> {
|
||||
permissionGroupInfo.icon = R.drawable.ic_permission_android
|
||||
permissionGroupInfo.name = "android"
|
||||
}
|
||||
"com.google.android.gsf", "com.android.vending" -> {
|
||||
permissionGroupInfo.icon = R.drawable.ic_permission_google
|
||||
permissionGroupInfo.name = "google"
|
||||
}
|
||||
else -> {
|
||||
permissionGroupInfo.icon = R.drawable.ic_permission_unknown
|
||||
permissionGroupInfo.name = "unknown"
|
||||
}
|
||||
}
|
||||
return permissionGroupInfo
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user