Add ability to grant permission with Shizuku

This commit is contained in:
Maksim Karasev 2023-09-11 16:35:04 +03:00
parent 4b33b2427a
commit 0107d07cec
3 changed files with 94 additions and 10 deletions

View file

@ -43,6 +43,11 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
def shizuku_version = '13.1.4'
implementation "dev.rikka.shizuku:api:$shizuku_version"
implementation "dev.rikka.shizuku:provider:$shizuku_version"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

View file

@ -10,6 +10,13 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication">
<provider
android:name="rikka.shizuku.ShizukuProvider"
android:authorities="${applicationId}.shizuku"
android:multiprocess="false"
android:enabled="true"
android:exported="true"
android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />
<activity
android:name=".MainActivity"
android:exported="true">

View file

@ -1,39 +1,43 @@
package ru.karasevm.privatednstoggle
import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent
import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatActivity
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.IBinder
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.LinearLayoutManager
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import rikka.shizuku.Shizuku
import rikka.shizuku.ShizukuBinderWrapper
import rikka.shizuku.ShizukuProvider
import rikka.shizuku.SystemServiceHelper
import ru.karasevm.privatednstoggle.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogListener, DeleteServerDialogFragment.NoticeDialogListener {
class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogListener, DeleteServerDialogFragment.NoticeDialogListener, Shizuku.OnRequestPermissionResultListener {
private lateinit var linearLayoutManager: LinearLayoutManager
private lateinit var binding: ActivityMainBinding
private var items = mutableListOf<String>()
private lateinit var sharedPrefs: SharedPreferences
private lateinit var adapter: RecyclerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Shizuku.addRequestPermissionResultListener(this::onRequestPermissionResult)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
if (checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) != PackageManager.PERMISSION_GRANTED) {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://karasevm.github.io/PrivateDNSAndroid/"))
startActivity(browserIntent)
finish()
}
linearLayoutManager = LinearLayoutManager(this)
binding.recyclerView.layoutManager = linearLayoutManager
@ -56,6 +60,38 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
return true
}
override fun onResume() {
super.onResume()
// Check if Shizuku is available
if (Shizuku.pingBinder()) {
// check if permission is granted already
val isGranted = if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
checkSelfPermission(ShizukuProvider.PERMISSION) == PackageManager.PERMISSION_GRANTED
} else {
Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED
}
// request permission if not granted
if (!isGranted && !Shizuku.shouldShowRequestPermissionRationale()) {
if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
requestPermissions(arrayOf(ShizukuProvider.PERMISSION), 1)
} else {
Shizuku.requestPermission(1)
}
}
} else {
if (checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) != PackageManager.PERMISSION_GRANTED) {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://karasevm.github.io/PrivateDNSAndroid/"))
startActivity(browserIntent)
finish()
}
}
}
override fun onDestroy() {
super.onDestroy()
Shizuku.removeRequestPermissionResultListener(this::onRequestPermissionResult)
}
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.add_server -> {
val newFragment = AddServerDialogFragment()
@ -96,5 +132,41 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
}
@SuppressLint("PrivateApi")
override fun onRequestPermissionResult(requestCode: Int, grantResult: Int) {
val isGranted = grantResult == PackageManager.PERMISSION_GRANTED
if (isGranted) {
val packageName = "ru.karasevm.privatednstoggle"
val iPmClass = Class.forName("android.content.pm.IPackageManager")
val iPmStub = Class.forName("android.content.pm.IPackageManager\$Stub")
val asInterfaceMethod = iPmStub.getMethod("asInterface", IBinder::class.java)
val grantRuntimePermissionMethod = iPmClass.getMethod(
"grantRuntimePermission",
String::class.java /* package name */,
String::class.java /* permission name */,
Int::class.java /* user ID */
)
val iPmInstance = asInterfaceMethod.invoke(
null, ShizukuBinderWrapper(
SystemServiceHelper.getSystemService("package")
)
)
grantRuntimePermissionMethod.invoke(
iPmInstance,
packageName,
Manifest.permission.WRITE_SECURE_SETTINGS,
0
)
} else if (checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) != PackageManager.PERMISSION_GRANTED) {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://karasevm.github.io/PrivateDNSAndroid/"))
startActivity(browserIntent)
finish()
}
}
}