diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b0ce8ab3a..f3d05d832 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -12,12 +12,24 @@
tools:ignore="ProtectedPermissions" />
+
+
+
+
+
+
-
\ No newline at end of file
diff --git a/app/src/main/java/com/topjohnwu/magisk/AutoRootFragment.java b/app/src/main/java/com/topjohnwu/magisk/AutoRootFragment.java
index 10f054b96..4207f34d6 100644
--- a/app/src/main/java/com/topjohnwu/magisk/AutoRootFragment.java
+++ b/app/src/main/java/com/topjohnwu/magisk/AutoRootFragment.java
@@ -9,7 +9,6 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.app.ListFragment;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -30,7 +29,7 @@ public class AutoRootFragment extends ListFragment {
private ApplicationAdapter listadaptor = null;
public ListView listView;
public SharedPreferences prefs;
- List arrayBlackList, arrayWhiteList;
+ List arrayBlackList;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -49,9 +48,6 @@ public class AutoRootFragment extends ListFragment {
set.add("com.google.android.apps.walletnfcrel");
set.add("com.google.android.gms");
editor.putStringSet("auto_blacklist", set);
- set.clear();
- set.add("com.kermidas.TitaniumBackupPro");
- editor.putStringSet("auto_whitelist", set);
editor.apply();
}
new LoadApplications().execute();
@@ -75,29 +71,15 @@ public class AutoRootFragment extends ListFragment {
private void ToggleApp(String appToCheck, int position, View v) {
Set blackListSet = prefs.getStringSet("auto_blacklist", null);
- Set whiteListSet = prefs.getStringSet("auto_whitelist", null);
+
assert blackListSet != null;
arrayBlackList = new ArrayList<>(blackListSet);
- assert whiteListSet != null;
- arrayWhiteList = new ArrayList<>(whiteListSet);
- Log.d("Magisk", "Trying to toggle for " + appToCheck + " stringset is " + arrayBlackList.toString());
- if ((!arrayBlackList.contains(appToCheck)) && (!arrayWhiteList.contains(appToCheck))) {
- Log.d("Magisk", "App is not in any array, adding to whitelist");
- arrayWhiteList.add(appToCheck);
-
- } else if (arrayWhiteList.contains(appToCheck)) {
- Log.d("Magisk", "App is in whitelist, moving to blacklist");
- for (int i = 0; i < arrayWhiteList.size(); i++) {
- if (appToCheck.equals(arrayWhiteList.get(i))) {
- arrayWhiteList.remove(i);
- }
- }
+ if (!arrayBlackList.contains(appToCheck)) {
arrayBlackList.add(appToCheck);
- } else if (arrayBlackList.contains(appToCheck)) {
- Log.d("Magisk", "App is in Blacklist, removing");
+ } else {
for (int i = 0; i < arrayBlackList.size(); i++) {
if (appToCheck.equals(arrayBlackList.get(i))) {
arrayBlackList.remove(i);
@@ -105,12 +87,7 @@ public class AutoRootFragment extends ListFragment {
}
}
- Set set2 = new HashSet<>(arrayBlackList);
- Log.d("Magisk", "Committing set, value is: " + set2);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putStringSet("auto_blacklist", new HashSet<>(arrayBlackList));
- editor.putStringSet("auto_whitelist", new HashSet<>(arrayWhiteList));
- editor.apply();
+ prefs.edit().putStringSet("auto_blacklist", new HashSet<>(arrayBlackList)).apply();
listadaptor.UpdateRootStatusView(position, v);
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/MonitorService.java b/app/src/main/java/com/topjohnwu/magisk/MonitorService.java
index 3ac25a528..49faf019e 100644
--- a/app/src/main/java/com/topjohnwu/magisk/MonitorService.java
+++ b/app/src/main/java/com/topjohnwu/magisk/MonitorService.java
@@ -1,36 +1,28 @@
package com.topjohnwu.magisk;
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.Service;
-import android.app.usage.UsageStats;
-import android.app.usage.UsageStatsManager;
-import android.content.Context;
+import android.content.ComponentName;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
-import android.os.IBinder;
import android.preference.PreferenceManager;
-import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
-import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.util.ArrayList;
-import java.util.List;
import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-public class MonitorService extends Service
-
-{
+public class MonitorService extends AccessibilityService {
private static final String TAG = "Magisk";
private final Handler handler = new Handler();
private Boolean disableroot;
@@ -38,65 +30,85 @@ public class MonitorService extends Service
private int counter = 0;
private String mPackageName = "";
- @Nullable
@Override
- public IBinder onBind(Intent intent) {
- return null;
- }
+ protected void onServiceConnected() {
+ super.onServiceConnected();
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- return START_STICKY;
+ //Configure these here for compatibility with API 13 and below.
+ AccessibilityServiceInfo config = new AccessibilityServiceInfo();
+ config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
+ config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
+ disableroot = false;
+ disablerootprev = disableroot;
+ if (Build.VERSION.SDK_INT >= 16)
+ //Just in case this helps
+ config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+
+ setServiceInfo(config);
}
@Override
public void onCreate() {
super.onCreate();
- checkProcesses.run();
Log.d("Magisk","MonitorService: Service created");
}
@Override
- public void onDestroy() {
- super.onDestroy();
- Log.d("Magisk","MonitorService: Service destroyed");
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+ ComponentName componentName = new ComponentName(
+ event.getPackageName().toString(),
+ event.getClassName().toString()
+ );
+
+ ActivityInfo activityInfo = tryGetActivity(componentName);
+ boolean isActivity = activityInfo != null;
+ if (isActivity) {
+ Log.i("Magisk","CurrentActivity: " + componentName.getPackageName());
+ String mPackage = componentName.getPackageName();
+
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ if (prefs.getBoolean("autoRootEnable", false)) {
+
+ Set setBlackList = prefs.getStringSet("auto_blacklist", null);
+ Set setWhiteList = prefs.getStringSet("auto_whitelist", null);
+
+ if (setBlackList != null) {
+ disableroot = setBlackList.contains(mPackage);
+ if (disableroot) {
+ ForceDisableRoot();
+ } else {
+ ForceEnableRoot();
+ }
+ String appFriendly = getAppName(mPackage);
+ ShowNotification(disableroot,appFriendly);
+ }
+ }
+ }
+ }
}
- private Runnable checkProcesses = new Runnable() {
- @Override
- public void run() {
-
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
- if (prefs.getBoolean("autoRootEnable", false)) {
-
- Set setBlackList = prefs.getStringSet("auto_blacklist", null);
- Set setWhiteList = prefs.getStringSet("auto_whitelist", null);
-
- if (setBlackList != null) {
- disableroot = getStats(setBlackList);
- }
-
- if (disableroot != disablerootprev) {
-
- String rootstatus = (disableroot ? "disabled" : "enabled");
- if (disableroot) {
- ForceDisableRoot();
- } else {
- ForceEnableRoot();
- }
-
- ShowNotification(disableroot);
-
- }
- disablerootprev = disableroot;
- //Log.d(TAG,"Root check completed, set to " + (disableroot ? "disabled" : "enabled"));
-
- }
- handler.postDelayed(checkProcesses, 500);
+ private String getAppName (String packageName) {
+ PackageManager pkManager = getPackageManager();
+ ApplicationInfo appInfo;
+ String appname = "";
+ try {
+ appInfo = pkManager.getApplicationInfo(packageName, 0);
+ appname = (String) ((appInfo != null) ? pkManager.getApplicationLabel(appInfo) : "???");
+ return appname;
+ } catch (final PackageManager.NameNotFoundException e) {
+ return "";
}
+ }
- };
+ private ActivityInfo tryGetActivity(ComponentName componentName) {
+ try {
+ return getPackageManager().getActivityInfo(componentName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ }
private void ForceDisableRoot() {
Log.d("Magisk", "MonitorService: Forcedisable called.");
@@ -113,10 +125,10 @@ public class MonitorService extends Service
Utils.toggleRoot(true);
if (!Utils.rootEnabled()) {
Utils.toggleRoot(true);
- }
+ }
}
- private void ShowNotification(boolean rootAction) {
+ private void ShowNotification(boolean rootAction, String packageName) {
NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder;
@@ -130,10 +142,10 @@ public class MonitorService extends Service
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
- if (mPackageName.equals("")) {
+ if (packageName.equals("")) {
rootMessage = "Root has been disabled";
} else {
- rootMessage = "Root has been disabled for " + mPackageName;
+ rootMessage = "Root has been disabled for " + packageName;
}
mBuilder =
new NotificationCompat.Builder(getApplicationContext())
@@ -149,64 +161,7 @@ public class MonitorService extends Service
}
- private boolean getStats(Set seti) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- boolean inStats = false;
- if (seti != null) {
- ArrayList statList = new ArrayList<>(seti);
- for (int i = 0; i < statList.size(); i++) {
- if (isAppForeground(statList.get(i))) {
- inStats = (isAppForeground(statList.get(i)));
- }
- }
- return inStats;
- }
- Log.d(TAG, "SDK check failed.");
- }
- return false;
+ @Override
+ public void onInterrupt() {
}
-
- private String getAppName (String packageName) {
- PackageManager pkManager = getPackageManager();
- ApplicationInfo appInfo;
- String appname = "";
- try {
- appInfo = pkManager.getApplicationInfo(packageName, 0);
- appname = (String) ((appInfo != null) ? pkManager.getApplicationLabel(appInfo) : "???");
- return appname;
- } catch (final PackageManager.NameNotFoundException e) {
- return null;
- }
- }
-
-
- protected boolean isAppForeground(String packageName) {
- UsageStatsManager usageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
- long time = System.currentTimeMillis();
- List stats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 10, time);
- String topPackageName = "";
- if (stats != null) {
-
- SortedMap mySortedMap = new TreeMap<>();
- for (UsageStats usageStats : stats) {
- mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
-
- }
- if (!mySortedMap.isEmpty()) {
- topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
- if (topPackageName.equals("com.topjohnwu.magisk")) {
- mySortedMap.remove(mySortedMap.lastKey());
- topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
- Log.d("Magisk","MonitorService: Package is " + topPackageName);
- mPackageName = getAppName(topPackageName);
- }
-
- }
- }
- return topPackageName.equals(packageName);
-
-
- }
-
-}
-
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/topjohnwu/magisk/RootFragment.java b/app/src/main/java/com/topjohnwu/magisk/RootFragment.java
index fe87ace29..7865c76a9 100644
--- a/app/src/main/java/com/topjohnwu/magisk/RootFragment.java
+++ b/app/src/main/java/com/topjohnwu/magisk/RootFragment.java
@@ -9,7 +9,6 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
-import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
@@ -126,13 +125,7 @@ public class RootFragment extends Fragment {
}
- private void CheckAccessPermissions() {
- if (!Utils.hasStatsPermission(getActivity())) {
- Toast.makeText(getActivity(),"Please allow Usage Access for auto root to work.",Toast.LENGTH_LONG).show();
- startActivityForResult(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS), 100);
- }
- }
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
@@ -141,24 +134,27 @@ public class RootFragment extends Fragment {
// Make sure the request was successful
if (resultCode == Activity.RESULT_OK) {
Log.d("Magisk","Got result code OK for permissions");
- Toast.makeText(getActivity(),"Auto-root disabled, permissions required.",Toast.LENGTH_LONG).show();
} else {
autoRootToggle.setEnabled(false);
+ Toast.makeText(getActivity(),"Auto-root disabled, permissions required.",Toast.LENGTH_LONG).show();
+
}
}
}
private void ToggleAutoRoot(boolean toggleState) {
- CheckAccessPermissions();
- if (Utils.hasStatsPermission(getActivity())) {
autoRootStatus = toggleState;
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("autoRootEnable", (toggleState));
editor.apply();
if (toggleState) {
+ if (!Utils.hasStatsPermission(getActivity(),"com.topjohnwu.magisk/WindowChangeDetectingService")) {
+ Intent intent = new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS);
+ startActivityForResult(intent, 100);
+ }
Intent myIntent = new Intent(getActivity(), MonitorService.class);
getActivity().startService(myIntent);
rootToggle.setEnabled(false);
@@ -172,7 +168,7 @@ public class RootFragment extends Fragment {
getActivity().stopService(myIntent);
rootToggle.setEnabled(true);
}
- }
+
}
@Override
diff --git a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java
index 8b83f88cd..309847076 100644
--- a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java
+++ b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java
@@ -9,7 +9,6 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
-import android.provider.Settings;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
@@ -86,7 +85,7 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
- super.onDrawerSlide(drawerView, 0); // this disables the arrow @ completed state
+ super.onDrawerSlide(drawerView, 0); // this disables the arrow @ completed tate
}
@Override
diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/ApplicationAdapter.java b/app/src/main/java/com/topjohnwu/magisk/utils/ApplicationAdapter.java
index b83e8c8ef..9a108f591 100644
--- a/app/src/main/java/com/topjohnwu/magisk/utils/ApplicationAdapter.java
+++ b/app/src/main/java/com/topjohnwu/magisk/utils/ApplicationAdapter.java
@@ -9,6 +9,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
@@ -24,8 +25,6 @@ public class ApplicationAdapter extends ArrayAdapter {
private PackageManager packageManager;
public ArrayList arrayList;
public SharedPreferences prefs;
- private int BLACKLIST_LIST = 1;
- private int WHITELIST_LIST = 2;
public ApplicationAdapter(Context context, int textViewResourceId,
List appsList) {
@@ -66,14 +65,14 @@ public class ApplicationAdapter extends ArrayAdapter {
TextView appName = (TextView) view.findViewById(R.id.app_name);
TextView packageName = (TextView) view.findViewById(R.id.app_paackage);
ImageView iconview = (ImageView) view.findViewById(R.id.app_icon);
- ImageView statusview = (ImageView) view.findViewById(R.id.app_status);
+ CheckBox statusview = (CheckBox) view.findViewById(R.id.checkbox);
appName.setText(applicationInfo.loadLabel(packageManager));
packageName.setText(applicationInfo.packageName);
iconview.setImageDrawable(applicationInfo.loadIcon(packageManager));
- if (CheckApp(applicationInfo.packageName, BLACKLIST_LIST)) {
- statusview.setImageDrawable(this.context.getDrawable(R.drawable.root));
+ if (CheckApp(applicationInfo.packageName)) {
+ statusview.setChecked(true);
} else {
- statusview.setImageDrawable(null);
+ statusview.setChecked(false);
}
}
return view;
@@ -88,21 +87,18 @@ public class ApplicationAdapter extends ArrayAdapter {
}
ApplicationInfo applicationInfo = appsList.get(position);
if (null != applicationInfo) {
- ImageView statusview = (ImageView) view.findViewById(R.id.app_status);
- if (CheckApp(applicationInfo.packageName, BLACKLIST_LIST)) {
- statusview.setImageDrawable(this.context.getDrawable(R.drawable.root));
- } else if (CheckApp(applicationInfo.packageName, WHITELIST_LIST)) {
- statusview.setImageDrawable(this.context.getDrawable(R.drawable.ic_stat_notification_autoroot_off));
+ CheckBox statusview = (CheckBox) view.findViewById(R.id.checkbox);
+ if (CheckApp(applicationInfo.packageName)) {
+ statusview.setChecked(true);
} else {
- statusview.setImageDrawable(null);
+ statusview.setChecked(false);
}
}
}
- private boolean CheckApp(String appToCheck, int list) {
+ private boolean CheckApp(String appToCheck) {
boolean starter = false;
- if (list == BLACKLIST_LIST) {
Set set = prefs.getStringSet("auto_blacklist", null);
if (set != null) {
arrayList = new ArrayList<>(set);
@@ -113,18 +109,6 @@ public class ApplicationAdapter extends ArrayAdapter {
}
}
- } else {
- Set set = prefs.getStringSet("auto_whitelist", null);
- if (set != null) {
- arrayList = new ArrayList<>(set);
- for (String string : set) {
- if (string.equals(appToCheck)) {
- starter = true;
- }
- }
- }
-
- }
return starter;
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java
index 8987096b9..5ef1ed198 100644
--- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java
+++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java
@@ -1,6 +1,7 @@
package com.topjohnwu.magisk.utils;
import android.Manifest;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AppOpsManager;
@@ -23,6 +24,8 @@ import android.support.v7.app.AlertDialog;
import android.util.Base64;
import android.util.Log;
import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import com.topjohnwu.magisk.ModulesFragment;
@@ -171,14 +174,24 @@ public class Utils {
return value;
}
- public static boolean hasStatsPermission(Context context) {
- AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
- android.os.Process.myUid(), context.getPackageName());
- return mode == AppOpsManager.MODE_ALLOWED;
+
+ public static boolean hasStatsPermission(Context context, String id) {
+
+ AccessibilityManager am = (AccessibilityManager) context
+ .getSystemService(Context.ACCESSIBILITY_SERVICE);
+
+ List runningServices = am
+ .getEnabledAccessibilityServiceList(AccessibilityEvent.TYPES_ALL_MASK);
+ for (AccessibilityServiceInfo service : runningServices) {
+ if (id.equals(service.getId())) {
+ return true;
+ }
}
+ return false;
+ }
+
public abstract static class DownloadReceiver extends BroadcastReceiver {
public Context mContext;
diff --git a/app/src/main/res/layout/app_list_row.xml b/app/src/main/res/layout/app_list_row.xml
index 0b7a2d156..793f481a3 100644
--- a/app/src/main/res/layout/app_list_row.xml
+++ b/app/src/main/res/layout/app_list_row.xml
@@ -1,59 +1,73 @@
-
-
+
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:padding="10dp">
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_toEndOf="@+id/app_icon"
+ android:gravity="center_vertical"
+ android:paddingEnd="3dp"
+ android:paddingStart="3dp"
+ android:textStyle="bold" />
+
+
+
+
+
+
-
\ No newline at end of file
+
+
+
+
diff --git a/app/src/main/res/layout/auto_root_fragment.xml b/app/src/main/res/layout/auto_root_fragment.xml
index 214589074..3984d2a31 100644
--- a/app/src/main/res/layout/auto_root_fragment.xml
+++ b/app/src/main/res/layout/auto_root_fragment.xml
@@ -6,7 +6,10 @@
+ android:divider="@android:color/transparent"
+ android:dividerHeight="10.0sp"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="15dp" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_repo.xml b/app/src/main/res/layout/list_item_repo.xml
index b8bcb8f61..ef78a023e 100644
--- a/app/src/main/res/layout/list_item_repo.xml
+++ b/app/src/main/res/layout/list_item_repo.xml
@@ -5,10 +5,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:layout_marginBottom="3dip"
- android:layout_marginLeft="8dip"
- android:layout_marginRight="8dip"
- android:layout_marginTop="3dip"
+ android:layout_margin="8dp"
android:background="?android:attr/selectableItemBackground"
android:minHeight="?android:attr/listPreferredItemHeight"
card_view:cardCornerRadius="2dp"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 74b9fea33..c4801921f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -82,6 +82,8 @@
This feature will not work without permission to write external storage.
No root access, functionality limited
No thanks
+ Accessibility service required for Magisk auto-unroot feature
+ Magisk Manager
%1$s Update!
New version v%2$s of %1$s is available!\nChangelog:\n%3$s
Download and install
diff --git a/app/src/main/res/xml/accessibilityservice.xml b/app/src/main/res/xml/accessibilityservice.xml
new file mode 100644
index 000000000..08bf96e91
--- /dev/null
+++ b/app/src/main/res/xml/accessibilityservice.xml
@@ -0,0 +1,11 @@
+
+
+
\ No newline at end of file