Compare commits

...

8 Commits

Author SHA1 Message Date
topjohnwu
d1b5ebad7d Several fixes 2017-02-07 07:32:40 +08:00
Exalm
f4ce813de9 Better icon 2017-02-07 06:17:54 +08:00
drbeat
b44ac994d8 fix typos and translate new strings 2017-02-07 06:16:53 +08:00
Exalm
333948814c Russian translation 2017-02-07 06:16:14 +08:00
linar10
1a51ad6e01 Update strings - pl 2017-02-07 06:15:52 +08:00
topjohnwu
22a5c11f0d Fix MagiskHide startup issue 2017-02-07 06:02:06 +08:00
topjohnwu
51b22d1ad4 Make callback events non-static 2017-02-07 04:09:49 +08:00
topjohnwu
bef5969580 No more static crap :) 2017-02-07 02:01:32 +08:00
42 changed files with 775 additions and 504 deletions

View File

@@ -8,8 +8,8 @@ android {
applicationId "com.topjohnwu.magisk"
minSdkVersion 21
targetSdkVersion 25
versionCode 20
versionName "4.0"
versionCode 22
versionName "4.1"
jackOptions {
enabled true
jackInProcess true

View File

@@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:name=".MagiskManager"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
@@ -59,6 +60,8 @@
</intent-filter>
</receiver>
<service android:name=".receivers.BootReceiver$BootupIntentService" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.topjohnwu.magisk.provider"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 73 KiB

View File

@@ -1,13 +1,12 @@
package com.topjohnwu.magisk;
import android.app.AlertDialog;
import android.support.v7.app.AlertDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.text.Spanned;
@@ -17,6 +16,7 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Utils;
@@ -26,7 +26,7 @@ import java.io.InputStream;
import butterknife.BindView;
import butterknife.ButterKnife;
public class AboutActivity extends AppCompatActivity {
public class AboutActivity extends Activity {
private static final String DONATION_URL = "http://topjohnwu.github.io/donate";
private static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382";
@@ -46,7 +46,7 @@ public class AboutActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
String theme = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("theme", "");
Logger.dev("AboutActivity: Theme is " + theme);
if (Global.Configs.isDarkTheme) {
if (getTopApplication().isDarkTheme) {
setTheme(R.style.AppTheme_dh);
}
setContentView(R.layout.activity_about);

View File

@@ -1,133 +0,0 @@
package com.topjohnwu.magisk;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.preference.PreferenceManager;
import android.util.SparseArray;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.utils.CallbackHandler;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ValueSortedMap;
import java.io.File;
import java.util.List;
public class Global {
public static final String MAGISK_DISABLE_FILE = "/cache/.disable_magisk";
public static class Info {
public static double magiskVersion;
public static String magiskVersionString = "(none)";
public static double remoteMagiskVersion = -1;
public static String magiskLink;
public static String releaseNoteLink;
public static int SNCheckResult = -1;
public static String bootBlock = null;
public static boolean isSuClient = false;
public static String suVersion = null;
public static boolean disabled = false;
}
public static class Data {
public static ValueSortedMap<String, Repo> repoMap;
public static ValueSortedMap<String, Module> moduleMap;
public static List<String> blockList;
public static List<ApplicationInfo> appList;
public static List<String> magiskHideList;
}
public static class Events {
public static final CallbackHandler.Event blockDetectionDone = new CallbackHandler.Event();
public static final CallbackHandler.Event packageLoadDone = new CallbackHandler.Event();
public static final CallbackHandler.Event reloadMainActivity = new CallbackHandler.Event();
public static final CallbackHandler.Event moduleLoadDone = new CallbackHandler.Event();
public static final CallbackHandler.Event repoLoadDone = new CallbackHandler.Event();
public static final CallbackHandler.Event updateCheckDone = new CallbackHandler.Event();
public static final CallbackHandler.Event safetyNetDone = new CallbackHandler.Event();
public static SparseArray<CallbackHandler.Event> uidMap = new SparseArray<>();
}
public static class Configs {
public static boolean isDarkTheme;
public static boolean shellLogging;
public static boolean devLogging;
public static boolean magiskHide;
public static int suRequestTimeout;
public static int suLogTimeout = 14;
public static int suAccessState;
public static int suResponseType;
public static int suNotificationType;
}
public static void init(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Configs.isDarkTheme = prefs.getBoolean("dark_theme", false);
Configs.devLogging = prefs.getBoolean("developer_logging", false);
Configs.shellLogging = prefs.getBoolean("shell_logging", false);
Configs.magiskHide = prefs.getBoolean("magiskhide", false);
updateMagiskInfo();
initSuAccess();
initSuConfigs(context);
// Initialize prefs
prefs.edit()
.putBoolean("dark_theme", Configs.isDarkTheme)
.putBoolean("magiskhide", Configs.magiskHide)
.putBoolean("busybox", Utils.commandExists("busybox"))
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
.putString("su_request_timeout", String.valueOf(Configs.suRequestTimeout))
.putString("su_auto_response", String.valueOf(Configs.suResponseType))
.putString("su_notification", String.valueOf(Configs.suNotificationType))
.putString("su_access", String.valueOf(Configs.suAccessState))
.apply();
}
public static void initSuConfigs(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Configs.suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
Configs.suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
Configs.suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
}
public static void initSuAccess() {
List<String> ret = Shell.sh("su -v");
if (Utils.isValidShellResponse(ret)) {
Info.suVersion = ret.get(0);
Info.isSuClient = Info.suVersion.toUpperCase().contains("MAGISK");
}
if (Info.isSuClient) {
ret = Shell.sh("getprop persist.sys.root_access");
if (Utils.isValidShellResponse(ret))
Configs.suAccessState = Integer.parseInt(ret.get(0));
else {
Shell.su(true, "setprop persist.sys.root_access 3");
Configs.suAccessState = 3;
}
}
}
public static void updateMagiskInfo() {
List<String> ret = Shell.sh("getprop magisk.version");
if (!Utils.isValidShellResponse(ret)) {
Info.magiskVersion = -1;
} else {
try {
Info.magiskVersionString = ret.get(0);
Info.magiskVersion = Double.parseDouble(ret.get(0));
} catch (NumberFormatException e) {
// Custom version don't need to receive updates
Info.magiskVersion = Double.POSITIVE_INFINITY;
}
}
ret = Shell.sh("getprop ro.magisk.disable");
try {
Info.disabled = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
} catch (NumberFormatException e) {
Info.disabled = false;
}
}
}

View File

@@ -6,7 +6,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.CardView;
import android.view.LayoutInflater;
import android.view.View;
@@ -17,8 +16,9 @@ import android.widget.CheckBox;
import android.widget.Spinner;
import android.widget.TextView;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.receivers.MagiskDlReceiver;
import com.topjohnwu.magisk.utils.CallbackHandler;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
@@ -33,7 +33,7 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class InstallFragment extends Fragment implements CallbackHandler.EventListener {
public class InstallFragment extends Fragment implements CallbackEvent.Listener<Void> {
private static final String UNINSTALLER = "magisk_uninstaller.sh";
@@ -54,19 +54,19 @@ public class InstallFragment extends Fragment implements CallbackHandler.EventLi
View v = inflater.inflate(R.layout.fragment_install, container, false);
unbinder = ButterKnife.bind(this, v);
detectButton.setOnClickListener(v1 -> toAutoDetect());
currentVersionTitle.setText(getString(R.string.current_magisk_title, Global.Info.magiskVersionString));
installTitle.setText(getString(R.string.install_magisk_title, Global.Info.remoteMagiskVersion));
currentVersionTitle.setText(getString(R.string.current_magisk_title, getApplication().magiskVersionString));
installTitle.setText(getString(R.string.install_magisk_title, getApplication().remoteMagiskVersion));
flashButton.setOnClickListener(v1 -> {
String bootImage;
if (Global.Info.bootBlock != null) {
if (getApplication().bootBlock != null) {
if (spinner.getSelectedItemPosition() > 0)
bootImage = Global.Data.blockList.get(spinner.getSelectedItemPosition() - 1);
bootImage = getApplication().blockList.get(spinner.getSelectedItemPosition() - 1);
else
bootImage = Global.Info.bootBlock;
bootImage = getApplication().bootBlock;
} else {
bootImage = Global.Data.blockList.get(spinner.getSelectedItemPosition());
bootImage = getApplication().blockList.get(spinner.getSelectedItemPosition());
}
String filename = "Magisk-v" + Global.Info.remoteMagiskVersion + ".zip";
String filename = "Magisk-v" + getApplication().remoteMagiskVersion + ".zip";
Utils.getAlertDialogBuilder(getActivity())
.setTitle(getString(R.string.repo_install_title, getString(R.string.magisk)))
.setMessage(getString(R.string.repo_install_msg, filename))
@@ -74,15 +74,15 @@ public class InstallFragment extends Fragment implements CallbackHandler.EventLi
.setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.dlAndReceive(
getActivity(),
new MagiskDlReceiver(bootImage, keepEncChkbox.isChecked(), keepVerityChkbox.isChecked()),
Global.Info.magiskLink,
getApplication().magiskLink,
Utils.getLegalFilename(filename)))
.setNeutralButton(R.string.check_release_notes, (dialog, which) -> {
getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Global.Info.releaseNoteLink)));
getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getApplication().releaseNoteLink)));
})
.setNegativeButton(R.string.no_thanks, null)
.show();
});
if (Global.Info.magiskVersion < 10.3) {
if (getApplication().magiskVersion < 10.3) {
uninstallButton.setVisibility(View.GONE);
} else {
uninstallButton.setOnClickListener(vi -> {
@@ -125,21 +125,21 @@ public class InstallFragment extends Fragment implements CallbackHandler.EventLi
});
}
if (Global.Events.blockDetectionDone.isTriggered) {
if (getApplication().blockDetectionDone.isTriggered) {
updateUI();
}
return v;
}
@Override
public void onTrigger(CallbackHandler.Event event) {
public void onTrigger(CallbackEvent<Void> event) {
updateUI();
}
private void updateUI() {
List<String> items = new ArrayList<>(Global.Data.blockList);
if (Global.Info.bootBlock != null)
items.add(0, getString(R.string.auto_detect, Global.Info.bootBlock));
List<String> items = new ArrayList<>(getApplication().blockList);
if (getApplication().bootBlock != null)
items.add(0, getString(R.string.auto_detect, getApplication().bootBlock));
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
@@ -148,7 +148,7 @@ public class InstallFragment extends Fragment implements CallbackHandler.EventLi
}
private void toAutoDetect() {
if (Global.Info.bootBlock != null) {
if (getApplication().bootBlock != null) {
spinner.setSelection(0);
}
}
@@ -157,12 +157,12 @@ public class InstallFragment extends Fragment implements CallbackHandler.EventLi
public void onStart() {
super.onStart();
getActivity().setTitle(R.string.install);
CallbackHandler.register(Global.Events.blockDetectionDone, this);
getApplication().blockDetectionDone.register(this);
}
@Override
public void onStop() {
CallbackHandler.unRegister(Global.Events.blockDetectionDone, this);
getApplication().blockDetectionDone.unRegister(this);
super.onStop();
}

View File

@@ -3,13 +3,13 @@ package com.topjohnwu.magisk;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.topjohnwu.magisk.adapters.TabFragmentAdapter;
import com.topjohnwu.magisk.components.Fragment;
import butterknife.BindView;
import butterknife.ButterKnife;
@@ -33,7 +33,7 @@ public class LogFragment extends Fragment {
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
if (Global.Info.isSuClient) {
if (getApplication().isSuClient) {
adapter.addTab(new SuLogFragment(), getString(R.string.superuser));
tab.setupWithViewPager(viewPager);
tab.setVisibility(View.VISIBLE);

View File

@@ -3,7 +3,6 @@ package com.topjohnwu.magisk;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
@@ -16,15 +15,16 @@ import android.view.ViewGroup;
import android.widget.SearchView;
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.CallbackHandler;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.Logger;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class MagiskHideFragment extends Fragment implements CallbackHandler.EventListener {
public class MagiskHideFragment extends Fragment implements CallbackEvent.Listener<Void> {
private Unbinder unbinder;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
@@ -50,7 +50,7 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
PackageManager packageManager = getActivity().getPackageManager();
mSwipeRefreshLayout.setRefreshing(true);
mSwipeRefreshLayout.setOnRefreshListener(() -> new Async.LoadApps(packageManager).exec());
mSwipeRefreshLayout.setOnRefreshListener(() -> new Async.LoadApps(getApplication()).exec());
appAdapter = new ApplicationAdapter(packageManager);
recyclerView.setAdapter(appAdapter);
@@ -71,6 +71,9 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
}
};
if (getApplication().packageLoadDone.isTriggered)
onTrigger(getApplication().packageLoadDone);
return view;
}
@@ -85,15 +88,12 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
public void onStart() {
super.onStart();
getActivity().setTitle(R.string.magiskhide);
CallbackHandler.register(Global.Events.packageLoadDone, this);
if (Global.Events.packageLoadDone.isTriggered) {
onTrigger(Global.Events.packageLoadDone);
}
getApplication().packageLoadDone.register(this);
}
@Override
public void onStop() {
CallbackHandler.unRegister(Global.Events.packageLoadDone, this);
getApplication().packageLoadDone.unRegister(this);
super.onStop();
}
@@ -104,9 +104,9 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
}
@Override
public void onTrigger(CallbackHandler.Event event) {
public void onTrigger(CallbackEvent<Void> event) {
Logger.dev("MagiskHideFragment: UI refresh");
appAdapter.setLists(Global.Data.appList, Global.Data.magiskHideList);
appAdapter.setLists(getApplication().appList, getApplication().magiskHideList);
mSwipeRefreshLayout.setRefreshing(false);
if (!TextUtils.isEmpty(lastFilter)) {
appAdapter.filter(lastFilter);

View File

@@ -11,7 +11,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -25,6 +24,7 @@ import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;

View File

@@ -0,0 +1,153 @@
package com.topjohnwu.magisk;
import android.app.Application;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.SparseArray;
import android.widget.Toast;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ValueSortedMap;
import java.io.File;
import java.util.List;
public class MagiskManager extends Application {
public static final String MAGISK_DISABLE_FILE = "/cache/.disable_magisk";
public static final String MAGISK_MANAGER_BOOT = "/dev/.magisk_manager_boot";
// Events
public final CallbackEvent<Void> blockDetectionDone = new CallbackEvent<>();
public final CallbackEvent<Void> packageLoadDone = new CallbackEvent<>();
public final CallbackEvent<Void> reloadMainActivity = new CallbackEvent<>();
public final CallbackEvent<Void> moduleLoadDone = new CallbackEvent<>();
public final CallbackEvent<Void> repoLoadDone = new CallbackEvent<>();
public final CallbackEvent<Void> updateCheckDone = new CallbackEvent<>();
public final CallbackEvent<Void> safetyNetDone = new CallbackEvent<>();
public SparseArray<CallbackEvent<Policy>> uidMap = new SparseArray<>();
// Info
public double magiskVersion;
public String magiskVersionString = "(none)";
public double remoteMagiskVersion = -1;
public String magiskLink;
public String releaseNoteLink;
public int SNCheckResult = -1;
public String bootBlock = null;
public boolean isSuClient = false;
public String suVersion = null;
public boolean disabled = false;
// Data
public ValueSortedMap<String, Repo> repoMap;
public ValueSortedMap<String, Module> moduleMap;
public List<String> blockList;
public List<ApplicationInfo> appList;
public List<String> magiskHideList;
// Configurations
public static boolean shellLogging;
public static boolean devLogging;
public boolean magiskHide;
public boolean isDarkTheme;
public int suRequestTimeout;
public int suLogTimeout = 14;
public int suAccessState;
public int suResponseType;
public int suNotificationType;
public SharedPreferences prefs;
private static Handler mHandler = new Handler();
@Override
public void onCreate() {
super.onCreate();
prefs = PreferenceManager.getDefaultSharedPreferences(this);
}
public void toast(String msg, int duration) {
mHandler.post(() -> Toast.makeText(this, msg, duration).show());
}
public void toast(int resId, int duration) {
mHandler.post(() -> Toast.makeText(this, resId, duration).show());
}
public void init() {
isDarkTheme = prefs.getBoolean("dark_theme", false);
devLogging = prefs.getBoolean("developer_logging", false);
shellLogging = prefs.getBoolean("shell_logging", false);
magiskHide = prefs.getBoolean("magiskhide", false);
updateMagiskInfo();
initSuAccess();
initSuConfigs();
// Initialize prefs
prefs.edit()
.putBoolean("dark_theme", isDarkTheme)
.putBoolean("magiskhide", magiskHide)
.putBoolean("busybox", Utils.commandExists("busybox"))
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
.putString("su_request_timeout", String.valueOf(suRequestTimeout))
.putString("su_auto_response", String.valueOf(suResponseType))
.putString("su_notification", String.valueOf(suNotificationType))
.putString("su_access", String.valueOf(suAccessState))
.apply();
}
public void initSuConfigs() {
suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
}
public void initSuAccess() {
List<String> ret = Shell.sh("su -v");
if (Utils.isValidShellResponse(ret)) {
suVersion = ret.get(0);
isSuClient = suVersion.toUpperCase().contains("MAGISK");
}
if (isSuClient) {
ret = Shell.sh("getprop persist.sys.root_access");
if (Utils.isValidShellResponse(ret))
suAccessState = Integer.parseInt(ret.get(0));
else {
Shell.su(true, "setprop persist.sys.root_access 3");
suAccessState = 3;
}
}
}
public void updateMagiskInfo() {
List<String> ret = Shell.sh("getprop magisk.version");
if (!Utils.isValidShellResponse(ret)) {
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;
}
}
ret = Shell.sh("getprop ro.magisk.disable");
try {
disabled = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
} catch (NumberFormatException e) {
disabled = false;
}
}
}

View File

@@ -15,20 +15,20 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.topjohnwu.magisk.utils.CallbackHandler;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.Shell;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, CallbackHandler.EventListener {
public class MainActivity extends Activity
implements NavigationView.OnNavigationItemSelectedListener, CallbackEvent.Listener<Void> {
private final Handler mDrawerHandler = new Handler();
private SharedPreferences prefs;
@@ -44,7 +44,7 @@ public class MainActivity extends AppCompatActivity
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (Global.Configs.isDarkTheme) {
if (getTopApplication().isDarkTheme) {
setTheme(R.style.AppTheme_dh);
}
super.onCreate(savedInstanceState);
@@ -79,28 +79,28 @@ public class MainActivity extends AppCompatActivity
navigate(R.id.status);
navigationView.setNavigationItemSelectedListener(this);
CallbackHandler.register(Global.Events.reloadMainActivity, this);
getTopApplication().reloadMainActivity.register(this);
}
@Override
protected void onResume() {
super.onResume();
CallbackHandler.register(Global.Events.updateCheckDone, this);
if (Global.Events.updateCheckDone.isTriggered)
onTrigger(Global.Events.updateCheckDone);
getTopApplication().updateCheckDone.register(this);
// if (getTopApplication().updateCheckDone.isTriggered)
// onTrigger(getTopApplication().updateCheckDone);
checkHideSection();
}
@Override
protected void onPause() {
CallbackHandler.unRegister(Global.Events.updateCheckDone, this);
getTopApplication().updateCheckDone.unRegister(this);
super.onPause();
}
@Override
protected void onDestroy() {
CallbackHandler.unRegister(Global.Events.reloadMainActivity, this);
getTopApplication().reloadMainActivity.unRegister(this);
super.onDestroy();
}
@@ -121,12 +121,12 @@ public class MainActivity extends AppCompatActivity
}
@Override
public void onTrigger(CallbackHandler.Event event) {
if (event == Global.Events.updateCheckDone) {
public void onTrigger(CallbackEvent<Void> event) {
if (event == getTopApplication().updateCheckDone) {
Menu menu = navigationView.getMenu();
menu.findItem(R.id.install).setVisible(Global.Info.remoteMagiskVersion > 0 &&
Shell.rootAccess());
} else if (event == Global.Events.reloadMainActivity) {
menu.findItem(R.id.install).setVisible(
getTopApplication().remoteMagiskVersion > 0 && Shell.rootAccess());
} else if (event == getTopApplication().reloadMainActivity) {
recreate();
}
}
@@ -135,11 +135,11 @@ public class MainActivity extends AppCompatActivity
Menu menu = navigationView.getMenu();
if (Shell.rootAccess()) {
menu.findItem(R.id.magiskhide).setVisible(
Global.Info.magiskVersion >= 8 && prefs.getBoolean("magiskhide", false));
menu.findItem(R.id.modules).setVisible(Global.Info.magiskVersion >= 4);
menu.findItem(R.id.downloads).setVisible(Global.Info.magiskVersion >= 4);
getTopApplication().magiskVersion >= 8 && prefs.getBoolean("magiskhide", false));
menu.findItem(R.id.modules).setVisible(getTopApplication().magiskVersion >= 4);
menu.findItem(R.id.downloads).setVisible(getTopApplication().magiskVersion >= 4);
menu.findItem(R.id.log).setVisible(true);
menu.findItem(R.id.superuser).setVisible(Global.Info.isSuClient);
menu.findItem(R.id.superuser).setVisible(getTopApplication().isSuClient);
}
}

View File

@@ -5,7 +5,6 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -15,10 +14,10 @@ import android.widget.TextView;
import com.github.clans.fab.FloatingActionButton;
import com.topjohnwu.magisk.adapters.ModulesAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.module.ModuleHelper;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.CallbackHandler;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.Logger;
import java.util.ArrayList;
@@ -28,7 +27,7 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class ModulesFragment extends Fragment implements CallbackHandler.EventListener {
public class ModulesFragment extends Fragment implements CallbackEvent.Listener<Void> {
private static final int FETCH_ZIP_CODE = 2;
@@ -54,7 +53,7 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
mSwipeRefreshLayout.setOnRefreshListener(() -> {
recyclerView.setVisibility(View.GONE);
new Async.LoadModules().exec();
new Async.LoadModules(getApplication()).exec();
});
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@@ -69,7 +68,7 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
}
});
if (Global.Events.moduleLoadDone.isTriggered) {
if (getApplication().moduleLoadDone.isTriggered) {
updateUI();
}
@@ -77,7 +76,7 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
}
@Override
public void onTrigger(CallbackHandler.Event event) {
public void onTrigger(CallbackEvent<Void> event) {
Logger.dev("ModulesFragment: UI refresh triggered");
updateUI();
}
@@ -95,13 +94,13 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
@Override
public void onStart() {
super.onStart();
CallbackHandler.register(Global.Events.moduleLoadDone, this);
getApplication().moduleLoadDone.register(this);
getActivity().setTitle(R.string.modules);
}
@Override
public void onStop() {
CallbackHandler.unRegister(Global.Events.moduleLoadDone, this);
getApplication().moduleLoadDone.unRegister(this);
super.onStop();
}
@@ -112,7 +111,8 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
}
private void updateUI() {
ModuleHelper.getModuleList(listModules);
listModules.clear();
listModules.addAll(getApplication().moduleMap.values());
if (listModules.size() == 0) {
emptyRv.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);

View File

@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
@@ -16,10 +15,11 @@ import android.widget.TextView;
import com.topjohnwu.magisk.adapters.ReposAdapter;
import com.topjohnwu.magisk.adapters.SimpleSectionedRecyclerViewAdapter;
import com.topjohnwu.magisk.module.ModuleHelper;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.CallbackHandler;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.Logger;
import java.util.ArrayList;
@@ -29,7 +29,7 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class ReposFragment extends Fragment implements CallbackHandler.EventListener {
public class ReposFragment extends Fragment implements CallbackEvent.Listener<Void> {
private Unbinder unbinder;
@BindView(R.id.recyclerView) RecyclerView recyclerView;
@@ -68,10 +68,10 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
mSwipeRefreshLayout.setOnRefreshListener(() -> {
recyclerView.setVisibility(View.GONE);
new Async.LoadRepos(getActivity()).exec();
new Async.LoadRepos(getApplication()).exec();
});
if (Global.Events.repoLoadDone.isTriggered) {
if (getApplication().repoLoadDone.isTriggered) {
reloadRepos();
updateUI();
}
@@ -93,7 +93,7 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
}
@Override
public void onTrigger(CallbackHandler.Event event) {
public void onTrigger(CallbackEvent<Void> event) {
Logger.dev("ReposFragment: UI refresh triggered");
reloadRepos();
updateUI();
@@ -109,13 +109,13 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
@Override
public void onStart() {
super.onStart();
CallbackHandler.register(Global.Events.repoLoadDone, this);
getApplication().repoLoadDone.register(this);
getActivity().setTitle(R.string.downloads);
}
@Override
public void onStop() {
CallbackHandler.unRegister(Global.Events.repoLoadDone, this);
getApplication().repoLoadDone.unRegister(this);
super.onStop();
}
@@ -126,7 +126,20 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
}
private void reloadRepos() {
ModuleHelper.getRepoLists(mUpdateRepos, mInstalledRepos, mOthersRepos);
mUpdateRepos.clear();
mInstalledRepos.clear();
mOthersRepos.clear();
for (Repo repo : getApplication().repoMap.values()) {
Module module = getApplication().moduleMap.get(repo.getId());
if (module != null) {
if (repo.getVersionCode() > module.getVersionCode())
mUpdateRepos.add(repo);
else
mInstalledRepos.add(repo);
} else {
mOthersRepos.add(repo);
}
}
fUpdateRepos.clear();
fInstalledRepos.clear();
fOthersRepos.clear();

View File

@@ -9,11 +9,11 @@ import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.preference.SwitchPreference;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.WindowManager;
import android.widget.Toast;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.module.ModuleHelper;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.Logger;
@@ -23,14 +23,14 @@ import com.topjohnwu.magisk.utils.Utils;
import butterknife.BindView;
import butterknife.ButterKnife;
public class SettingsActivity extends AppCompatActivity {
public class SettingsActivity extends Activity {
@BindView(R.id.toolbar) Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Global.Configs.isDarkTheme) {
if (getTopApplication().isDarkTheme) {
setTheme(R.style.AppTheme_dh);
}
@@ -77,6 +77,10 @@ public class SettingsActivity extends AppCompatActivity {
private ListPreference suAccess, autoRes, suNotification, requestTimeout;
private MagiskManager getApplication() {
return (MagiskManager) getActivity().getApplication();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -99,7 +103,7 @@ public class SettingsActivity extends AppCompatActivity {
setSummary();
findPreference("clear").setOnPreferenceClickListener((pref) -> {
ModuleHelper.clearRepoCache(getActivity());
ModuleHelper.clearRepoCache(getApplication());
return true;
});
@@ -107,11 +111,11 @@ public class SettingsActivity extends AppCompatActivity {
prefScreen.removePreference(magiskCategory);
prefScreen.removePreference(suCategory);
} else {
if (!Global.Info.isSuClient)
if (!getApplication().isSuClient)
prefScreen.removePreference(suCategory);
if (Global.Info.magiskVersion < 11)
if (getApplication().magiskVersion < 11)
prefScreen.removePreference(magiskCategory);
if (Global.Info.disabled) {
if (getApplication().disabled) {
busybox.setEnabled(false);
magiskHide.setEnabled(false);
hosts.setEnabled(false);
@@ -139,10 +143,10 @@ public class SettingsActivity extends AppCompatActivity {
switch (key) {
case "dark_theme":
enabled = prefs.getBoolean("dark_theme", false);
if (Global.Configs.isDarkTheme != enabled) {
Global.Configs.isDarkTheme = enabled;
if (getApplication().isDarkTheme != enabled) {
getApplication().isDarkTheme = enabled;
getActivity().recreate();
Global.Events.reloadMainActivity.trigger();
getApplication().reloadMainActivity.trigger();
}
break;
case "disable":
@@ -152,9 +156,9 @@ public class SettingsActivity extends AppCompatActivity {
@Override
protected Void doInBackground(Void... voids) {
if (enable) {
Utils.createFile(Global.MAGISK_DISABLE_FILE);
Utils.createFile(MagiskManager.MAGISK_DISABLE_FILE);
} else {
Utils.removeItem(Global.MAGISK_DISABLE_FILE);
Utils.removeItem(MagiskManager.MAGISK_DISABLE_FILE);
}
return null;
}
@@ -183,7 +187,7 @@ public class SettingsActivity extends AppCompatActivity {
case "magiskhide":
enabled = prefs.getBoolean("magiskhide", false);
if (enabled) {
if (!Global.Info.isSuClient) {
if (!getApplication().isSuClient) {
Utils.getAlertDialogBuilder(getActivity())
.setTitle(R.string.no_magisksu_title)
.setMessage(R.string.no_magisksu_msg)
@@ -212,23 +216,23 @@ public class SettingsActivity extends AppCompatActivity {
}.exec();
break;
case "su_access":
Global.Configs.suAccessState = Utils.getPrefsInt(prefs, "su_access", 0);
Shell.su("setprop persist.sys.root_access " + Global.Configs.suAccessState);
getApplication().suAccessState = Utils.getPrefsInt(prefs, "su_access", 0);
Shell.su("setprop persist.sys.root_access " + getApplication().suAccessState);
break;
case "su_request_timeout":
Global.Configs.suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
getApplication().suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
break;
case "su_auto_response":
Global.Configs.suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
getApplication().suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
break;
case "su_notification":
Global.Configs.suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
getApplication().suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
break;
case "developer_logging":
Global.Configs.devLogging = prefs.getBoolean("developer_logging", false);
getApplication().devLogging = prefs.getBoolean("developer_logging", false);
break;
case "shell_logging":
Global.Configs.shellLogging = prefs.getBoolean("shell_logging", false);
getApplication().shellLogging = prefs.getBoolean("shell_logging", false);
break;
}
setSummary();
@@ -236,11 +240,11 @@ public class SettingsActivity extends AppCompatActivity {
private void setSummary() {
suAccess.setSummary(getResources()
.getStringArray(R.array.su_access)[Global.Configs.suAccessState]);
.getStringArray(R.array.su_access)[getApplication().suAccessState]);
autoRes.setSummary(getResources()
.getStringArray(R.array.auto_response)[Global.Configs.suResponseType]);
.getStringArray(R.array.auto_response)[getApplication().suResponseType]);
suNotification.setSummary(getResources()
.getStringArray(R.array.su_notification)[Global.Configs.suNotificationType]);
.getStringArray(R.array.su_notification)[getApplication().suNotificationType]);
requestTimeout.setSummary(
getString(R.string.request_timeout_summary, prefs.getString("su_request_timeout", "10")));
}

View File

@@ -2,31 +2,45 @@ package com.topjohnwu.magisk;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
public class SplashActivity extends AppCompatActivity {
import java.util.List;
public class SplashActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MagiskManager magiskManager = getTopApplication();
// Init the info and configs and root shell
Global.init(getApplicationContext());
magiskManager.init();
// Check MagiskHide status
List<String> ret = Shell.sh("getprop persist.magisk.hide");
boolean started = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
// Now fire all async tasks
new Async.CheckUpdates().exec();
new Async.GetBootBlocks().exec();
new Async.LoadModules() {
new Async.CheckUpdates(magiskManager).exec();
new Async.GetBootBlocks(magiskManager).exec();
if (magiskManager.magiskHide && !magiskManager.disabled &&
magiskManager.magiskVersion > 11 && !started) {
new Async.MagiskHide().enable();
}
new Async.LoadModules(magiskManager) {
@Override
protected void onPostExecute(Void v) {
super.onPostExecute(v);
new Async.LoadRepos(getApplicationContext()).exec();
new Async.LoadRepos(magiskManager).exec();
}
}.exec();
new Async.LoadApps(getPackageManager()).exec();
new Async.LoadApps(magiskManager).exec();
// Preparation done, now start main activity
Intent intent = new Intent(getApplicationContext(), MainActivity.class);

View File

@@ -1,11 +1,10 @@
package com.topjohnwu.magisk;
import android.app.AlertDialog;
import android.support.v7.app.AlertDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
@@ -15,8 +14,9 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.CallbackHandler;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
@@ -26,7 +26,7 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class StatusFragment extends Fragment implements CallbackHandler.EventListener {
public class StatusFragment extends Fragment implements CallbackEvent.Listener<Void> {
private static boolean noDialog = false;
@@ -80,11 +80,11 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
safetyNetStatusText.setText(R.string.safetyNet_check_text);
safetyNetStatusText.setTextColor(defaultColor);
Global.Events.safetyNetDone.isTriggered = false;
getApplication().safetyNetDone.isTriggered = false;
noDialog = false;
updateUI();
new Async.CheckUpdates().exec();
new Async.CheckUpdates(getApplication()).exec();
});
safetyNetContainer.setOnClickListener(view -> {
@@ -92,10 +92,10 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
safetyNetContainer.setBackgroundColor(trans);
safetyNetIcon.setImageResource(0);
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
Async.checkSafetyNet(getActivity());
Async.checkSafetyNet(getApplication());
});
if (Global.Info.magiskVersion < 0 && Shell.rootAccess() && !noDialog) {
if (getApplication().magiskVersion < 0 && Shell.rootAccess() && !noDialog) {
noDialog = true;
Utils.getAlertDialogBuilder(getActivity())
.setTitle(R.string.no_magisk_title)
@@ -104,7 +104,7 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
.setPositiveButton(R.string.goto_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);
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
try {
transaction.replace(R.id.content_frame, new InstallFragment(), "install").commit();
} catch (IllegalStateException ignored) {}
@@ -115,15 +115,20 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
updateUI();
if (getApplication().updateCheckDone.isTriggered)
updateCheckUI();
if (getApplication().safetyNetDone.isTriggered)
updateSafetyNetUI();
return v;
}
@Override
public void onTrigger(CallbackHandler.Event event) {
if (event == Global.Events.updateCheckDone) {
public void onTrigger(CallbackEvent<Void> event) {
if (event == getApplication().updateCheckDone) {
Logger.dev("StatusFragment: Update Check UI refresh triggered");
updateCheckUI();
} else if (event == Global.Events.safetyNetDone) {
} else if (event == getApplication().safetyNetDone) {
Logger.dev("StatusFragment: SafetyNet UI refresh triggered");
updateSafetyNetUI();
}
@@ -132,21 +137,15 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
@Override
public void onStart() {
super.onStart();
CallbackHandler.register(Global.Events.updateCheckDone, this);
CallbackHandler.register(Global.Events.safetyNetDone, this);
if (Global.Events.updateCheckDone.isTriggered) {
updateCheckUI();
}
if (Global.Events.safetyNetDone.isTriggered) {
updateSafetyNetUI();
}
getApplication().updateCheckDone.register(this);
getApplication().safetyNetDone.register(this);
getActivity().setTitle(R.string.status);
}
@Override
public void onStop() {
CallbackHandler.unRegister(Global.Events.updateCheckDone, this);
CallbackHandler.unRegister(Global.Events.safetyNetDone, this);
getApplication().updateCheckDone.unRegister(this);
getApplication().safetyNetDone.unRegister(this);
super.onStop();
}
@@ -159,14 +158,14 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
private void updateUI() {
int image, color;
Global.updateMagiskInfo();
getApplication().updateMagiskInfo();
if (Global.Info.magiskVersion < 0) {
if (getApplication().magiskVersion < 0) {
magiskVersionText.setText(R.string.magisk_version_error);
} else if (Global.Info.disabled) {
magiskVersionText.setText(getString(R.string.magisk_version_disable, Global.Info.magiskVersionString));
} else if (getApplication().disabled) {
magiskVersionText.setText(getString(R.string.magisk_version_disable, getApplication().magiskVersionString));
} else {
magiskVersionText.setText(getString(R.string.magisk_version, Global.Info.magiskVersionString));
magiskVersionText.setText(getString(R.string.magisk_version, getApplication().magiskVersionString));
}
switch (Shell.rootStatus) {
@@ -177,11 +176,11 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
rootInfoText.setText(R.string.root_info_warning);
break;
case 1:
if (Global.Info.suVersion != null) {
if (getApplication().suVersion != null) {
color = colorOK;
image = R.drawable.ic_check_circle;
rootStatusText.setText(R.string.proper_root);
rootInfoText.setText(Global.Info.suVersion);
rootInfoText.setText(getApplication().suVersion);
break;
}
case -1:
@@ -200,24 +199,24 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
private void updateCheckUI() {
int image, color;
if (Global.Info.remoteMagiskVersion < 0) {
if (getApplication().remoteMagiskVersion < 0) {
color = colorNeutral;
image = R.drawable.ic_help;
magiskUpdateText.setText(R.string.cannot_check_updates);
} else if (Global.Info.remoteMagiskVersion > Global.Info.magiskVersion) {
} else if (getApplication().remoteMagiskVersion > getApplication().magiskVersion) {
color = colorInfo;
image = R.drawable.ic_update;
magiskUpdateText.setText(getString(R.string.magisk_update_available, Global.Info.remoteMagiskVersion));
magiskUpdateText.setText(getString(R.string.magisk_update_available, getApplication().remoteMagiskVersion));
} else {
color = colorOK;
image = R.drawable.ic_check_circle;
magiskUpdateText.setText(getString(R.string.up_to_date, getString(R.string.magisk)));
}
if (Global.Info.magiskVersion < 0) {
if (getApplication().magiskVersion < 0) {
color = colorBad;
image = R.drawable.ic_cancel;
} else if (Global.Info.disabled) {
} else if (getApplication().disabled) {
color = colorNeutral;
image = R.drawable.ic_cancel;
}
@@ -232,7 +231,7 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
updateMagisk = Utils.getAlertDialogBuilder(getActivity())
.setTitle(R.string.magisk_update_title)
.setMessage(getString(R.string.magisk_update_message, Global.Info.remoteMagiskVersion))
.setMessage(getString(R.string.magisk_update_message, getApplication().remoteMagiskVersion))
.setCancelable(true)
.setPositiveButton(R.string.goto_install, (dialogInterface, i) -> {
((MainActivity) getActivity()).navigationView.setCheckedItem(R.id.install);
@@ -243,12 +242,12 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
} catch (IllegalStateException ignored) {}
})
.setNeutralButton(R.string.check_release_notes, (dialog, which) -> {
getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Global.Info.releaseNoteLink)));
getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getApplication().releaseNoteLink)));
})
.setNegativeButton(R.string.no_thanks, null)
.create();
if (Global.Info.magiskVersion < Global.Info.remoteMagiskVersion && Shell.rootAccess()) {
if (getApplication().magiskVersion < getApplication().remoteMagiskVersion && Shell.rootAccess()) {
magiskStatusContainer.setOnClickListener(view -> updateMagisk.show());
if (!noDialog) {
noDialog = true;
@@ -260,7 +259,7 @@ public class StatusFragment extends Fragment implements CallbackHandler.EventLis
private void updateSafetyNetUI() {
int image, color;
safetyNetProgress.setVisibility(View.GONE);
switch (Global.Info.SNCheckResult) {
switch (getApplication().SNCheckResult) {
case -3:
color = colorNeutral;
image = R.drawable.ic_help;

View File

@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -13,6 +12,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.topjohnwu.magisk.adapters.SuLogAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.superuser.SuLogDatabaseHelper;
import com.topjohnwu.magisk.superuser.SuLogEntry;

View File

@@ -3,7 +3,6 @@ package com.topjohnwu.magisk;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
@@ -11,6 +10,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.topjohnwu.magisk.adapters.PolicyAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.superuser.SuDatabaseHelper;

View File

@@ -0,0 +1,12 @@
package com.topjohnwu.magisk.components;
import android.support.v7.app.AppCompatActivity;
import com.topjohnwu.magisk.MagiskManager;
public class Activity extends AppCompatActivity {
public MagiskManager getTopApplication() {
return (MagiskManager) getApplication();
}
}

View File

@@ -0,0 +1,11 @@
package com.topjohnwu.magisk.components;
import com.topjohnwu.magisk.MagiskManager;
public class Fragment extends android.support.v4.app.Fragment {
public MagiskManager getApplication() {
return (MagiskManager) getActivity().getApplicationContext();
}
}

View File

@@ -6,7 +6,7 @@ import android.widget.Toast;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.topjohnwu.magisk.Global;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.Logger;
@@ -22,7 +22,6 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -36,29 +35,29 @@ public class ModuleHelper {
private static final String REPO_KEY = "repomap";
private static final String FILE_KEY = "RepoMap";
public static void createModuleMap() {
public static void createModuleMap(MagiskManager magiskManager) {
Logger.dev("ModuleHelper: Loading modules");
Global.Data.moduleMap = new ValueSortedMap<>();
magiskManager.moduleMap = new ValueSortedMap<>();
for (String path : Utils.getModList(MAGISK_PATH)) {
Logger.dev("ModuleHelper: Adding modules from " + path);
Module module;
try {
module = new Module(path);
Global.Data.moduleMap.put(module.getId(), module);
magiskManager.moduleMap.put(module.getId(), module);
} catch (BaseModule.CacheModException ignored) {}
}
Logger.dev("ModuleHelper: Data load done");
}
public static void createRepoMap(Context context) {
public static void createRepoMap(MagiskManager magiskManager) {
Logger.dev("ModuleHelper: Loading repos");
SharedPreferences prefs = context.getSharedPreferences(FILE_KEY, Context.MODE_PRIVATE);
SharedPreferences prefs = magiskManager.prefs;
Global.Data.repoMap = new ValueSortedMap<>();
magiskManager.repoMap = new ValueSortedMap<>();
Gson gson = new Gson();
String jsonString;
@@ -88,7 +87,7 @@ public class ModuleHelper {
// Making a request to main URL for repo info
jsonString = WebService.request(
context.getString(R.string.url_main), WebService.GET, null, header, false);
magiskManager.getString(R.string.url_main), WebService.GET, null, header, false);
if (!jsonString.isEmpty()) {
try {
@@ -115,13 +114,13 @@ public class ModuleHelper {
try {
if (repo == null) {
Logger.dev("ModuleHelper: Create new repo " + id);
repo = new Repo(context, name, updatedDate);
repo = new Repo(magiskManager, name, updatedDate);
} else {
Logger.dev("ModuleHelper: Update cached repo " + id);
repo.update(updatedDate);
}
if (repo.getId() != null) {
Global.Data.repoMap.put(id, repo);
magiskManager.repoMap.put(id, repo);
}
} catch (BaseModule.CacheModException ignored) {}
}
@@ -131,50 +130,27 @@ public class ModuleHelper {
} else {
// Use cached if no internet or no updates
Logger.dev("ModuleHelper: No updates, use cached");
Global.Data.repoMap.putAll(cached);
magiskManager.repoMap.putAll(cached);
}
prefs.edit()
.putInt(VERSION_KEY, GSON_DB_VER)
.putString(REPO_KEY, gson.toJson(Global.Data.repoMap))
.putString(REPO_KEY, gson.toJson(magiskManager.repoMap))
.putString(ETAG_KEY, etag)
.apply();
Logger.dev("ModuleHelper: Repo load done");
}
public static void getModuleList(List<Module> moduleList) {
moduleList.clear();
moduleList.addAll(Global.Data.moduleMap.values());
}
public static void getRepoLists(List<Repo> update, List<Repo> installed, List<Repo> others) {
update.clear();
installed.clear();
others.clear();
for (Repo repo : Global.Data.repoMap.values()) {
Module module = Global.Data.moduleMap.get(repo.getId());
if (module != null) {
if (repo.getVersionCode() > module.getVersionCode()) {
update.add(repo);
} else {
installed.add(repo);
}
} else {
others.add(repo);
}
}
}
public static void clearRepoCache(Context context) {
SharedPreferences repoMap = context.getSharedPreferences(FILE_KEY, Context.MODE_PRIVATE);
public static void clearRepoCache(MagiskManager magiskManager) {
SharedPreferences repoMap = magiskManager.getSharedPreferences(FILE_KEY, Context.MODE_PRIVATE);
repoMap.edit()
.remove(ETAG_KEY)
.remove(VERSION_KEY)
.apply();
Global.Events.repoLoadDone.isTriggered = false;
new Async.LoadRepos(context).exec();
Toast.makeText(context, R.string.repo_cache_cleared, Toast.LENGTH_SHORT).show();
magiskManager.repoLoadDone.isTriggered = false;
new Async.LoadRepos(magiskManager).exec();
Toast.makeText(magiskManager, R.string.repo_cache_cleared, Toast.LENGTH_SHORT).show();
}
}

View File

@@ -1,26 +1,45 @@
package com.topjohnwu.magisk.receivers;
import android.app.IntentService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.widget.Toast;
import com.topjohnwu.magisk.Global;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.util.List;
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Global.initSuAccess();
Global.updateMagiskInfo();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (prefs.getBoolean("magiskhide", false) && !Global.Info.disabled && Global.Info.magiskVersion > 10.3) {
Toast.makeText(context, R.string.start_magiskhide, Toast.LENGTH_SHORT).show();
new Async.MagiskHide(true).enable();
context.startService(new Intent(context, BootupIntentService.class));
}
public static class BootupIntentService extends IntentService {
public BootupIntentService() {
super("BootupIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
MagiskManager magiskManager = (MagiskManager) getApplicationContext();
magiskManager.initSuAccess();
magiskManager.updateMagiskInfo();
List<String> ret = Shell.sh("getprop persist.magisk.hide");
boolean started = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
if (magiskManager.prefs.getBoolean("magiskhide", false) &&
!magiskManager.disabled && !started && magiskManager.magiskVersion > 11) {
magiskManager.toast(R.string.start_magiskhide, Toast.LENGTH_LONG);
Shell.su(true, Async.MAGISK_HIDE_PATH + "enable",
"setprop persist.magisk.hide 1");
}
}
}
}

View File

@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.receivers;
import android.net.Uri;
import com.topjohnwu.magisk.Global;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.Shell;
@@ -56,7 +56,7 @@ public class MagiskDlReceiver extends DownloadReceiver {
@Override
protected Void doInBackground(Void... params) {
Shell.su("setprop magisk.version "
+ String.valueOf(Global.Info.remoteMagiskVersion));
+ String.valueOf(((MagiskManager) mContext.getApplicationContext()).remoteMagiskVersion));
return null;
}
}.exec();

View File

@@ -2,11 +2,10 @@ package com.topjohnwu.magisk.superuser;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.topjohnwu.magisk.Global;
import com.topjohnwu.magisk.components.Activity;
public class RequestActivity extends AppCompatActivity {
public class RequestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -18,7 +17,7 @@ public class RequestActivity extends AppCompatActivity {
return;
}
Global.initSuConfigs(this);
getTopApplication().initSuConfigs();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClass(this, SuRequestActivity.class);
startActivity(intent);

View File

@@ -5,7 +5,7 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.topjohnwu.magisk.Global;
import com.topjohnwu.magisk.MagiskManager;
import java.util.ArrayList;
import java.util.List;
@@ -15,8 +15,11 @@ public class SuLogDatabaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VER = 1;
private static final String TABLE_NAME = "logs";
private MagiskManager magiskManager;
public SuLogDatabaseHelper(Context context) {
super(context, "sulog.db", null, DATABASE_VER);
magiskManager = (MagiskManager) context.getApplicationContext();
}
@Override
@@ -57,7 +60,7 @@ public class SuLogDatabaseHelper extends SQLiteOpenHelper {
SQLiteDatabase db = getWritableDatabase();
// Clear outdated logs
db.delete(TABLE_NAME, "time < ?", new String[] { String.valueOf(
System.currentTimeMillis() / 1000 - Global.Configs.suLogTimeout * 86400) });
System.currentTimeMillis() / 1000 - magiskManager.suLogTimeout * 86400) });
try (Cursor c = db.query(TABLE_NAME, null, selection, null, null, null, "time DESC")) {
while (c.moveToNext())
ret.add(new SuLogEntry(c));

View File

@@ -6,7 +6,7 @@ import android.content.Intent;
import android.os.Process;
import android.widget.Toast;
import com.topjohnwu.magisk.Global;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import java.util.Date;
@@ -23,6 +23,8 @@ public class SuReceiver extends BroadcastReceiver {
String command, action;
Policy policy;
MagiskManager magiskManager = (MagiskManager) context.getApplicationContext();
if (intent == null) return;
fromUid = intent.getIntExtra("from.uid", -1);
@@ -40,7 +42,7 @@ public class SuReceiver extends BroadcastReceiver {
return;
}
Global.initSuConfigs(context);
magiskManager.initSuConfigs();
SuLogEntry log = new SuLogEntry(policy);
@@ -58,7 +60,7 @@ public class SuReceiver extends BroadcastReceiver {
return;
}
if (policy.notification && Global.Configs.suNotificationType == TOAST)
if (policy.notification && magiskManager.suNotificationType == TOAST)
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
if (policy.logging) {

View File

@@ -8,7 +8,6 @@ import android.net.LocalSocketAddress;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.FileObserver;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.Window;
import android.widget.ArrayAdapter;
@@ -18,10 +17,11 @@ import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import com.topjohnwu.magisk.Global;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.CallbackHandler;
import com.topjohnwu.magisk.utils.CallbackEvent;
import java.io.DataInputStream;
import java.io.IOException;
@@ -29,7 +29,7 @@ import java.io.IOException;
import butterknife.BindView;
import butterknife.ButterKnife;
public class SuRequestActivity extends AppCompatActivity implements CallbackHandler.EventListener {
public class SuRequestActivity extends Activity implements CallbackEvent.Listener<Policy> {
private static final int[] timeoutList = {0, -1, 10, 20, 30, 60};
private static final int SU_PROTOCOL_PARAM_MAX = 20;
@@ -51,12 +51,13 @@ public class SuRequestActivity extends AppCompatActivity implements CallbackHand
private String socketPath;
private LocalSocket socket;
private PackageManager pm;
private MagiskManager magiskManager;
private int uid;
private Policy policy;
private CountDownTimer timer;
private CallbackHandler.EventListener self;
private CallbackHandler.Event event = null;
private CallbackEvent.Listener<Policy> self;
private CallbackEvent<Policy> event = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -64,6 +65,7 @@ public class SuRequestActivity extends AppCompatActivity implements CallbackHand
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
pm = getPackageManager();
magiskManager = getTopApplication();
Intent intent = getIntent();
socketPath = intent.getStringExtra("socket");
@@ -85,7 +87,7 @@ public class SuRequestActivity extends AppCompatActivity implements CallbackHand
void showRequest() {
switch (Global.Configs.suResponseType) {
switch (magiskManager.suResponseType) {
case AUTO_DENY:
handleAction(Policy.DENY, 0);
return;
@@ -108,7 +110,7 @@ public class SuRequestActivity extends AppCompatActivity implements CallbackHand
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
timeout.setAdapter(adapter);
timer = new CountDownTimer(Global.Configs.suRequestTimeout * 1000, 1000) {
timer = new CountDownTimer(magiskManager.suRequestTimeout * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
deny_btn.setText(getString(R.string.deny_with_str, "(" + millisUntilFinished / 1000 + ")"));
@@ -141,14 +143,11 @@ public class SuRequestActivity extends AppCompatActivity implements CallbackHand
}
@Override
public void onTrigger(CallbackHandler.Event event) {
Policy policy = (Policy) event.getResult();
public void onTrigger(CallbackEvent<Policy> event) {
Policy policy = event.getResult();
String response = "socket:DENY";
if (policy != null) {
Global.Events.uidMap.remove(policy.uid);
if (policy.policy == Policy.ALLOW)
response = "socket:ALLOW";
}
if (policy != null &&policy.policy == Policy.ALLOW )
response = "socket:ALLOW";
try {
socket.getOutputStream().write((response).getBytes());
} catch (Exception ignored) {}
@@ -224,19 +223,20 @@ public class SuRequestActivity extends AppCompatActivity implements CallbackHand
return;
}
boolean showRequest = false;
event = Global.Events.uidMap.get(uid);
event = magiskManager.uidMap.get(uid);
if (event == null) {
showRequest = true;
event = new CallbackHandler.Event() {
event = new CallbackEvent<Policy>() {
@Override
public void trigger(Object result) {
public void trigger(Policy result) {
super.trigger(result);
CallbackHandler.unRegister(this);
unRegister();
magiskManager.uidMap.remove(uid);
}
};
Global.Events.uidMap.put(uid, event);
magiskManager.uidMap.put(uid, event);
}
CallbackHandler.register(event, self);
event.register(self);
try {
if (showRequest) {
policy = new Policy(uid, pm);

View File

@@ -10,7 +10,7 @@ import android.os.AsyncTask;
import android.provider.OpenableColumns;
import android.widget.Toast;
import com.topjohnwu.magisk.Global;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
import com.topjohnwu.magisk.module.ModuleHelper;
@@ -51,94 +51,106 @@ public class Async {
public static class CheckUpdates extends NormalTask<Void, Void, Void> {
MagiskManager magiskManager;
public CheckUpdates(MagiskManager context) {
magiskManager = context;
}
@Override
protected Void doInBackground(Void... voids) {
String jsonStr = WebService.request(UPDATE_JSON, WebService.GET);
try {
JSONObject json = new JSONObject(jsonStr);
JSONObject magisk = json.getJSONObject("magisk");
Global.Info.remoteMagiskVersion = magisk.getDouble("versionCode");
Global.Info.magiskLink = magisk.getString("link");
Global.Info.releaseNoteLink = magisk.getString("note");
magiskManager.remoteMagiskVersion = magisk.getDouble("versionCode");
magiskManager.magiskLink = magisk.getString("link");
magiskManager.releaseNoteLink = magisk.getString("note");
} catch (JSONException ignored) {}
return null;
}
@Override
protected void onPostExecute(Void v) {
Global.Events.updateCheckDone.trigger();
magiskManager.updateCheckDone.trigger();
}
}
public static void checkSafetyNet(Context context) {
new SafetyNetHelper(context) {
public static void checkSafetyNet(MagiskManager magiskManager) {
new SafetyNetHelper(magiskManager) {
@Override
public void handleResults(int i) {
Global.Info.SNCheckResult = i;
Global.Events.safetyNetDone.trigger();
magiskManager.SNCheckResult = i;
magiskManager.safetyNetDone.trigger();
}
}.requestTest();
}
public static class LoadModules extends RootTask<Void, Void, Void> {
protected MagiskManager magiskManager;
public LoadModules(MagiskManager context) {
magiskManager = context;
}
@Override
protected Void doInBackground(Void... voids) {
ModuleHelper.createModuleMap();
ModuleHelper.createModuleMap(magiskManager);
return null;
}
@Override
protected void onPostExecute(Void v) {
Global.Events.moduleLoadDone.trigger();
magiskManager.moduleLoadDone.trigger();
}
}
public static class LoadRepos extends NormalTask<Void, Void, Void> {
private Context mContext;
private MagiskManager magiskManager;
public LoadRepos(Context context) {
mContext = context;
public LoadRepos(MagiskManager context) {
magiskManager = context;
}
@Override
protected Void doInBackground(Void... voids) {
ModuleHelper.createRepoMap(mContext);
ModuleHelper.createRepoMap(magiskManager);
return null;
}
@Override
protected void onPostExecute(Void v) {
Global.Events.repoLoadDone.trigger();
magiskManager.repoLoadDone.trigger();
}
}
public static class LoadApps extends RootTask<Void, Void, Void> {
private PackageManager pm;
private MagiskManager magiskManager;
public LoadApps(PackageManager packageManager) {
pm = packageManager;
public LoadApps(MagiskManager context) {
magiskManager = context;
}
@Override
protected Void doInBackground(Void... voids) {
Global.Data.appList = pm.getInstalledApplications(0);
for (Iterator<ApplicationInfo> i = Global.Data.appList.iterator(); i.hasNext(); ) {
PackageManager pm = magiskManager.getPackageManager();
magiskManager.appList = pm.getInstalledApplications(0);
for (Iterator<ApplicationInfo> i = magiskManager.appList.iterator(); i.hasNext(); ) {
ApplicationInfo info = i.next();
if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled)
i.remove();
}
Collections.sort(Global.Data.appList, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
Collections.sort(magiskManager.appList, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
.compareTo(b.loadLabel(pm).toString().toLowerCase()));
Global.Data.magiskHideList = Shell.su(Async.MAGISK_HIDE_PATH + "list");
magiskManager.magiskHideList = Shell.su(Async.MAGISK_HIDE_PATH + "list");
return null;
}
@Override
protected void onPostExecute(Void v) {
Global.Events.packageLoadDone.trigger();
magiskManager.packageLoadDone.trigger();
}
}
@@ -149,19 +161,22 @@ public class Async {
private String mFilename;
protected ProgressDialog progress;
private Context mContext;
private MagiskManager magiskManager;
public FlashZIP(Context context, Uri uri, String filename) {
mContext = context;
magiskManager = (MagiskManager) context.getApplicationContext();
mUri = uri;
mFilename = filename;
}
public FlashZIP(Context context, Uri uri) {
mContext = context;
magiskManager = (MagiskManager) context.getApplicationContext();
mUri = uri;
// Try to get the filename ourselves
Cursor c = mContext.getContentResolver().query(uri, null, null, null, null);
Cursor c = magiskManager.getContentResolver().query(uri, null, null, null, null);
if (c != null) {
int nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME);
c.moveToFirst();
@@ -179,14 +194,14 @@ public class Async {
protected void preProcessing() throws Throwable {}
protected void copyToCache() throws Throwable {
publishProgress(mContext.getString(R.string.copying_msg));
mCachedFile = new File(mContext.getCacheDir().getAbsolutePath() + "/install.zip");
publishProgress(magiskManager.getString(R.string.copying_msg));
mCachedFile = new File(magiskManager.getCacheDir().getAbsolutePath() + "/install.zip");
if (mCachedFile.exists() && !mCachedFile.delete()) {
Logger.error("FlashZip: Error while deleting already existing file");
throw new IOException();
}
try (
InputStream in = mContext.getContentResolver().openInputStream(mUri);
InputStream in = magiskManager.getContentResolver().openInputStream(mUri);
OutputStream outputStream = new FileOutputStream(mCachedFile)
) {
byte buffer[] = new byte[1024];
@@ -236,7 +251,7 @@ public class Async {
return -1;
}
if (!unzipAndCheck()) return 0;
publishProgress(mContext.getString(R.string.zip_install_progress_msg, mFilename));
publishProgress(magiskManager.getString(R.string.zip_install_progress_msg, mFilename));
ret = Shell.su(
"BOOTMODE=true sh " + mCachedFile.getParent() +
"/META-INF/com/google/android/update-binary dummy 1 " + mCachedFile.getPath(),
@@ -264,12 +279,12 @@ public class Async {
progress.dismiss();
switch (result) {
case -1:
Toast.makeText(mContext, mContext.getString(R.string.install_error), Toast.LENGTH_LONG).show();
Toast.makeText(mContext, mContext.getString(R.string.manual_install_1, mUri.getPath()), Toast.LENGTH_LONG).show();
Toast.makeText(mContext, mContext.getString(R.string.manual_install_2), Toast.LENGTH_LONG).show();
Toast.makeText(magiskManager, magiskManager.getString(R.string.install_error), Toast.LENGTH_LONG).show();
Toast.makeText(magiskManager, magiskManager.getString(R.string.manual_install_1, mUri.getPath()), Toast.LENGTH_LONG).show();
Toast.makeText(magiskManager, magiskManager.getString(R.string.manual_install_2), Toast.LENGTH_LONG).show();
break;
case 0:
Toast.makeText(mContext, mContext.getString(R.string.invalid_zip), Toast.LENGTH_LONG).show();
Toast.makeText(magiskManager, magiskManager.getString(R.string.invalid_zip), Toast.LENGTH_LONG).show();
break;
case 1:
onSuccess();
@@ -278,8 +293,8 @@ public class Async {
}
protected void onSuccess() {
Global.Events.updateCheckDone.trigger();
new LoadModules().exec();
magiskManager.updateCheckDone.trigger();
new LoadModules(magiskManager).exec();
Utils.getAlertDialogBuilder(mContext)
.setTitle(R.string.reboot_title)
@@ -292,18 +307,10 @@ public class Async {
public static class MagiskHide extends RootTask<Object, Void, Void> {
private boolean newShell = false;
public MagiskHide() {}
public MagiskHide(boolean b) {
newShell = b;
}
@Override
protected Void doInBackground(Object... params) {
String command = (String) params[0];
Shell.su(newShell, MAGISK_HIDE_PATH + command);
Shell.su(MAGISK_HIDE_PATH + command);
return null;
}
@@ -316,29 +323,36 @@ public class Async {
}
public void enable() {
exec("enable");
exec("enable; setprop persist.magisk.hide 1");
}
public void disable() {
exec("disable");
exec("disable; setprop persist.magisk.hide 0");
}
}
public static class GetBootBlocks extends RootTask<Void, Void, Void> {
MagiskManager magiskManager;
public GetBootBlocks(MagiskManager context) {
magiskManager = context;
}
@Override
protected Void doInBackground(Void... params) {
if (Shell.rootAccess()) {
Global.Data.blockList = Shell.su("ls /dev/block | grep mmc");
if (Global.Info.bootBlock == null)
Global.Info.bootBlock = Utils.detectBootImage();
magiskManager.blockList = Shell.su("ls /dev/block | grep mmc");
if (magiskManager.bootBlock == null)
magiskManager.bootBlock = Utils.detectBootImage();
}
return null;
}
@Override
protected void onPostExecute(Void v) {
Global.Events.blockDetectionDone.trigger();
magiskManager.blockDetectionDone.trigger();
}
}
}

View File

@@ -0,0 +1,47 @@
package com.topjohnwu.magisk.utils;
import java.util.HashSet;
import java.util.Set;
public class CallbackEvent<Result> {
public boolean isTriggered = false;
private Result result;
private Set<Listener<Result>> listeners;
public void register(Listener<Result> l) {
if (listeners == null)
listeners = new HashSet<>();
listeners.add(l);
}
public void unRegister() {
listeners = null;
}
public void unRegister(Listener<Result> l) {
if (listeners != null)
listeners.remove(l);
}
public void trigger() {
trigger(null);
}
public void trigger(Result r) {
result = r;
isTriggered = true;
if (listeners != null) {
for (Listener<Result> listener : listeners)
listener.onTrigger(this);
}
}
public Result getResult() {
return result;
}
public interface Listener<R> {
void onTrigger(CallbackEvent<R> event);
}
}

View File

@@ -1,67 +0,0 @@
package com.topjohnwu.magisk.utils;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class CallbackHandler {
private static Map<Event, Set<EventListener>> listeners = new HashMap<>();
public static void register(Event event, EventListener listener) {
Set<EventListener> list = listeners.get(event);
if (list == null) {
list = new HashSet<>();
listeners.put(event, list);
}
list.add(listener);
}
public static void unRegister(Event event) {
Set<EventListener> list = listeners.remove(event);
if (list != null) {
list.clear();
}
}
public static void unRegister(Event event, EventListener listener) {
Set<EventListener> list = listeners.get(event);
if (list != null) {
list.remove(listener);
}
}
private static void triggerCallback(Event event) {
Set<EventListener> list = listeners.get(event);
if (list != null) {
for (EventListener listener : list) {
listener.onTrigger(event);
}
}
}
public static class Event {
public boolean isTriggered = false;
private Object result;
public void trigger() {
trigger(null);
}
public void trigger(Object result) {
this.result = result;
isTriggered = true;
triggerCallback(this);
}
public Object getResult() {
return result;
}
}
public interface EventListener {
void onTrigger(Event event);
}
}

View File

@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.utils;
import android.util.Log;
import com.topjohnwu.magisk.Global;
import com.topjohnwu.magisk.MagiskManager;
public class Logger {
@@ -17,7 +17,7 @@ public class Logger {
}
public static void dev(String msg, Object... args) {
if (Global.Configs.devLogging) {
if (MagiskManager.devLogging) {
if (args.length == 1 && args[0] instanceof Throwable) {
Log.d(TAG, "DEV: " + msg, (Throwable) args[0]);
} else {
@@ -27,13 +27,13 @@ public class Logger {
}
public static void dev(String msg) {
if (Global.Configs.devLogging) {
if (MagiskManager.devLogging) {
Log.d(TAG, "DEBUG: " + msg);
}
}
public static void shell(boolean root, String msg) {
if (Global.Configs.shellLogging) {
if (MagiskManager.shellLogging) {
Log.d(root ? "SU" : "SH", msg);
}
}

View File

@@ -132,6 +132,13 @@ public class Shell {
process = Runtime.getRuntime().exec("su");
STDIN = new DataOutputStream(process.getOutputStream());
STDOUT = new StreamGobbler(process.getInputStream(), res);
// Run the new shell with busybox and proper umask
STDIN.write(("umask 022\n").getBytes("UTF-8"));
STDIN.flush();
STDIN.write(("PATH=`[ -e /dev/busybox ] && echo /dev/busybox || " +
"echo /data/busybox`:$PATH\n").getBytes("UTF-8"));
STDIN.flush();
} catch (IOException err) {
return null;
}

View File

@@ -1,7 +1,6 @@
package com.topjohnwu.magisk.utils;
import android.Manifest;
import android.app.AlertDialog;
import android.app.DownloadManager;
import android.content.Context;
import android.content.IntentFilter;
@@ -10,10 +9,11 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.widget.Toast;
import com.topjohnwu.magisk.Global;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.receivers.DownloadReceiver;
@@ -115,7 +115,7 @@ public class Utils {
}
public static AlertDialog.Builder getAlertDialogBuilder(Context context) {
if (Global.Configs.isDarkTheme) {
if (((MagiskManager) context.getApplicationContext()).isDarkTheme) {
return new AlertDialog.Builder(context, R.style.AlertDialog_dh);
} else {
return new AlertDialog.Builder(context);

View File

@@ -1,6 +1,6 @@
package com.topjohnwu.magisk.utils;
import android.app.AlertDialog;
import android.support.v7.app.AlertDialog;
import android.content.Context;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -23,7 +23,7 @@
<string name="checking_for_updates">Suche nach Updates…</string>
<string name="magisk_update_available">Magisk v%1$.1f ist verfügbar!</string>
<string name="cannot_check_updates">Updatesuche fehlgeschlagen.\nIst eine Internetverbindung verfügbar?</string>
<string name="up_to_date">Die neuste Version von %1$s ist bereits installiert</string>
<string name="up_to_date">Die neueste Version von %1$s ist bereits installiert</string>
<string name="root_error">Gerootet, aber keine root-Rechte. Wurde der root-Zugriff verweigert?</string>
<string name="not_rooted">Nicht gerootet</string>
<string name="proper_root">Ordnungsgemäß gerootet</string>
@@ -44,7 +44,10 @@
<string name="keep_force_encryption">\"force encryption\" beibehalten</string>
<string name="keep_dm_verity">\"dm-verity\"-Test beibehalten</string>
<string name="current_magisk_title">Installierte Magisk-Version: v%1$s</string>
<string name="install_magisk_title">Neuste Magisk-Version: v%1$.1f</string>
<string name="install_magisk_title">Neueste Magisk-Version: v%1$.1f</string>
<string name="uninstall">Deinstallieren</string>
<string name="reboot_countdown">Neustart in %1$d</string>
<!--Module Fragment-->
@@ -85,7 +88,7 @@
<string name="support_thread">Hilfeforum</string>
<!--Toasts, Dialogs-->
<string name="permissionNotGranted">Diese Funktion benötigt Rechte zum Schreiben auf den externen Speicher.</string>
<string name="permissionNotGranted">Diese Funktion benötigt Rechte zum Schreiben auf dem externen Speicher.</string>
<string name="no_thanks">Nein danke</string>
<string name="yes">Ja</string>
<string name="repo_install_title">Installiere %1$s</string>
@@ -126,7 +129,7 @@
<string name="settings_dark_theme_title">Dunkles Theme</string>
<string name="settings_dark_theme_summary">Dunkles Theme aktivieren</string>
<string name="settings_clear_cache_title">Repo-Cache löschen</string>
<string name="settings_clear_cache_summary">Löscht die zwischengespeicherten Informtionen der Online-Repos. Erzwingt eine Aktualisierung</string>
<string name="settings_clear_cache_summary">Löscht die zwischengespeicherten Informationen der Online-Repos. Erzwingt eine Aktualisierung</string>
<string name="settings_disable_title">Magisk deaktivieren</string>
<string name="settings_disable_summary">Deaktiviert alles außer den root-Zugang (MagiskSU)</string>
@@ -188,5 +191,5 @@
<string name="pid">PID:\u0020</string>
<string name="target_uid">Ziel-UID:\u0020</string>
<string name="command">Befehl:\u0020</string>
</resources>

View File

@@ -26,14 +26,14 @@
<string name="up_to_date">Zainstalowana najnowsza wersja %1$s</string>
<string name="root_error">Zrotowany ale bez dostępu do roota</string>
<string name="not_rooted">Nie zrootowany</string>
<string name="proper_root">Prawidłowo zrootowany</string>
<string name="proper_root">Zrootowany prawidłowo</string>
<string name="safetyNet_check_text">Dotknij aby sprawdzić SafetyNet</string>
<string name="checking_safetyNet_status">Sprawdzanie statusu SafetyNet…</string>
<string name="safetyNet_connection_failed">Nie można połączyć się z Google API</string>
<string name="safetyNet_connection_suspended">Połączenie z Google API zostało zawieszone</string>
<string name="safetyNet_error">Nie można sprawdzić SafetyNet bez Internetu</string>
<string name="safetyNet_fail">SafetyNet Failed: CTS profile mismatch</string>
<string name="safetyNet_pass">SafetyNet Prawidłowy</string>
<string name="safetyNet_fail">Błąd SafetyNet: Niezgodność profilu CTS</string>
<string name="safetyNet_pass">SafetyNet Poprawny</string>
<string name="root_info_warning">Funkcjonalność znacznie ograniczona</string>
<!--Install Fragment-->
@@ -45,7 +45,9 @@
<string name="keep_dm_verity">Keep dm-verity</string>
<string name="current_magisk_title">Zainstalowana Wersja Magisk: v%1$s</string>
<string name="install_magisk_title">Ostatnia Wersja Magisk: v%1$.1f</string>
<string name="uninstall">Odinstaluj</string>
<string name="reboot_countdown">Restartuj do %1$d</string>
<!--Module Fragment-->
<string name="no_info_provided">(Nie umieszczono informacji)</string>
@@ -79,7 +81,7 @@
<string name="app_changelog">Zmiany w Aplikacji</string>
<string name="translators" />
<string name="app_version">Wersja Aplikacji</string>
<string name="app_source_code">Source code</string>
<string name="app_source_code">Kod źródłowy</string>
<string name="donation">Dotacja</string>
<string name="app_translators">Tłumacze Aplikacji</string>
<string name="support_thread">Strona Wsparcia</string>
@@ -115,6 +117,9 @@
<string name="repo_cache_cleared">Cache repozytorium wyczyszczone</string>
<string name="safetyNet_hide_notice">Ta aplikacja wykorzystuje SafetyNet\nJuż jest domyślnie obsługiwana przez MagiskHide</string>
<string name="start_magiskhide">Uruchamianie MagiskHide …</string>
<string name="no_magisksu_title">Nie Używaj MagiskSU!</string>
<string name="no_magisksu_msg">Jeśli nie masz roota z MagiskSU, używanie samego MagiskHide może nie wystarczyć! Inne metody nie są oficjalnie obsługiwane. Do poprawnego działania SaftyNet potrzebne będą dodatkowe narzędzia (np suhide)</string>
<string name="understand">Rozumiem</string>
<!--URL Templates-->
@@ -128,8 +133,8 @@
<string name="settings_clear_cache_title">Wyczyść Cache Repozytorium</string>
<string name="settings_clear_cache_summary">Wyczyść cache dla repozytorium, wymusza odświeżenie online przez aplikację</string>
<string name="settings_disable_title">Wyłącz Montowanie Magisk</string>
<string name="settings_disable_summary">Disable Magic Mount, co uniemożliwi wszystkim modułom działanie</string>
<string name="settings_disable_title">Wyłącz Magisk</string>
<string name="settings_disable_summary">Wszystko zostanie wyłączone za wyjątkiem roota (MagiskSU)</string>
<string name="settings_magiskhide_summary">Włącz Hide Magisk dla wykrytych aplikacji</string>
<string name="settings_busybox_title">Włącz BusyBox</string>
<string name="settings_busybox_summary">Zmień montowanie Magisk z wbudowanego busybox do xbin</string>

View File

@@ -0,0 +1,187 @@
<resources>
<!--Welcome Activity-->
<string name="navigation_drawer_open">Открыть меню навигации</string>
<string name="navigation_drawer_close">Закрыть меню навигации</string>
<string name="magiskhide">Magisk Hide</string>
<string name="modules">Модули</string>
<string name="downloads">Загрузки</string>
<string name="superuser">Суперпользователь</string>
<string name="log">Лог</string>
<string name="settings">Настройки</string>
<string name="status">Статус</string>
<string name="install">Установка</string>
<!--Status Fragment-->
<string name="magisk_version">Установлен Magisk v%1$s</string>
<string name="magisk_version_disable">Magisk v%1$s выключен</string>
<string name="magisk_version_error">Magisk не установлен</string>
<string name="checking_for_updates">Проверка обновлений…</string>
<string name="magisk_update_available">Доступен Magisk v%1$.1f!</string>
<string name="cannot_check_updates">Невозможно проверить обновления, нет соединения?</string>
<string name="up_to_date">Установлена последняя версия %1$s</string>
<string name="root_error">Рут есть, но нет разрешения, не разрешено?</string>
<string name="not_rooted">Нет рута</string>
<string name="proper_root">Рут получен правильно</string>
<string name="safetyNet_check_text">Нажмите для запуска проверки SafetyNet</string>
<string name="checking_safetyNet_status">Проверка статуса SafetyNet…</string>
<string name="safetyNet_connection_failed">Невозможно соединиться с API Google</string>
<string name="safetyNet_connection_suspended">Соединение с API Google было приостановлено</string>
<string name="safetyNet_error">Невозможно выполнить проверку SafetyNet, нет соединения?</string>
<string name="safetyNet_fail">SafetyNet не пройден: несовпадение профиля CTS</string>
<string name="safetyNet_pass">SafetyNet пройден</string>
<string name="root_info_warning">Функциональность значительно ограничена</string>
<!--Install Fragment-->
<string name="auto_detect">"(Авто) %1$s"</string>
<string name="boot_image_title">Местоположение образа Boot</string>
<string name="detect_button">Определить</string>
<string name="advanced_settings_title">Дополнительные настройки</string>
<string name="keep_force_encryption">Оставить шифрование</string>
<string name="keep_dm_verity">Оставить dm-verity</string>
<string name="current_magisk_title">Установленная версия Magisk: v%1$s</string>
<string name="install_magisk_title">Последняя версия Magisk: v%1$.1f</string>
<string name="uninstall">Удалить</string>
<string name="reboot_countdown">Перезагрузка через %1$d</string>
<!--Module Fragment-->
<string name="no_info_provided">(Нет информации)</string>
<string name="no_modules_found">Модули не найдены</string>
<string name="update_file_created">Модуль будет обновлён при перезагрузке</string>
<string name="remove_file_created">Модуль будет удалён при перезагрузке</string>
<string name="remove_file_deleted">Модуль не будет удалён при перезагрузке</string>
<string name="disable_file_created">Модуль будет выключён при перезагрузке</string>
<string name="disable_file_removed">Модуль будет включён при перезагрузке</string>
<string name="author">Автор: %1$s</string>
<string name="fab_flash_zip">Прошить модуль из zip-архива</string>
<!--Repo Fragment-->
<string name="update_available">Доступно обновление</string>
<string name="installed">Установлен</string>
<string name="not_installed">Не установлен</string>
<string name="changelog">Изменения</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Сохранить на SD-карту</string>
<string name="menuReload">Обновить</string>
<string name="menuClearLog">Очистить</string>
<string name="logs_cleared">Лог успешно очищен</string>
<string name="log_is_empty">Лог пуст</string>
<string name="logs_save_failed">Не удалось сохранить лог на SD-карту:</string>
<!--About Activity-->
<string name="about">О приложении</string>
<string name="app_developers">Основные разработчики</string>
<string name="app_developers_"><![CDATA[Приложение создано <a href="https://github.com/topjohnwu">topjohnwu</a> совместно с <a href="https://github.com/d8ahazard">Digitalhigh</a> и <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
<string name="app_changelog">Список изменений</string>
<string name="translators">Exalm</string>
<string name="app_version">Версия</string>
<string name="app_source_code">Исходный код</string>
<string name="donation">Пожертвовать</string>
<string name="app_translators">Переводчики</string>
<string name="support_thread">Страница поддержки</string>
<!--Toasts, Dialogs-->
<string name="permissionNotGranted">Это не будет работать без доступа к внешнему хранилищу</string>
<string name="no_thanks">Нет, спасибо</string>
<string name="yes">Да</string>
<string name="repo_install_title">Установить %1$s</string>
<string name="repo_install_msg">Вы хотите установить %1$s ?</string>
<string name="download_install">Скачать и установить</string>
<string name="goto_install">Перейти в раздел «Установка»</string>
<string name="download_file_error">Ошибка при скачивании файла</string>
<string name="install_error">Ошибка при установке!</string>
<string name="manual_install_1">Zip-файл помещён в %1$s</string>
<string name="manual_install_2">Прошейте руками через рекавери</string>а
<string name="invalid_zip">Этот архив не содержит модуль Magisk!!</string>
<string name="reboot_title">Установка успешна!</string>
<string name="reboot_msg">Вы хотите перезагрузиться?</string>
<string name="reboot">Перезагрузка</string>
<string name="copying_msg">Копирование архива во временную директорию</string>
<string name="zip_install_progress_title">Установка</string>
<string name="zip_install_unzip_zip_msg">Распаковка zip-файла…</string>
<string name="zip_install_process_zip_msg">Обработка zip-файла…</string>
<string name="zip_install_progress_msg">"Установка %1$s…"</string>
<string name="no_magisk_title">Magisk не установлен!</string>
<string name="no_magisk_msg">Вы хотите скачать и установить Magisk?</string>
<string name="downloading_toast">Скачивание %1$s</string>
<string name="magisk_update_title">Доступно обновление Magisk!</string>
<string name="magisk_update_message">Вышел Magisk версии v%1$.1f, установить?</string>
<string name="settings_reboot_toast">Перезагрузитесь для применения изменений</string>
<string name="check_release_notes">Посмотреть примечания к выпуску</string>
<string name="repo_cache_cleared">Кэш репозиториев очищен</string>
<string name="safetyNet_hide_notice">Это приложение использует SafetyNet\nУже обработано MagiskHide по умолчанию</string>
<string name="start_magiskhide">Запуск MagiskHide…</string>
<string name="no_magisksu_title">MagiskSU не используется!</string>
<string name="no_magisksu_msg">Если рут получен не через MagiskSU, использования MagiskHide может не хватить!\nЭто официально не поддерживается, и вам могут понадобиться дополнительные инструменты (например, suhide), чтобы пройти SafetyNet.</string>
<string name="understand">Я понимаю</string>
<!--Settings Activity -->
<string name="settings_general_category">Основные</string>
<string name="settings_dark_theme_title">Тёмная тема</string>
<string name="settings_dark_theme_summary">Включить тёмную тему</string>
<string name="settings_clear_cache_title">Очистить кэш репозиториев</string>
<string name="settings_clear_cache_summary">Удалить сохранённую информацию о сетевых репозиториях, чтобы приложение обновило информацию из сети</string>
<string name="settings_disable_title">Отключить Magisk</string>
<string name="settings_disable_summary">Будет выключено все, кроме рута (MagiskSU)</string>
<string name="settings_magiskhide_summary">Скрыть Magisk от различных проверок</string>
<string name="settings_busybox_title">Включить BusyBox</string>
<string name="settings_busybox_summary">Примонтировать встроенный busybox из Magisk в xbin</string>
<string name="settings_hosts_title">Включить Systemless hosts</string>
<string name="settings_hosts_summary">Поддержа Systemless hosts для блокировщиков рекламы</string>
<string name="settings_su_app_adb">Для приложений и ADB</string>
<string name="settings_su_app">Только для приложений</string>
<string name="settings_su_adb">Только для ADB</string>
<string name="settings_su_disable">Выключен</string>
<string name="settings_su_request_10">10 секунд</string>
<string name="settings_su_request_20">20 секунд</string>
<string name="settings_su_request_30">30 секунд</string>
<string name="settings_su_request_60">60 секунд</string>
<string name="superuser_access">Доступ суперпользователя</string>
<string name="auto_response">Автоматический ответ</string>
<string name="request_timeout">Таймаут запроса</string>
<string name="superuser_notification">Уведомление суперпользователя</string>
<string name="request_timeout_summary">%1$s секунд</string>
<string name="settings_development_category">Разработка</string>
<string name="settings_developer_logging_title">Включить подробное логгирование</string>
<string name="settings_developer_logging_summary">Нажмите, чтобы включить подробную запись</string>
<string name="settings_shell_logging_title">Включить подробное логгирование команд оболочки</string>
<string name="settings_shell_logging_summary">Нажмите, чтобы включить запись всех команд оболочки и их вывод</string>
<!--Superuser-->
<string name="su_request_title">Запрос прав суперпользователя</string>
<string name="deny_with_str">Отказать %1$s</string>
<string name="deny">Отказать</string>
<string name="prompt">Запрос</string>
<string name="grant">Предоставить</string>
<string name="su_warning">Предоставить полный доступ к устройству.\nОтклоните, если не уверены!</string>
<string name="forever">Навсегда</string>
<string name="once">Один раз</string>
<string name="tenmin">На 10 минут</string>
<string name="twentymin">На 20 минут</string>
<string name="thirtymin">На 30 минут</string>
<string name="sixtymin">На 60 минут</string>
<string name="su_allow_toast">Права суперпользователя предоставлены для %1$s</string>
<string name="su_deny_toast">Отказано в получении прав суперпользователя для %1$s</string>
<string name="no_apps_found">Приложения не найдены</string>
<string name="su_snack_grant">Права суперпользователя предоставлены для %1$s</string>
<string name="su_snack_deny">Права суперпользователя для %1$s не предоставлены</string>
<string name="su_snack_notif_on">Включены уведомления для %1$s</string>
<string name="su_snack_notif_off">Выключены уведомления для %1$s</string>
<string name="su_snack_log_on">Включено логгирование для %1$s</string>
<string name="su_snack_log_off">Выключено логгирование для %1$s</string>
<string name="su_snack_revoke">Права для %1$s убраны</string>
<string name="su_revoke_title">Убрать?</string>
<string name="su_revoke_msg">Вы действительно хотите убрать права суперпользователя для %1$s?</string>
<string name="toast">Сообщение</string>
<string name="none">Ничего</string>
<!--Superuser logs-->
<string name="pid">PID:\u0020</string>
<string name="target_uid">Идентификатор UID:\u0020</string>
<string name="command">Команда:\u0020</string>
</resources>