package com.example.modifier; import android.accessibilityservice.AccessibilityServiceInfo; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ServiceInfo; import android.content.res.AssetManager; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.accessibility.AccessibilityManager; import androidx.annotation.DrawableRes; import com.google.android.material.button.MaterialButton; import com.google.android.material.progressindicator.CircularProgressIndicatorSpec; import com.google.android.material.progressindicator.IndeterminateDrawable; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; 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"); Process p = new ProcessBuilder("su").start(); StringBuilder res = new StringBuilder(); StringBuilder err = new StringBuilder(); new Thread(() -> { try { res.append(IOUtils.toString(p.getInputStream(), StandardCharsets.UTF_8)); } catch (IOException ignored) { } }).start(); new Thread(() -> { try { err.append(IOUtils.toString(p.getErrorStream(), StandardCharsets.UTF_8)); } catch (IOException ignored) { } }).start(); DataOutputStream outputStream = new DataOutputStream(p.getOutputStream()); for (String cmd : cmds) { outputStream.writeBytes(cmd + "\n"); outputStream.flush(); Log.i(TAG, "Running command: " + cmd); } Thread.sleep(500); outputStream.writeBytes("exit\n"); outputStream.flush(); p.waitFor(); Log.i(TAG, "Output: " + res); if (err.length() > 0) { Log.i(TAG, "Error: " + err); } return res.toString(); } 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; } public static String generateIMEI() { int pos; int[] str = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int sum = 0; int final_digit; int t; int len_offset; int len = 15; String imei = ""; String[] rbi = new String[]{"01", "10", "30", "33", "35", "44", "45", "49", "50", "51", "52", "53", "54", "86", "91", "98", "99"}; String[] arr = rbi[(int) Math.floor(Math.random() * rbi.length)].split(""); str[0] = Integer.parseInt(arr[0]); str[1] = Integer.parseInt(arr[1]); pos = 2; while (pos < len - 1) { str[pos++] = (int) (Math.floor(Math.random() * 10) % 10); } len_offset = (len + 1) % 2; for (pos = 0; pos < len - 1; pos++) { if ((pos + len_offset) % 2 != 0) { t = str[pos] * 2; if (t > 9) { t -= 9; } sum += t; } else { sum += str[pos]; } } final_digit = (10 - (sum % 10)) % 10; str[len - 1] = final_digit; for (int d : str) { imei += String.valueOf(d); } return imei; } public static void makeLoadingButton(Context context, MaterialButton button) { CircularProgressIndicatorSpec spec = new CircularProgressIndicatorSpec(context, null, 0, com.google.android.material.R.style.Widget_Material3_CircularProgressIndicator_ExtraSmall); IndeterminateDrawable progressIndicatorDrawable = IndeterminateDrawable.createCircularDrawable(context, spec); button.setIcon(progressIndicatorDrawable); button.setEnabled(false); } public static boolean copyAssetFolder(AssetManager assetManager, String fromAssetPath, String toPath) { try { String[] files = assetManager.list(fromAssetPath); new File(toPath).mkdirs(); boolean res = true; for (String file : files) if (file.contains(".")) res &= copyAsset(assetManager, fromAssetPath + "/" + file, toPath + "/" + file); else res &= copyAssetFolder(assetManager, fromAssetPath + "/" + file, toPath + "/" + file); return res; } catch (Exception e) { e.printStackTrace(); return false; } } public static boolean copyAsset(AssetManager assetManager, String fromAssetPath, String toPath) { InputStream in = null; OutputStream out = null; try { in = assetManager.open(fromAssetPath); new File(toPath).createNewFile(); out = Files.newOutputStream(Paths.get(toPath)); IOUtils.copy(in, out); in.close(); out.flush(); out.close(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } public static int dp2px(Context context, int dp) { float scale = context.getResources().getDisplayMetrics().density; return (int) (dp * scale + 0.5f); } }