diff --git a/README.md b/README.md new file mode 100644 index 000000000..383c8685d --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# Magisk Manager + +Because I love to stay on cutting edge, the project can only be compiled on Android Studio Version 2.2.0+ (currently in beta) + diff --git a/app/build.gradle b/app/build.gradle index 054ffa779..8704501f2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,5 +1,5 @@ apply plugin: 'com.android.application' -apply plugin: 'android-apt' +//apply plugin: 'android-apt' android { compileSdkVersion 24 @@ -11,13 +11,21 @@ android { targetSdkVersion 24 versionCode 4 versionName "2.0" + jackOptions { + enabled true + } } buildTypes { release { - minifyEnabled false + minifyEnabled true + shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { @@ -26,6 +34,6 @@ dependencies { compile 'com.android.support:cardview-v7:24.2.0' compile 'com.android.support:design:24.2.0' - compile 'com.jakewharton:butterknife:8.2.1' - apt 'com.jakewharton:butterknife-compiler:8.2.1' + compile 'com.jakewharton:butterknife:8.4.0' + annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c74ce0f47..b4e518ad8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -26,6 +26,15 @@ + + + \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java index 57ba0a210..b32daaecc 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java @@ -1,20 +1,23 @@ package com.topjohnwu.magisk; import android.Manifest; -import android.app.ProgressDialog; +import android.app.DownloadManager; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; +import android.support.v4.content.FileProvider; import android.support.v7.app.AlertDialog; import android.text.Html; import android.text.TextUtils; @@ -26,22 +29,19 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; +import com.topjohnwu.magisk.utils.DownloadReceiver; import com.topjohnwu.magisk.utils.Shell; import org.json.JSONException; import org.json.JSONObject; -import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; -import java.io.OutputStream; +import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.net.URL; -import java.net.URLConnection; import java.util.List; import butterknife.BindColor; @@ -50,7 +50,7 @@ import butterknife.ButterKnife; public class MagiskFragment extends Fragment { - private static final String JSON_UPDATE_CHECK = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/master/app/magisk_update.json"; + private static final String JSON_UPDATE_CHECK = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/updates/magisk_update.json"; @BindView(R.id.progressBarVersion) ProgressBar progressBar; @@ -82,6 +82,7 @@ public class MagiskFragment extends Fragment { private String mLastLink; private boolean mLastIsApp; private List version; + private long apkID, zipID; @Nullable @Override @@ -100,7 +101,7 @@ public class MagiskFragment extends Fragment { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - new DownloadFile(getContext(), mLastLink, mLastIsApp).execute(); + downloadFile(); } else { Toast.makeText(getContext(), R.string.permissionNotGranted, Toast.LENGTH_LONG).show(); } @@ -123,32 +124,73 @@ public class MagiskFragment extends Fragment { String text = app ? getString(R.string.app_name) : getString(R.string.magisk); final String msg = getString(R.string.update_available_message, text, versionCode, changelog); - clickView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - new AlertDialog.Builder(getContext()) - .setTitle(R.string.update_available) - .setMessage(Html.fromHtml(msg)) - .setCancelable(false) - .setPositiveButton(R.string.update, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - mLastLink = link; - mLastIsApp = app; + clickView.setOnClickListener(view -> new AlertDialog.Builder(getContext()) + .setTitle(R.string.update_available) + .setMessage(Html.fromHtml(msg)) + .setCancelable(false) + .setPositiveButton(R.string.update, (dialogInterface, i) -> { + mLastLink = link; + mLastIsApp = app; - if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED - && Build.VERSION.SDK_INT >= 23) { - requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); - return; - } + if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + downloadFile(); + } else { + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); + } - new DownloadFile(getContext(), link, app).execute(); - } - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } - }); + }) + .setNegativeButton(R.string.no_thanks, null) + .show()); + } + + private void downloadFile() { + + File downloadFile, dir = new File(Environment.getExternalStorageDirectory() + "/MagiskManager"); + DownloadReceiver receiver; + + if (mLastIsApp) { + downloadFile = new File(dir + "/MagiskManager.apk"); + + } else { + downloadFile = new File(dir + "/Magisk.zip"); + } + + if (!dir.exists()) dir.mkdir(); + + DownloadManager downloadManager = (DownloadManager) getContext().getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager.Request request = new DownloadManager.Request(Uri.parse(mLastLink)); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) + .setDestinationUri(Uri.fromFile(downloadFile)); + + if (downloadFile.exists()) downloadFile.delete(); + + long downloadID = downloadManager.enqueue(request); + + if (mLastIsApp) { + receiver = new DownloadReceiver(downloadID) { + @Override + public void task(File file) { + Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE); + install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + install.setData(FileProvider.getUriForFile(context, "com.topjohnwu.magisk.provider", file)); + context.startActivity(install); + } + }; + } else { + receiver = new DownloadReceiver(downloadID) { + @Override + public void task(final File file) { + new AlertDialog.Builder(context) + .setTitle("Reboot Recovery") + .setMessage("Do you want to flash in recovery now?") + .setCancelable(false) + .setPositiveButton("Yes, flash now", (dialogInterface, i) -> Toast.makeText(context, file.getPath(), Toast.LENGTH_LONG).show()) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } + }; + } + getActivity().registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); } private class updateUI extends AsyncTask { @@ -164,11 +206,9 @@ public class MagiskFragment extends Fragment { protected void onPostExecute(Void v) { super.onPostExecute(v); - progressBar.setVisibility(View.GONE); - version = Shell.sh("getprop magisk.version"); - if (version.isEmpty()) { + if (version.get(0).replaceAll("\\s", "").isEmpty()) { magiskStatusContainer.setBackgroundColor(grey500); magiskStatusIcon.setImageResource(statusUnknown); @@ -182,6 +222,7 @@ public class MagiskFragment extends Fragment { magiskVersion.setText(getString(R.string.magisk_version, version.get(0))); } + progressBar.setVisibility(View.GONE); magiskStatusView.setVisibility(View.VISIBLE); } } @@ -251,7 +292,7 @@ public class MagiskFragment extends Fragment { appCheckUpdatesStatus.setText(getString(R.string.up_to_date, getString(R.string.app_name))); } - String v = version.isEmpty() ? "" : version.get(0); + String v = version.get(0).replaceAll("\\s", ""); int versionInt = TextUtils.isEmpty(v) ? 0 : Integer.parseInt(v); @@ -267,103 +308,4 @@ public class MagiskFragment extends Fragment { } } } - - private class DownloadFile extends AsyncTask { - - private final Context context; - private final String link; - private final File downloadFile; - private final ProgressDialog progress; - - public DownloadFile(Context context, String link, boolean apk) { - this.link = link; - this.context = context; - - File dir = new File(Environment.getExternalStorageDirectory() + "/Magisk"); - - if (!dir.exists()) dir.mkdir(); - - if (apk) { - downloadFile = new File(dir + "/MagiskManager.apk"); - } else { - downloadFile = new File(dir + "/Magisk.zip"); - } - - Toast.makeText(context, downloadFile.getPath(), Toast.LENGTH_SHORT).show(); - - progress = new ProgressDialog(getContext()); - progress.setTitle(null); - progress.setMessage(getString(R.string.loading)); - progress.setIndeterminate(true); - progress.setCancelable(false); - progress.setButton(android.app.AlertDialog.BUTTON_POSITIVE, getString(android.R.string.cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - cancel(true); - } - }); - progress.show(); - } - - @Override - protected Boolean doInBackground(Void... voids) { - try { - URL u = new URL(link); - URLConnection conn = u.openConnection(); - conn.connect(); - - int length = conn.getContentLength(); - - InputStream input = new BufferedInputStream(u.openStream(), 8192); - OutputStream output = new FileOutputStream(downloadFile); - - byte data[] = new byte[1024]; - long total = 0; - - int count; - while ((count = input.read(data)) != -1) { - total += count; - output.write(data, 0, count); - - publishProgress((int) ((total * 100) / length)); - } - - output.flush(); - - output.close(); - input.close(); - - return true; - } catch (IOException e) { - return false; - } - } - - @Override - protected void onProgressUpdate(Integer... values) { - super.onProgressUpdate(values); - - progress.setMessage(getString(R.string.loading) + " " + values[0] + "%"); - } - - @Override - protected void onPostExecute(Boolean result) { - super.onPostExecute(result); - progress.dismiss(); - if (!result) { - Toast.makeText(context, R.string.error_download_file, Toast.LENGTH_LONG).show(); - return; - } - - if (downloadFile.getPath().contains("apk")) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(downloadFile), "application/vnd.android.package-archive"); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - } else { - Toast.makeText(context, R.string.flash_recovery, Toast.LENGTH_LONG).show(); - } - - } - } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 55d2a4685..4acada288 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -85,10 +85,6 @@ public class ModulesFragment extends Fragment { @Override protected Void doInBackground(Void... voids) { - - listModules.clear(); - listModulesCache.clear(); - listModules.clear(); listModulesCache.clear(); List magisk = Utils.getModList(MAGISK_PATH); @@ -98,7 +94,6 @@ public class ModulesFragment extends Fragment { listModules.add(new Module(mod)); } } - if (!magiskCache.isEmpty()) { for (String mod : magiskCache) { listModulesCache.add(new Module(mod)); diff --git a/app/src/main/java/com/topjohnwu/magisk/RootFragment.java b/app/src/main/java/com/topjohnwu/magisk/RootFragment.java index 9300f276e..19ca32189 100644 --- a/app/src/main/java/com/topjohnwu/magisk/RootFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/RootFragment.java @@ -2,6 +2,7 @@ package com.topjohnwu.magisk; import android.os.AsyncTask; import android.os.Bundle; +import android.os.Handler; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; @@ -63,20 +64,14 @@ public class RootFragment extends Fragment { 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"); - new updateUI().execute(); - } + rootToggle.setOnClickListener(toggle -> { + Shell.su(((CompoundButton) toggle).isChecked() ? "setprop magisk.root 1" : "setprop magisk.root 0"); + new Handler().postDelayed(() -> new updateUI().execute(), 1000); }); - selinuxToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean b) { - Shell.su(b ? "setenforce 1" : "setenforce 0"); - new updateUI().execute(); - } + selinuxToggle.setOnClickListener(toggle -> { + Shell.su(((CompoundButton) toggle).isChecked() ? "setenforce 1" : "setenforce 0"); + new Handler().postDelayed(() -> new updateUI().execute(), 1000); }); return view; @@ -132,7 +127,6 @@ public class RootFragment extends Fragment { } if (new File("/system/framework/twframework.jar").exists()) { - selinuxToggleView.setVisibility(View.GONE); selinuxStatus.append("\n" + getString(R.string.selinux_samsung_info)); } diff --git a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java index 64dfbbde7..bf0356ec8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java @@ -71,12 +71,7 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView if (savedInstanceState == null) { mDrawerHandler.removeCallbacksAndMessages(null); - mDrawerHandler.postDelayed(new Runnable() { - @Override - public void run() { - navigate(mSelectedId); - } - }, 250); + mDrawerHandler.postDelayed(() -> navigate(mSelectedId), 250); } navigationView.setNavigationItemSelectedListener(this); @@ -103,12 +98,7 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView public boolean onNavigationItemSelected(@NonNull final MenuItem menuItem) { mSelectedId = menuItem.getItemId(); mDrawerHandler.removeCallbacksAndMessages(null); - mDrawerHandler.postDelayed(new Runnable() { - @Override - public void run() { - navigate(menuItem.getItemId()); - } - }, 250); + mDrawerHandler.postDelayed(() -> navigate(menuItem.getItemId()), 250); drawer.closeDrawer(GravityCompat.START); return true; diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/DownloadReceiver.java b/app/src/main/java/com/topjohnwu/magisk/utils/DownloadReceiver.java new file mode 100644 index 000000000..58703ee2e --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/DownloadReceiver.java @@ -0,0 +1,54 @@ +package com.topjohnwu.magisk.utils; + +import android.app.DownloadManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.util.Log; +import android.widget.Toast; + +import com.topjohnwu.magisk.R; + +import java.io.File; + +/** + * Created by topjohnwu on 2016/8/27. + */ +public abstract class DownloadReceiver extends BroadcastReceiver{ + public Context context; + DownloadManager downloadManager; + long downloadID; + + public DownloadReceiver(long downloadID) { + this.downloadID = downloadID; + } + @Override + public void onReceive(Context context, Intent intent) { + this.context = context; + downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + String action = intent.getAction(); + if(DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)){ + DownloadManager.Query query = new DownloadManager.Query(); + query.setFilterById(downloadID); + Cursor c = downloadManager.query(query); + if (c.moveToFirst()) { + int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS); + int status = c.getInt(columnIndex); + switch (status) { + case DownloadManager.STATUS_SUCCESSFUL: + File file = new File(Uri.parse(c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))).getPath()); + task(file); + break; + default: + Toast.makeText(context, R.string.error_download_file, Toast.LENGTH_LONG).show(); + break; + } + context.unregisterReceiver(this); + } + } + } + + public abstract void task(File file); +} 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 273f060be..0f47f27ff 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java @@ -14,10 +14,8 @@ import java.util.List; public class Shell { - - public static String suPath; // -1 = problematic/unknown issue; 0 = not rooted; 1 = properly rooted; 2 = improperly rooted; - public static int rootStatus = 0; + public static int rootStatus; private static Process rootShell; private static DataOutputStream rootSTDIN; @@ -29,27 +27,27 @@ public class Shell { } 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; - } try { - rootShell = Runtime.getRuntime().exec(suPath); - rootSTDIN = new DataOutputStream(rootShell.getOutputStream()); - rootSTDOUT = new StreamGobbler(rootShell.getInputStream(), rootOutList); - rootSTDOUT.start(); + rootShell = Runtime.getRuntime().exec(sh("getprop magisk.supath").get(0) + "/su"); + rootStatus = 1; } catch (IOException e) { - // runtime error! No binary found! Means no root - rootStatus = 0; - return; + try { + // Improper root + rootShell = Runtime.getRuntime().exec("su"); + rootStatus = 2; + } catch (IOException err) { + // No root + rootStatus = 0; + return; + } } - ret = su("echo -BOC-", "id"); + rootSTDIN = new DataOutputStream(rootShell.getOutputStream()); + rootSTDOUT = new StreamGobbler(rootShell.getInputStream(), rootOutList); + rootSTDOUT.start(); + + List ret = su("echo -BOC-", "id"); if (ret == null) { // Something wrong with root, not allowed? rootStatus = -1; @@ -74,7 +72,6 @@ public class Shell { if (rootAccess()) { rootSTDIN.write("exit\n".getBytes("UTF-8")); rootSTDIN.flush(); - rootSTDIN.flush(); rootShell.waitFor(); rootSTDIN.close(); rootSTDOUT.join(); @@ -134,39 +131,37 @@ public class Shell { rootOutList.clear(); try { - try { - for (String write : commands) { - rootSTDIN.write((write + "\n").getBytes("UTF-8")); - rootSTDIN.flush(); - } - rootSTDIN.write(("echo \'-done-\'\n").getBytes("UTF-8")); + for (String write : commands) { + rootSTDIN.write((write + "\n").getBytes("UTF-8")); rootSTDIN.flush(); - } catch (IOException e) { - if (!e.getMessage().contains("EPIPE")) { - throw e; - } } + rootSTDIN.write(("echo \' \'\n").getBytes("UTF-8")); + rootSTDIN.flush(); + rootSTDIN.write(("echo \'-done-\'\n").getBytes("UTF-8")); + rootSTDIN.flush(); + } catch (IOException e) { + if (!e.getMessage().contains("EPIPE")) { + return null; + } + } - while (true) { - try { - // Process terminated, it means the interactive shell cannot be initialized - rootShell.exitValue(); - return null; - } catch (IllegalThreadStateException e) { - // Process still running, gobble output until done - if (rootOutList != null && !rootOutList.isEmpty()) { - if (rootOutList.get(rootOutList.size() - 1).equals("-done-")) { - rootOutList.remove(rootOutList.size() - 1); - break; - } + while (true) { + try { + // Process terminated, it means the interactive shell cannot be initialized + rootShell.exitValue(); + return null; + } catch (IllegalThreadStateException e) { + // Process still running, gobble output until done + int end = rootOutList.size() - 1; + if (rootOutList != null && end > 0) { + if (rootOutList.get(end).equals("-done-")) { + rootOutList.remove(end); + rootOutList.remove(end - 1); + break; } - rootSTDOUT.join(100); } + try { rootSTDOUT.join(100); } catch (InterruptedException err) { return null; } } - - } catch (IOException | InterruptedException e) { - // shell probably not found - return null; } return new ArrayList<>(rootOutList); 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 1409880f4..8b40775ab 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java @@ -36,8 +36,7 @@ public class StreamGobbler extends Thread { try { String line; while ((line = reader.readLine()) != null) { - if (!line.replaceAll("\\s", "").isEmpty()) - writer.add(line); + 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 11b45a7f0..526f03914 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -37,7 +37,7 @@ public class Utils { public static List readFile(String path) { List ret; ret = Shell.sh("cat " + path); - if (ret.isEmpty() && Shell.rootAccess()) ret = Shell.su("cat " + path, "echo \' \'"); + if (ret.isEmpty() && Shell.rootAccess()) ret = Shell.su("cat " + path); return ret; } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 04a86a4d3..74b85f90b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -12,14 +12,14 @@ 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 + Safety Net (Android Pay) should work, but no root temporarily\nYou might need to manually add a card in Android Pay app to refresh the root status of AP Improperly Installed Root improperly installed. Safety Net (Android Pay) will NOT work, and impossible to toggle SELinux Status Unknown SELinux is enforced SELinux is permissive\nOnly turn off SELinux if necessary! - Samsung do not support switching SELinux status! + Samsung need custom kernel for switching SELinux status! Root Toggle SELinux Toggle diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml new file mode 100644 index 000000000..4495c28c8 --- /dev/null +++ b/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 5e76393d7..fa49c82eb 100644 --- a/build.gradle +++ b/build.gradle @@ -6,8 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.3' - classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' + classpath 'com.android.tools.build:gradle:2.2.0-beta1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files