package com.example.modifier; import android.accessibilityservice.AccessibilityServiceInfo; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ServiceInfo; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.accessibility.AccessibilityManager; import androidx.appcompat.app.AlertDialog; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Objects; public class Utils { private static final String TAG = "Modifier"; public static Context getContext() { try { Class activityThreadClass = Class.forName("android.app.ActivityThread"); Method currentActivityThreadMethod = activityThreadClass.getMethod("currentActivityThread"); currentActivityThreadMethod.setAccessible(true); Object currentActivityThread = currentActivityThreadMethod.invoke(null); Method getApplicationMethod = activityThreadClass.getMethod("getApplication"); getApplicationMethod.setAccessible(true); return (Context) getApplicationMethod.invoke(currentActivityThread); } catch (Exception e) { e.printStackTrace(); } return null; } public static String runAsRoot(String... cmds) throws IOException, InterruptedException { Log.i(TAG, "Trying to run as root"); Context context = getContext(); File outputDir = context.getCacheDir(); // context being the Activity pointer File outputFile = File.createTempFile("su0000000", ".log", outputDir); Process p = new ProcessBuilder("su") .redirectErrorStream(true) .redirectOutput(outputFile) .start(); DataOutputStream outputStream = new DataOutputStream(p.getOutputStream()); for (String cmd : cmds) { outputStream.writeBytes(cmd + "\n"); outputStream.flush(); Log.i(TAG, "Running command: " + cmd); } outputStream.writeBytes("exit\n"); outputStream.flush(); p.waitFor(); String res = FileUtils.readFileToString(outputFile, "UTF-8"); Log.i(TAG, "Command output: \n" + res); outputFile.delete(); return res; } public static boolean isAccessibilityEnabled() { Context context = getContext(); AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); List enabledServices = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK); for (AccessibilityServiceInfo enabledService : enabledServices) { Log.i(TAG, "Enabled service: " + enabledService.getResolveInfo().serviceInfo.packageName + "/" + enabledService.getResolveInfo().serviceInfo.name); ServiceInfo enabledServiceInfo = enabledService.getResolveInfo().serviceInfo; if (enabledServiceInfo.packageName.equals(context.getPackageName()) && enabledServiceInfo.name.equals(ModifierService.NAME)) return true; } return false; } public static boolean hasRootAccess() { boolean rootAccess = false; try { String res = runAsRoot("echo 'imrooted'"); if (res.contains("imrooted")) { rootAccess = true; } } catch (Exception e) { e.printStackTrace(); } return rootAccess; } public static boolean enableAccessibility() { Context context = getContext(); AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); List enabledServices = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK); List names = new ArrayList<>(); for (AccessibilityServiceInfo enabledService : enabledServices) { names.add(enabledService.getResolveInfo().serviceInfo.packageName + "/" + enabledService.getResolveInfo().serviceInfo.name); } names.add(context.getPackageName() + "/" + ModifierService.NAME); try { runAsRoot("settings put secure enabled_accessibility_services " + TextUtils.join(":", names), "settings put secure accessibility_enabled 1"); return true; } catch (Exception e) { e.printStackTrace(); } return false; } public static String getUniqueID() { Context context = getContext(); Objects.requireNonNull(context); SharedPreferences sharedPrefs = context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE); String uniqueID = sharedPrefs.getString("unique_id", null); if (StringUtils.isBlank(uniqueID)) { try { uniqueID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); } catch (Exception e) { e.printStackTrace(); } } if (StringUtils.isBlank(uniqueID)) { uniqueID = java.util.UUID.randomUUID().toString(); } sharedPrefs.edit().putString("unique_id", uniqueID).apply(); return uniqueID; } }