diff --git a/app/build.gradle b/app/build.gradle index 435fc68e8..054ffa779 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'android-apt' android { compileSdkVersion 24 - buildToolsVersion "24.0.1" + buildToolsVersion "24.0.2" defaultConfig { applicationId "com.topjohnwu.magisk" diff --git a/app/src/main/java/com/topjohnwu/magisk/LogFragment.java b/app/src/main/java/com/topjohnwu/magisk/LogFragment.java index 4ecce58a6..3bf3f6e25 100644 --- a/app/src/main/java/com/topjohnwu/magisk/LogFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/LogFragment.java @@ -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 logList = Utils.readFile(MAGISK_LOG); @@ -225,8 +219,6 @@ public class LogFragment extends Fragment { } return ""; } - - } @Override diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java index 0adac46a0..1d8250943 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java @@ -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 { - 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 selinux = Shell.sh("getenforce"); + List 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(); - } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 5a91fa779..b6d8ab66b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -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 listModules = new ArrayList<>(); -// protected static List listModulesCache = new ArrayList<>(); + private static List listModules = new ArrayList<>(); + private static List 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 listModules() { - return Utils.listModules; + return listModules; } } @@ -93,18 +85,46 @@ public class ModulesFragment extends Fragment { @Override protected List listModules() { - return Utils.listModulesCache; + return listModulesCache; } } - private class CheckFolders extends AsyncTask { + public static class loadModules extends AsyncTask { @Override protected Void doInBackground(Void... voids) { - // Ensure initialize is done + + listModules.clear(); + listModulesCache.clear(); + + listModules.clear(); + listModulesCache.clear(); + List magisk = Utils.getModList(MAGISK_PATH); + List 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 { + + @Override + protected Void doInBackground(Void... voids) { + // Ensure loadMod is done try { - Utils.initialize.get(); + loadMod.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java index cf73a4a1f..ac6bd8712 100644 --- a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java @@ -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 { - - 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(); - } - } } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java b/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java index 86f60fc34..273f060be 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java @@ -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 rootOutList = new ArrayList<>(); static { + init(); + } + + private static void init() { List 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 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 sh(String... commands) { List res = Collections.synchronizedList(new ArrayList()); diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java b/app/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java index 8b40775ab..1409880f4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java @@ -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 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 20f4a3118..11b45a7f0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -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 listModules = new ArrayList<>(); - public static List listModulesCache = new ArrayList<>(); - public static List listLog; - - public static class Init extends AsyncTask { - - @Override - protected Void doInBackground(Void... voids) { - Shell.startRoot(); - listModules.clear(); - listModulesCache.clear(); - List magisk = getModList("/magisk"); - List 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 ret; ret = Shell.sh("if [ -f " + path + " ]; then echo true; else echo false; fi"); diff --git a/app/src/main/res/layout/magisk_fragment.xml b/app/src/main/res/layout/magisk_fragment.xml index cb4795fad..6f0dbc5ba 100644 --- a/app/src/main/res/layout/magisk_fragment.xml +++ b/app/src/main/res/layout/magisk_fragment.xml @@ -11,12 +11,19 @@ android:layout_height="wrap_content" android:orientation="vertical"> + + + app:cardCornerRadius="0dp" + android:visibility="gone"> + app:cardCornerRadius="0dp" + android:visibility="gone"> + app:cardUseCompatPadding="true" + android:visibility="gone"> + app:cardUseCompatPadding="true" + android:visibility="gone"> + app:cardUseCompatPadding="true" + android:visibility="gone"> + app:cardUseCompatPadding="true" + android:visibility="gone"> #F44336 #4CAF50 #9E9E9E + #CDDC39 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3fcb13031..0f0ef1111 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,19 +1,27 @@ Magisk Manager + + Installed Magisk v%1$s + Have you installed Magisk? + + Root Error + Safety Net Status Unknown + Not Rooted + Safety Net (Android Pay) should work Root mounted Root mounted and enabled. Safety Net (Android Pay) will NOT work Root not mounted Safety Net (Android Pay) should work, but no root temporarily - SELinux is enforced - SELinux is permissive\nOnly turn off SELinux if necessary! - Root Toggle - SeLinux Toggle Improperly Installed Root improperly installed. Safety Net (Android Pay) will NOT work, and impossible to toggle - Not Rooted - Safety Net (Android Pay) should work - Installed Magisk v%1$s - Samsung do not support switching SELinux status! + + SELinux Status Unknown + SELinux is enforced + SELinux is permissive\nOnly turn off SELinux if necessary! + Samsung do not support switching SELinux status! + + Root Toggle + SELinux Toggle Open navigation drawer Close navigation drawer