More root stuff

Because we can can can...
This commit is contained in:
d8ahazard 2016-09-19 16:48:13 -05:00
parent 3fe5647a15
commit 8a8aa1337b
12 changed files with 211 additions and 251 deletions

View File

@ -12,12 +12,24 @@
tools:ignore="ProtectedPermissions" /> tools:ignore="ProtectedPermissions" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
tools:ignore="AllowBackup,GoogleAppIndexingWarning"> tools:ignore="AllowBackup,GoogleAppIndexingWarning">
<service
android:label="@string/accessibility_service_name"
android:name=".MonitorService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibilityservice"/>
</service>
<activity <activity
android:name=".WelcomeActivity" android:name=".WelcomeActivity"
android:exported="true" android:exported="true"
@ -73,9 +85,6 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<service
android:name=".MonitorService"
android:exported="false" />
</application> </application>
</manifest> </manifest>

View File

@ -9,7 +9,6 @@ import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.ListFragment; import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -30,7 +29,7 @@ public class AutoRootFragment extends ListFragment {
private ApplicationAdapter listadaptor = null; private ApplicationAdapter listadaptor = null;
public ListView listView; public ListView listView;
public SharedPreferences prefs; public SharedPreferences prefs;
List<String> arrayBlackList, arrayWhiteList; List<String> arrayBlackList;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 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.apps.walletnfcrel");
set.add("com.google.android.gms"); set.add("com.google.android.gms");
editor.putStringSet("auto_blacklist", set); editor.putStringSet("auto_blacklist", set);
set.clear();
set.add("com.kermidas.TitaniumBackupPro");
editor.putStringSet("auto_whitelist", set);
editor.apply(); editor.apply();
} }
new LoadApplications().execute(); new LoadApplications().execute();
@ -75,29 +71,15 @@ public class AutoRootFragment extends ListFragment {
private void ToggleApp(String appToCheck, int position, View v) { private void ToggleApp(String appToCheck, int position, View v) {
Set<String> blackListSet = prefs.getStringSet("auto_blacklist", null); Set<String> blackListSet = prefs.getStringSet("auto_blacklist", null);
Set<String> whiteListSet = prefs.getStringSet("auto_whitelist", null);
assert blackListSet != null; assert blackListSet != null;
arrayBlackList = new ArrayList<>(blackListSet); 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))) { if (!arrayBlackList.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);
}
}
arrayBlackList.add(appToCheck); arrayBlackList.add(appToCheck);
} else if (arrayBlackList.contains(appToCheck)) { } else {
Log.d("Magisk", "App is in Blacklist, removing");
for (int i = 0; i < arrayBlackList.size(); i++) { for (int i = 0; i < arrayBlackList.size(); i++) {
if (appToCheck.equals(arrayBlackList.get(i))) { if (appToCheck.equals(arrayBlackList.get(i))) {
arrayBlackList.remove(i); arrayBlackList.remove(i);
@ -105,12 +87,7 @@ public class AutoRootFragment extends ListFragment {
} }
} }
Set<String> set2 = new HashSet<>(arrayBlackList); prefs.edit().putStringSet("auto_blacklist", new HashSet<>(arrayBlackList)).apply();
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();
listadaptor.UpdateRootStatusView(position, v); listadaptor.UpdateRootStatusView(position, v);
} }

View File

@ -1,36 +1,28 @@
package com.topjohnwu.magisk; package com.topjohnwu.magisk;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.content.ComponentName;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.util.Log; import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Set; 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 static final String TAG = "Magisk";
private final Handler handler = new Handler(); private final Handler handler = new Handler();
private Boolean disableroot; private Boolean disableroot;
@ -38,34 +30,43 @@ public class MonitorService extends Service
private int counter = 0; private int counter = 0;
private String mPackageName = ""; private String mPackageName = "";
@Nullable
@Override @Override
public IBinder onBind(Intent intent) { protected void onServiceConnected() {
return null; super.onServiceConnected();
}
@Override //Configure these here for compatibility with API 13 and below.
public int onStartCommand(Intent intent, int flags, int startId) { AccessibilityServiceInfo config = new AccessibilityServiceInfo();
return START_STICKY; 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 @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
checkProcesses.run();
Log.d("Magisk","MonitorService: Service created"); Log.d("Magisk","MonitorService: Service created");
} }
@Override @Override
public void onDestroy() { public void onAccessibilityEvent(AccessibilityEvent event) {
super.onDestroy(); if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
Log.d("Magisk","MonitorService: Service destroyed"); ComponentName componentName = new ComponentName(
} event.getPackageName().toString(),
event.getClassName().toString()
);
private Runnable checkProcesses = new Runnable() { ActivityInfo activityInfo = tryGetActivity(componentName);
@Override boolean isActivity = activityInfo != null;
public void run() { if (isActivity) {
Log.i("Magisk","CurrentActivity: " + componentName.getPackageName());
String mPackage = componentName.getPackageName();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (prefs.getBoolean("autoRootEnable", false)) { if (prefs.getBoolean("autoRootEnable", false)) {
@ -74,29 +75,40 @@ public class MonitorService extends Service
Set<String> setWhiteList = prefs.getStringSet("auto_whitelist", null); Set<String> setWhiteList = prefs.getStringSet("auto_whitelist", null);
if (setBlackList != null) { if (setBlackList != null) {
disableroot = getStats(setBlackList); disableroot = setBlackList.contains(mPackage);
}
if (disableroot != disablerootprev) {
String rootstatus = (disableroot ? "disabled" : "enabled");
if (disableroot) { if (disableroot) {
ForceDisableRoot(); ForceDisableRoot();
} else { } else {
ForceEnableRoot(); ForceEnableRoot();
} }
String appFriendly = getAppName(mPackage);
ShowNotification(disableroot); ShowNotification(disableroot,appFriendly);
}
}
} }
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() { private void ForceDisableRoot() {
Log.d("Magisk", "MonitorService: Forcedisable called."); Log.d("Magisk", "MonitorService: Forcedisable called.");
@ -116,7 +128,7 @@ public class MonitorService extends Service
} }
} }
private void ShowNotification(boolean rootAction) { private void ShowNotification(boolean rootAction, String packageName) {
NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder; NotificationCompat.Builder mBuilder;
@ -130,10 +142,10 @@ public class MonitorService extends Service
0, 0,
intent, intent,
PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent.FLAG_UPDATE_CURRENT);
if (mPackageName.equals("")) { if (packageName.equals("")) {
rootMessage = "Root has been disabled"; rootMessage = "Root has been disabled";
} else { } else {
rootMessage = "Root has been disabled for " + mPackageName; rootMessage = "Root has been disabled for " + packageName;
} }
mBuilder = mBuilder =
new NotificationCompat.Builder(getApplicationContext()) new NotificationCompat.Builder(getApplicationContext())
@ -149,64 +161,7 @@ public class MonitorService extends Service
} }
private boolean getStats(Set<String> seti) { @Override
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { public void onInterrupt() {
boolean inStats = false;
if (seti != null) {
ArrayList<String> 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;
}
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<UsageStats> stats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 10, time);
String topPackageName = "";
if (stats != null) {
SortedMap<Long, UsageStats> 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);
}
}

View File

@ -9,7 +9,6 @@ import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.util.Log; 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 @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
@ -141,24 +134,27 @@ public class RootFragment extends Fragment {
// Make sure the request was successful // Make sure the request was successful
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
Log.d("Magisk","Got result code OK for permissions"); Log.d("Magisk","Got result code OK for permissions");
Toast.makeText(getActivity(),"Auto-root disabled, permissions required.",Toast.LENGTH_LONG).show();
} else { } else {
autoRootToggle.setEnabled(false); autoRootToggle.setEnabled(false);
Toast.makeText(getActivity(),"Auto-root disabled, permissions required.",Toast.LENGTH_LONG).show();
} }
} }
} }
private void ToggleAutoRoot(boolean toggleState) { private void ToggleAutoRoot(boolean toggleState) {
CheckAccessPermissions();
if (Utils.hasStatsPermission(getActivity())) {
autoRootStatus = toggleState; autoRootStatus = toggleState;
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("autoRootEnable", (toggleState)); editor.putBoolean("autoRootEnable", (toggleState));
editor.apply(); editor.apply();
if (toggleState) { 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); Intent myIntent = new Intent(getActivity(), MonitorService.class);
getActivity().startService(myIntent); getActivity().startService(myIntent);
rootToggle.setEnabled(false); rootToggle.setEnabled(false);
@ -172,7 +168,7 @@ public class RootFragment extends Fragment {
getActivity().stopService(myIntent); getActivity().stopService(myIntent);
rootToggle.setEnabled(true); rootToggle.setEnabled(true);
} }
}
} }
@Override @Override

View File

@ -9,7 +9,6 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.annotation.IdRes; import android.support.annotation.IdRes;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView; import android.support.design.widget.NavigationView;
@ -86,7 +85,7 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
@Override @Override
public void onDrawerOpened(View drawerView) { public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(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 @Override

View File

@ -9,6 +9,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
@ -24,8 +25,6 @@ public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
private PackageManager packageManager; private PackageManager packageManager;
public ArrayList arrayList; public ArrayList arrayList;
public SharedPreferences prefs; public SharedPreferences prefs;
private int BLACKLIST_LIST = 1;
private int WHITELIST_LIST = 2;
public ApplicationAdapter(Context context, int textViewResourceId, public ApplicationAdapter(Context context, int textViewResourceId,
List<ApplicationInfo> appsList) { List<ApplicationInfo> appsList) {
@ -66,14 +65,14 @@ public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
TextView appName = (TextView) view.findViewById(R.id.app_name); TextView appName = (TextView) view.findViewById(R.id.app_name);
TextView packageName = (TextView) view.findViewById(R.id.app_paackage); TextView packageName = (TextView) view.findViewById(R.id.app_paackage);
ImageView iconview = (ImageView) view.findViewById(R.id.app_icon); 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)); appName.setText(applicationInfo.loadLabel(packageManager));
packageName.setText(applicationInfo.packageName); packageName.setText(applicationInfo.packageName);
iconview.setImageDrawable(applicationInfo.loadIcon(packageManager)); iconview.setImageDrawable(applicationInfo.loadIcon(packageManager));
if (CheckApp(applicationInfo.packageName, BLACKLIST_LIST)) { if (CheckApp(applicationInfo.packageName)) {
statusview.setImageDrawable(this.context.getDrawable(R.drawable.root)); statusview.setChecked(true);
} else { } else {
statusview.setImageDrawable(null); statusview.setChecked(false);
} }
} }
return view; return view;
@ -88,21 +87,18 @@ public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
} }
ApplicationInfo applicationInfo = appsList.get(position); ApplicationInfo applicationInfo = appsList.get(position);
if (null != applicationInfo) { if (null != applicationInfo) {
ImageView statusview = (ImageView) view.findViewById(R.id.app_status); CheckBox statusview = (CheckBox) view.findViewById(R.id.checkbox);
if (CheckApp(applicationInfo.packageName, BLACKLIST_LIST)) { if (CheckApp(applicationInfo.packageName)) {
statusview.setImageDrawable(this.context.getDrawable(R.drawable.root)); statusview.setChecked(true);
} else if (CheckApp(applicationInfo.packageName, WHITELIST_LIST)) {
statusview.setImageDrawable(this.context.getDrawable(R.drawable.ic_stat_notification_autoroot_off));
} else { } else {
statusview.setImageDrawable(null); statusview.setChecked(false);
} }
} }
} }
private boolean CheckApp(String appToCheck, int list) { private boolean CheckApp(String appToCheck) {
boolean starter = false; boolean starter = false;
if (list == BLACKLIST_LIST) {
Set<String> set = prefs.getStringSet("auto_blacklist", null); Set<String> set = prefs.getStringSet("auto_blacklist", null);
if (set != null) { if (set != null) {
arrayList = new ArrayList<>(set); arrayList = new ArrayList<>(set);
@ -113,18 +109,6 @@ public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
} }
} }
} else {
Set<String> 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; return starter;
} }

View File

@ -1,6 +1,7 @@
package com.topjohnwu.magisk.utils; package com.topjohnwu.magisk.utils;
import android.Manifest; import android.Manifest;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AppOpsManager; import android.app.AppOpsManager;
@ -23,6 +24,8 @@ import android.support.v7.app.AlertDialog;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast; import android.widget.Toast;
import com.topjohnwu.magisk.ModulesFragment; import com.topjohnwu.magisk.ModulesFragment;
@ -171,12 +174,22 @@ public class Utils {
return value; 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<AccessibilityServiceInfo> runningServices = am
.getEnabledAccessibilityServiceList(AccessibilityEvent.TYPES_ALL_MASK);
for (AccessibilityServiceInfo service : runningServices) {
if (id.equals(service.getId())) {
return true;
}
}
return false;
} }

View File

@ -1,59 +1,73 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="5dp"> android:layout_gravity="center"
android:layout_marginBottom="3dip"
android:layout_marginLeft="8dip"
android:layout_marginRight="8dip"
android:layout_marginTop="3dip"
android:background="?android:attr/selectableItemBackground"
<ImageView card_view:cardCornerRadius="2dp"
card_view:cardElevation="2dp"
style="@style/Base.CardView">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp">
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/app_icon" android:id="@+id/app_icon"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="50dp" android:layout_height="50dp"
android:padding="3dp" android:layout_centerVertical="true"
android:scaleType="centerCrop" /> android:scaleType="centerCrop" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/lynn"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingLeft="5dp"
android:paddingRight="50dp">
<TextView <TextView
android:id="@+id/app_name" android:id="@+id/app_name"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_toEndOf="@+id/app_icon"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingEnd="3dp"
android:paddingStart="3dp"
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <TextView
android:id="@+id/app_paackage" android:id="@+id/app_paackage"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"></RelativeLayout>
</LinearLayout>
<ImageView
android:id="@+id/app_status"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_gravity="center_horizontal" android:layout_below="@+id/app_name"
android:padding="3dp" android:layout_toEndOf="@+id/app_icon"
android:scaleType="centerCrop"/> android:gravity="center_vertical"
android:paddingEnd="3dp"
android:paddingStart="3dp" />
<CheckBox
android:id="@+id/checkbox"
android:layout_width="68dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:focusable="false"
android:gravity="center"
android:src="@drawable/ic_menu_overflow_material"
/>
</RelativeLayout> </RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>

View File

@ -6,7 +6,10 @@
<ListView android:id="@android:id/list" <ListView android:id="@android:id/list"
android:paddingTop="5dip" android:paddingTop="5dip"
android:paddingBottom="5dip" android:paddingBottom="5dip"
android:layout_width="fill_parent" android:divider="@android:color/transparent"
android:layout_height="fill_parent"/> android:dividerHeight="10.0sp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp" />
</LinearLayout> </LinearLayout>

View File

@ -5,10 +5,7 @@
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginBottom="3dip" android:layout_margin="8dp"
android:layout_marginLeft="8dip"
android:layout_marginRight="8dip"
android:layout_marginTop="3dip"
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
android:minHeight="?android:attr/listPreferredItemHeight" android:minHeight="?android:attr/listPreferredItemHeight"
card_view:cardCornerRadius="2dp" card_view:cardCornerRadius="2dp"

View File

@ -82,6 +82,8 @@
<string name="permissionNotGranted">This feature will not work without permission to write external storage.</string> <string name="permissionNotGranted">This feature will not work without permission to write external storage.</string>
<string name="no_root_access">No root access, functionality limited</string> <string name="no_root_access">No root access, functionality limited</string>
<string name="no_thanks">No thanks</string> <string name="no_thanks">No thanks</string>
<string name="accessibility_service_description">Accessibility service required for Magisk auto-unroot feature</string>
<string name="accessibility_service_name">Magisk Manager</string>
<string name="update_title">%1$s Update!</string> <string name="update_title">%1$s Update!</string>
<string name="update_msg">New version v%2$s of %1$s is available!\nChangelog:\n%3$s</string> <string name="update_msg">New version v%2$s of %1$s is available!\nChangelog:\n%3$s</string>
<string name="download_install">Download and install</string> <string name="download_install">Download and install</string>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- These options MUST be specified here in order for the events to be received on first
start in Android 4.1.1 -->
<accessibility-service
xmlns:tools="http://schemas.android.com/tools"
android:accessibilityEventTypes="typeWindowStateChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagIncludeNotImportantViews"
android:description="@string/accessibility_service_description"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:ignore="UnusedAttribute"/>