package com.example.modifier.service import android.accessibilityservice.AccessibilityService import android.accessibilityservice.AccessibilityServiceInfo import android.annotation.SuppressLint import android.content.ComponentName 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.text.TextUtils import android.util.Base64 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.annotation.MenuRes import androidx.appcompat.widget.PopupMenu import androidx.core.content.ContextCompat 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.backup import com.example.modifier.Global.changeClashProfile import com.example.modifier.Global.load import com.example.modifier.Global.resetAll import com.example.modifier.Global.restartModifier import com.example.modifier.Global.stopClash import com.example.modifier.R import com.example.modifier.TraverseResult import com.example.modifier.Utils import com.example.modifier.constants.CMD_BACK import com.example.modifier.constants.CMD_CONVERSATION_LIST_ACTIVITY import com.example.modifier.constants.CMD_MESSAGING_APP import com.example.modifier.constants.CMD_RCS_SETTINGS_ACTIVITY import com.example.modifier.constants.PACKAGE_GMS import com.example.modifier.constants.PACKAGE_MESSAGING import com.example.modifier.data.AppDatabase import com.example.modifier.data.BackupItemDao import com.example.modifier.databinding.FloatingWindowBinding import com.example.modifier.enums.RcsConfigureState import com.example.modifier.enums.RcsConnectionStatus import com.example.modifier.extension.kill import com.example.modifier.hasRootAccess import com.example.modifier.http.KtorClient import com.example.modifier.http.api.DeviceApi import com.example.modifier.http.api.RcsNumberApi import com.example.modifier.http.api.SysConfigApi import com.example.modifier.http.request.RcsNumberRequest import com.example.modifier.http.response.DeviceResponse import com.example.modifier.http.response.ErrorResponse import com.example.modifier.http.response.RcsNumberResponse import com.example.modifier.http.response.SysConfigResponse import com.example.modifier.model.InstallApkAction import com.example.modifier.model.SocketCallback import com.example.modifier.model.TaskAction import com.example.modifier.model.TaskExecutionResult import com.example.modifier.model.TelephonyConfig import com.example.modifier.serializer.Json import com.example.modifier.shellRun import com.google.android.material.color.DynamicColors import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.engine.okhttp.OkHttp import io.ktor.client.plugins.ClientRequestException import io.ktor.client.plugins.HttpResponseValidator import io.ktor.client.plugins.ServerResponseException import io.ktor.client.plugins.resources.get import io.ktor.client.plugins.resources.post import io.ktor.client.plugins.resources.put import io.ktor.client.request.prepareGet import io.ktor.client.request.setBody import io.ktor.http.ContentType import io.ktor.http.contentType import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.core.isEmpty import io.ktor.utils.io.core.readBytes 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.suspendCancellableCoroutine import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeout import kotlinx.coroutines.withTimeoutOrNull import kotlinx.serialization.encodeToString import org.apache.commons.collections4.queue.CircularFifoQueue import org.apache.commons.lang3.RandomStringUtils import org.json.JSONException import org.json.JSONObject import java.io.File import java.time.LocalDateTime import java.time.temporal.ChronoUnit import java.util.Optional import java.util.Timer import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.locks.ReentrantLock 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 = "ModifierService1" const val NAME: String = BuildConfig.APPLICATION_ID + ".service.ModifierService" @JvmStatic var instance: ModifierService? = null private set } private val handler = Handler(Looper.getMainLooper()) private val mSocketOpts = IO.Options() private lateinit var mSocket: Socket private lateinit var binding: FloatingWindowBinding val lock = ReentrantLock() 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 = 0L private val running = MutableLiveData(false) private val requesting = MutableLiveData(false) private val preparing = MutableLiveData(false) private val checkingConnection = MutableLiveData(false) private var currentTaskId = 0 private var busy = MediatorLiveData().apply { addSource(running) { value = it || requesting.value!! } addSource(requesting) { value = it || running.value!! } addSource(preparing) { value = it || running.value!! } addSource(checkingConnection) { value = it || running.value!! } value = requesting.value!! || running.value!! || preparing.value!! || checkingConnection.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=WaitingForGoogleTosState")) { rcsConfigureState.postValue(RcsConfigureState.WAITING_FOR_TOS) } else if (line.contains("destState=RetryState")) { rcsConfigureState.postValue(RcsConfigureState.RETRY) } else if (line.contains("destState=ReplayRequestState")) { rcsConfigureState.postValue(RcsConfigureState.REPLAY_REQUEST) } Regex("(?