From 57af984e6870c0fb391ccb2982dd9e2ec722e5eb Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 25 Dec 2016 03:05:22 +0800 Subject: [PATCH] Add status fragment --- .../com/topjohnwu/magisk/InstallFragment.java | 71 +++++ .../com/topjohnwu/magisk/LogFragment.java | 1 + .../com/topjohnwu/magisk/MagiskFragment.java | 300 ------------------ .../topjohnwu/magisk/MagiskHideFragment.java | 1 + .../com/topjohnwu/magisk/MainActivity.java | 28 +- .../com/topjohnwu/magisk/ModulesFragment.java | 1 + .../com/topjohnwu/magisk/ReposFragment.java | 1 + .../topjohnwu/magisk/SettingsActivity.java | 4 +- .../com/topjohnwu/magisk/SplashActivity.java | 20 -- .../com/topjohnwu/magisk/StatusFragment.java | 267 ++++++++++++++++ .../com/topjohnwu/magisk/utils/Async.java | 16 +- .../magisk/utils/SafetyNetHelper.java | 1 - app/src/main/res/drawable/ic_cancel.xml | 9 + .../res/drawable/ic_device_information.xml | 9 + .../main/res/drawable/ic_file_download.xml | 9 - app/src/main/res/drawable/ic_update.xml | 9 + app/src/main/res/drawable/ic_warning.xml | 9 - app/src/main/res/layout/install_fragment.xml | 6 + ...agisk_fragment.xml => status_fragment.xml} | 125 ++++---- app/src/main/res/menu/drawer.xml | 9 +- app/src/main/res/values/strings.xml | 26 +- 21 files changed, 492 insertions(+), 430 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/InstallFragment.java delete mode 100644 app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/StatusFragment.java create mode 100644 app/src/main/res/drawable/ic_cancel.xml create mode 100644 app/src/main/res/drawable/ic_device_information.xml delete mode 100644 app/src/main/res/drawable/ic_file_download.xml create mode 100644 app/src/main/res/drawable/ic_update.xml delete mode 100644 app/src/main/res/drawable/ic_warning.xml create mode 100644 app/src/main/res/layout/install_fragment.xml rename app/src/main/res/layout/{magisk_fragment.xml => status_fragment.xml} (81%) diff --git a/app/src/main/java/com/topjohnwu/magisk/InstallFragment.java b/app/src/main/java/com/topjohnwu/magisk/InstallFragment.java new file mode 100644 index 000000000..3b2da17d5 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/InstallFragment.java @@ -0,0 +1,71 @@ +package com.topjohnwu.magisk; + +import android.app.Fragment; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AlertDialog; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.topjohnwu.magisk.receivers.DownloadReceiver; +import com.topjohnwu.magisk.utils.Async; +import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.ZipUtils; + +import java.io.File; + +import butterknife.ButterKnife; + +// Currently empty, placing some code that we be used in the future +public class InstallFragment extends Fragment { + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.install_fragment, container, false); + ButterKnife.bind(this, v); + return v; + } + + @Override + public void onResume() { + super.onResume(); + getActivity().setTitle(R.string.install); + } + + private AlertDialog.OnClickListener flashMagisk = (dialogInterface, i) -> Utils.dlAndReceive( + getActivity(), + new DownloadReceiver() { + @Override + public void task(Uri uri) { + new Async.FlashZIP(mContext, uri, mFilename) { + @Override + protected boolean unzipAndCheck() { + publishProgress(mContext.getString(R.string.zip_install_unzip_zip_msg)); + if (Shell.rootAccess()) { + // We might not have busybox yet, unzip with Java + // We will have complete busybox after Magisk installation + ZipUtils.unzip(mCachedFile, new File(mCachedFile.getParent(), "magisk")); + Shell.su( + "mkdir -p " + Async.TMP_FOLDER_PATH + "/magisk", + "cp -af " + mCachedFile.getParent() + "/magisk/. " + Async.TMP_FOLDER_PATH + "/magisk" + ); + } + super.unzipAndCheck(); + return true; + } + + @Override + protected void done() { + Shell.su("setprop magisk.version " + String.valueOf(StatusFragment.remoteMagiskVersion)); + super.done(); + } + }.exec(); + } + }, + StatusFragment.magiskLink, + "Magisk-v" + String.valueOf(StatusFragment.remoteMagiskVersion) + ".zip"); +} diff --git a/app/src/main/java/com/topjohnwu/magisk/LogFragment.java b/app/src/main/java/com/topjohnwu/magisk/LogFragment.java index 295c53ab7..972ea28f0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/LogFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/LogFragment.java @@ -67,6 +67,7 @@ public class LogFragment extends Fragment { super.onResume(); setHasOptionsMenu(true); new LogManager().read(); + getActivity().setTitle(R.string.log); } @Override diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java deleted file mode 100644 index 434d659e1..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java +++ /dev/null @@ -1,300 +0,0 @@ -package com.topjohnwu.magisk; - -import android.app.Fragment; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.support.annotation.Nullable; -import android.support.v4.content.FileProvider; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.app.AlertDialog; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; - -import com.topjohnwu.magisk.receivers.DownloadReceiver; -import com.topjohnwu.magisk.utils.Async; -import com.topjohnwu.magisk.utils.Logger; -import com.topjohnwu.magisk.utils.Shell; -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.utils.ZipUtils; - -import java.io.File; -import java.util.List; - -import butterknife.BindColor; -import butterknife.BindView; -import butterknife.ButterKnife; - -public class MagiskFragment extends Fragment { - - public static int remoteAppVersionCode = -1; - public static double magiskVersion, remoteMagiskVersion = -1; - public static String magiskVersionString, magiskLink, magiskChangelog, appLink, appChangelog, remoteAppVersion; - - @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; - - @BindView(R.id.magiskStatusView) View magiskStatusView; - @BindView(R.id.magisk_status_container) View magiskStatusContainer; - @BindView(R.id.magisk_status_icon) ImageView magiskStatusIcon; - @BindView(R.id.magisk_version) TextView magiskVersionText; - - @BindView(R.id.app_updateView) View appUpdateView; - @BindView(R.id.app_check_updates_container) View appCheckUpdatesContainer; - @BindView(R.id.app_check_updates_icon) ImageView appCheckUpdatesIcon; - @BindView(R.id.app_check_updates_status) TextView appCheckUpdatesStatus; - @BindView(R.id.app_check_updates_progress) ProgressBar appCheckUpdatesProgress; - - @BindView(R.id.magisk_updateView) View magiskUpdateView; - @BindView(R.id.magisk_check_updates_container) View magiskCheckUpdatesContainer; - @BindView(R.id.magisk_check_updates_icon) ImageView magiskCheckUpdatesIcon; - @BindView(R.id.magisk_check_updates_status) TextView magiskCheckUpdatesStatus; - @BindView(R.id.magisk_check_updates_progress) ProgressBar magiskCheckUpdatesProgress; - - @BindColor(R.color.green500) int colorOK; - @BindColor(R.color.yellow500) int colorWarn; - @BindColor(R.color.grey500) int colorNeutral; - @BindColor(R.color.blue500) int colorInfo; - - @BindColor(android.R.color.transparent) int trans; - - int statusOK = R.drawable.ic_check_circle; - int statusUnknown = R.drawable.ic_help; - - private AlertDialog.Builder builder; - - private SharedPreferences prefs; - private SharedPreferences.OnSharedPreferenceChangeListener listener; - - private AlertDialog.OnClickListener flashMagisk = (dialogInterface, i) -> Utils.dlAndReceive( - getActivity(), - new DownloadReceiver() { - @Override - public void task(Uri uri) { - new Async.FlashZIP(mContext, uri, mFilename) { - @Override - protected boolean unzipAndCheck() { - publishProgress(mContext.getString(R.string.zip_install_unzip_zip_msg)); - if (Shell.rootAccess()) { - // We might not have busybox yet, unzip with Java - // We will have complete busybox after Magisk installation - ZipUtils.unzip(mCachedFile, new File(mCachedFile.getParent(), "magisk")); - Shell.su( - "mkdir -p " + Async.TMP_FOLDER_PATH + "/magisk", - "cp -af " + mCachedFile.getParent() + "/magisk/. " + Async.TMP_FOLDER_PATH + "/magisk" - ); - } - super.unzipAndCheck(); - return true; - } - - @Override - protected void done() { - Shell.su("setprop magisk.version " + String.valueOf(remoteMagiskVersion)); - super.done(); - } - }.exec(); - } - }, - magiskLink, - "Magisk-v" + String.valueOf(remoteMagiskVersion) + ".zip"); - - private AlertDialog.OnClickListener installMagiskApk = (dialogInterface, i) -> Utils.dlAndReceive( - getActivity(), - new DownloadReceiver() { - @Override - public void task(Uri uri) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE); - install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - Uri content = FileProvider.getUriForFile(getActivity(), "com.topjohnwu.magisk.provider", new File(uri.getPath())); - install.setData(content); - mContext.startActivity(install); - } else { - Intent install = new Intent(Intent.ACTION_VIEW); - install.setDataAndType(uri, "application/vnd.android.package-archive"); - install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(install); - } - } - }, - appLink, - "MagiskManager-v" + remoteAppVersion + ".apk"); - - static { - updateMagiskVersion(); - } - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.magisk_fragment, container, false); - ButterKnife.bind(this, v); - - prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); - - mSwipeRefreshLayout.setOnRefreshListener(() -> { - prefs.edit().putBoolean("update_check_done", false).apply(); - - appCheckUpdatesContainer.setBackgroundColor(trans); - magiskCheckUpdatesContainer.setBackgroundColor(trans); - - appCheckUpdatesIcon.setImageResource(0); - magiskCheckUpdatesIcon.setImageResource(0); - - appCheckUpdatesStatus.setText(null); - magiskCheckUpdatesStatus.setText(null); - - appCheckUpdatesProgress.setVisibility(View.VISIBLE); - magiskCheckUpdatesProgress.setVisibility(View.VISIBLE); - - new Async.CheckUpdates(prefs).exec(); - }); - - if (prefs.getBoolean("update_check_done", false)) { - updateUI(); - } - - listener = (pref, s) -> { - if (s.equals("update_check_done")) { - if (pref.getBoolean(s, false)) { - Logger.dev("MagiskFragment: UI refresh triggered"); - updateMagiskVersion(); - updateUI(); - } - } - }; - - return v; - } - - @Override - public void onResume() { - super.onResume(); - prefs.registerOnSharedPreferenceChangeListener(listener); - } - - @Override - public void onDestroy() { - super.onDestroy(); - prefs.unregisterOnSharedPreferenceChangeListener(listener); - } - - private static void updateMagiskVersion() { - List ret = Shell.sh("getprop magisk.version"); - if (ret.get(0).length() == 0) { - magiskVersion = -1; - } else try { - magiskVersionString = ret.get(0); - magiskVersion = Double.parseDouble(ret.get(0)); - } catch (NumberFormatException e) { - // Custom version don't need to receive updates - magiskVersion = Double.POSITIVE_INFINITY; - } - } - - - private void updateUI() { - String theme = prefs.getString("theme", ""); - if (theme.equals("Dark")) { - builder = new AlertDialog.Builder(getActivity(), R.style.AlertDialog_dh); - } else { - builder = new AlertDialog.Builder(getActivity()); - } - - if (magiskVersion == -1) { - magiskStatusContainer.setBackgroundColor(colorNeutral); - magiskStatusIcon.setImageResource(statusUnknown); - - magiskVersionText.setTextColor(colorNeutral); - magiskVersionText.setText(R.string.magisk_version_error); - } else { - magiskStatusContainer.setBackgroundColor(colorOK); - magiskStatusIcon.setImageResource(statusOK); - - magiskVersionText.setText(getString(R.string.magisk_version, magiskVersionString)); - magiskVersionText.setTextColor(colorOK); - } - - if (remoteMagiskVersion == -1) { - appCheckUpdatesContainer.setBackgroundColor(colorWarn); - magiskCheckUpdatesContainer.setBackgroundColor(colorWarn); - - appCheckUpdatesIcon.setImageResource(R.drawable.ic_warning); - magiskCheckUpdatesIcon.setImageResource(R.drawable.ic_warning); - - appCheckUpdatesStatus.setText(R.string.cannot_check_updates); - appCheckUpdatesStatus.setTextColor(colorWarn); - magiskCheckUpdatesStatus.setText(R.string.cannot_check_updates); - magiskCheckUpdatesStatus.setTextColor(colorWarn); - } else { - if (remoteMagiskVersion > magiskVersion) { - magiskCheckUpdatesContainer.setBackgroundColor(colorInfo); - magiskCheckUpdatesIcon.setImageResource(R.drawable.ic_file_download); - magiskCheckUpdatesStatus.setText(getString(R.string.magisk_update_available, String.valueOf(remoteMagiskVersion))); - magiskCheckUpdatesStatus.setTextColor(colorInfo); - magiskUpdateView.setOnClickListener(view -> builder - .setTitle(getString(R.string.update_title, getString(R.string.magisk))) - .setMessage(getString(R.string.update_msg, getString(R.string.magisk), String.valueOf(remoteMagiskVersion), magiskChangelog)) - .setCancelable(true) - .setPositiveButton(R.string.download_install, flashMagisk) - .setNegativeButton(R.string.no_thanks, null) - .show()); - - } else { - magiskCheckUpdatesContainer.setBackgroundColor(colorOK); - magiskCheckUpdatesIcon.setImageResource(R.drawable.ic_check_circle); - magiskCheckUpdatesStatus.setText(getString(R.string.up_to_date, getString(R.string.magisk))); - magiskCheckUpdatesStatus.setTextColor(colorOK); - magiskUpdateView.setOnClickListener(view -> builder - .setTitle(getString(R.string.repo_install_title, getString(R.string.magisk))) - .setMessage(getString(R.string.repo_install_msg, "Magisk-v" + String.valueOf(remoteMagiskVersion))) - .setCancelable(true) - .setPositiveButton(R.string.download_install, flashMagisk) - .setNegativeButton(R.string.no_thanks, null) - .show()); - } - - if (remoteAppVersionCode > BuildConfig.VERSION_CODE) { - appCheckUpdatesContainer.setBackgroundColor(colorInfo); - appCheckUpdatesIcon.setImageResource(R.drawable.ic_file_download); - appCheckUpdatesStatus.setText(getString(R.string.app_update_available, remoteAppVersion)); - appCheckUpdatesStatus.setTextColor(colorInfo); - appUpdateView.setOnClickListener(view -> builder - .setTitle(getString(R.string.update_title, getString(R.string.app_name))) - .setMessage(getString(R.string.update_msg, getString(R.string.app_name), remoteAppVersion, appChangelog)) - .setCancelable(true) - .setPositiveButton(R.string.download_install, installMagiskApk) - .setNegativeButton(R.string.no_thanks, null) - .show() - ); - } else { - appCheckUpdatesContainer.setBackgroundColor(colorOK); - appCheckUpdatesIcon.setImageResource(R.drawable.ic_check_circle); - appCheckUpdatesStatus.setText(getString(R.string.up_to_date, getString(R.string.app_name))); - appCheckUpdatesStatus.setTextColor(colorOK); - - } - } - - appCheckUpdatesProgress.setVisibility(View.GONE); - magiskCheckUpdatesProgress.setVisibility(View.GONE); - mSwipeRefreshLayout.setRefreshing(false); - - if (magiskVersion == -1) { - builder - .setTitle(R.string.no_magisk_title) - .setMessage(R.string.no_magisk_msg) - .setCancelable(true) - .setPositiveButton(R.string.download_install, flashMagisk) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java index 4598e5534..00ed18559 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java @@ -84,6 +84,7 @@ public class MagiskHideFragment extends Fragment { super.onResume(); setHasOptionsMenu(true); mView = this.getView(); + getActivity().setTitle(R.string.magiskhide); } private class LoadApps extends Async.RootTask { diff --git a/app/src/main/java/com/topjohnwu/magisk/MainActivity.java b/app/src/main/java/com/topjohnwu/magisk/MainActivity.java index 75b13b691..cde89a1bd 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MainActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/MainActivity.java @@ -37,10 +37,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.drawer_layout) DrawerLayout drawer; - @BindView(R.id.nav_view) NavigationView navigationView; + @BindView(R.id.nav_view) public NavigationView navigationView; @IdRes - private int mSelectedId = R.id.magisk; + private int mSelectedId = R.id.status; @Override protected void onCreate(final Bundle savedInstanceState) { @@ -59,10 +59,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); } - if (!Shell.rootAccess()) { - Snackbar.make(findViewById(android.R.id.content), R.string.no_root_access, Snackbar.LENGTH_LONG).show(); - } - setSupportActionBar(toolbar); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) { @@ -125,7 +121,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On private void checkHideSection() { Menu menu = navigationView.getMenu(); - if (MagiskFragment.magiskVersion == -1) { + if (StatusFragment.magiskVersion == -1) { menu.findItem(R.id.magiskhide).setVisible(false); menu.findItem(R.id.modules).setVisible(false); menu.findItem(R.id.downloads).setVisible(false); @@ -141,28 +137,27 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On Fragment navFragment = null; String tag = ""; switch (itemId) { - case R.id.magisk: - setTitle(R.string.magisk); - tag = "magisk"; - navFragment = new MagiskFragment(); + case R.id.status: + tag = "status"; + navFragment = new StatusFragment(); + break; + case R.id.install: + tag = "install"; + navFragment = new InstallFragment(); break; case R.id.modules: - setTitle(R.string.modules); tag = "modules"; navFragment = new ModulesFragment(); break; case R.id.downloads: - setTitle(R.string.downloads); tag = "downloads"; navFragment = new ReposFragment(); break; case R.id.magiskhide: - setTitle(R.string.magiskhide); tag = "magiskhide"; navFragment = new MagiskHideFragment(); break; case R.id.log: - setTitle(R.string.log); tag = "log"; navFragment = new LogFragment(); break; @@ -179,8 +174,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On transaction.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out); try { transaction.replace(R.id.content_frame, navFragment, tag).commit(); - } catch (IllegalStateException ignored) { - } + } catch (IllegalStateException ignored) {} } } } \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 8c00367f1..cd390892f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -92,6 +92,7 @@ public class ModulesFragment extends Fragment { super.onResume(); mView = this.getView(); prefs.registerOnSharedPreferenceChangeListener(listener); + getActivity().setTitle(R.string.modules); } @Override diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java index ec75056e4..cc1513f43 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java @@ -114,6 +114,7 @@ public class ReposFragment extends Fragment { super.onResume(); setHasOptionsMenu(true); prefs.registerOnSharedPreferenceChangeListener(listener); + getActivity().setTitle(R.string.downloads); } @Override diff --git a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java index 847693b75..b657e6937 100644 --- a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java @@ -89,10 +89,10 @@ public class SettingsActivity extends AppCompatActivity { themePreference.setSummary(themePreference.getValue()); - if (MagiskFragment.magiskVersion < 9) { + if (StatusFragment.magiskVersion < 9) { hostsPreference.setEnabled(false); busyboxPreference.setEnabled(false); - } else if (MagiskFragment.magiskVersion < 8) { + } else if (StatusFragment.magiskVersion < 8) { magiskhidePreference.setEnabled(false); } else { busyboxPreference.setEnabled(true); diff --git a/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java b/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java index bba73ff64..3367b1da5 100644 --- a/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java @@ -5,11 +5,9 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v7.app.AppCompatActivity; -import android.widget.Toast; import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Logger; -import com.topjohnwu.magisk.utils.SafetyNetHelper; import com.topjohnwu.magisk.utils.Utils; public class SplashActivity extends AppCompatActivity { @@ -38,24 +36,6 @@ public class SplashActivity extends AppCompatActivity { .putBoolean("hosts", Utils.itemExist(false, "/magisk/.core/hosts")) .apply(); - // Simple POC for checking SN status - new SafetyNetHelper(getApplicationContext()) { - @Override - public void handleResults(int i) { - switch (i) { - case -1: - Toast.makeText(mContext, "SN: Error", Toast.LENGTH_LONG).show(); - break; - case 0: - Toast.makeText(mContext, "SN: Fail", Toast.LENGTH_LONG).show(); - break; - case 1: - Toast.makeText(mContext, "SN: Success", Toast.LENGTH_LONG).show(); - break; - } - } - }.requestTest(); - new Async.CheckUpdates(prefs).exec(); new Async.LoadModules(prefs) { diff --git a/app/src/main/java/com/topjohnwu/magisk/StatusFragment.java b/app/src/main/java/com/topjohnwu/magisk/StatusFragment.java new file mode 100644 index 000000000..7f43ca8e6 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/StatusFragment.java @@ -0,0 +1,267 @@ +package com.topjohnwu.magisk; + +import android.app.Fragment; +import android.app.FragmentTransaction; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.annotation.Nullable; +import android.support.v4.content.FileProvider; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.app.AlertDialog; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.topjohnwu.magisk.receivers.DownloadReceiver; +import com.topjohnwu.magisk.utils.Async; +import com.topjohnwu.magisk.utils.Logger; +import com.topjohnwu.magisk.utils.SafetyNetHelper; +import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.ZipUtils; + +import java.io.File; +import java.util.List; + +import butterknife.BindColor; +import butterknife.BindView; +import butterknife.ButterKnife; + +public class StatusFragment extends Fragment { + + public static int remoteAppVersionCode = -1; + public static double magiskVersion, remoteMagiskVersion = -1; + public static String magiskVersionString, magiskLink, magiskChangelog, appLink, appChangelog, remoteAppVersion; + + private static int lastSNCheckResult = -1; + + @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; + + @BindView(R.id.magisk_status_container) View magiskStatusContainer; + @BindView(R.id.magisk_status_icon) ImageView magiskStatusIcon; + @BindView(R.id.magisk_version) TextView magiskVersionText; + @BindView(R.id.magisk_update_status) TextView magiskUpdateText; + @BindView(R.id.magisk_check_updates_progress) ProgressBar magiskCheckUpdatesProgress; + + @BindView(R.id.root_status_container) View rootStatusContainer; + @BindView(R.id.root_status_icon) ImageView rootStatusIcon; + @BindView(R.id.root_status) TextView rootStatusText; + @BindView(R.id.root_info) TextView rootInfoText; + + @BindView(R.id.safetyNet_container) View safetyNetContainer; + @BindView(R.id.safetyNet_icon) ImageView safetyNetIcon; + @BindView(R.id.safetyNet_status) TextView safetyNetStatusText; + @BindView(R.id.safetyNet_check_progress) ProgressBar safetyNetProgress; + + @BindColor(R.color.red500) int colorBad; + @BindColor(R.color.green500) int colorOK; + @BindColor(R.color.yellow500) int colorWarn; + @BindColor(R.color.grey500) int colorNeutral; + @BindColor(R.color.blue500) int colorInfo; + @BindColor(android.R.color.transparent) int trans; + + private AlertDialog.Builder builder; + + private SharedPreferences prefs; + private SharedPreferences.OnSharedPreferenceChangeListener listener; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.status_fragment, container, false); + ButterKnife.bind(this, v); + + prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); + + String theme = prefs.getString("theme", ""); + if (theme.equals("Dark")) { + builder = new AlertDialog.Builder(getActivity(), R.style.AlertDialog_dh); + } else { + builder = new AlertDialog.Builder(getActivity()); + } + + mSwipeRefreshLayout.setOnRefreshListener(() -> { + prefs.edit().putBoolean("update_check_done", false).apply(); + + magiskStatusContainer.setBackgroundColor(trans); + magiskStatusIcon.setImageResource(0); + magiskUpdateText.setText(R.string.checking_for_updates); + magiskCheckUpdatesProgress.setVisibility(View.VISIBLE); + + new Async.CheckUpdates(prefs).exec(); + checkSafetyNet(); + }); + + listener = (pref, s) -> { + if (s.equals("update_check_done")) { + if (pref.getBoolean(s, false)) { + Logger.dev("StatusFragment: UI refresh triggered"); + updateUI(); + updateCheckUI(); + } + } + }; + + updateUI(); + if (prefs.getBoolean("update_check_done", false)) { + updateCheckUI(); + } + if (lastSNCheckResult == -1) { + checkSafetyNet(); + } else { + updateSafetyNetUI(); + } + + if (magiskVersion < 0) { + builder + .setTitle(R.string.no_magisk_title) + .setMessage(R.string.no_magisk_msg) + .setCancelable(true) + .setPositiveButton(R.string.download_install, (dialogInterface, i) -> { + ((MainActivity) getActivity()).navigationView.setCheckedItem(R.id.install); + FragmentTransaction transaction = getFragmentManager().beginTransaction(); + transaction.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out); + try { + transaction.replace(R.id.content_frame, new InstallFragment(), "install").commit(); + } catch (IllegalStateException ignored) {} + }) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } + + return v; + } + + @Override + public void onResume() { + super.onResume(); + prefs.registerOnSharedPreferenceChangeListener(listener); + getActivity().setTitle(R.string.status); + } + + @Override + public void onDestroy() { + super.onDestroy(); + prefs.unregisterOnSharedPreferenceChangeListener(listener); + } + + private void updateUI() { + int image, color; + + List ret = Shell.sh("getprop magisk.version"); + if (ret.get(0).length() == 0) { + magiskVersion = -1; + magiskVersionText.setText(R.string.magisk_version_error); + } else { + try { + magiskVersionString = ret.get(0); + magiskVersion = Double.parseDouble(ret.get(0)); + } catch (NumberFormatException e) { + // Custom version don't need to receive updates + magiskVersion = Double.POSITIVE_INFINITY; + } + magiskVersionText.setText(getString(R.string.magisk_version, magiskVersionString)); + } + + if (Shell.rootStatus == 1) { + color = colorOK; + image = R.drawable.ic_check_circle; + rootStatusText.setText(R.string.proper_root); + rootInfoText.setText(Shell.sh("su -v").get(0)); + + } else { + rootInfoText.setText(R.string.root_info_warning); + if (Shell.rootStatus == 0) { + color = colorBad; + image = R.drawable.ic_cancel; + rootStatusText.setText(R.string.not_rooted); + } else { + color = colorNeutral; + image = R.drawable.ic_help; + rootStatusText.setText(R.string.root_error); + } + } + rootStatusContainer.setBackgroundColor(color); + rootStatusText.setTextColor(color); + rootInfoText.setTextColor(color); + rootStatusIcon.setImageResource(image); + } + + private void updateCheckUI() { + int image, color; + + if (remoteMagiskVersion < 0) { + color = colorNeutral; + image = R.drawable.ic_help; + magiskUpdateText.setText(R.string.cannot_check_updates); + } else if (remoteMagiskVersion > magiskVersion) { + color = colorInfo; + image = R.drawable.ic_update; + magiskUpdateText.setText(getString(R.string.magisk_update_available, String.valueOf(remoteMagiskVersion))); + } else { + color = colorOK; + image = R.drawable.ic_check_circle; + magiskUpdateText.setText(getString(R.string.up_to_date, getString(R.string.magisk))); + } + + if (magiskVersion < 0) { + color = colorBad; + image = R.drawable.ic_cancel; + } + magiskStatusContainer.setBackgroundColor(color); + magiskVersionText.setTextColor(color); + magiskUpdateText.setTextColor(color); + magiskStatusIcon.setImageResource(image); + + magiskCheckUpdatesProgress.setVisibility(View.GONE); + mSwipeRefreshLayout.setRefreshing(false); + } + + private void updateSafetyNetUI() { + int image, color; + safetyNetProgress.setVisibility(View.GONE); + switch (lastSNCheckResult) { + case -1: + color = colorNeutral; + image = R.drawable.ic_help; + safetyNetStatusText.setText(R.string.safetyNet_error); + break; + case 0: + color = colorBad; + image = R.drawable.ic_cancel; + safetyNetStatusText.setText(R.string.safetyNet_fail); + break; + case 1: + default: + color = colorOK; + image = R.drawable.ic_check_circle; + safetyNetStatusText.setText(R.string.safetyNet_pass); + break; + } + safetyNetContainer.setBackgroundColor(color); + safetyNetStatusText.setTextColor(color); + safetyNetIcon.setImageResource(image); + } + + private void checkSafetyNet() { + safetyNetProgress.setVisibility(View.VISIBLE); + safetyNetContainer.setBackgroundColor(trans); + safetyNetIcon.setImageResource(0); + safetyNetStatusText.setText(R.string.checking_safetyNet_status); + new SafetyNetHelper(getActivity()) { + @Override + public void handleResults(int i) { + lastSNCheckResult = i; + updateSafetyNetUI(); + } + }.requestTest(); + } +} + diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Async.java b/app/src/main/java/com/topjohnwu/magisk/utils/Async.java index 4a1093c27..63593f5e1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Async.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Async.java @@ -12,8 +12,8 @@ import android.support.v7.app.AlertDialog; import android.util.Log; import android.widget.Toast; -import com.topjohnwu.magisk.MagiskFragment; import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.StatusFragment; import org.json.JSONException; import org.json.JSONObject; @@ -63,14 +63,14 @@ public class Async { JSONObject magisk = json.getJSONObject("magisk"); JSONObject app = json.getJSONObject("app"); - MagiskFragment.remoteMagiskVersion = magisk.getDouble("versionCode"); - MagiskFragment.magiskLink = magisk.getString("link"); - MagiskFragment.magiskChangelog = magisk.getString("changelog"); + StatusFragment.remoteMagiskVersion = magisk.getDouble("versionCode"); + StatusFragment.magiskLink = magisk.getString("link"); + StatusFragment.magiskChangelog = magisk.getString("changelog"); - MagiskFragment.remoteAppVersion = app.getString("version"); - MagiskFragment.remoteAppVersionCode = app.getInt("versionCode"); - MagiskFragment.appLink = app.getString("link"); - MagiskFragment.appChangelog = app.getString("changelog"); + StatusFragment.remoteAppVersion = app.getString("version"); + StatusFragment.remoteAppVersionCode = app.getInt("versionCode"); + StatusFragment.appLink = app.getString("link"); + StatusFragment.appChangelog = app.getString("changelog"); } catch (JSONException ignored) { Logger.dev("JSON error!"); diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/SafetyNetHelper.java b/app/src/main/java/com/topjohnwu/magisk/utils/SafetyNetHelper.java index abd547a57..f2213750b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/SafetyNetHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/SafetyNetHelper.java @@ -15,7 +15,6 @@ import org.json.JSONException; import org.json.JSONObject; import java.security.SecureRandom; -import java.util.Arrays; public abstract class SafetyNetHelper implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks { diff --git a/app/src/main/res/drawable/ic_cancel.xml b/app/src/main/res/drawable/ic_cancel.xml new file mode 100644 index 000000000..e6545bf8a --- /dev/null +++ b/app/src/main/res/drawable/ic_cancel.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_device_information.xml b/app/src/main/res/drawable/ic_device_information.xml new file mode 100644 index 000000000..2c4e5c7f4 --- /dev/null +++ b/app/src/main/res/drawable/ic_device_information.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_file_download.xml b/app/src/main/res/drawable/ic_file_download.xml deleted file mode 100644 index 0db3296cd..000000000 --- a/app/src/main/res/drawable/ic_file_download.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_update.xml b/app/src/main/res/drawable/ic_update.xml new file mode 100644 index 000000000..b2a2c14f0 --- /dev/null +++ b/app/src/main/res/drawable/ic_update.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_warning.xml b/app/src/main/res/drawable/ic_warning.xml deleted file mode 100644 index 6af62ea04..000000000 --- a/app/src/main/res/drawable/ic_warning.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/install_fragment.xml b/app/src/main/res/layout/install_fragment.xml new file mode 100644 index 000000000..f9504c9a4 --- /dev/null +++ b/app/src/main/res/layout/install_fragment.xml @@ -0,0 +1,6 @@ + + + + diff --git a/app/src/main/res/layout/magisk_fragment.xml b/app/src/main/res/layout/status_fragment.xml similarity index 81% rename from app/src/main/res/layout/magisk_fragment.xml rename to app/src/main/res/layout/status_fragment.xml index b549ff4c1..2d0663d59 100644 --- a/app/src/main/res/layout/magisk_fragment.xml +++ b/app/src/main/res/layout/status_fragment.xml @@ -37,6 +37,15 @@ android:layout_height="wrap_content" android:orientation="vertical"> + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -157,13 +175,14 @@ + android:textStyle="bold" + android:text="@string/checking_safetyNet_status" /> diff --git a/app/src/main/res/menu/drawer.xml b/app/src/main/res/menu/drawer.xml index f0cab2d82..2cb13d2c3 100644 --- a/app/src/main/res/menu/drawer.xml +++ b/app/src/main/res/menu/drawer.xml @@ -6,9 +6,14 @@ android:id="@+id/main_group"> + + + android:title="@string/install"/> Downloads Log Settings + Status + Install - + Installed Magisk v%1$s - Have you installed Magisk? + Magisk not installed - Magisk Manager App v%1$s update! - Magisk v%1$s update! - Cannot check for updates + Checking for updates… + Magisk v%1$s available! + Cannot check for updates, no Internet? Latest version of %1$s installed + Rooted but no root permission, not allowed? + Not rooted + Properly rooted + Checking SafetyNet status… + Cannot check SafetyNet, no Internet? + SafetyNet Failed: CTS profile mismatch + SafetyNet Passed + Functionality greatly limited @@ -54,7 +64,7 @@ Main developers topjohnwu in collaboration with Digitalhigh and Dvdandroid.]]> App\'s changelog - + App\'s version Source code Donation @@ -65,11 +75,9 @@ This feature will not work without permission to write external storage. No root access, functionality limited No thanks - %1$s Update! - New version v%2$s of %1$s is available!\nChangelog:\n%3$s Install %1$s Do you want to install %1$s ? - Download and install + Go to \"Install\" section Error downloading file Installation error! Zip file placed in %1$s