package com.example.modifier.service import android.accessibilityservice.AccessibilityService import android.accessibilityservice.AccessibilityServiceInfo import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.graphics.PixelFormat import android.graphics.Rect import android.net.Uri import android.os.Build import android.os.Handler import android.os.Looper import android.util.DisplayMetrics import android.util.Log import android.view.Gravity import android.view.LayoutInflater import android.view.MotionEvent import android.view.View import android.view.View.OnTouchListener import android.view.WindowManager import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityNodeInfo import android.widget.CompoundButton import android.widget.FrameLayout import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.preferencesDataStore import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Observer import androidx.lifecycle.liveData import com.example.modifier.BuildConfig import com.example.modifier.Global import com.example.modifier.Global.load import com.example.modifier.Global.resetAll import com.example.modifier.R import com.example.modifier.TraverseResult import com.example.modifier.Utils import com.example.modifier.databinding.FloatingWindowBinding import com.example.modifier.enums.RcsConfigureState import com.example.modifier.extension.waitUntilValueIs import com.example.modifier.http.KtorClient import com.example.modifier.http.RcsNumberApi import com.example.modifier.http.request.RcsNumberRequest import com.example.modifier.http.response.RcsNumberResponse import com.example.modifier.model.TelephonyConfig import com.google.android.material.color.DynamicColors import io.ktor.client.call.body import io.ktor.client.plugins.resources.get import io.ktor.client.plugins.resources.put import io.ktor.client.request.setBody import io.ktor.http.ContentType import io.ktor.http.contentType import io.socket.client.IO import io.socket.client.Socket import io.socket.emitter.Emitter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeout import kotlinx.coroutines.withTimeoutOrNull import org.apache.commons.collections4.queue.CircularFifoQueue import org.apache.commons.lang3.RandomStringUtils import org.apache.commons.lang3.StringUtils import org.json.JSONArray import org.json.JSONException import org.json.JSONObject import java.util.Optional import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.ScheduledThreadPoolExecutor import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicReference import kotlin.coroutines.coroutineContext import kotlin.coroutines.resume import kotlin.math.max import kotlin.math.min import kotlin.time.Duration import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds val Context.dataStore: DataStore by preferencesDataStore(name = "serverConfig") @SuppressLint("SetTextI18n") class ModifierService : AccessibilityService(), Emitter.Listener { companion object { private const val TAG = "ModifierService" const val NAME: String = BuildConfig.APPLICATION_ID + ".service.ModifierService" @JvmStatic var instance: ModifierService? = null private set } private val handler = Handler(Looper.getMainLooper()) private val mExecutor: ScheduledExecutorService = ScheduledThreadPoolExecutor(8) private val mSocketOpts = IO.Options() private lateinit var mSocket: Socket private lateinit var binding: FloatingWindowBinding private var canSend: Boolean get() { return getSharedPreferences( BuildConfig.APPLICATION_ID, MODE_PRIVATE ).getBoolean("canSend", false) } set(value) { getSharedPreferences(BuildConfig.APPLICATION_ID, MODE_PRIVATE).edit() .putBoolean("canSend", value).apply() reportDeviceStatues() } private var counter = 0 private var cleanCount = 0 private var lastSend = 0L private var rcsInterval = 0L private var requestNumberInterval = 0 private val running = MutableLiveData(false) private val requesting = MutableLiveData(false) private var currentTaskId = 0 private var busy = MediatorLiveData().apply { addSource(running) { value = it || requesting.value!! } addSource(requesting) { value = it || running.value!! } value = requesting.value!! || running.value!! } private val rcsConfigureState = MutableLiveData(RcsConfigureState.CONFIGURED) private var sendCount: Int get() { return getSharedPreferences( BuildConfig.APPLICATION_ID, MODE_PRIVATE ).getInt("sendCount", 0) } set(value) { getSharedPreferences(BuildConfig.APPLICATION_ID, MODE_PRIVATE).edit() .putInt("sendCount", value).apply() } private var requestNumberCount: Int get() { return getSharedPreferences( BuildConfig.APPLICATION_ID, MODE_PRIVATE ).getInt("requestNumberCount", 0) } set(value) { getSharedPreferences(BuildConfig.APPLICATION_ID, MODE_PRIVATE).edit() .putInt("requestNumberCount", value).apply() } private val logcat = liveData(Dispatchers.IO) { try { val logs = CircularFifoQueue(128) val p = Runtime.getRuntime().exec("su") p.outputStream.bufferedWriter().use { writer -> writer.write("logcat -c") writer.newLine() writer.flush() writer.write("logcat BugleRcsEngine:D *:S -v time") writer.newLine() writer.flush() } p.inputStream .bufferedReader() .useLines { lines -> lines.forEach { line -> if (line.contains("destState=CheckPreconditionsState")) { rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED) } else if (line.contains("destState=ReadyState")) { rcsConfigureState.postValue(RcsConfigureState.READY) } else if (line.contains("destState=WaitingForOtpState")) { rcsConfigureState.postValue(RcsConfigureState.WAITING_FOR_OTP) } else if (line.contains("destState=VerifyOtpState")) { rcsConfigureState.postValue(RcsConfigureState.VERIFYING_OTP) } else if (line.contains("destState=ConfiguredState")) { rcsConfigureState.postValue(RcsConfigureState.CONFIGURED) } else if (line.contains("destState=WaitingForRcsDefaultOnState")) { rcsConfigureState.postValue(RcsConfigureState.WAITING_FOR_DEFAULT_ON) } else if (line.contains("destState=RetryState")) { rcsConfigureState.postValue(RcsConfigureState.RETRY) } Regex("(?