Add status fragment

This commit is contained in:
topjohnwu 2016-12-25 03:05:22 +08:00
parent 442e840a53
commit 57af984e68
21 changed files with 492 additions and 430 deletions

View File

@ -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");
}

View File

@ -67,6 +67,7 @@ public class LogFragment extends Fragment {
super.onResume(); super.onResume();
setHasOptionsMenu(true); setHasOptionsMenu(true);
new LogManager().read(); new LogManager().read();
getActivity().setTitle(R.string.log);
} }
@Override @Override

View File

@ -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<String> 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();
}
}
}

View File

@ -84,6 +84,7 @@ public class MagiskHideFragment extends Fragment {
super.onResume(); super.onResume();
setHasOptionsMenu(true); setHasOptionsMenu(true);
mView = this.getView(); mView = this.getView();
getActivity().setTitle(R.string.magiskhide);
} }
private class LoadApps extends Async.RootTask<Void, Void, Void> { private class LoadApps extends Async.RootTask<Void, Void, Void> {

View File

@ -37,10 +37,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
@BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.drawer_layout) DrawerLayout drawer; @BindView(R.id.drawer_layout) DrawerLayout drawer;
@BindView(R.id.nav_view) NavigationView navigationView; @BindView(R.id.nav_view) public NavigationView navigationView;
@IdRes @IdRes
private int mSelectedId = R.id.magisk; private int mSelectedId = R.id.status;
@Override @Override
protected void onCreate(final Bundle savedInstanceState) { 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); 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); setSupportActionBar(toolbar);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) { 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() { private void checkHideSection() {
Menu menu = navigationView.getMenu(); Menu menu = navigationView.getMenu();
if (MagiskFragment.magiskVersion == -1) { if (StatusFragment.magiskVersion == -1) {
menu.findItem(R.id.magiskhide).setVisible(false); menu.findItem(R.id.magiskhide).setVisible(false);
menu.findItem(R.id.modules).setVisible(false); menu.findItem(R.id.modules).setVisible(false);
menu.findItem(R.id.downloads).setVisible(false); menu.findItem(R.id.downloads).setVisible(false);
@ -141,28 +137,27 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
Fragment navFragment = null; Fragment navFragment = null;
String tag = ""; String tag = "";
switch (itemId) { switch (itemId) {
case R.id.magisk: case R.id.status:
setTitle(R.string.magisk); tag = "status";
tag = "magisk"; navFragment = new StatusFragment();
navFragment = new MagiskFragment(); break;
case R.id.install:
tag = "install";
navFragment = new InstallFragment();
break; break;
case R.id.modules: case R.id.modules:
setTitle(R.string.modules);
tag = "modules"; tag = "modules";
navFragment = new ModulesFragment(); navFragment = new ModulesFragment();
break; break;
case R.id.downloads: case R.id.downloads:
setTitle(R.string.downloads);
tag = "downloads"; tag = "downloads";
navFragment = new ReposFragment(); navFragment = new ReposFragment();
break; break;
case R.id.magiskhide: case R.id.magiskhide:
setTitle(R.string.magiskhide);
tag = "magiskhide"; tag = "magiskhide";
navFragment = new MagiskHideFragment(); navFragment = new MagiskHideFragment();
break; break;
case R.id.log: case R.id.log:
setTitle(R.string.log);
tag = "log"; tag = "log";
navFragment = new LogFragment(); navFragment = new LogFragment();
break; 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); transaction.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
try { try {
transaction.replace(R.id.content_frame, navFragment, tag).commit(); transaction.replace(R.id.content_frame, navFragment, tag).commit();
} catch (IllegalStateException ignored) { } catch (IllegalStateException ignored) {}
}
} }
} }
} }

View File

@ -92,6 +92,7 @@ public class ModulesFragment extends Fragment {
super.onResume(); super.onResume();
mView = this.getView(); mView = this.getView();
prefs.registerOnSharedPreferenceChangeListener(listener); prefs.registerOnSharedPreferenceChangeListener(listener);
getActivity().setTitle(R.string.modules);
} }
@Override @Override

View File

@ -114,6 +114,7 @@ public class ReposFragment extends Fragment {
super.onResume(); super.onResume();
setHasOptionsMenu(true); setHasOptionsMenu(true);
prefs.registerOnSharedPreferenceChangeListener(listener); prefs.registerOnSharedPreferenceChangeListener(listener);
getActivity().setTitle(R.string.downloads);
} }
@Override @Override

View File

@ -89,10 +89,10 @@ public class SettingsActivity extends AppCompatActivity {
themePreference.setSummary(themePreference.getValue()); themePreference.setSummary(themePreference.getValue());
if (MagiskFragment.magiskVersion < 9) { if (StatusFragment.magiskVersion < 9) {
hostsPreference.setEnabled(false); hostsPreference.setEnabled(false);
busyboxPreference.setEnabled(false); busyboxPreference.setEnabled(false);
} else if (MagiskFragment.magiskVersion < 8) { } else if (StatusFragment.magiskVersion < 8) {
magiskhidePreference.setEnabled(false); magiskhidePreference.setEnabled(false);
} else { } else {
busyboxPreference.setEnabled(true); busyboxPreference.setEnabled(true);

View File

@ -5,11 +5,9 @@ import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.Logger; import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.SafetyNetHelper;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
public class SplashActivity extends AppCompatActivity { public class SplashActivity extends AppCompatActivity {
@ -38,24 +36,6 @@ public class SplashActivity extends AppCompatActivity {
.putBoolean("hosts", Utils.itemExist(false, "/magisk/.core/hosts")) .putBoolean("hosts", Utils.itemExist(false, "/magisk/.core/hosts"))
.apply(); .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.CheckUpdates(prefs).exec();
new Async.LoadModules(prefs) { new Async.LoadModules(prefs) {

View File

@ -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<String> 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();
}
}

View File

@ -12,8 +12,8 @@ import android.support.v7.app.AlertDialog;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import com.topjohnwu.magisk.MagiskFragment;
import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.StatusFragment;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -63,14 +63,14 @@ public class Async {
JSONObject magisk = json.getJSONObject("magisk"); JSONObject magisk = json.getJSONObject("magisk");
JSONObject app = json.getJSONObject("app"); JSONObject app = json.getJSONObject("app");
MagiskFragment.remoteMagiskVersion = magisk.getDouble("versionCode"); StatusFragment.remoteMagiskVersion = magisk.getDouble("versionCode");
MagiskFragment.magiskLink = magisk.getString("link"); StatusFragment.magiskLink = magisk.getString("link");
MagiskFragment.magiskChangelog = magisk.getString("changelog"); StatusFragment.magiskChangelog = magisk.getString("changelog");
MagiskFragment.remoteAppVersion = app.getString("version"); StatusFragment.remoteAppVersion = app.getString("version");
MagiskFragment.remoteAppVersionCode = app.getInt("versionCode"); StatusFragment.remoteAppVersionCode = app.getInt("versionCode");
MagiskFragment.appLink = app.getString("link"); StatusFragment.appLink = app.getString("link");
MagiskFragment.appChangelog = app.getString("changelog"); StatusFragment.appChangelog = app.getString("changelog");
} catch (JSONException ignored) { } catch (JSONException ignored) {
Logger.dev("JSON error!"); Logger.dev("JSON error!");

View File

@ -15,7 +15,6 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Arrays;
public abstract class SafetyNetHelper public abstract class SafetyNetHelper
implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks { implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#fff"
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M13,7h-2v2h2L13,7zM13,11h-2v6h2v-6zM17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#fff"
android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#fff"
android:pathData="M21,10.12h-6.78l2.74,-2.82c-2.73,-2.7 -7.15,-2.8 -9.88,-0.1 -2.73,2.71 -2.73,7.08 0,9.79 2.73,2.71 7.15,2.71 9.88,0C18.32,15.65 19,14.08 19,12.1h2c0,1.98 -0.88,4.55 -2.64,6.29 -3.51,3.48 -9.21,3.48 -12.72,0 -3.5,-3.47 -3.53,-9.11 -0.02,-12.58 3.51,-3.47 9.14,-3.47 12.65,0L21,3v7.12zM12.5,8v4.25l3.5,2.08 -0.72,1.21L11,13V8h1.5z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#fff"
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
</vector>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>

View File

@ -37,6 +37,15 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<TextView
android:id="@+id/magisk_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="6dp"
android:textStyle="bold"/>
<FrameLayout <FrameLayout
android:id="@+id/magisk_status_container" android:id="@+id/magisk_status_container"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -51,52 +60,6 @@
android:layout_height="84dp" android:layout_height="84dp"
android:layout_gravity="center"/> android:layout_gravity="center"/>
</FrameLayout>
<TextView
android:id="@+id/magisk_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="6dp"
android:textStyle="bold"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/magisk_updateView"
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"
style="?attr/cardStyle"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:id="@+id/magisk_check_updates_container"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="?android:attr/selectableItemBackground"
android:foregroundGravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/magisk_check_updates_icon"
android:layout_width="84dp"
android:layout_height="84dp"
android:layout_gravity="center"
android:src="@drawable/ic_check_circle"/>
<ProgressBar <ProgressBar
android:id="@+id/magisk_check_updates_progress" android:id="@+id/magisk_check_updates_progress"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -106,7 +69,62 @@
</FrameLayout> </FrameLayout>
<TextView <TextView
android:id="@+id/magisk_check_updates_status" android:id="@+id/magisk_update_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="6dp"
android:textStyle="bold"
android:text="@string/checking_for_updates" />
</LinearLayout>
</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"
style="?attr/cardStyle"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/root_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="6dp"
android:textStyle="bold"/>
<FrameLayout
android:id="@+id/root_status_container"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="?android:attr/selectableItemBackground"
android:foregroundGravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/root_status_icon"
android:layout_width="84dp"
android:layout_height="84dp"
android:layout_gravity="center" />
</FrameLayout>
<TextView
android:id="@+id/root_info"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
@ -119,7 +137,7 @@
</android.support.v7.widget.CardView> </android.support.v7.widget.CardView>
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
android:id="@+id/app_updateView" android:id="@+id/safetyNetView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp"
@ -135,21 +153,21 @@
android:orientation="vertical"> android:orientation="vertical">
<FrameLayout <FrameLayout
android:id="@+id/app_check_updates_container" android:id="@+id/safetyNet_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="100dp" android:layout_height="100dp"
android:foregroundGravity="center" android:foregroundGravity="center"
android:orientation="vertical"> android:orientation="vertical">
<ImageView <ImageView
android:id="@+id/app_check_updates_icon" android:id="@+id/safetyNet_icon"
android:layout_width="84dp" android:layout_width="84dp"
android:layout_height="84dp" android:layout_height="84dp"
android:layout_gravity="center" android:layout_gravity="center"
android:src="@drawable/ic_check_circle"/> android:src="@drawable/ic_check_circle"/>
<ProgressBar <ProgressBar
android:id="@+id/app_check_updates_progress" android:id="@+id/safetyNet_check_progress"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center"/> android:layout_gravity="center"/>
@ -157,13 +175,14 @@
</FrameLayout> </FrameLayout>
<TextView <TextView
android:id="@+id/app_check_updates_status" android:id="@+id/safetyNet_status"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:gravity="center" android:gravity="center"
android:padding="6dp" android:padding="6dp"
android:textStyle="bold"/> android:textStyle="bold"
android:text="@string/checking_safetyNet_status" />
</LinearLayout> </LinearLayout>

View File

@ -6,9 +6,14 @@
android:id="@+id/main_group"> android:id="@+id/main_group">
<item <item
android:id="@+id/magisk" android:id="@+id/status"
android:icon="@drawable/ic_device_information"
android:title="@string/status"/>
<item
android:id="@+id/install"
android:icon="@drawable/magisk" android:icon="@drawable/magisk"
android:title="@string/magisk"/> android:title="@string/install"/>
<item <item
android:id="@+id/modules" android:id="@+id/modules"

View File

@ -11,15 +11,25 @@
<string name="downloads">Downloads</string> <string name="downloads">Downloads</string>
<string name="log">Log</string> <string name="log">Log</string>
<string name="settings">Settings</string> <string name="settings">Settings</string>
<string name="status">Status</string>
<string name="install">Install</string>
<!--Magisk Fragment--> <!--Status Fragment-->
<string name="magisk_version">Installed Magisk v%1$s</string> <string name="magisk_version">Installed Magisk v%1$s</string>
<string name="magisk_version_error">Have you installed Magisk?</string> <string name="magisk_version_error">Magisk not installed</string>
<string name="app_update_available">Magisk Manager App v%1$s update!</string> <string name="checking_for_updates">Checking for updates…</string>
<string name="magisk_update_available">Magisk v%1$s update!</string> <string name="magisk_update_available">Magisk v%1$s available!</string>
<string name="cannot_check_updates">Cannot check for updates</string> <string name="cannot_check_updates">Cannot check for updates, no Internet?</string>
<string name="up_to_date">Latest version of %1$s installed</string> <string name="up_to_date">Latest version of %1$s installed</string>
<string name="root_error">Rooted but no root permission, not allowed?</string>
<string name="not_rooted">Not rooted</string>
<string name="proper_root">Properly rooted</string>
<string name="checking_safetyNet_status">Checking SafetyNet status…</string>
<string name="safetyNet_error">Cannot check SafetyNet, no Internet?</string>
<string name="safetyNet_fail">SafetyNet Failed: CTS profile mismatch</string>
<string name="safetyNet_pass">SafetyNet Passed</string>
<string name="root_info_warning">Functionality greatly limited</string>
<!--Root Fragment--> <!--Root Fragment-->
@ -65,11 +75,9 @@
<string name="permissionNotGranted">This feature will not work without permission to write external storage.</string> <string name="permissionNotGranted">This feature will not work without permission to write external storage.</string>
<string name="no_root_access">No root access, functionality limited</string> <string name="no_root_access">No root access, functionality limited</string>
<string name="no_thanks">No thanks</string> <string name="no_thanks">No thanks</string>
<string name="update_title">%1$s Update!</string>
<string name="update_msg">New version v%2$s of %1$s is available!\nChangelog:\n%3$s</string>
<string name="repo_install_title">Install %1$s</string> <string name="repo_install_title">Install %1$s</string>
<string name="repo_install_msg">Do you want to install %1$s ?</string> <string name="repo_install_msg">Do you want to install %1$s ?</string>
<string name="download_install">Download and install</string> <string name="download_install">Go to \"Install\" section</string>
<string name="download_file_error">Error downloading file</string> <string name="download_file_error">Error downloading file</string>
<string name="install_error">Installation error!</string> <string name="install_error">Installation error!</string>
<string name="manual_install_1">Zip file placed in %1$s</string> <string name="manual_install_1">Zip file placed in %1$s</string>