Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">

<application
android:name=".App"
android:description="@android:string/unknownName"
android:label="Xposed Example"
android:theme="@android:style/Theme.DeviceDefault"
Expand Down
67 changes: 67 additions & 0 deletions app/src/main/java/io/github/libxposed/example/App.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package io.github.libxposed.example

import android.app.Application
import io.github.libxposed.service.XposedService
import io.github.libxposed.service.XposedServiceHelper
import java.util.concurrent.CopyOnWriteArraySet
import kotlin.concurrent.Volatile

class App : Application(), XposedServiceHelper.OnServiceListener {


companion object {
@Volatile
var mService: XposedService? = null
private set
private val serviceStateListeners =
CopyOnWriteArraySet<ServiceStateListener>()

private fun dispatchServiceState(
listener: ServiceStateListener,
service: XposedService?
) {
if (serviceStateListeners.contains(listener)) {
listener.onServiceStateChanged(service)
}
}

fun addServiceStateListener(
listener: ServiceStateListener,
notifyImmediately: Boolean
) {
serviceStateListeners.add(listener)
if (notifyImmediately) {
dispatchServiceState(listener, mService)
}
}

fun removeServiceStateListener(listener: ServiceStateListener) {
serviceStateListeners.remove(listener)
}
}

private fun notifyServiceStateChanged(service: XposedService?) {
for (listener in serviceStateListeners) {
dispatchServiceState(listener, service)
}
}

override fun onCreate() {
super.onCreate()
XposedServiceHelper.registerListener(this)
}

interface ServiceStateListener {
fun onServiceStateChanged(service: XposedService?)
}

override fun onServiceBind(service: XposedService) {
mService = service
notifyServiceStateChanged(mService)
}

override fun onServiceDied(service: XposedService) {
mService = null
notifyServiceStateChanged(mService)
}
}
82 changes: 54 additions & 28 deletions app/src/main/java/io/github/libxposed/example/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,86 @@ package io.github.libxposed.example
import android.annotation.SuppressLint
import android.app.Activity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import io.github.libxposed.example.databinding.ActivityMainBinding
import io.github.libxposed.service.XposedService
import io.github.libxposed.service.XposedService.OnScopeEventListener
import io.github.libxposed.service.XposedServiceHelper
import java.io.FileWriter
import kotlin.random.Random

class MainActivity : Activity() {

@SuppressLint("SetTextI18n")
class MainActivity : Activity(), App.ServiceStateListener {
private var mService: XposedService? = null
private lateinit var binding: ActivityMainBinding

private val mCallback = object : OnScopeEventListener {
override fun onScopeRequestApproved(approved: List<String>) {
runOnUiThread {
Toast.makeText(this@MainActivity, "onScopeRequestApproved: $approved", Toast.LENGTH_SHORT).show()
Toast.makeText(
this@MainActivity,
"onScopeRequestApproved: $approved",
Toast.LENGTH_SHORT
).show()
binding.scope.text = "Scope: " + mService?.scope
}
}

override fun onScopeRequestFailed(message: String) {
runOnUiThread {
Toast.makeText(this@MainActivity, "onScopeRequestFailed: $message", Toast.LENGTH_SHORT).show()
Toast.makeText(
this@MainActivity,
"onScopeRequestFailed: $message",
Toast.LENGTH_SHORT
).show()
binding.scope.text = "Scope: " + mService?.scope
}
}
}

@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding = ActivityMainBinding.inflate(layoutInflater)
binding.let {
setContentView(it.root)
it.binder.text = "Loading"
}
}

override fun onStart() {
super.onStart()
App.addServiceStateListener(this, true)
}

binding.binder.text = "Loading"
XposedServiceHelper.registerListener(object : XposedServiceHelper.OnServiceListener {
override fun onServiceBind(service: XposedService) {
mService = service
override fun onStop() {
App.removeServiceStateListener(this)
super.onStop()
}

override fun onServiceStateChanged(service: XposedService?) {
mService = service
runOnUiThread {
if (service == null) {
binding.binder.text = "Binder is null"
} else {
binding.binder.text = "Binder acquired"
binding.api.text = "API " + service.apiVersion
binding.framework.text = "Framework " + service.frameworkName
binding.frameworkVersion.text = "Framework version " + service.frameworkVersion
binding.frameworkVersionCode.text = "Framework version code " + service.frameworkVersionCode
binding.frameworkProperties.text = "Framework properties: " + service.frameworkProperties.toHexString()
binding.frameworkVersionCode.text =
"Framework version code " + service.frameworkVersionCode
val cap = service.frameworkProperties
val capStringList = mutableListOf<String>()
if (cap.and(XposedService.PROP_CAP_SYSTEM) != 0L) {
capStringList.add("PROP_CAP_SYSTEM")
}
if (cap.and(XposedService.PROP_CAP_REMOTE) != 0L) {
capStringList.add("PROP_CAP_REMOTE")
}
if (cap.and(XposedService.PROP_RT_API_PROTECTION) != 0L) {
capStringList.add("PROP_RT_API_PROTECTION")
}
binding.frameworkProperties.text =
"Framework properties: $capStringList"
binding.scope.text = "Scope: " + service.scope

binding.requestScope.setOnClickListener {
Expand All @@ -57,7 +93,7 @@ class MainActivity : Activity() {
val old = prefs.getInt("test", -1)
val new = Random.nextInt()
Toast.makeText(this@MainActivity, "$old -> $new", Toast.LENGTH_SHORT).show()
prefs.edit().putInt("test", new).apply()
prefs.edit()?.putInt("test", new)?.apply()
}
binding.remoteFile.setOnClickListener {
service.openRemoteFile("test.txt").use { pfd ->
Expand All @@ -67,16 +103,6 @@ class MainActivity : Activity() {
}
}
}

override fun onServiceDied(service: XposedService) {
}
})

val handler = Handler(Looper.getMainLooper())
handler.postDelayed({
if (mService == null) {
binding.binder.text = "Binder is null"
}
}, 5000)
}
}
}
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
tasks.register("Delete", Delete::class) {
delete(rootProject.buildDir)
delete(rootProject.layout.buildDirectory)
}
Loading