| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- package com.example.modifier.ui.utils
- import android.os.Bundle
- import android.os.Handler
- import android.os.Looper
- import android.util.Log
- import android.view.LayoutInflater
- import android.view.View
- import android.view.ViewGroup
- import android.widget.Toast
- import androidx.appcompat.app.AlertDialog
- import androidx.fragment.app.Fragment
- import com.example.modifier.CMD_BACK_APP
- import com.example.modifier.Frida
- import com.example.modifier.Global
- import com.example.modifier.Global.clear
- import com.example.modifier.Global.clearConv
- import com.example.modifier.Global.resetAll
- import com.example.modifier.Global.suspend
- import com.example.modifier.Global.unsuspend
- import com.example.modifier.R
- import com.example.modifier.Utils
- import com.example.modifier.databinding.DialogUpdateBinding
- import com.example.modifier.databinding.FragmentUtilsBinding
- import com.example.modifier.http.KtorClient
- import com.example.modifier.http.api.SysConfigApi
- import com.example.modifier.http.response.SysConfigResponse
- import com.example.modifier.service.ModifierService
- import com.google.android.material.dialog.MaterialAlertDialogBuilder
- import com.google.android.material.dialog.MaterialDialogs
- import com.google.android.material.progressindicator.CircularProgressIndicatorSpec
- import com.google.android.material.progressindicator.DeterminateDrawable
- import com.google.android.material.progressindicator.IndeterminateDrawable
- import io.ktor.client.call.body
- import io.ktor.client.plugins.onDownload
- import io.ktor.client.plugins.resources.get
- import io.ktor.client.request.get
- import io.ktor.client.request.prepareGet
- import io.ktor.http.contentLength
- import io.ktor.utils.io.ByteReadChannel
- import io.ktor.utils.io.core.isEmpty
- import io.ktor.utils.io.core.readBytes
- import kotlinx.coroutines.CoroutineScope
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.Job
- import kotlinx.coroutines.delay
- import kotlinx.coroutines.launch
- import kotlinx.coroutines.withContext
- import java.io.File
- import java.util.concurrent.ExecutorService
- import java.util.concurrent.Executors
- class UtilsFragment : Fragment() {
- private lateinit var binding: FragmentUtilsBinding
- var handler: Handler = Handler(Looper.getMainLooper())
- var executor: ExecutorService = Executors.newFixedThreadPool(4)
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- }
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- if (this::binding.isInitialized) {
- return binding.root
- }
- binding = FragmentUtilsBinding.inflate(inflater, container, false)
- binding.btnClear.setOnClickListener { v: View? ->
- onClear()
- }
- binding.btnStop.setOnClickListener { v: View? ->
- onStopClick()
- }
- binding.btnSend.setOnClickListener { v: View? ->
- Utils.makeLoadingButton(context, binding.btnSend)
- CoroutineScope(Dispatchers.Main).launch {
- delay(1000L)
- val otp = binding.etOtp.text.toString()
- withContext(Dispatchers.IO) {
- Global.sendSmsIntent("3538", "Your Messenger verification code is G-$otp")
- }
- binding.btnSend.setIconResource(R.drawable.ic_done)
- binding.btnSend.text = "OK"
- delay(1500L)
- binding.btnSend.isEnabled = true
- binding.btnSend.icon = null
- binding.btnSend.text = "Send"
- }
- }
- binding.btnClearConv.setOnClickListener { v: View? ->
- binding.btnClearConv.isEnabled = false
- Utils.makeLoadingButton(context, binding.btnClearConv)
- handler.post {
- executor.execute {
- clearConv()
- handler.post {
- binding.btnClearConv.setIconResource(R.drawable.ic_done)
- binding.btnClearConv.text = "OK"
- handler.postDelayed({
- binding.btnClearConv.isEnabled = true
- binding.btnClearConv.icon = null
- binding.btnClearConv.text = "Clear Msg"
- }, 1500)
- }
- }
- }
- }
- binding.btnCheckA10y.setOnClickListener {
- Utils.makeLoadingButton(context, binding.btnCheckA10y)
- CoroutineScope(Dispatchers.Main).launch {
- var a10y: Boolean? = null
- withContext(Dispatchers.IO) {
- a10y = ModifierService.instance?.checkRcsAvailability()
- Utils.runAsRoot(CMD_BACK_APP)
- }
- if (isAdded) {
- MaterialAlertDialogBuilder(requireContext())
- .setMessage("RCS is ${if (a10y == true) "available" else "not available"}")
- .setPositiveButton("OK") { _, _ -> }
- .show()
- }
- binding.btnCheckA10y.setIconResource(R.drawable.ic_done)
- binding.btnCheckA10y.text = "OK"
- delay(1500L)
- binding.btnCheckA10y.isEnabled = true
- binding.btnCheckA10y.icon = null
- binding.btnCheckA10y.text = "Check A10y"
- }
- }
- binding.btnSuspend.setOnClickListener {
- binding.btnSuspend.isEnabled = false
- Utils.makeLoadingButton(context, binding.btnSuspend)
- executor.execute {
- val gsf = binding.cbGsf.isChecked
- val gms = binding.cbGms.isChecked
- val sms = binding.cbSms.isChecked
- suspend(gsf, gms, sms)
- handler.post {
- binding.btnSuspend.setIconResource(R.drawable.ic_done)
- binding.btnSuspend.text = "OK"
- handler.postDelayed({
- binding.btnSuspend.isEnabled = true
- binding.btnSuspend.icon = null
- binding.btnSuspend.text = "Suspend"
- }, 1500)
- }
- }
- }
- binding.btnUnsuspend.setOnClickListener {
- binding.btnUnsuspend.isEnabled = false
- Utils.makeLoadingButton(context, binding.btnUnsuspend)
- executor.execute {
- val gsf = binding.cbGsf.isChecked
- val gms = binding.cbGms.isChecked
- val sms = binding.cbSms.isChecked
- unsuspend(gsf, gms, sms)
- handler.post {
- binding.btnUnsuspend.setIconResource(R.drawable.ic_done)
- binding.btnUnsuspend.text = "OK"
- handler.postDelayed({
- binding.btnUnsuspend.isEnabled = true
- binding.btnUnsuspend.icon = null
- binding.btnUnsuspend.text = "Unsuspend"
- }, 1500)
- }
- }
- }
- binding.btnStartFrida.setOnClickListener {
- CoroutineScope(Dispatchers.Main).launch {
- withContext(Dispatchers.IO) {
- Frida.start()
- }
- }
- Toast.makeText(context, "Frida started", Toast.LENGTH_SHORT).show()
- }
- binding.btnStopFrida.setOnClickListener {
- CoroutineScope(Dispatchers.Main).launch {
- withContext(Dispatchers.IO) {
- Frida.stop()
- }
- }
- Toast.makeText(context, "Frida stopped", Toast.LENGTH_SHORT).show()
- }
- binding.btnKillPhone.setOnClickListener {
- binding.btnKillPhone.isEnabled = false
- Utils.makeLoadingButton(context, binding.btnKillPhone)
- CoroutineScope(Dispatchers.IO).launch {
- val success = Global.killPhoneProcess(force = true)
- withContext(Dispatchers.Main) {
- if (success) {
- binding.btnKillPhone.setIconResource(R.drawable.ic_done)
- binding.btnKillPhone.text = "OK"
- } else {
- binding.btnKillPhone.setIconResource(R.drawable.ic_error)
- binding.btnKillPhone.text = "Fail"
- }
- delay(1500L)
- binding.btnKillPhone.isEnabled = true
- binding.btnKillPhone.icon = null
- binding.btnKillPhone.text = "Kill Phone"
- }
- }
- }
- binding.btnSyncTime.setOnClickListener {
- binding.btnSyncTime.isEnabled = false
- Utils.makeLoadingButton(context, binding.btnSyncTime)
- CoroutineScope(Dispatchers.IO).launch {
- Global.syncTime()
- withContext(Dispatchers.Main) {
- binding.btnSyncTime.setIconResource(R.drawable.ic_done)
- binding.btnSyncTime.text = "OK"
- delay(1500L)
- binding.btnSyncTime.isEnabled = true
- binding.btnSyncTime.icon = null
- binding.btnSyncTime.text = "Sync Time"
- }
- }
- }
- binding.btnUpdateModifier.setOnClickListener {
- CoroutineScope(Dispatchers.IO).launch {
- try {
- val config = KtorClient.get(SysConfigApi.Id(SysConfigApi(), "modifier_apk"))
- .body<SysConfigResponse>()
- installApk(config.value)
- } catch (e: Exception) {
- Log.e("Modifier", "Failed to get message apk", e)
- }
- }
- }
- binding.btnUpdateMessage.setOnClickListener {
- CoroutineScope(Dispatchers.IO).launch {
- try {
- val config = KtorClient.get(SysConfigApi.Id(SysConfigApi(), "message_apk"))
- .body<SysConfigResponse>()
- installApk(config.value)
- } catch (e: Exception) {
- Log.e("Modifier", "Failed to get message apk", e)
- }
- }
- }
- return binding.root
- }
- private fun onClear() {
- binding.btnClear.isEnabled = false
- Utils.makeLoadingButton(context, binding.btnClear)
- executor.execute {
- val all = binding.cbAll.isChecked
- val gsf = binding.cbGsf.isChecked
- val gms = binding.cbGms.isChecked
- val sms = binding.cbSms.isChecked
- if (all) {
- resetAll()
- } else {
- clear(gsf, gms, sms)
- }
- handler.post {
- binding.btnClear.setIconResource(R.drawable.ic_done)
- binding.btnClear.text = "OK"
- handler.postDelayed({
- binding.btnClear.isEnabled = true
- binding.btnClear.icon = null
- binding.btnClear.text = "Clear"
- }, 1500)
- }
- }
- }
- private fun onStopClick() {
- binding.btnStop.isEnabled = false
- Utils.makeLoadingButton(context, binding.btnStop)
- executor.execute {
- val gsf = binding.cbGsf.isChecked
- val gms = binding.cbGms.isChecked
- val sms = binding.cbSms.isChecked
- suspend(gsf, gms, sms)
- unsuspend(gsf, gms, sms)
- handler.post {
- binding.btnStop.setIconResource(R.drawable.ic_done)
- binding.btnStop.text = "OK"
- handler.postDelayed({
- binding.btnStop.isEnabled = true
- binding.btnStop.icon = null
- binding.btnStop.text = "Stop"
- }, 1500)
- }
- }
- }
- private suspend fun installApk(url: String) {
- if (url.isEmpty()) {
- Toast.makeText(context, "URL is empty", Toast.LENGTH_SHORT).show()
- return
- }
- if (!url.endsWith(".apk")) {
- Toast.makeText(context, "URL is not an APK", Toast.LENGTH_SHORT).show()
- return
- }
- if (!url.startsWith("http")) {
- Toast.makeText(context, "URL is not valid", Toast.LENGTH_SHORT).show()
- return
- }
- var job: Job? = null
- lateinit var dialogBinding: DialogUpdateBinding
- lateinit var dialog: AlertDialog
- withContext(Dispatchers.Main) {
- dialogBinding = DialogUpdateBinding.inflate(layoutInflater)
- dialog = MaterialAlertDialogBuilder(requireContext())
- .setTitle("Installing...")
- .setView(dialogBinding.root)
- .setCancelable(false)
- .setNegativeButton("Cancel") { _, _ ->
- job?.cancel()
- }
- .create()
- dialog.show()
- }
- job = CoroutineScope(Dispatchers.IO).launch {
- try {
- val file = File.createTempFile("files", ".apk")
- KtorClient.prepareGet("https://nebuai.oss-cn-hangzhou.aliyuncs.com/application/20240701/bgpj4axa.apk")
- .execute { httpResponse ->
- val channel: ByteReadChannel = httpResponse.body()
- while (!channel.isClosedForRead) {
- val packet = channel.readRemaining(DEFAULT_BUFFER_SIZE.toLong())
- while (!packet.isEmpty) {
- val bytes = packet.readBytes()
- file.appendBytes(bytes)
- withContext(
- Dispatchers.Main
- ) {
- dialogBinding.progressBar.isIndeterminate = false
- dialogBinding.progressBar.progress =
- (file.length() * 100 / httpResponse.contentLength()!!).toInt()
- }
- }
- }
- }
- Log.i("Modifier", "A file saved to ${file.path}")
- Utils.runAsRoot("pm install -d -r ${file.path}")
- } catch (e: Exception) {
- Log.e("Modifier", "Failed to download apk", e)
- }
- withContext(Dispatchers.Main) {
- dialog.dismiss()
- }
- }
- }
- }
|