From 38e9e8771d416ca565db361b0560630632610c97 Mon Sep 17 00:00:00 2001 From: Rahul Kumar Patel Date: Mon, 1 Mar 2021 14:08:13 +0530 Subject: [PATCH] Add Permissions on Onboading Page --- app/src/main/AndroidManifest.xml | 3 +- app/src/main/assets/permissions.json | 12 ++ .../java/com/aurora/store/MainActivity.kt | 44 ++--- .../com/aurora/store/data/model/Permission.kt | 37 ++++ .../view/custom/layouts/PermissionGroup.kt | 2 +- .../epoxy/views/preference/PermissionView.kt | 84 +++++++++ .../view/ui/onboarding/OnboardingActivity.kt | 5 +- .../view/ui/onboarding/PermissionsFragment.kt | 167 ++++++++++++++++++ .../fragment_onboarding_permissions.xml | 72 ++++++++ .../fragment_onboarding_permissions.xml | 63 +++++++ app/src/main/res/layout/layout_permission.xml | 42 +++++ app/src/main/res/layout/view_installer.xml | 2 +- app/src/main/res/layout/view_permission.xml | 45 +++-- app/src/main/res/layout/view_theme.xml | 2 +- app/src/main/res/values/strings.xml | 12 ++ 15 files changed, 541 insertions(+), 51 deletions(-) create mode 100755 app/src/main/assets/permissions.json create mode 100644 app/src/main/java/com/aurora/store/data/model/Permission.kt create mode 100644 app/src/main/java/com/aurora/store/view/epoxy/views/preference/PermissionView.kt create mode 100644 app/src/main/java/com/aurora/store/view/ui/onboarding/PermissionsFragment.kt create mode 100644 app/src/main/res/layout-land/fragment_onboarding_permissions.xml create mode 100644 app/src/main/res/layout/fragment_onboarding_permissions.xml create mode 100644 app/src/main/res/layout/layout_permission.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9d5bfeb2f..6bc41341a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -40,8 +40,7 @@ android:name="android.permission.DELETE_PACKAGES" tools:ignore="ProtectedPermissions" /> - - + = Build.VERSION_CODES.R) { - if (!Environment.isExternalStorageManager()) - startActivity(Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)) + /*Check only if download to external storage is enabled*/ + if (Preferences.getBoolean(this, Preferences.PREFERENCE_DOWNLOAD_EXTERNAL)) { + checkExternalStorageAccessPermission() + checkExternalStorageManagerPermission() } } @@ -232,17 +222,17 @@ class MainActivity : BaseActivity() { } } - private fun pickExternalFileDir() { - val getContentIntent = Intent(Intent.ACTION_GET_CONTENT) - getContentIntent.type = "*/*" - getContentIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) - getContentIntent.putExtra(Intent.EXTRA_LOCAL_ONLY, true) - getContentIntent.addCategory(Intent.CATEGORY_OPENABLE) - startActivityForResult( - Intent.createChooser( - getContentIntent, - "Aurora Store - External Storage Access" - ), 1337 - ) + private fun checkExternalStorageAccessPermission() = runWithPermissions( + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) { + Log.i("Required permissions available") + } + + private fun checkExternalStorageManagerPermission() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (!Environment.isExternalStorageManager()) + startActivity(Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/data/model/Permission.kt b/app/src/main/java/com/aurora/store/data/model/Permission.kt new file mode 100644 index 000000000..ff00f29ed --- /dev/null +++ b/app/src/main/java/com/aurora/store/data/model/Permission.kt @@ -0,0 +1,37 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * 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 . + * + */ + +package com.aurora.store.data.model + +data class Permission( + var id: Int, + var title: String, + var subtitle: String +) { + override fun equals(other: Any?): Boolean { + return when (other) { + is Permission -> other.id == id + else -> false + } + } + + override fun hashCode(): Int { + return id.hashCode() + } +} diff --git a/app/src/main/java/com/aurora/store/view/custom/layouts/PermissionGroup.kt b/app/src/main/java/com/aurora/store/view/custom/layouts/PermissionGroup.kt index 26840b18c..83895eeb4 100644 --- a/app/src/main/java/com/aurora/store/view/custom/layouts/PermissionGroup.kt +++ b/app/src/main/java/com/aurora/store/view/custom/layouts/PermissionGroup.kt @@ -70,7 +70,7 @@ class PermissionGroup : LinearLayout { } private fun init() { - inflate(context, R.layout.view_permission, this) + inflate(context, R.layout.layout_permission, this) packageManager = context.packageManager } diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/preference/PermissionView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/PermissionView.kt new file mode 100644 index 000000000..08aa592d7 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/PermissionView.kt @@ -0,0 +1,84 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * 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 . + * + */ + +package com.aurora.store.view.epoxy.views.preference + +import android.content.Context +import android.util.AttributeSet +import android.widget.RelativeLayout +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.extensions.getString +import com.aurora.store.R +import com.aurora.store.data.model.Permission +import com.aurora.store.databinding.ViewPermissionBinding +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseView::class +) +class PermissionView : RelativeLayout { + + private lateinit var B: ViewPermissionBinding + + constructor(context: Context?) : super(context) { + init(context, null) + } + + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) { + init(context, attrs) + } + + private fun init(context: Context?, attrs: AttributeSet?) { + val view = inflate(context, R.layout.view_permission, this) + B = ViewPermissionBinding.bind(view) + } + + @ModelProp + fun permission(installer: Permission) { + B.line1.text = installer.title + B.line2.text = installer.subtitle + } + + @ModelProp + fun isGranted(granted: Boolean) { + if (granted) { + B.btnAction.isEnabled = false + B.btnAction.text = getString(R.string.action_granted) + } else { + B.btnAction.isEnabled = true + B.btnAction.text = getString(R.string.action_grant) + } + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + B.btnAction.setOnClickListener(onClickListener) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/ui/onboarding/OnboardingActivity.kt b/app/src/main/java/com/aurora/store/view/ui/onboarding/OnboardingActivity.kt index 0aeb1d698..a1ec82073 100644 --- a/app/src/main/java/com/aurora/store/view/ui/onboarding/OnboardingActivity.kt +++ b/app/src/main/java/com/aurora/store/view/ui/onboarding/OnboardingActivity.kt @@ -104,7 +104,7 @@ class OnboardingActivity : BaseActivity() { override fun onPageSelected(position: Int) { runOnUiThread { B.btnBackward.isEnabled = position != 0 - if (position == 3) { + if (position == 4) { B.btnForward.text = getString(R.string.action_finish) B.btnForward.setOnClickListener { save(PREFERENCE_INTRO, true) @@ -169,12 +169,13 @@ class OnboardingActivity : BaseActivity() { 1 -> return InstallerFragment() 2 -> return ThemeFragment() 3 -> return AccentFragment() + 4 -> return PermissionsFragment() } return Fragment() } override fun getItemCount(): Int { - return 4 + return 5 } } } \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/ui/onboarding/PermissionsFragment.kt b/app/src/main/java/com/aurora/store/view/ui/onboarding/PermissionsFragment.kt new file mode 100644 index 000000000..a56ab1cb2 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/ui/onboarding/PermissionsFragment.kt @@ -0,0 +1,167 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * 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 . + * + */ + +package com.aurora.store.view.ui.onboarding + +import android.Manifest +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.os.Environment +import android.provider.Settings +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.app.ActivityCompat +import com.aurora.extensions.isOAndAbove +import com.aurora.extensions.isRAndAbove +import com.aurora.extensions.toast +import com.aurora.store.BuildConfig +import com.aurora.store.R +import com.aurora.store.data.model.Permission +import com.aurora.store.databinding.FragmentOnboardingInstallerBinding +import com.aurora.store.view.epoxy.views.preference.PermissionViewModel_ +import com.aurora.store.view.ui.commons.BaseFragment +import com.livinglifetechway.quickpermissions_kotlin.runWithPermissions + + +class PermissionsFragment : BaseFragment() { + + private lateinit var B: FragmentOnboardingInstallerBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + B = FragmentOnboardingInstallerBinding.bind( + inflater.inflate( + R.layout.fragment_onboarding_installer, + container, + false + ) + ) + + return B.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + updateController() + } + + private fun updateController() { + + val installerList: List = listOf( + Permission( + 0, + getString(R.string.onboarding_permission_esa), + getString(R.string.onboarding_permission_esa_desc) + ), + + Permission( + 1, + getString(R.string.onboarding_permission_esm), + getString(R.string.onboarding_permission_esm_desc) + ), + + Permission( + 2, + getString(R.string.onboarding_permission_installer), + getString(R.string.onboarding_permission_installer_desc) + ) + ) + + B.epoxyRecycler.withModels { + setFilterDuplicates(true) + installerList.forEach { + add( + PermissionViewModel_() + .id(it.id) + .permission(it) + .isGranted( + when (it.id) { + 0 -> ActivityCompat.checkSelfPermission( + requireContext(), + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) == PackageManager.PERMISSION_GRANTED + 1 -> isRAndAbove() && Environment.isExternalStorageManager() + 2 -> isOAndAbove() && requireContext().packageManager.canRequestPackageInstalls() + else -> false + } + ) + .click { _ -> + when (it.id) { + 0 -> checkStorageAccessPermission() + 1 -> checkStorageManagerPermission() + 2 -> checkUnknownResourceInstallation() + } + } + ) + } + } + } + + private fun checkStorageAccessPermission() = runWithPermissions( + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE + ) { + toast(R.string.toast_permission_granted) + B.epoxyRecycler.requestModelBuild() + } + + private fun checkStorageManagerPermission() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (Environment.isExternalStorageManager()) { + toast("Permission granted") + } else { + startActivityForResult( + Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION), + 99 + ) + } + } + } + + private fun checkUnknownResourceInstallation() { + if (isOAndAbove()) { + startActivityForResult( + Intent( + Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, + Uri.parse("package:${BuildConfig.APPLICATION_ID}") + ), + 999 + ) + } else { + toast("Permission granted") + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + 99, 999 -> { + toast(R.string.toast_permission_granted) + B.epoxyRecycler.requestModelBuild() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout-land/fragment_onboarding_permissions.xml b/app/src/main/res/layout-land/fragment_onboarding_permissions.xml new file mode 100644 index 000000000..88f3060b8 --- /dev/null +++ b/app/src/main/res/layout-land/fragment_onboarding_permissions.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_onboarding_permissions.xml b/app/src/main/res/layout/fragment_onboarding_permissions.xml new file mode 100644 index 000000000..4cb1ca2b2 --- /dev/null +++ b/app/src/main/res/layout/fragment_onboarding_permissions.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_permission.xml b/app/src/main/res/layout/layout_permission.xml new file mode 100644 index 000000000..4f586bd5b --- /dev/null +++ b/app/src/main/res/layout/layout_permission.xml @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/app/src/main/res/layout/view_installer.xml b/app/src/main/res/layout/view_installer.xml index f5ed4726f..280c468c4 100644 --- a/app/src/main/res/layout/view_installer.xml +++ b/app/src/main/res/layout/view_installer.xml @@ -55,7 +55,7 @@ android:layout_width="@dimen/icon_size_category" android:layout_height="@dimen/icon_size_category" android:layout_alignParentEnd="true" - android:layout_centerInParent="true" + android:layout_centerVertical="true" android:clickable="false" android:focusable="false" android:minWidth="0dp" /> diff --git a/app/src/main/res/layout/view_permission.xml b/app/src/main/res/layout/view_permission.xml index 4f586bd5b..7b26cb7d6 100644 --- a/app/src/main/res/layout/view_permission.xml +++ b/app/src/main/res/layout/view_permission.xml @@ -20,23 +20,34 @@ + android:background="@drawable/bg_outlined_padded" + android:orientation="horizontal"> - - - - + android:layout_toStartOf="@id/btn_action" /> + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_theme.xml b/app/src/main/res/layout/view_theme.xml index 84baf03a6..362f33db2 100644 --- a/app/src/main/res/layout/view_theme.xml +++ b/app/src/main/res/layout/view_theme.xml @@ -45,6 +45,6 @@ android:layout_width="@dimen/icon_size_category" android:layout_height="@dimen/icon_size_category" android:layout_alignParentEnd="true" - android:layout_centerInParent="true" + android:layout_centerVertical="true" android:minWidth="0dp" /> \ 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 df992e8b0..1c5f344e5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -79,6 +79,8 @@ "Ratings" "Finish" "Save App bundle" + "Grant" + "Granted" "Home" "Ignore" Ignore version @@ -241,13 +243,22 @@ "Click to install" "Select a suitable installer" + "Aurora Store requires following permissions" "Select what you like" "Accent" "Installer" + "Permissions" "Themes" "Welcome" "How you doing?" + "External Storage Access" + "To save downloads (APKs & OBBs), export & import device configs on external storage." + "External Storage Manager" + "Required on devices running Android R+, additional to External Storage Access" + "Installer Permission" + "Allow installing apps from Aurora Store" + "Force clear installation sessions" "Clear abandon or pending installation sessions" "Downloads" @@ -328,5 +339,6 @@ "Whitelisted" "Copied to clipboard" "Failed to open developer settings, make sure it is enabled from device settings." + "Permission granted" "Device spoof applied successfully." \ No newline at end of file