Finalize 2.0 version

This commit is contained in:
topjohnwu 2016-08-25 18:08:07 +08:00
parent 3e97d29bcf
commit dc06a132bc
11 changed files with 232 additions and 248 deletions

View File

@ -3,7 +3,7 @@ apply plugin: 'android-apt'
android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "com.topjohnwu.magisk"

View File

@ -25,6 +25,7 @@ import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.io.File;
@ -201,13 +202,6 @@ public class LogFragment extends Fragment {
@Override
protected String doInBackground(Void... voids) {
// Ensure initialize is done
try {
Utils.initialize.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
if (readLog) {
List<String> logList = Utils.readFile(MAGISK_LOG);
@ -225,8 +219,6 @@ public class LogFragment extends Fragment {
}
return "";
}
}
@Override

View File

@ -1,15 +1,15 @@
package com.topjohnwu.magisk;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Switch;
import android.widget.TextView;
@ -17,7 +17,7 @@ import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutionException;
import butterknife.BindColor;
@ -26,10 +26,16 @@ import butterknife.ButterKnife;
public class MagiskFragment extends Fragment {
@BindView(R.id.rootSwitchView) View rootToggleView;
@BindView(R.id.root_toggle) Switch rootToggle;
@BindView(R.id.progressBar) ProgressBar progressBar;
@BindView(R.id.rootSwitchView) View rootToggleView;
@BindView(R.id.selinuxSwitchView) View selinuxToggleView;
@BindView(R.id.magiskStatusView) View magiskStatusView;
@BindView(R.id.rootStatusView) View rootStatusView;
@BindView(R.id.safetynetStatusView) View safetynetStatusView;
@BindView(R.id.selinuxStatusView) View selinuxStatusView;
@BindView(R.id.root_toggle) Switch rootToggle;
@BindView(R.id.selinux_toggle) Switch selinuxToggle;
@BindView(R.id.magisk_status_container) View magiskStatusContainer;
@ -50,6 +56,7 @@ public class MagiskFragment extends Fragment {
@BindColor(R.color.red500) int red500;
@BindColor(R.color.green500) int green500;
@BindColor(R.color.grey500) int grey500;
@BindColor(R.color.lime500) int lime500;
int statusOK = R.drawable.ic_check_circle;
int statusError = R.drawable.ic_error;
@ -61,19 +68,13 @@ public class MagiskFragment extends Fragment {
View view = inflater.inflate(R.layout.magisk_fragment, container, false);
ButterKnife.bind(this, view);
try {
Utils.initialize.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
updateStatus();
new updateUI().execute();
rootToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
Shell.su(b ? "setprop magisk.root 1" : "setprop magisk.root 0");
updateStatus();
new updateUI().execute();
}
});
@ -81,115 +82,140 @@ public class MagiskFragment extends Fragment {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
Shell.su(b ? "setenforce 1" : "setenforce 0");
updateStatus();
new updateUI().execute();
}
});
new android.os.Handler().postDelayed(new Runnable() {
@Override
public void run() {
updateStatus(); // update status again
}
}, 1000);
return view;
}
private void updateStatus() {
String selinux = Shell.sh("getenforce").get(0);
String version = Shell.sh("getprop magisk.version").get(0);
private class updateUI extends AsyncTask<Void, Void, Void> {
if (TextUtils.isEmpty(version)) {
magiskStatusContainer.setBackgroundColor(grey500);
magiskStatusIcon.setImageResource(statusUnknown);
magiskVersion.setTextColor(grey500);
magiskVersion.setText("?");
} else {
magiskStatusContainer.setBackgroundColor(green500);
magiskStatusIcon.setImageResource(statusOK);
magiskVersion.setTextColor(green500);
magiskVersion.setText(getString(R.string.magisk_version, version));
@Override
protected Void doInBackground(Void... voids) {
// Make sure static block invoked
Shell.rootAccess();
return null;
}
if (selinux.equals("Enforcing")) {
selinuxStatusContainer.setBackgroundColor(green500);
selinuxStatusIcon.setImageResource(statusOK);
@Override
protected void onPostExecute(Void v) {
super.onPostExecute(v);
selinuxStatus.setText(R.string.selinux_enforcing_info);
selinuxStatus.setTextColor(green500);
selinuxToggle.setChecked(true);
} else {
selinuxStatusContainer.setBackgroundColor(red500);
selinuxStatusIcon.setImageResource(statusError);
progressBar.setVisibility(View.GONE);
selinuxStatus.setText(R.string.selinux_permissive_info);
selinuxStatus.setTextColor(red500);
selinuxToggle.setChecked(false);
}
magiskStatusView.setVisibility(View.VISIBLE);
rootStatusView.setVisibility(View.VISIBLE);
safetynetStatusView.setVisibility(View.VISIBLE);
selinuxStatusView.setVisibility(View.VISIBLE);
if (new File("/system/framework/twframework.jar").exists()) {
selinuxToggleView.setVisibility(View.GONE);
selinuxStatus.append("\n" + getString(R.string.selinux_samsung));
}
if (new File("/system/xbin/su").exists()) {
rootStatusContainer.setBackgroundColor(red500);
rootStatusIcon.setImageResource(statusError);
rootStatus.setTextColor(red500);
rootToggle.setChecked(true);
safetyNetStatusIcon.setImageResource(statusError);
if (!Shell.rootAccess()) {
rootStatusContainer.setBackgroundColor(red500);
rootStatusIcon.setImageResource(statusUnknown);
rootStatus.setTextColor(red500);
rootStatus.setText(R.string.root_system);
rootToggleView.setVisibility(View.GONE);
selinuxToggleView.setVisibility(View.GONE);
safetyNetStatus.setText(R.string.root_system_info);
} else {
rootStatusContainer.setBackgroundColor(green500);
rootStatusIcon.setImageResource(statusError);
rootStatus.setTextColor(green500);
rootStatus.setText(R.string.root_mounted);
safetyNetStatus.setText(R.string.root_mounted_info);
if (Shell.rootAccess()) {
rootToggleView.setVisibility(View.VISIBLE);
selinuxToggleView.setVisibility(View.VISIBLE);
}
} else {
rootStatusContainer.setBackgroundColor(green500);
rootStatusIcon.setImageResource(statusOK);
rootStatus.setTextColor(green500);
rootToggle.setChecked(false);
List<String> selinux = Shell.sh("getenforce");
List<String> version = Shell.sh("getprop magisk.version");
safetyNetStatusIcon.setImageResource(statusOK);
if (version.isEmpty()) {
magiskStatusContainer.setBackgroundColor(grey500);
magiskStatusIcon.setImageResource(statusUnknown);
if (!Shell.rootAccess()) {
rootStatusContainer.setBackgroundColor(red500);
rootStatusIcon.setImageResource(statusError);
rootStatus.setTextColor(red500);
rootStatus.setText(R.string.root_none);
rootToggleView.setVisibility(View.GONE);
selinuxToggleView.setVisibility(View.GONE);
safetyNetStatusIcon.setImageResource(statusError);
safetyNetStatus.setText(R.string.root_none_info);
magiskVersion.setTextColor(grey500);
magiskVersion.setText(R.string.magisk_version_error);
} else {
rootStatus.setText(R.string.root_unmounted);
safetyNetStatus.setText(R.string.root_unmounted_info);
magiskStatusContainer.setBackgroundColor(green500);
magiskStatusIcon.setImageResource(statusOK);
magiskVersion.setTextColor(green500);
magiskVersion.setText(getString(R.string.magisk_version, version.get(0)));
}
if (selinux.isEmpty()) {
selinuxStatusContainer.setBackgroundColor(grey500);
selinuxStatusIcon.setImageResource(statusUnknown);
selinuxStatus.setText(R.string.selinux_error_info);
selinuxStatus.setTextColor(grey500);
selinuxToggle.setChecked(false);
} else if (selinux.get(0).equals("Enforcing")) {
selinuxStatusContainer.setBackgroundColor(green500);
selinuxStatusIcon.setImageResource(statusOK);
selinuxStatus.setText(R.string.selinux_enforcing_info);
selinuxStatus.setTextColor(green500);
selinuxToggle.setChecked(true);
} else {
selinuxStatusContainer.setBackgroundColor(red500);
selinuxStatusIcon.setImageResource(statusError);
selinuxStatus.setText(R.string.selinux_permissive_info);
selinuxStatus.setTextColor(red500);
selinuxToggle.setChecked(false);
}
if (new File("/system/framework/twframework.jar").exists()) {
selinuxToggleView.setVisibility(View.GONE);
selinuxStatus.append("\n" + getString(R.string.selinux_samsung_info));
}
switch (Shell.rootStatus) {
case -1:
// Root Error
rootStatusContainer.setBackgroundColor(grey500);
rootStatusIcon.setImageResource(statusUnknown);
rootStatus.setTextColor(grey500);
rootStatus.setText(R.string.root_error);
rootToggle.setChecked(false);
safetyNetStatusIcon.setImageResource(statusUnknown);
safetyNetStatus.setText(R.string.root_error_info);
break;
case 0:
// Not rooted
rootStatusContainer.setBackgroundColor(green500);
rootStatusIcon.setImageResource(statusOK);
rootStatus.setTextColor(green500);
rootStatus.setText(R.string.root_none);
rootToggle.setChecked(false);
safetyNetStatusIcon.setImageResource(statusOK);
safetyNetStatus.setText(R.string.root_none_info);
break;
case 1:
// Proper root
if (new File("/system/xbin/su").exists()) {
// Mounted
rootStatusContainer.setBackgroundColor(lime500);
rootStatusIcon.setImageResource(statusError);
rootStatus.setTextColor(lime500);
rootStatus.setText(R.string.root_mounted);
rootToggle.setChecked(true);
safetyNetStatusIcon.setImageResource(statusError);
safetyNetStatus.setText(R.string.root_mounted_info);
break;
} else {
// Not Mounted
rootStatusContainer.setBackgroundColor(green500);
rootStatusIcon.setImageResource(statusOK);
rootStatus.setTextColor(green500);
rootStatus.setText(R.string.root_unmounted);
rootToggle.setChecked(false);
safetyNetStatusIcon.setImageResource(statusOK);
safetyNetStatus.setText(R.string.root_unmounted_info);
break;
}
case 2:
// Improper root
rootStatusContainer.setBackgroundColor(red500);
rootStatusIcon.setImageResource(statusError);
rootStatus.setTextColor(red500);
rootStatus.setText(R.string.root_system);
rootToggle.setChecked(true);
safetyNetStatusIcon.setImageResource(statusError);
safetyNetStatus.setText(R.string.root_system_info);
rootToggleView.setVisibility(View.GONE);
break;
}
}
}
public void onRootGranted() {
updateStatus();
}
}

View File

@ -17,10 +17,9 @@ import android.view.ViewGroup;
import android.widget.ProgressBar;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
@ -33,28 +32,22 @@ public class ModulesFragment extends Fragment {
private static final String MAGISK_PATH = "/magisk";
private static final String MAGISK_CACHE_PATH = "/cache/magisk";
// protected static List<Module> listModules = new ArrayList<>();
// protected static List<Module> listModulesCache = new ArrayList<>();
private static List<Module> listModules = new ArrayList<>();
private static List<Module> listModulesCache = new ArrayList<>();
public static loadModules loadMod;
@BindView(R.id.progressBar) ProgressBar progressBar;
@BindView(R.id.pager) ViewPager viewPager;
@BindView(R.id.tab_layout) TabLayout tabLayout;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// listModules.clear();
// listModulesCache.clear();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.modules_fragment, container, false);
ButterKnife.bind(this, view);
new CheckFolders().execute();
new updateUI().execute();
setHasOptionsMenu(true);
return view;
@ -70,10 +63,9 @@ public class ModulesFragment extends Fragment {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.force_reload:
listModules.clear();
listModulesCache.clear();
new CheckFolders().execute();
loadMod = new loadModules();
loadMod.execute();
new updateUI().execute();
break;
}
@ -84,7 +76,7 @@ public class ModulesFragment extends Fragment {
@Override
protected List<Module> listModules() {
return Utils.listModules;
return listModules;
}
}
@ -93,18 +85,46 @@ public class ModulesFragment extends Fragment {
@Override
protected List<Module> listModules() {
return Utils.listModulesCache;
return listModulesCache;
}
}
private class CheckFolders extends AsyncTask<Void, Integer, Void> {
public static class loadModules extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
// Ensure initialize is done
listModules.clear();
listModulesCache.clear();
listModules.clear();
listModulesCache.clear();
List<String> magisk = Utils.getModList(MAGISK_PATH);
List<String> magiskCache = Utils.getModList(MAGISK_CACHE_PATH);
if (!magisk.isEmpty()) {
for (String mod : magisk) {
listModules.add(new Module(mod));
}
}
if (!magiskCache.isEmpty()) {
for (String mod : magiskCache) {
listModulesCache.add(new Module(mod));
}
}
return null;
}
}
private class updateUI extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
// Ensure loadMod is done
try {
Utils.initialize.get();
loadMod.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}

View File

@ -1,15 +1,12 @@
package com.topjohnwu.magisk;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
@ -17,15 +14,9 @@ import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
@ -53,9 +44,9 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
Utils.initialize = new Utils.Init();
Utils.initialize.execute();
// Load mods in the background
ModulesFragment.loadMod = new ModulesFragment.loadModules();
ModulesFragment.loadMod.execute();
setSupportActionBar(toolbar);
@ -158,41 +149,4 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
}
}
}
public static class Init extends AsyncTask<Void, Integer, Void> {
private final AppCompatActivity activity;
private ProgressDialog progress;
public Init(AppCompatActivity activity) {
this.activity = activity;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
progress = ProgressDialog.show(activity, null, activity.getString(R.string.loading), true, false);
}
@Override
protected Void doInBackground(Void... voids) {
return null;
}
@Override
protected void onPostExecute(Void v) {
super.onPostExecute(v);
progress.dismiss();
if (!Shell.rootAccess()) {
Snackbar.make(view, R.string.no_root_access, Snackbar.LENGTH_LONG).show();
return;
}
MagiskFragment fragment = (MagiskFragment) activity.getSupportFragmentManager().findFragmentByTag("magisk");
fragment.onRootGranted();
}
}
}

View File

@ -1,5 +1,7 @@
package com.topjohnwu.magisk.utils;
import android.os.AsyncTask;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
@ -23,21 +25,18 @@ public class Shell {
private static List<String> rootOutList = new ArrayList<>();
static {
init();
}
private static void init() {
List<String> ret = sh("getprop magisk.supath");
if(!ret.isEmpty()) {
suPath = ret.get(0) + "/su";
rootStatus = 1;
} else {
suPath = "su";
rootStatus = 2;
}
}
public static boolean rootAccess() {
return rootStatus > 0;
}
public static void startRoot() {
rootStatus = rootStatus == 0 ? 1 : 2;
try {
rootShell = Runtime.getRuntime().exec(suPath);
@ -45,15 +44,14 @@ public class Shell {
rootSTDOUT = new StreamGobbler(rootShell.getInputStream(), rootOutList);
rootSTDOUT.start();
} catch (IOException e) {
// runtime error! No binary found!
// runtime error! No binary found! Means no root
rootStatus = 0;
return;
}
List<String> ret = su("echo -BOC-", "id");
ret = su("echo -BOC-", "id");
if (ret == null) {
// Something wrong with root install, not enabled?
// Something wrong with root, not allowed?
rootStatus = -1;
return;
}
@ -84,6 +82,10 @@ public class Shell {
}
}
public static boolean rootAccess() {
return rootStatus > 0;
}
public static List<String> sh(String... commands) {
List<String> res = Collections.synchronizedList(new ArrayList<String>());

View File

@ -36,7 +36,8 @@ public class StreamGobbler extends Thread {
try {
String line;
while ((line = reader.readLine()) != null) {
writer.add(line);
if (!line.replaceAll("\\s", "").isEmpty())
writer.add(line);
}
} catch (IOException e) {
// reader probably closed, expected exit condition

View File

@ -1,45 +1,9 @@
package com.topjohnwu.magisk.utils;
import android.os.AsyncTask;
import com.topjohnwu.magisk.module.Module;
import java.util.ArrayList;
import java.util.List;
public class Utils {
public static Init initialize;
public static List<Module> listModules = new ArrayList<>();
public static List<Module> listModulesCache = new ArrayList<>();
public static List<String> listLog;
public static class Init extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
Shell.startRoot();
listModules.clear();
listModulesCache.clear();
List<String> magisk = getModList("/magisk");
List<String> magiskCache = getModList("/cache/magisk");
if (!magisk.isEmpty()) {
for (String mod : magisk) {
listModules.add(new Module(mod));
}
}
if (!magiskCache.isEmpty()) {
for (String mod : magiskCache) {
listModulesCache.add(new Module(mod));
}
}
listLog = readFile("/cache/magisk.log");
return null;
}
}
public static boolean fileExist(String path) {
List<String> ret;
ret = Shell.sh("if [ -f " + path + " ]; then echo true; else echo false; fi");

View File

@ -11,12 +11,19 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
<android.support.v7.widget.CardView
android:id="@+id/rootSwitchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="2dp"
app:cardCornerRadius="0dp">
app:cardCornerRadius="0dp"
android:visibility="gone">
<Switch
android:id="@+id/root_toggle"
@ -35,7 +42,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:elevation="2dp"
app:cardCornerRadius="0dp">
app:cardCornerRadius="0dp"
android:visibility="gone">
<Switch
android:id="@+id/selinux_toggle"
@ -49,13 +57,15 @@
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/magiskStatusView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="6dp"
app:cardUseCompatPadding="true">
app:cardUseCompatPadding="true"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"
@ -92,13 +102,15 @@
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/rootStatusView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="6dp"
app:cardUseCompatPadding="true">
app:cardUseCompatPadding="true"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"
@ -134,13 +146,15 @@
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/safetynetStatusView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="6dp"
app:cardUseCompatPadding="true">
app:cardUseCompatPadding="true"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"
@ -168,13 +182,15 @@
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/selinuxStatusView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="6dp"
app:cardUseCompatPadding="true">
app:cardUseCompatPadding="true"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"

View File

@ -10,5 +10,6 @@
<color name="red500">#F44336</color>
<color name="green500">#4CAF50</color>
<color name="grey500">#9E9E9E</color>
<color name="lime500">#CDDC39</color>
</resources>

View File

@ -1,19 +1,27 @@
<resources>
<string name="app_name">Magisk Manager</string>
<string name="magisk_version">Installed Magisk v%1$s</string>
<string name="magisk_version_error">Have you installed Magisk?</string>
<string name="root_error">Root Error</string>
<string name="root_error_info">Safety Net Status Unknown</string>
<string name="root_none">Not Rooted</string>
<string name="root_none_info">Safety Net (Android Pay) should work</string>
<string name="root_mounted">Root mounted</string>
<string name="root_mounted_info">Root mounted and enabled. Safety Net (Android Pay) will NOT work</string>
<string name="root_unmounted">Root not mounted</string>
<string name="root_unmounted_info">Safety Net (Android Pay) should work, but no root temporarily</string>
<string name="selinux_enforcing_info">SELinux is enforced</string>
<string name="selinux_permissive_info">SELinux is permissive\nOnly turn off SELinux if necessary!</string>
<string name="root_toggle">Root Toggle</string>
<string name="selinux_toggle">SeLinux Toggle</string>
<string name="root_system">Improperly Installed</string>
<string name="root_system_info">Root improperly installed. Safety Net (Android Pay) will NOT work, and impossible to toggle</string>
<string name="root_none">Not Rooted</string>
<string name="root_none_info">Safety Net (Android Pay) should work</string>
<string name="magisk_version">Installed Magisk v%1$s</string>
<string name="selinux_samsung">Samsung do not support switching SELinux status!</string>
<string name="selinux_error_info">SELinux Status Unknown</string>
<string name="selinux_enforcing_info">SELinux is enforced</string>
<string name="selinux_permissive_info">SELinux is permissive\nOnly turn off SELinux if necessary!</string>
<string name="selinux_samsung_info">Samsung do not support switching SELinux status!</string>
<string name="root_toggle">Root Toggle</string>
<string name="selinux_toggle">SELinux Toggle</string>
<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>