Compare commits

...

23 Commits

Author SHA1 Message Date
topjohnwu
3550d1e61c Bump version 2017-07-19 00:38:25 +08:00
topjohnwu
6513ad249c Fix string.xml 2017-07-19 00:36:54 +08:00
killer7mod
50297b1880 update strings.xml portuguese brazil 2017-07-19 00:25:36 +08:00
#DarkBasic - BasicHD
f189b78b9e #DBC01 - Translation update 2017-07-19 00:25:23 +08:00
zertyuiop
5c0250f495 Fix too long string
checking_safetyNet_status string is too long.
2017-07-19 00:24:47 +08:00
pavlaras
2093f726e9 Update strings.xml
corrected Greek translation
2017-07-19 00:24:36 +08:00
topjohnwu
10efe3859d Update repo fragment and adapter 2017-07-18 23:18:57 +08:00
topjohnwu
6933bcf7bb Merge shells 2017-07-18 17:14:42 +08:00
topjohnwu
2ea046cd80 Add flashing screen 2017-07-18 17:14:42 +08:00
topjohnwu
f4097a372b Root shell with no outputs 2017-07-18 01:06:05 +08:00
topjohnwu
87ea2a2bef Rewrite root shell 2017-07-16 03:00:01 +08:00
JpegXguy
cc14a1c361 Fix untranslated strings 2017-07-15 01:23:59 +08:00
topjohnwu
bcdface60d Fix crashing when installing modules 2017-07-15 01:22:00 +08:00
topjohnwu
4dc9419d2e Bump version 2017-07-14 02:31:29 +08:00
topjohnwu
d2bcac813e Fix update notifications on Android O 2017-07-14 02:27:02 +08:00
topjohnwu
080c37a7f6 Remove busybox from strings 2017-07-14 01:18:20 +08:00
topjohnwu
f9a3838db6 Fix strings 2017-07-13 15:37:00 +08:00
JpegXguy
1e61db104b Added Greek Language 2017-07-13 15:22:53 +08:00
Generator
30a9c7718d Added (European) Portuguese
Split Portuguese into pt_BR and pt_PT
2017-07-13 15:22:40 +08:00
Dmitry Val'd
34b052b5d3 Update strings.xml
Full and correct translation to russian language
2017-07-13 15:21:27 +08:00
topjohnwu
aaa12853ad Prevent crashing when requesting SN check while checking
Fixed #208, fixed #212
2017-07-13 15:12:43 +08:00
topjohnwu
b0ab55b0bf Only show one notification at a time 2017-07-13 14:51:12 +08:00
topjohnwu
d2f8496f4e Update dependency 2017-07-13 14:47:47 +08:00
51 changed files with 1395 additions and 1067 deletions

View File

@@ -8,8 +8,8 @@ android {
applicationId "com.topjohnwu.magisk"
minSdkVersion 21
targetSdkVersion 26
versionCode 44
versionName "5.0.4"
versionCode 50
versionName "5.1.0"
ndk {
moduleName 'zipadjust'
abiFilters 'x86', 'armeabi-v7a'
@@ -52,12 +52,12 @@ dependencies {
implementation 'com.android.support:cardview-v7:26.0.0-beta2'
implementation 'com.android.support:design:26.0.0-beta2'
implementation 'com.android.support:support-v4:26.0.0-beta2'
implementation 'com.jakewharton:butterknife:8.6.0'
implementation 'com.jakewharton:butterknife:8.7.0'
implementation 'com.thoughtbot:expandablerecyclerview:1.4'
implementation 'us.feras.mdv:markdownview:1.1.0'
implementation 'com.madgag.spongycastle:core:1.54.0.0'
implementation 'com.madgag.spongycastle:prov:1.54.0.0'
implementation 'com.madgag.spongycastle:pkix:1.54.0.0'
implementation 'com.google.android.gms:play-services-safetynet:9.0.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
}

View File

@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
package="com.topjohnwu.magisk"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.topjohnwu.magisk">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application
android:name=".MagiskManager"
@@ -21,8 +21,7 @@
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:exported="true"/>
android:exported="true" />
<activity
android:name=".SplashActivity"
android:configChanges="orientation|screenSize"
@@ -30,16 +29,22 @@
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".AboutActivity"
android:theme="@style/AppTheme.Transparent"/>
android:theme="@style/AppTheme.Transparent" />
<activity
android:name=".SettingsActivity"
android:theme="@style/AppTheme.Transparent" />
<activity
android:name=".FlashActivity"
android:screenOrientation="nosensor"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/AppTheme.Transparent" />
<activity
android:name=".superuser.RequestActivity"
android:excludeFromRecents="true"
@@ -53,29 +58,26 @@
android:theme="@style/SuRequest" />
<receiver android:name=".superuser.SuReceiver" />
<receiver android:name=".receivers.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".receivers.PackageReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<receiver android:name=".receivers.ManagerUpdate" />
<service android:name=".services.OnBootIntentService" />
<service
android:name=".services.UpdateCheckService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true" />
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
<provider
android:name="android.support.v4.content.FileProvider"
@@ -93,4 +95,4 @@
</application>
</manifest>
</manifest>

View File

@@ -0,0 +1,98 @@
package com.topjohnwu.magisk;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.topjohnwu.magisk.asyncs.FlashZip;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.AdaptiveList;
import com.topjohnwu.magisk.utils.Shell;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class FlashActivity extends Activity {
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.flash_logs) RecyclerView flashLogs;
@BindView(R.id.button_panel) LinearLayout buttonPanel;
private AdaptiveList<String> rootShellOutput;
@OnClick(R.id.no_thanks)
public void dismiss() {
finish();
}
@OnClick(R.id.reboot)
public void reboot() {
Shell.getShell(this).su_raw("reboot");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flash);
ButterKnife.bind(this);
rootShellOutput = new AdaptiveList<>(flashLogs);
setSupportActionBar(toolbar);
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setTitle(R.string.flashing);
}
setFloating();
flashLogs.setAdapter(new FlashLogAdapter());
// We must receive a Uri of the target zip
Uri uri = getIntent().getData();
new FlashZip(this, uri, rootShellOutput)
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
.exec();
}
@Override
public void onBackPressed() {
// Prevent user accidentally press back button
}
private class FlashLogAdapter extends RecyclerView.Adapter<ViewHolder> {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item_flashlog, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.text.setText(rootShellOutput.get(position));
}
@Override
public int getItemCount() {
return rootShellOutput.size();
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.textView) TextView text;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}

View File

@@ -25,7 +25,6 @@ import android.widget.Spinner;
import android.widget.TextView;
import com.topjohnwu.magisk.asyncs.CheckUpdates;
import com.topjohnwu.magisk.asyncs.ProcessMagiskZip;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.components.SnackbarMaker;
@@ -104,25 +103,18 @@ public class MagiskFragment extends Fragment
collapse();
}
@OnClick(R.id.detect_bootimage)
public void toAutoDetect() {
if (magiskManager.bootBlock != null) {
spinner.setSelection(0);
}
}
@OnClick(R.id.install_button)
public void install() {
String bootImage = null;
if (magiskManager.blockList != null) {
int idx = spinner.getSelectedItemPosition();
if (Shell.rootAccess()) {
if (magiskManager.bootBlock != null) {
bootImage = magiskManager.bootBlock;
} else {
int idx = spinner.getSelectedItemPosition();
if (idx > 0) {
bootImage = magiskManager.blockList.get(idx - 1);
} else {
SnackbarMaker.make(getActivity(), R.string.manual_boot_image, Snackbar.LENGTH_LONG);
SnackbarMaker.make(getActivity(), R.string.manual_boot_image, Snackbar.LENGTH_LONG).show();
return;
}
}
@@ -134,21 +126,32 @@ public class MagiskFragment extends Fragment
.setMessage(getString(R.string.repo_install_msg, filename))
.setCancelable(true)
.setPositiveButton(Shell.rootAccess() ? R.string.install : R.string.download,
(dialogInterface, i) -> Utils.dlAndReceive(
getActivity(),
new DownloadReceiver() {
private String boot = finalBootImage;
private boolean enc = keepEncChkbox.isChecked();
private boolean verity = keepVerityChkbox.isChecked();
(d, i) ->
Utils.dlAndReceive(
getActivity(),
new DownloadReceiver() {
private String boot = finalBootImage;
private boolean enc = keepEncChkbox.isChecked();
private boolean verity = keepVerityChkbox.isChecked();
@Override
public void onDownloadDone(Uri uri) {
new ProcessMagiskZip(getActivity(), uri, boot, enc, verity).exec();
}
},
magiskManager.magiskLink,
Utils.getLegalFilename(filename)))
.setNeutralButton(R.string.release_notes, (dialog, which) -> {
@Override
public void onDownloadDone(Uri uri) {
if (Shell.rootAccess()) {
magiskManager.shell.su_raw(
"rm -f /dev/.magisk",
"echo \"BOOTIMAGE=" + boot + "\" >> /dev/.magisk",
"echo \"KEEPFORCEENCRYPT=" + String.valueOf(enc) + "\" >> /dev/.magisk",
"echo \"KEEPVERITY=" + String.valueOf(verity) + "\" >> /dev/.magisk"
);
startActivity(new Intent(getActivity(), FlashActivity.class).setData(uri));
} else {
Utils.showUriSnack(getActivity(), uri);
}
}
},
magiskManager.magiskLink,
Utils.getLegalFilename(filename)))
.setNeutralButton(R.string.release_notes, (d, i) -> {
if (magiskManager.releaseNoteLink != null) {
Intent openReleaseNoteLink = new Intent(Intent.ACTION_VIEW, Uri.parse(magiskManager.releaseNoteLink));
openReleaseNoteLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -196,7 +199,7 @@ public class MagiskFragment extends Fragment
@Override
public void onFinish() {
progress.setMessage(getString(R.string.reboot_countdown, 0));
Shell.su(true,
magiskManager.shell.su_raw(
"mv -f " + uninstaller + " /cache/" + MagiskManager.UNINSTALLER,
"mv -f " + utils + " /data/magisk/" + MagiskManager.UTIL_FUNCTIONS,
"reboot"
@@ -285,8 +288,6 @@ public class MagiskFragment extends Fragment
updateCheckUI();
} else if (event == magiskManager.safetyNetDone) {
updateSafetyNetUI();
} else if (event == magiskManager.blockDetectionDone) {
updateInstallUI();
}
}
@@ -298,11 +299,8 @@ public class MagiskFragment extends Fragment
updateCheckUI();
if (magiskManager.safetyNetDone.isTriggered)
updateSafetyNetUI();
if (magiskManager.blockDetectionDone.isTriggered || !Shell.rootAccess())
updateInstallUI();
magiskManager.updateCheckDone.register(this);
magiskManager.safetyNetDone.register(this);
magiskManager.blockDetectionDone.register(this);
getActivity().setTitle(R.string.magisk);
}
@@ -310,7 +308,6 @@ public class MagiskFragment extends Fragment
public void onStop() {
magiskManager.updateCheckDone.unRegister(this);
magiskManager.safetyNetDone.unRegister(this);
magiskManager.blockDetectionDone.unRegister(this);
super.onStop();
}
@@ -322,6 +319,8 @@ public class MagiskFragment extends Fragment
private void updateUI() {
((MainActivity) getActivity()).checkHideSection();
magiskManager.updateMagiskInfo();
final int ROOT = 0x1, NETWORK = 0x2, UPTODATE = 0x4;
int status = 0;
status |= Shell.rootAccess() ? ROOT : 0;
@@ -333,14 +332,9 @@ public class MagiskFragment extends Fragment
installOptionCard.setVisibility(Utils.checkBits(status, NETWORK, ROOT) ? View.VISIBLE : View.GONE);
installButton.setVisibility(Utils.checkBits(status, NETWORK) ? View.VISIBLE : View.GONE);
uninstallButton.setVisibility(Utils.checkBits(status, UPTODATE, ROOT) ? View.VISIBLE : View.GONE);
updateVersionUI();
}
private void updateVersionUI() {
int image, color;
magiskManager.updateMagiskInfo();
if (magiskManager.magiskVersionCode < 0) {
color = colorBad;
image = R.drawable.ic_cancel;
@@ -376,6 +370,25 @@ public class MagiskFragment extends Fragment
rootStatusIcon.setImageResource(image);
rootStatusIcon.setColorFilter(color);
if (!Shell.rootAccess()) {
installText.setText(R.string.download);
} else {
installText.setText(R.string.download_install);
List<String> items = new ArrayList<>();
if (magiskManager.bootBlock != null) {
items.add(getString(R.string.auto_detect, magiskManager.bootBlock));
spinner.setEnabled(false);
} else {
items.add(getString(R.string.cannot_auto_detect));
items.addAll(magiskManager.blockList);
}
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
}
}
private void updateCheckUI() {
@@ -399,28 +412,6 @@ public class MagiskFragment extends Fragment
mSwipeRefreshLayout.setRefreshing(false);
}
private void updateInstallUI() {
if (!Shell.rootAccess()) {
installText.setText(R.string.download);
} else {
installText.setText(R.string.download_install);
List<String> items = new ArrayList<>();
if (magiskManager.bootBlock != null) {
items.add(getString(R.string.auto_detect, magiskManager.bootBlock));
spinner.setEnabled(false);
} else {
items.add(getString(R.string.cannot_auto_detect));
items.addAll(magiskManager.blockList);
}
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
toAutoDetect();
}
}
private void updateSafetyNetUI() {
int image, color;
safetyNetProgress.setVisibility(View.GONE);

View File

@@ -2,6 +2,7 @@ package com.topjohnwu.magisk;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
@@ -24,10 +25,9 @@ import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.topjohnwu.magisk.asyncs.RootTask;
import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.io.File;
@@ -67,7 +67,7 @@ public class MagiskLogFragment extends Fragment {
txtLog.setTextIsSelectable(true);
new LogManager().read();
new LogManager(getActivity()).read();
return view;
}
@@ -81,7 +81,7 @@ public class MagiskLogFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
new LogManager().read();
new LogManager(getActivity()).read();
}
@Override
@@ -100,13 +100,13 @@ public class MagiskLogFragment extends Fragment {
mClickedMenuItem = item;
switch (item.getItemId()) {
case R.id.menu_refresh:
new LogManager().read();
new LogManager(getActivity()).read();
return true;
case R.id.menu_save:
new LogManager().save();
new LogManager(getActivity()).save();
return true;
case R.id.menu_clear:
new LogManager().clear();
new LogManager(getActivity()).clear();
return true;
default:
return true;
@@ -127,18 +127,22 @@ public class MagiskLogFragment extends Fragment {
}
}
private class LogManager extends RootTask<Object, Void, Object> {
private class LogManager extends ParallelTask<Object, Void, Object> {
int mode;
File targetFile;
LogManager(Activity activity) {
super(activity);
}
@SuppressLint("DefaultLocale")
@Override
protected Object doInRoot(Object... params) {
protected Object doInBackground(Object... params) {
mode = (int) params[0];
switch (mode) {
case 0:
List<String> logList = Utils.readFile(MAGISK_LOG);
List<String> logList = Utils.readFile(magiskManager.shell, MAGISK_LOG);
if (Utils.isValidShellResponse(logList)) {
StringBuilder llog = new StringBuilder(15 * 10 * 1024);
@@ -150,7 +154,7 @@ public class MagiskLogFragment extends Fragment {
return "";
case 1:
Shell.su("echo > " + MAGISK_LOG);
magiskManager.shell.su_raw("echo > " + MAGISK_LOG);
SnackbarMaker.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
return "";
@@ -180,7 +184,7 @@ public class MagiskLogFragment extends Fragment {
return false;
}
List<String> in = Utils.readFile(MAGISK_LOG);
List<String> in = Utils.readFile(magiskManager.shell, MAGISK_LOG);
if (Utils.isValidShellResponse(in)) {
try (FileWriter out = new FileWriter(targetFile)) {

View File

@@ -1,8 +1,12 @@
package com.topjohnwu.magisk;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.text.TextUtils;
@@ -31,9 +35,9 @@ public class MagiskManager extends Application {
public static final String BUSYBOX_VERSION = "1.26.2";
public static final String MAGISKHIDE_PROP = "persist.magisk.hide";
public static final String DISABLE_INDICATION_PROP = "ro.magisk.disable";
public static final String NOTIFICATION_CHANNEL = "magisk_update_notice";
// Events
public final CallbackEvent<Void> blockDetectionDone = new CallbackEvent<>();
public final CallbackEvent<Void> magiskHideDone = new CallbackEvent<>();
public final CallbackEvent<Void> reloadMainActivity = new CallbackEvent<>();
public final CallbackEvent<Void> moduleLoadDone = new CallbackEvent<>();
@@ -83,13 +87,16 @@ public class MagiskManager extends Application {
// Global resources
public SharedPreferences prefs;
public SuDatabaseHelper suDB;
public Shell shell;
private static Handler mHandler = new Handler();
@Override
public void onCreate() {
super.onCreate();
new File(getApplicationInfo().dataDir).mkdirs(); /* Create the app data directory */
prefs = PreferenceManager.getDefaultSharedPreferences(this);
shell = Shell.getShell();
}
public void toast(String msg, int duration) {
@@ -112,14 +119,13 @@ public class MagiskManager extends Application {
magiskHide = prefs.getBoolean("magiskhide", true);
updateNotification = prefs.getBoolean("notification", true);
initSU();
// Always start a new root shell manually, just for safety
Shell.init();
updateMagiskInfo();
updateBlockInfo();
// Initialize busybox
File busybox = new File(getApplicationInfo().dataDir + "/busybox/busybox");
if (!busybox.exists() || !TextUtils.equals(prefs.getString("busybox_version", ""), BUSYBOX_VERSION)) {
busybox.getParentFile().mkdirs();
Shell.su(
shell.su_raw(
"cp -f " + new File(getApplicationInfo().nativeLibraryDir, "libbusybox.so") + " " + busybox,
"chmod -R 755 " + busybox.getParent(),
busybox + " --install -s " + busybox.getParent()
@@ -131,7 +137,7 @@ public class MagiskManager extends Application {
.putBoolean("magiskhide", magiskHide)
.putBoolean("notification", updateNotification)
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
.putBoolean("disable", Utils.itemExist(shell, MAGISK_DISABLE_FILE))
.putBoolean("su_reauth", suReauth)
.putString("su_request_timeout", String.valueOf(suRequestTimeout))
.putString("su_auto_response", String.valueOf(suResponseType))
@@ -142,7 +148,15 @@ public class MagiskManager extends Application {
.putString("busybox_version", BUSYBOX_VERSION)
.apply();
// Add busybox to PATH
Shell.su("PATH=$PATH:" + busybox.getParent());
shell.su_raw("PATH=$PATH:" + busybox.getParent());
// Create notification channel on Android O
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL,
getString(R.string.magisk_updates), NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
}
}
public void initSUConfig() {
@@ -154,12 +168,9 @@ public class MagiskManager extends Application {
}
public void initSU() {
// Create the app data directory, so su binary can work properly
new File(getApplicationInfo().dataDir).mkdirs();
initSUConfig();
List<String> ret = Shell.sh("su -v");
List<String> ret = shell.sh("su -v");
if (Utils.isValidShellResponse(ret)) {
suVersion = ret.get(0);
isSuClient = suVersion.toUpperCase().contains("MAGISK");
@@ -173,9 +184,9 @@ public class MagiskManager extends Application {
public void updateMagiskInfo() {
List<String> ret;
ret = Shell.sh("magisk -v");
ret = shell.sh("magisk -v");
if (!Utils.isValidShellResponse(ret)) {
ret = Shell.sh("getprop magisk.version");
ret = shell.sh("getprop magisk.version");
if (Utils.isValidShellResponse(ret)) {
try {
magiskVersionString = ret.get(0);
@@ -184,24 +195,39 @@ public class MagiskManager extends Application {
}
} else {
magiskVersionString = ret.get(0).split(":")[0];
ret = Shell.sh("magisk -V");
ret = shell.sh("magisk -V");
try {
magiskVersionCode = Integer.parseInt(ret.get(0));
} catch (NumberFormatException ignored) {}
}
ret = Shell.sh("getprop " + DISABLE_INDICATION_PROP);
ret = shell.sh("getprop " + DISABLE_INDICATION_PROP);
try {
disabled = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
} catch (NumberFormatException e) {
disabled = false;
}
ret = Shell.sh("getprop " + MAGISKHIDE_PROP);
ret = shell.sh("getprop " + MAGISKHIDE_PROP);
try {
magiskHide = !Utils.isValidShellResponse(ret) || Integer.parseInt(ret.get(0)) != 0;
} catch (NumberFormatException e) {
magiskHide = true;
}
}
public void updateBlockInfo() {
List<String> res = shell.su(
"for BLOCK in boot_a BOOT_A kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do",
"BOOTIMAGE=`ls /dev/block/by-name/$BLOCK || ls /dev/block/platform/*/by-name/$BLOCK || ls /dev/block/platform/*/*/by-name/$BLOCK` 2>/dev/null",
"[ ! -z \"$BOOTIMAGE\" ] && break",
"done",
"[ ! -z \"$BOOTIMAGE\" -a -L \"$BOOTIMAGE\" ] && BOOTIMAGE=`readlink $BOOTIMAGE`",
"echo \"$BOOTIMAGE\""
);
if (Utils.isValidShellResponse(res)) {
bootBlock = res.get(0);
} else {
blockList = shell.su("ls -d /dev/block/mmc* /dev/block/sd* 2>/dev/null");
}
}
}

View File

@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
@@ -14,7 +13,6 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.topjohnwu.magisk.adapters.ModulesAdapter;
import com.topjohnwu.magisk.asyncs.FlashZip;
import com.topjohnwu.magisk.asyncs.LoadModules;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.module.Module;
@@ -86,8 +84,9 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener<
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) {
// Get the URI of the selected file
final Uri uri = data.getData();
new FlashZip(getActivity(), uri).exec();
Intent intent = new Intent(getActivity(), FlashActivity.class);
intent.setData(data.getData()).putExtra("ACTION", "flash");
startActivity(intent);
}
}

View File

@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -14,18 +13,11 @@ import android.widget.SearchView;
import android.widget.TextView;
import com.topjohnwu.magisk.adapters.ReposAdapter;
import com.topjohnwu.magisk.adapters.SimpleSectionedRecyclerViewAdapter;
import com.topjohnwu.magisk.asyncs.LoadRepos;
import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.Logger;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
@@ -37,16 +29,7 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
@BindView(R.id.empty_rv) TextView emptyRv;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
private List<Repo> mUpdateRepos = new ArrayList<>();
private List<Repo> mInstalledRepos = new ArrayList<>();
private List<Repo> mOthersRepos = new ArrayList<>();
private List<Repo> fUpdateRepos = new ArrayList<>();
private List<Repo> fInstalledRepos = new ArrayList<>();
private List<Repo> fOthersRepos = new ArrayList<>();
private SimpleSectionedRecyclerViewAdapter mSectionedAdapter;
private SearchView.OnQueryTextListener searchListener;
private ReposAdapter adapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -60,10 +43,9 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
View view = inflater.inflate(R.layout.fragment_repos, container, false);
unbinder = ButterKnife.bind(this, view);
mSectionedAdapter = new SimpleSectionedRecyclerViewAdapter(R.layout.section,
R.id.section_text, new ReposAdapter(fUpdateRepos, fInstalledRepos, fOthersRepos));
adapter = new ReposAdapter(getApplication().repoMap);
recyclerView.setAdapter(mSectionedAdapter);
recyclerView.setAdapter(adapter);
mSwipeRefreshLayout.setRefreshing(true);
@@ -73,38 +55,42 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
});
if (getApplication().repoLoadDone.isTriggered) {
reloadRepos();
updateUI();
onTrigger(null);
}
searchListener = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
new FilterApps().exec(newText);
return false;
}
};
return view;
}
@Override
public void onTrigger(CallbackEvent<Void> event) {
Logger.dev("ReposFragment: UI refresh triggered");
reloadRepos();
updateUI();
if (getApplication().repoMap.isEmpty()) {
recyclerView.setVisibility(View.GONE);
emptyRv.setVisibility(View.VISIBLE);
} else {
adapter.filter(getApplication().moduleMap, "");
recyclerView.setVisibility(View.VISIBLE);
emptyRv.setVisibility(View.GONE);
mSwipeRefreshLayout.setRefreshing(false);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_repo, menu);
SearchView search = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.repo_search));
search.setOnQueryTextListener(searchListener);
SearchView search = (SearchView) menu.findItem(R.id.repo_search).getActionView();
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.filter(getApplication().moduleMap, newText);
return false;
}
});
}
@Override
@@ -125,92 +111,4 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
super.onDestroyView();
unbinder.unbind();
}
private void reloadRepos() {
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();
fUpdateRepos.addAll(mUpdateRepos);
fInstalledRepos.addAll(mInstalledRepos);
fOthersRepos.addAll(mOthersRepos);
}
private void updateUI() {
if (fUpdateRepos.size() + fInstalledRepos.size() + fOthersRepos.size() == 0) {
emptyRv.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
List<SimpleSectionedRecyclerViewAdapter.Section> sections = new ArrayList<>();
if (!fUpdateRepos.isEmpty()) {
sections.add(new SimpleSectionedRecyclerViewAdapter.Section(0, getString(R.string.update_available)));
}
if (!fInstalledRepos.isEmpty()) {
sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size(), getString(R.string.installed)));
}
if (!fOthersRepos.isEmpty()) {
sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size() + fInstalledRepos.size(), getString(R.string.not_installed)));
}
SimpleSectionedRecyclerViewAdapter.Section[] array = sections.toArray(new SimpleSectionedRecyclerViewAdapter.Section[sections.size()]);
mSectionedAdapter.setSections(array);
emptyRv.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}
mSwipeRefreshLayout.setRefreshing(false);
}
private class FilterApps extends ParallelTask<String, Void, Void> {
@Override
protected Void doInBackground(String... strings) {
String newText = strings[0];
fUpdateRepos.clear();
fInstalledRepos.clear();
fOthersRepos.clear();
for (Repo repo: mUpdateRepos) {
if (repo.getName().toLowerCase().contains(newText.toLowerCase())
|| repo.getAuthor().toLowerCase().contains(newText.toLowerCase())
|| repo.getDescription().toLowerCase().contains(newText.toLowerCase())
) {
fUpdateRepos.add(repo);
}
}
for (Repo repo: mInstalledRepos) {
if (repo.getName().toLowerCase().contains(newText.toLowerCase())
|| repo.getAuthor().toLowerCase().contains(newText.toLowerCase())
|| repo.getDescription().toLowerCase().contains(newText.toLowerCase())
) {
fInstalledRepos.add(repo);
}
}
for (Repo repo: mOthersRepos) {
if (repo.getName().toLowerCase().contains(newText.toLowerCase())
|| repo.getAuthor().toLowerCase().contains(newText.toLowerCase())
|| repo.getDescription().toLowerCase().contains(newText.toLowerCase())
) {
fOthersRepos.add(repo);
}
}
return null;
}
@Override
protected void onPostExecute(Void v) {
updateUI();
}
}
}

View File

@@ -149,9 +149,9 @@ public class SettingsActivity extends Activity {
case "disable":
enabled = prefs.getBoolean("disable", false);
if (enabled) {
Utils.createFile(MagiskManager.MAGISK_DISABLE_FILE);
Utils.createFile(magiskManager.shell, MagiskManager.MAGISK_DISABLE_FILE);
} else {
Utils.removeItem(MagiskManager.MAGISK_DISABLE_FILE);
Utils.removeItem(magiskManager.shell, MagiskManager.MAGISK_DISABLE_FILE);
}
Toast.makeText(getActivity(), R.string.settings_reboot_toast, Toast.LENGTH_LONG).show();
break;
@@ -162,24 +162,24 @@ public class SettingsActivity extends Activity {
new AlertDialogBuilder(getActivity())
.setTitle(R.string.no_magisksu_title)
.setMessage(R.string.no_magisksu_msg)
.setPositiveButton(R.string.understand, (dialog, which) -> new MagiskHide().enable())
.setPositiveButton(R.string.understand, (dialog, which) -> new MagiskHide(getActivity()).enable())
.setCancelable(false)
.show();
} else {
new MagiskHide().enable();
new MagiskHide(getActivity()).enable();
}
} else {
new MagiskHide().disable();
new MagiskHide(getActivity()).disable();
}
break;
case "hosts":
enabled = prefs.getBoolean("hosts", false);
if (enabled) {
Shell.su_async(null,
magiskManager.shell.su_raw(
"cp -af /system/etc/hosts /magisk/.core/hosts",
"mount -o bind /magisk/.core/hosts /system/etc/hosts");
} else {
Shell.su_async(null,
magiskManager.shell.su_raw(
"umount -l /system/etc/hosts",
"rm -f /magisk/.core/hosts");
}

View File

@@ -8,7 +8,6 @@ import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import com.topjohnwu.magisk.asyncs.GetBootBlocks;
import com.topjohnwu.magisk.asyncs.LoadApps;
import com.topjohnwu.magisk.asyncs.LoadModules;
import com.topjohnwu.magisk.asyncs.LoadRepos;
@@ -25,12 +24,13 @@ public class SplashActivity extends Activity{
super.onCreate(savedInstanceState);
// Init the info and configs and root shell
// Init the info and configs and root sh
getApplicationContext().init();
// Now fire all async tasks
new GetBootBlocks(this).exec();
new LoadModules(this).setCallBack(() -> new LoadRepos(this).exec()).exec();
new LoadModules(this)
.setCallBack(() -> new LoadRepos(this).exec())
.exec();
new LoadApps(this).exec();
if (Utils.checkNetworkStatus(this)) {

View File

@@ -1,5 +1,6 @@
package com.topjohnwu.magisk.adapters;
import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.support.design.widget.Snackbar;
@@ -86,10 +87,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
holder.checkBox.setChecked(mHideList.contains(info.packageName));
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
if (isChecked) {
new MagiskHide().add(info.packageName);
new MagiskHide((Activity) holder.itemView.getContext()).add(info.packageName);
mHideList.add(info.packageName);
} else {
new MagiskHide().rm(info.packageName);
new MagiskHide((Activity) holder.itemView.getContext()).rm(info.packageName);
mHideList.remove(info.packageName);
}
});

View File

@@ -38,6 +38,7 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Context context = holder.itemView.getContext();
Shell rootShell = Shell.getShell(context);
final Module module = mList.get(position);
String version = module.getVersion();
@@ -55,10 +56,10 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
int snack;
if (isChecked) {
module.removeDisableFile();
module.removeDisableFile(rootShell);
snack = R.string.disable_file_removed;
} else {
module.createDisableFile();
module.createDisableFile(rootShell);
snack = R.string.disable_file_created;
}
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
@@ -68,10 +69,10 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
boolean removed = module.willBeRemoved();
int snack;
if (removed) {
module.deleteRemoveFile();
module.deleteRemoveFile(rootShell);
snack = R.string.remove_file_deleted;
} else {
module.createRemoveFile();
module.createRemoveFile(rootShell);
snack = R.string.remove_file_created;
}
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();

View File

@@ -16,98 +16,184 @@ import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.MarkDownWindow;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.receivers.DownloadReceiver;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ValueSortedMap;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder> {
public class ReposAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int SECTION_TYPE = 0;
private static final int REPO_TYPE = 1;
private List<Repo> mUpdateRepos, mInstalledRepos, mOthersRepos;
private Context mContext;
private int[] sectionList;
private int size;
private ValueSortedMap<String, Repo> repoMap;
public ReposAdapter(List<Repo> update, List<Repo> installed, List<Repo> others) {
mUpdateRepos = update;
mInstalledRepos = installed;
mOthersRepos = others;
public ReposAdapter(ValueSortedMap<String, Repo> map) {
repoMap = map;
mUpdateRepos = new ArrayList<>();
mInstalledRepos = new ArrayList<>();
mOthersRepos = new ArrayList<>();
sectionList = new int[3];
size = 0;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
mContext = parent.getContext();
View v = LayoutInflater.from(mContext).inflate(R.layout.list_item_repo, parent, false);
return new ViewHolder(v);
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
View v;
RecyclerView.ViewHolder holder = null;
switch (viewType) {
case SECTION_TYPE:
v = LayoutInflater.from(context).inflate(R.layout.section, parent, false);
holder = new SectionHolder(v);
break;
case REPO_TYPE:
v = LayoutInflater.from(context).inflate(R.layout.list_item_repo, parent, false);
holder = new RepoHolder(v);
break;
}
return holder;
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Repo repo = getItem(position);
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Context context = holder.itemView.getContext();
switch (getItemViewType(position)) {
case SECTION_TYPE:
SectionHolder section = (SectionHolder) holder;
if (position == sectionList[0]) {
section.sectionText.setText(context.getString(R.string.update_available));
} else if (position == sectionList[1]) {
section.sectionText.setText(context.getString(R.string.installed));
} else {
section.sectionText.setText(context.getString(R.string.not_installed));
}
break;
case REPO_TYPE:
RepoHolder repoHolder = (RepoHolder) holder;
Repo repo = getRepo(position);
repoHolder.title.setText(repo.getName());
repoHolder.versionName.setText(repo.getVersion());
String author = repo.getAuthor();
repoHolder.author.setText(TextUtils.isEmpty(author) ? null : context.getString(R.string.author, author));
repoHolder.description.setText(repo.getDescription());
holder.title.setText(repo.getName());
holder.versionName.setText(repo.getVersion());
String author = repo.getAuthor();
holder.author.setText(TextUtils.isEmpty(author) ? null : mContext.getString(R.string.author, author));
holder.description.setText(repo.getDescription());
repoHolder.infoLayout.setOnClickListener(v -> new MarkDownWindow(null, repo.getDetailUrl(), context));
holder.infoLayout.setOnClickListener(v -> new MarkDownWindow(null, repo.getDetailUrl(), mContext));
repoHolder.downloadImage.setOnClickListener(v -> {
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
new AlertDialogBuilder(context)
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
.setMessage(context.getString(R.string.repo_install_msg, filename))
.setCancelable(true)
.setPositiveButton(R.string.install, (d, i) -> Utils.dlAndReceive(
context,
new DownloadReceiver() {
@Override
public void onDownloadDone(Uri uri) {
new ProcessRepoZip((Activity) context, uri, true).exec();
}
},
repo.getZipUrl(),
Utils.getLegalFilename(filename)))
.setNeutralButton(R.string.download, (d, i) -> Utils.dlAndReceive(
context,
new DownloadReceiver() {
@Override
public void onDownloadDone(Uri uri) {
new ProcessRepoZip((Activity) context, uri, false).exec();
}
},
repo.getZipUrl(),
Utils.getLegalFilename(filename)))
.setNegativeButton(R.string.no_thanks, null)
.show();
});
break;
}
}
holder.downloadImage.setOnClickListener(v -> {
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
new AlertDialogBuilder(mContext)
.setTitle(mContext.getString(R.string.repo_install_title, repo.getName()))
.setMessage(mContext.getString(R.string.repo_install_msg, filename))
.setCancelable(true)
.setPositiveButton(R.string.install, (d, i) -> Utils.dlAndReceive(
mContext,
new DownloadReceiver() {
@Override
public void onDownloadDone(Uri uri) {
Activity activity = (Activity) mContext;
new ProcessRepoZip(activity, uri, true).exec();
}
},
repo.getZipUrl(),
Utils.getLegalFilename(filename)))
.setNeutralButton(R.string.download, (d, i) -> Utils.dlAndReceive(
mContext,
new DownloadReceiver() {
@Override
public void onDownloadDone(Uri uri) {
Activity activity = (Activity) mContext;
new ProcessRepoZip(activity, uri, false).exec();
}
},
repo.getZipUrl(),
Utils.getLegalFilename(filename)))
.setNegativeButton(R.string.no_thanks, null)
.show();
});
@Override
public int getItemViewType(int position) {
for (int i : sectionList) {
if (position == i)
return SECTION_TYPE;
}
return REPO_TYPE;
}
@Override
public int getItemCount() {
return mUpdateRepos.size() + mInstalledRepos.size() + mOthersRepos.size();
return size;
}
private Repo getItem(int position) {
if (position >= mUpdateRepos.size()) {
position -= mUpdateRepos.size();
if (position >= mInstalledRepos.size()) {
position -= mInstalledRepos.size();
return mOthersRepos.get(position);
} else {
return mInstalledRepos.get(position);
public void filter(ValueSortedMap<String, Module> moduleMap, String s) {
mUpdateRepos.clear();
mInstalledRepos.clear();
mOthersRepos.clear();
sectionList[0] = sectionList[1] = sectionList[2] = 0;
for (Repo repo : repoMap.values()) {
if (repo.getName().toLowerCase().contains(s.toLowerCase())
|| repo.getAuthor().toLowerCase().contains(s.toLowerCase())
|| repo.getDescription().toLowerCase().contains(s.toLowerCase())
) {
// Passed the filter
Module module = moduleMap.get(repo.getId());
if (module != null) {
if (repo.getVersionCode() > module.getVersionCode()) {
// Updates
mUpdateRepos.add(repo);
} else {
mInstalledRepos.add(repo);
}
} else {
mOthersRepos.add(repo);
}
}
} else {
return mUpdateRepos.get(position);
}
sectionList[0] = mUpdateRepos.isEmpty() ? -1 : 0;
size = mUpdateRepos.isEmpty() ? 0 : mUpdateRepos.size() + 1;
sectionList[1] = mInstalledRepos.isEmpty() ? -1 : size;
size += mInstalledRepos.isEmpty() ? 0 : mInstalledRepos.size() + 1;
sectionList[2] = mOthersRepos.isEmpty() ? -1 : size;
size += mOthersRepos.isEmpty() ? 0 : mOthersRepos.size() + 1;
notifyDataSetChanged();
}
private Repo getRepo(int position) {
if (!mUpdateRepos.isEmpty()) position -= 1;
if (position < mUpdateRepos.size()) return mUpdateRepos.get(position);
position -= mUpdateRepos.size();
if (!mInstalledRepos.isEmpty()) position -= 1;
if (position < mInstalledRepos.size()) return mInstalledRepos.get(position);
position -= mInstalledRepos.size();
if (!mOthersRepos.isEmpty()) position -= 1;
return mOthersRepos.get(position);
}
static class SectionHolder extends RecyclerView.ViewHolder {
@BindView(R.id.section_text) TextView sectionText;
SectionHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
static class ViewHolder extends RecyclerView.ViewHolder {
static class RepoHolder extends RecyclerView.ViewHolder {
@BindView(R.id.title) TextView title;
@BindView(R.id.version_name) TextView versionName;
@@ -116,7 +202,7 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
@BindView(R.id.info_layout) LinearLayout infoLayout;
@BindView(R.id.download) ImageView downloadImage;
ViewHolder(View itemView) {
RepoHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}

View File

@@ -1,178 +0,0 @@
package com.topjohnwu.magisk.adapters;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.Arrays;
import java.util.Comparator;
public class SimpleSectionedRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int SECTION_TYPE = 0;
private boolean mValid = true;
private int mSectionResourceId;
private int mTextResourceId;
private RecyclerView.Adapter mBaseAdapter;
private SparseArray<Section> mSections = new SparseArray<Section>();
public SimpleSectionedRecyclerViewAdapter(int sectionResourceId, int textResourceId,
RecyclerView.Adapter baseAdapter) {
mSectionResourceId = sectionResourceId;
mTextResourceId = textResourceId;
mBaseAdapter = baseAdapter;
mBaseAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
mValid = mBaseAdapter.getItemCount()>0;
notifyDataSetChanged();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
mValid = mBaseAdapter.getItemCount()>0;
notifyItemRangeChanged(positionStart, itemCount);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
mValid = mBaseAdapter.getItemCount()>0;
notifyItemRangeInserted(positionStart, itemCount);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
mValid = mBaseAdapter.getItemCount()>0;
notifyItemRangeRemoved(positionStart, itemCount);
}
});
}
public static class SectionViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public SectionViewHolder(View view, int mTextResourceid) {
super(view);
title = (TextView) view.findViewById(mTextResourceid);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int typeView) {
if (typeView == SECTION_TYPE) {
View view = LayoutInflater.from(parent.getContext()).inflate(mSectionResourceId, parent, false);
return new SectionViewHolder(view,mTextResourceId);
}else{
return mBaseAdapter.onCreateViewHolder(parent, typeView -1);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder sectionViewHolder, int position) {
if (isSectionHeaderPosition(position)) {
((SectionViewHolder)sectionViewHolder).title.setText(mSections.get(position).title);
}else{
mBaseAdapter.onBindViewHolder(sectionViewHolder,sectionedPositionToPosition(position));
}
}
@Override
public int getItemViewType(int position) {
return isSectionHeaderPosition(position)
? SECTION_TYPE
: mBaseAdapter.getItemViewType(sectionedPositionToPosition(position)) +1 ;
}
public static class Section {
int firstPosition;
int sectionedPosition;
CharSequence title;
public Section(int firstPosition, CharSequence title) {
this.firstPosition = firstPosition;
this.title = title;
}
public CharSequence getTitle() {
return title;
}
}
public void setSections(Section[] sections) {
mSections.clear();
Arrays.sort(sections, new Comparator<Section>() {
@Override
public int compare(Section o, Section o1) {
return (o.firstPosition == o1.firstPosition)
? 0
: ((o.firstPosition < o1.firstPosition) ? -1 : 1);
}
});
int offset = 0; // offset positions for the headers we're adding
for (Section section : sections) {
section.sectionedPosition = section.firstPosition + offset;
mSections.append(section.sectionedPosition, section);
++offset;
}
notifyDataSetChanged();
}
public int positionToSectionedPosition(int position) {
int offset = 0;
for (int i = 0; i < mSections.size(); i++) {
if (mSections.valueAt(i).firstPosition > position) {
break;
}
++offset;
}
return position + offset;
}
public int sectionedPositionToPosition(int sectionedPosition) {
if (isSectionHeaderPosition(sectionedPosition)) {
return RecyclerView.NO_POSITION;
}
int offset = 0;
for (int i = 0; i < mSections.size(); i++) {
if (mSections.valueAt(i).sectionedPosition > sectionedPosition) {
break;
}
--offset;
}
return sectionedPosition + offset;
}
public boolean isSectionHeaderPosition(int position) {
return mSections.get(position) != null;
}
@Override
public long getItemId(int position) {
return isSectionHeaderPosition(position)
? Integer.MAX_VALUE - mSections.indexOfKey(position)
: mBaseAdapter.getItemId(sectionedPositionToPosition(position));
}
@Override
public int getItemCount() {
return (mValid ? mBaseAdapter.getItemCount() + mSections.size() : 0);
}
}

View File

@@ -13,7 +13,6 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
private static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/magisk_update.json";
private boolean showNotification = false;
public CheckUpdates(Context context, boolean b) {
@@ -46,11 +45,10 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
@Override
protected void onPostExecute(Void v) {
if (showNotification && magiskManager.updateNotification) {
if (magiskManager.magiskVersionCode < magiskManager.remoteMagiskVersionCode) {
Utils.showMagiskUpdate(magiskManager);
}
if (BuildConfig.VERSION_CODE < magiskManager.remoteManagerVersionCode) {
Utils.showManagerUpdate(magiskManager);
} else if (magiskManager.magiskVersionCode < magiskManager.remoteMagiskVersionCode) {
Utils.showMagiskUpdate(magiskManager);
}
}
magiskManager.updateCheckDone.trigger();

View File

@@ -1,15 +1,12 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.app.ProgressDialog;
import android.net.Uri;
import android.widget.Toast;
import android.text.TextUtils;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.AdaptiveList;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils;
@@ -21,17 +18,18 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
public class FlashZip extends RootTask<Void, String, Integer> {
public class FlashZip extends ParallelTask<Void, String, Integer> {
private Uri mUri;
private File mCachedFile, mScriptFile, mCheckFile;
private String mFilename;
private ProgressDialog progress;
private AdaptiveList<String> mList;
public FlashZip(Activity context, Uri uri) {
public FlashZip(Activity context, Uri uri, AdaptiveList<String> list) {
super(context);
mUri = uri;
mList = list;
mCachedFile = new File(magiskManager.getCacheDir(), "install.zip");
mScriptFile = new File(magiskManager.getCacheDir(), "/META-INF/com/google/android/update-binary");
@@ -41,97 +39,77 @@ public class FlashZip extends RootTask<Void, String, Integer> {
mFilename = Utils.getNameFromUri(magiskManager, mUri);
}
private void copyToCache() throws Throwable {
publishProgress(magiskManager.getString(R.string.copying_msg));
private void copyToCache() throws Exception {
mList.add(magiskManager.getString(R.string.copying_msg));
if (mCachedFile.exists() && !mCachedFile.delete()) {
Logger.error("FlashZip: Error while deleting already existing file");
throw new IOException();
}
mCachedFile.delete();
try (
InputStream in = magiskManager.getContentResolver().openInputStream(mUri);
OutputStream outputStream = new FileOutputStream(mCachedFile)
InputStream in = magiskManager.getContentResolver().openInputStream(mUri);
OutputStream outputStream = new FileOutputStream(mCachedFile)
) {
byte buffer[] = new byte[1024];
int length;
if (in == null) throw new FileNotFoundException();
while ((length = in.read(buffer)) > 0)
outputStream.write(buffer, 0, length);
Logger.dev("FlashZip: File created successfully - " + mCachedFile.getPath());
} catch (FileNotFoundException e) {
Logger.error("FlashZip: Invalid Uri");
mList.add("! Invalid Uri");
throw e;
} catch (IOException e) {
Logger.error("FlashZip: Error in creating file");
mList.add("! Cannot copy to cache");
throw e;
}
}
private boolean unzipAndCheck() throws Exception {
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android");
List<String> ret;
ret = Utils.readFile(mCheckFile.getPath());
List<String> ret = Utils.readFile(magiskManager.shell, mCheckFile.getPath());
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
}
private int cleanup(int ret) {
Shell.su(
"rm -rf " + mCachedFile.getParent() + "/*",
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
);
return ret;
}
@Override
protected void onPreExecute() {
progress = new ProgressDialog(activity);
progress.setTitle(R.string.zip_install_progress_title);
progress.show();
// UI updates must run in the UI thread
mList.setCallback(this::publishProgress);
}
@Override
protected void onProgressUpdate(String... values) {
progress.setMessage(values[0]);
mList.updateView();
}
@Override
protected Integer doInRoot(Void... voids) {
Logger.dev("FlashZip Running... " + mFilename);
List<String> ret;
protected Integer doInBackground(Void... voids) {
try {
copyToCache();
if (!unzipAndCheck()) return cleanup(0);
publishProgress(magiskManager.getString(R.string.zip_install_progress_msg, mFilename));
ret = Shell.su(
"BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile,
"if [ $? -eq 0 ]; then echo true; else echo false; fi"
if (!unzipAndCheck()) return 0;
mList.add(magiskManager.getString(R.string.zip_install_progress_msg, mFilename));
magiskManager.shell.su(mList,
"BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile +
" && echo 'Success!' || echo 'Failed!'"
);
if (!Utils.isValidShellResponse(ret)) return -1;
Logger.dev("FlashZip: Console log:");
for (String line : ret) {
Logger.dev(line);
}
if (Boolean.parseBoolean(ret.get(ret.size() - 1)))
return cleanup(1);
} catch (Throwable e) {
if (TextUtils.equals(mList.get(mList.size() - 1), "Success!"))
return 1;
} catch (Exception e) {
e.printStackTrace();
}
return cleanup(-1);
return -1;
}
// -1 = error, manual install; 0 = invalid zip; 1 = success
@Override
protected void onPostExecute(Integer result) {
progress.dismiss();
magiskManager.shell.su_raw(
"rm -rf " + mCachedFile.getParent() + "/*",
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
);
switch (result) {
case -1:
Toast.makeText(magiskManager, magiskManager.getString(R.string.install_error), Toast.LENGTH_LONG).show();
mList.add(magiskManager.getString(R.string.install_error));
Utils.showUriSnack(activity, mUri);
break;
case 0:
Toast.makeText(magiskManager, magiskManager.getString(R.string.invalid_zip), Toast.LENGTH_LONG).show();
mList.add(magiskManager.getString(R.string.invalid_zip));
break;
case 1:
onSuccess();
@@ -141,14 +119,6 @@ public class FlashZip extends RootTask<Void, String, Integer> {
}
protected void onSuccess() {
magiskManager.updateCheckDone.trigger();
new LoadModules(activity).exec();
new AlertDialogBuilder(activity)
.setTitle(R.string.reboot_title)
.setMessage(R.string.reboot_msg)
.setPositiveButton(R.string.reboot, (dialogInterface, i) -> Shell.su(true, "reboot"))
.setNegativeButton(R.string.no_thanks, null)
.show();
}
}

View File

@@ -1,30 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
public class GetBootBlocks extends RootTask<Void, Void, Void> {
public GetBootBlocks(Activity context) {
super(context);
}
@Override
protected Void doInRoot(Void... params) {
magiskManager.blockList = Shell.su(
"find /dev/block -type b -maxdepth 1 | grep -v -E \"loop|ram|dm-0\""
);
if (magiskManager.bootBlock == null) {
magiskManager.bootBlock = Utils.detectBootImage();
}
return null;
}
@Override
protected void onPostExecute(Void v) {
magiskManager.blockDetectionDone.trigger();
super.onPostExecute(v);
}
}

View File

@@ -9,23 +9,22 @@ import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ValueSortedMap;
public class LoadModules extends RootTask<Void, Void, Void> {
public class LoadModules extends ParallelTask<Void, Void, Void> {
public LoadModules(Activity context) {
super(context);
}
@Override
protected Void doInRoot(Void... voids) {
protected Void doInBackground(Void... voids) {
Logger.dev("LoadModules: Loading modules");
magiskManager.moduleMap = new ValueSortedMap<>();
for (String path : Utils.getModList(MagiskManager.MAGISK_PATH)) {
for (String path : Utils.getModList(magiskManager.shell, MagiskManager.MAGISK_PATH)) {
Logger.dev("LoadModules: Adding modules from " + path);
Module module;
try {
module = new Module(path);
Module module = new Module(magiskManager.shell, path);
magiskManager.moduleMap.put(module.getId(), module);
} catch (BaseModule.CacheModException ignored) {}
}

View File

@@ -2,24 +2,20 @@ package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import com.topjohnwu.magisk.utils.Shell;
import java.util.List;
public class MagiskHide extends RootTask<Object, Void, Void> {
public class MagiskHide extends ParallelTask<Object, Void, Void> {
private boolean isList = false;
public MagiskHide() {}
public MagiskHide(Activity context) {
super(context);
}
@Override
protected Void doInRoot(Object... params) {
protected Void doInBackground(Object... params) {
String command = (String) params[0];
List<String> ret = Shell.su("magiskhide --" + command);
List<String> ret = magiskManager.shell.su("magiskhide --" + command);
if (isList) {
magiskManager.magiskHideList = ret;
}

View File

@@ -1,58 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.app.ProgressDialog;
import android.net.Uri;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
public class ProcessMagiskZip extends ParallelTask<Void, Void, Boolean> {
private Uri mUri;
private ProgressDialog progressDialog;
private String mBoot;
private boolean mEnc, mVerity;
public ProcessMagiskZip(Activity context, Uri uri, String boot, boolean enc, boolean verity) {
super(context);
mUri = uri;
mBoot = boot;
mEnc = enc;
mVerity = verity;
}
@Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(activity,
activity.getString(R.string.zip_process_title),
activity.getString(R.string.zip_unzip_msg));
}
@Override
protected Boolean doInBackground(Void... params) {
if (Shell.rootAccess()) {
synchronized (Shell.lock) {
Shell.su("rm -f /dev/.magisk",
(mBoot != null) ? "echo \"BOOTIMAGE=" + mBoot + "\" >> /dev/.magisk" : "",
"echo \"KEEPFORCEENCRYPT=" + String.valueOf(mEnc) + "\" >> /dev/.magisk",
"echo \"KEEPVERITY=" + String.valueOf(mVerity) + "\" >> /dev/.magisk"
);
}
return true;
}
return false;
}
@Override
protected void onPostExecute(Boolean result) {
progressDialog.dismiss();
if (result) {
new FlashZip(activity, mUri).exec();
} else {
Utils.showUriSnack(activity, mUri);
}
super.onPostExecute(result);
}
}

View File

@@ -2,9 +2,11 @@ package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.widget.Toast;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Shell;
@@ -85,13 +87,12 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
progressDialog.dismiss();
if (result) {
if (Shell.rootAccess() && mInstall) {
new FlashZip(activity, mUri).exec();
magiskManager.startActivity(new Intent(magiskManager, FlashActivity.class).setData(mUri));
} else {
Utils.showUriSnack(activity, mUri);
}
} else {
Toast.makeText(activity, R.string.process_error, Toast.LENGTH_LONG).show();
magiskManager.toast(R.string.process_error, Toast.LENGTH_LONG);
}
}
}

View File

@@ -1,33 +0,0 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import com.topjohnwu.magisk.utils.Shell;
public abstract class RootTask <Params, Progress, Result> extends ParallelTask<Params, Progress, Result> {
public RootTask() {}
public RootTask(Activity context) {
super(context);
}
@SafeVarargs
@Override
final protected Result doInBackground(Params... params) {
synchronized (Shell.lock) {
return doInRoot(params);
}
}
@SuppressWarnings("unchecked")
abstract protected Result doInRoot(Params... params);
@SuppressWarnings("unchecked")
@Override
public void exec(Params... params) {
if (Shell.rootAccess()) {
super.exec(params);
}
}
}

View File

@@ -1,6 +1,7 @@
package com.topjohnwu.magisk.module;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
public class Module extends BaseModule {
@@ -8,9 +9,9 @@ public class Module extends BaseModule {
private String mRemoveFile, mDisableFile, mUpdateFile;
private boolean mEnable, mRemove, mUpdated;
public Module(String path) throws CacheModException {
public Module(Shell shell, String path) throws CacheModException {
parseProps(Utils.readFile(path + "/module.prop"));
parseProps(Utils.readFile(shell, path + "/module.prop"));
mRemoveFile = path + "/remove";
mDisableFile = path + "/disable";
@@ -27,33 +28,33 @@ public class Module extends BaseModule {
Logger.dev("Creating Module, id: " + getId());
mEnable = !Utils.itemExist(mDisableFile);
mRemove = Utils.itemExist(mRemoveFile);
mUpdated = Utils.itemExist(mUpdateFile);
mEnable = !Utils.itemExist(shell, mDisableFile);
mRemove = Utils.itemExist(shell, mRemoveFile);
mUpdated = Utils.itemExist(shell, mUpdateFile);
}
public void createDisableFile() {
public void createDisableFile(Shell shell) {
mEnable = false;
Utils.createFile(mDisableFile);
Utils.createFile(shell, mDisableFile);
}
public void removeDisableFile() {
public void removeDisableFile(Shell shell) {
mEnable = true;
Utils.removeItem(mDisableFile);
Utils.removeItem(shell, mDisableFile);
}
public boolean isEnabled() {
return mEnable;
}
public void createRemoveFile() {
public void createRemoveFile(Shell shell) {
mRemove = true;
Utils.createFile(mRemoveFile);
Utils.createFile(shell, mRemoveFile);
}
public void deleteRemoveFile() {
public void deleteRemoveFile(Shell shell) {
mRemove = false;
Utils.removeItem(mRemoveFile);
Utils.removeItem(shell, mRemoveFile);
}
public boolean willBeRemoved() {

View File

@@ -12,7 +12,6 @@ import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Utils;
public abstract class DownloadReceiver extends BroadcastReceiver {
public Context mContext;
public String mFilename;
long downloadID;
@@ -20,7 +19,6 @@ public abstract class DownloadReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
mContext = context;
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {

View File

@@ -22,15 +22,15 @@ public class ManagerUpdate extends BroadcastReceiver {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE);
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri content = FileProvider.getUriForFile(mContext,
Uri content = FileProvider.getUriForFile(context,
"com.topjohnwu.magisk.provider", new File(uri.getPath()));
install.setData(content);
mContext.startActivity(install);
context.startActivity(install);
} else {
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(uri, "application/vnd.android.package-archive");
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(install);
context.startActivity(install);
}
}
},

View File

@@ -0,0 +1,36 @@
package com.topjohnwu.magisk.utils;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
public class AdaptiveList<E> extends ArrayList<E> {
private Runnable callback;
private RecyclerView mView;
public AdaptiveList(RecyclerView v) {
mView = v;
}
public void updateView() {
mView.getAdapter().notifyDataSetChanged();
mView.scrollToPosition(mView.getAdapter().getItemCount() - 1);
}
public void setCallback(Runnable cb) {
callback = cb;
}
public boolean add(E e) {
boolean ret = super.add(e);
if (ret) {
if (callback == null) {
updateView();
} else {
callback.run();
}
}
return ret;
}
}

View File

@@ -11,23 +11,39 @@ public class Logger {
public static final String MAIN_TAG = "Magisk";
public static final String DEBUG_TAG = "MagiskManager";
public static void debug(String line) {
Log.d(DEBUG_TAG, "DEBUG: " + line);
}
public static void debug(String fmt, Object... args) {
Log.d(DEBUG_TAG, "DEBUG: " + String.format(Locale.US, fmt, args));
debug(String.format(Locale.US, fmt, args));
}
public static void error(String line) {
Log.e(MAIN_TAG, "MANAGERERROR: " + line);
}
public static void error(String fmt, Object... args) {
Log.e(MAIN_TAG, "MANAGERERROR: " + String.format(Locale.US, fmt, args));
error(String.format(Locale.US, fmt, args));
}
public static void dev(String line) {
if (MagiskManager.devLogging) {
Log.d(DEBUG_TAG, line);
}
}
public static void dev(String fmt, Object... args) {
if (MagiskManager.devLogging) {
Log.d(DEBUG_TAG, String.format(Locale.US, fmt, args));
dev(String.format(Locale.US, fmt, args));
}
public static void shell(String line) {
if (MagiskManager.shellLogging) {
Log.d(DEBUG_TAG, "SHELL: " + line);
}
}
public static void shell(boolean root, String fmt, Object... args) {
if (MagiskManager.shellLogging) {
Log.d(DEBUG_TAG, (root ? "MANAGERSU: " : "MANAGERSH: ") + String.format(Locale.US, fmt, args));
}
public static void shell(String fmt, Object... args) {
shell(String.format(Locale.US, fmt, args));
}
}

View File

@@ -20,6 +20,8 @@ import java.security.SecureRandom;
public abstract class SafetyNetHelper
implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
private static boolean isRunning = false;
private GoogleApiClient mGoogleApiClient;
private Result ret;
protected FragmentActivity mActivity;
@@ -27,17 +29,20 @@ public abstract class SafetyNetHelper
public SafetyNetHelper(FragmentActivity activity) {
ret = new Result();
mActivity = activity;
mGoogleApiClient = new GoogleApiClient.Builder(activity)
.enableAutoManage(activity, this)
.addApi(SafetyNet.API)
.addConnectionCallbacks(this)
.build();
}
// Entry point to start test
public void requestTest() {
if (isRunning)
return;
// Connect Google Service
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
.enableAutoManage(mActivity, this)
.addApi(SafetyNet.API)
.addConnectionCallbacks(this)
.build();
mGoogleApiClient.connect();
isRunning = true;
}
@Override
@@ -92,6 +97,7 @@ public abstract class SafetyNetHelper
// Disconnect
mGoogleApiClient.stopAutoManage(mActivity);
mGoogleApiClient.disconnect();
isRunning = false;
handleResults(ret);
});
}

View File

@@ -1,11 +1,13 @@
package com.topjohnwu.magisk.utils;
import com.topjohnwu.magisk.asyncs.RootTask;
import android.content.Context;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -16,214 +18,134 @@ public class Shell {
// -1 = problematic/unknown issue; 0 = not rooted; 1 = properly rooted
public static int rootStatus;
public static final Object lock = new Object();
private static boolean isInit = false;
private static Process rootShell;
private static DataOutputStream rootSTDIN;
private static StreamGobbler rootSTDOUT;
private static List<String> rootOutList = Collections.synchronizedList(new ArrayList<String>());
private final Process shellProcess;
private final DataOutputStream STDIN;
private final DataInputStream STDOUT;
public static void init() {
private boolean isValid;
isInit = true;
private Shell() {
rootStatus = 1;
Process process = null;
DataOutputStream in = null;
DataInputStream out = null;
try {
rootShell = Runtime.getRuntime().exec("su");
rootStatus = 1;
} catch (IOException err) {
// No root
process = Runtime.getRuntime().exec("su");
in = new DataOutputStream(process.getOutputStream());
out = new DataInputStream(process.getInputStream());
} catch (IOException e) {
rootStatus = 0;
return;
}
rootSTDIN = new DataOutputStream(rootShell.getOutputStream());
rootSTDOUT = new StreamGobbler(rootShell.getInputStream(), rootOutList, true);
rootSTDOUT.start();
// Setup umask and PATH
su("umask 022");
List<String> ret = su("echo -BOC-", "id");
if (ret == null) {
// Something wrong with root, not allowed?
rootStatus = -1;
return;
}
for (String line : ret) {
if (line.contains("uid=")) {
// id command is working, let's see if we are actually root
rootStatus = line.contains("uid=0") ? rootStatus : -1;
return;
} else if (!line.contains("-BOC-")) {
rootStatus = -1;
return;
while (true) {
if (rootAccess()) {
try {
in.write(("id\n").getBytes("UTF-8"));
in.flush();
String s = new BufferedReader(new InputStreamReader(out)).readLine();
if (s.isEmpty() || !s.contains("uid=0")) {
in.close();
out.close();
process.destroy();
throw new IOException();
}
} catch (IOException e) {
rootStatus = -1;
continue;
}
break;
} else {
// Try to gain non-root sh
try {
process = Runtime.getRuntime().exec("sh");
in = new DataOutputStream(process.getOutputStream());
out = new DataInputStream(process.getInputStream());
} catch (IOException e) {
// Nothing works....
shellProcess = null;
STDIN = null;
STDOUT = null;
isValid = false;
return;
}
break;
}
}
isValid = true;
shellProcess = process;
STDIN = in;
STDOUT = out;
sh_raw("umask 022");
}
public static Shell getShell() {
return new Shell();
}
public static Shell getShell(Context context) {
return Utils.getMagiskManager(context).shell;
}
public static boolean rootAccess() {
return isInit && rootStatus > 0;
return rootStatus > 0;
}
public static List<String> sh(String... commands) {
List<String> res = Collections.synchronizedList(new ArrayList<String>());
try {
Process process = Runtime.getRuntime().exec("sh");
DataOutputStream STDIN = new DataOutputStream(process.getOutputStream());
StreamGobbler STDOUT = new StreamGobbler(process.getInputStream(), res);
STDOUT.start();
try {
for (String write : commands) {
STDIN.write((write + "\n").getBytes("UTF-8"));
STDIN.flush();
Logger.shell(false, write);
}
STDIN.write("exit\n".getBytes("UTF-8"));
STDIN.flush();
} catch (IOException e) {
if (!e.getMessage().contains("EPIPE")) {
throw e;
}
}
process.waitFor();
try {
STDIN.close();
} catch (IOException e) {
// might be closed already
}
STDOUT.join();
process.destroy();
} catch (IOException | InterruptedException e) {
// shell probably not found
res = null;
}
public List<String> sh(String... commands) {
List<String> res = new ArrayList<>();
if (!isValid) return res;
sh(res, commands);
return res;
}
// Run with the same shell by default
public static List<String> su(String... commands) {
return su(false, commands);
}
public static List<String> su(boolean newShell, String... commands) {
List<String> res;
Process process;
DataOutputStream STDIN;
StreamGobbler STDOUT;
// Create the default shell if not init
if (!newShell && !isInit) {
init();
}
if (!newShell && !rootAccess()) {
return null;
}
if (newShell) {
res = Collections.synchronizedList(new ArrayList<String>());
public void sh_raw(String... commands) {
if (!isValid) return;
synchronized (shellProcess) {
try {
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();
} catch (IOException err) {
return null;
}
STDOUT.start();
} else {
process = rootShell;
STDIN = rootSTDIN;
STDOUT = rootSTDOUT;
res = rootOutList;
res.clear();
}
try {
for (String write : commands) {
STDIN.write((write + "\n").getBytes("UTF-8"));
STDIN.flush();
Logger.shell(true, write);
}
if (newShell) {
STDIN.write("exit\n".getBytes("UTF-8"));
STDIN.flush();
process.waitFor();
try {
STDIN.close();
} catch (IOException ignore) {
// might be closed already
}
STDOUT.join();
process.destroy();
} else {
STDIN.write(("echo\n").getBytes("UTF-8"));
STDIN.flush();
STDIN.write(("echo \'-root-done-\'\n").getBytes("UTF-8"));
STDIN.flush();
while (true) {
try {
// Process terminated, it means the interactive shell has some issues
process.exitValue();
rootStatus = -1;
return null;
} catch (IllegalThreadStateException e) {
// Process still running, gobble output until done
int end = res.size() - 1;
if (end > 0) {
if (res.get(end).equals("-root-done-")) {
res.remove(end);
if (res.get(end -1).isEmpty()) {
res.remove(end -1);
}
break;
}
}
try { STDOUT.join(100); } catch (InterruptedException err) {
rootStatus = -1;
return null;
}
}
for (String command : commands) {
STDIN.write((command + "\n").getBytes("UTF-8"));
STDIN.flush();
}
} catch (IOException e) {
e.printStackTrace();
shellProcess.destroy();
isValid = false;
}
} catch (IOException e) {
if (!e.getMessage().contains("EPIPE")) {
Logger.dev("Shell: Root shell error...");
rootStatus = -1;
return null;
}
} catch(InterruptedException e) {
Logger.dev("Shell: Root shell error...");
rootStatus = -1;
return null;
}
return new ArrayList<>(res);
}
public static void su_async(List<String> result, String... commands) {
new RootTask<Void, Void, Void>() {
@Override
protected Void doInRoot(Void... params) {
List<String> ret = Shell.su(commands);
if (result != null) result.addAll(ret);
return null;
}
}.exec();
public void sh(List<String> output, String... commands) {
if (!isValid) return;
try {
shellProcess.exitValue();
isValid = false;
return; // The process is dead, return
} catch (IllegalThreadStateException ignored) {
// This should be the expected result
}
synchronized (shellProcess) {
StreamGobbler out = new StreamGobbler(this.STDOUT, output);
out.start();
sh_raw(commands);
sh_raw("echo \'-shell-done-\'");
try { out.join(); } catch (InterruptedException ignored) {}
}
}
public List<String> su(String... commands) {
if (!rootAccess()) return sh();
return sh(commands);
}
public void su_raw(String... commands) {
if (!rootAccess()) return;
sh_raw(commands);
}
public void su(List<String> output, String... commands) {
if (!rootAccess()) return;
sh(output, commands);
}
}

View File

@@ -1,5 +1,7 @@
package com.topjohnwu.magisk.utils;
import android.text.TextUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -19,7 +21,7 @@ public class StreamGobbler extends Thread {
/**
* <p>StreamGobbler constructor</p>
*
* <p>We use this class because shell STDOUT and STDERR should be read as quickly as
* <p>We use this class because sh STDOUT and STDERR should be read as quickly as
* possible to prevent a deadlock from occurring, or Process.waitFor() never
* returning (as the buffer is full, pausing the native process)</p>
*
@@ -27,26 +29,25 @@ public class StreamGobbler extends Thread {
* @param outputList {@literal List<String>} to write to, or null
*/
public StreamGobbler(InputStream inputStream, List<String> outputList) {
try {
while (inputStream.available() != 0) {
inputStream.skip(inputStream.available());
}
} catch (IOException ignored) {}
reader = new BufferedReader(new InputStreamReader(inputStream));
writer = outputList;
}
public StreamGobbler(InputStream inputStream, List<String> outputList, boolean root) {
reader = new BufferedReader(new InputStreamReader(inputStream));
writer = outputList;
isRoot = root;
}
@Override
public void run() {
// keep reading the InputStream until it ends (or an error occurs)
try {
String line;
while ((line = reader.readLine()) != null) {
if (TextUtils.equals(line, "-shell-done-"))
return;
writer.add(line);
if (!line.equals("-root-done-") && !line.isEmpty()) {
Logger.shell(isRoot, "OUT: " + line);
}
Logger.shell(line);
}
} catch (IOException e) {
// reader probably closed, expected exit condition

View File

@@ -43,37 +43,31 @@ public class Utils {
private static final int MAGISK_UPDATE_NOTIFICATION_ID = 1;
private static final int APK_UPDATE_NOTIFICATION_ID = 2;
public static boolean itemExist(String path) {
String command = "if [ -e " + path + " ]; then echo true; else echo false; fi";
List<String> ret = Shell.su(command);
public static boolean itemExist(Shell shell, String path) {
String command = "[ -e " + path + " ] && echo true || echo false";
List<String> ret = shell.su(command);
return isValidShellResponse(ret) && Boolean.parseBoolean(ret.get(0));
}
public static void createFile(String path) {
public static void createFile(Shell shell, String path) {
String folder = path.substring(0, path.lastIndexOf('/'));
String command = "mkdir -p " + folder + " 2>/dev/null; touch " + path + " 2>/dev/null; if [ -f \"" + path + "\" ]; then echo true; else echo false; fi";
Shell.su_async(null, command);
String command = "mkdir -p " + folder + " 2>/dev/null; touch " + path + " 2>/dev/null;";
shell.su_raw(command);
}
public static void removeItem(String path) {
String command = "rm -rf " + path + " 2>/dev/null; if [ -e " + path + " ]; then echo false; else echo true; fi";
Shell.su_async(null, command);
public static void removeItem(Shell shell, String path) {
String command = "rm -rf " + path + " 2>/dev/null";
shell.su_raw(command);
}
public static List<String> getModList(String path) {
public static List<String> getModList(Shell shell, String path) {
String command = "find " + path + " -type d -maxdepth 1 ! -name \"*.core\" ! -name \"*lost+found\" ! -name \"*magisk\"";
return Shell.su(command);
return shell.su(command);
}
public static List<String> readFile(String path) {
List<String> ret;
public static List<String> readFile(Shell shell, String path) {
String command = "cat " + path;
if (Shell.rootAccess()) {
ret = Shell.su(command);
} else {
ret = Shell.sh(command);
}
return ret;
return shell.su(command);
}
public static void dlAndReceive(Context context, DownloadReceiver receiver, String link, String filename) {
@@ -105,7 +99,7 @@ public class Utils {
receiver.setDownloadID(downloadManager.enqueue(request));
}
receiver.setFilename(filename);
context.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
context.getApplicationContext().registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
public static String getLegalFilename(CharSequence filename) {
@@ -114,7 +108,7 @@ public class Utils {
.replace("#", "").replace("@", "").replace("*", "");
}
public static String detectBootImage() {
public static String detectBootImage(Shell shell) {
String[] commands = {
"for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do",
"BOOTIMAGE=`readlink /dev/block/by-name/$PARTITION || " +
@@ -124,7 +118,7 @@ public class Utils {
"done",
"echo \"$BOOTIMAGE\""
};
List<String> ret = Shell.su(commands);
List<String> ret = shell.su(commands);
if (isValidShellResponse(ret)) {
return ret.get(0);
}
@@ -214,6 +208,7 @@ public class Utils {
builder.setSmallIcon(R.drawable.ic_magisk)
.setContentTitle(magiskManager.getString(R.string.magisk_update_title))
.setContentText(magiskManager.getString(R.string.magisk_update_available, magiskManager.remoteMagiskVersionString))
.setChannelId(MagiskManager.NOTIFICATION_CHANNEL)
.setVibrate(new long[]{0, 100, 100, 100})
.setAutoCancel(true);
Intent intent = new Intent(magiskManager, SplashActivity.class);
@@ -234,6 +229,7 @@ public class Utils {
builder.setSmallIcon(R.drawable.ic_magisk)
.setContentTitle(magiskManager.getString(R.string.manager_update_title))
.setContentText(magiskManager.getString(R.string.manager_download_install))
.setChannelId(MagiskManager.NOTIFICATION_CHANNEL)
.setVibrate(new long[]{0, 100, 100, 100})
.setAutoCancel(true);
Intent intent = new Intent(magiskManager, ManagerUpdate.class);

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:background="@android:color/black"
tools:context="com.topjohnwu.magisk.FlashActivity">
<include layout="@layout/toolbar"/>
<HorizontalScrollView
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp">
<android.support.v7.widget.RecyclerView
android:id="@+id/flash_logs"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:layoutManager="android.support.v7.widget.LinearLayoutManager">
</android.support.v7.widget.RecyclerView>
</HorizontalScrollView>
<LinearLayout
android:id="@+id/button_panel"
style="?android:buttonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="@android:color/darker_gray"
android:orientation="horizontal"
android:visibility="gone">
<Button
android:id="@+id/no_thanks"
style="?android:borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="@string/close" />
<Button
android:id="@+id/reboot"
style="?android:borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="@string/reboot" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:textColor="@android:color/white"
android:textSize="10sp" />

View File

@@ -138,7 +138,7 @@
<string name="settings_clear_cache_summary">حذف المعلومات المخزنة مؤقتا للمستودع على الانترنت، يجبر التطبيق لتحديث عبر الانترنت</string>
<string name="settings_core_only_title">Magisk الوضع الأساسي فقط</string>
<string name="settings_core_only_summary">تمكين الميزات الأساسية فقط، لن يتم تحميل جميع الإضافات. MagiskSU، MagiskHide، systemless hosts، و busybox لا يزال ممكنا</string>
<string name="settings_core_only_summary">تمكين الميزات الأساسية فقط، لن يتم تحميل جميع الإضافات. MagiskSU، MagiskHide، systemless hosts، و لا يزال ممكنا</string>
<string name="settings_magiskhide_summary">إخفاء Magisk من مختلف الاكتشافات</string>
<string name="settings_busybox_title">تفعيل BusyBox</string>
<string name="settings_busybox_summary">ربط تحميل Magisk\'s المدمج في busybox إلى xbin</string>

View File

@@ -143,7 +143,7 @@
<string name="settings_clear_cache_summary">Löscht die zwischengespeicherten Informationen der Online-Repos. Erzwingt eine Aktualisierung</string>
<string name="settings_core_only_title">Nur Kernfunktionen</string>
<string name="settings_core_only_summary">Aktiviert lediglich die Kernfunktionen, Module werden nicht geladen. MagiskSU, Magisk Hide, Systemless hosts und Busybox bleiben weiterhin aktiv</string>
<string name="settings_core_only_summary">Aktiviert lediglich die Kernfunktionen, Module werden nicht geladen. MagiskSU, Magisk Hide und Systemless hosts bleiben weiterhin aktiv</string>
<string name="settings_magiskhide_summary">Versteckt Magisk vor diversen Entdeckungsmethoden</string>
<string name="settings_busybox_title">BusyBox aktivieren</string>
<string name="settings_busybox_summary">Magisk\'s integriertes BusyBox nach xbin mounten</string>

View File

@@ -0,0 +1,220 @@
<resources>
<!--Welcome Activity-->
<string name="navigation_drawer_open">Άνοιγμα συρταριού πλοήγησης</string>
<string name="navigation_drawer_close">Κλείσιμο συρταριού πλοήγησης</string>
<string name="modules">Ενότητες</string>
<string name="downloads">Λήψεις</string>
<string name="superuser">Υπερχρήστης</string>
<string name="log">Aρχείο Kαταγραφής</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_core_only">Εγκατεστημένο 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$s είναι διαθέσιμο!</string>
<string name="cannot_check_updates">Αδυναμία ελέγχου για ενημερώσεις, δεν έχει Internet;</string>
<string name="up_to_date">Τελευταία έκδοση του %1$s εγκατεστημένη</string>
<string name="root_error">Υπάρχει root αλλά όχι άδεια για root, δεν επιτρέπεται;</string>
<string name="not_rooted">Δεν υπάρχει root</string>
<string name="proper_root">Rooted κανονικά</string>
<string name="safetyNet_check_text">Πατήστε για έλεγχο του SafetyNet</string>
<string name="checking_safetyNet_status">Έλεγχος κατάστασης SafetyNet…</string>
<string name="safetyNet_check_success">Επιτυχημένος έλεγχος SafetyNet</string>
<string name="safetyNet_connection_failed">Αδυναμία σύνδεσης στο Google API</string>
<string name="safetyNet_connection_suspended">Η σύνδεση στο Google API διακόπηκε</string>
<string name="safetyNet_no_response">Αδυναμία ελέγχου SafetyNet, δεν έχει Internet;</string>
<string name="safetyNet_fail">Αποτυχία SafetyNet: CTS profile mismatch</string>
<string name="safetyNet_pass">Το SafetyNet Πέρασε</string>
<string name="safetyNet_network_loss">Χάθηκε η σύνδεση στο δίκτυο</string>
<string name="safetyNet_service_disconnected">Η υπηρεσία τερματίστηκε</string>
<string name="safetyNet_res_invalid">Η απόκριση είναι άκυρη</string>
<string name="root_info_warning">Η λειτουργία είναι πολύ περιορισμένη</string>
<!--Install Fragment-->
<string name="auto_detect">(Αυτόματα) %1$s</string>
<string name="cannot_auto_detect">(Αδυναμία αυτόματης εύρεσης)</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: %1$s</string>
<string name="install_magisk_title">Τελευταία έκδοση Magisk: %1$s</string>
<string name="uninstall">Απεγκατάσταση</string>
<string name="reboot_countdown">Επανεκκίνηση σε %1$d</string>
<string name="uninstall_magisk_title">Απεγκατάσταση Magisk</string>
<string name="uninstall_magisk_msg">Αυτό θα αφαιρέσει όλες τις ενότητες, το MagiskSU και πιθανόν να κρυπτογραφύσει τα δεδομένα σας αν δεν είναι κρυπτογραφυμένα\nΕίστε σίγουρος/η ότι θέλετε να συνεχίσετε;</string>
<string name="version_none">(Καμία)</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">Flash Zip Ενότητας</string>
<!--Repo Fragment-->
<string name="update_available">Διαθέσιμη Ενημέρωση</string>
<string name="installed">Εγκαταστάθηκε</string>
<string name="not_installed">Μη εγκατεστημένη</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">JpegXguy</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="ok">OK</string>
<string name="close">Κλείσιμο</string>
<string name="repo_install_title">Εγκατάσταση %1$s</string>
<string name="repo_install_msg">Θέλετε να εγκαταστήσετε %1$s ;</string>
<string name="download_install">Κατέβασμα &amp; Εγκατάσταση</string>
<string name="download">Κατέβασμα</string>
<string name="goto_install">Μεταφορά στο τμήμα \"Εγκατάσταση\"</string>
<string name="download_file_error">Σφάλμα στο κατέβασμα του αρχείου</string>
<string name="install_error">Σφάλμα εγκατάστασης!</string>
<string name="invalid_zip">Αυτό το zip δεν είναι Ενότητα Magisk!!</string>
<string name="reboot_title">Η εγκατάσταση πέτυχε!</string>
<string name="reboot_msg">Θέλετε να κάνετε επανεκκίνηση τώρα;</string>
<string name="reboot">Επανεκκίνηση</string>
<string name="copying_msg">Αντιγραφή zip στον προσωρινό κατάλογο</string>
<string name="zip_install_progress_title">Εγκατάσταση</string>
<string name="zip_unzip_msg">Αποσυμπίεση αρχείου zip …</string>
<string name="zip_process_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="settings_reboot_toast">Επανεκκίνηση για εφαρμογή ρυθμίσεων</string>
<string name="release_notes">Σημειώσεις έκδοσης</string>
<string name="repo_cache_cleared">Η Repo cache καθαρίστηκε</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">Δεν είστε rooted με το MagiskSU, η χρήση του MagiskHide μόνο μπορεί να μην είναι αρκετή!\nΔεν υποτηρίζεται επισήμως, και θα χρειαζόσασταν πρόσθετα εργαλεία (π.χ. suhide) για να περάσετε το Safety Net.</string>
<string name="understand">Καταλαβαίνω</string>
<string name="process_error">Σφάλμα διαδικασίας</string>
<string name="internal_storage">Το zip είναι αποθηκευμένο σε:\n[Εσωτερική μνήμη]%1$s</string>
<string name="zip_process_title">Επεξεργασία</string>
<string name="manual_boot_image">Παρακαλώ επιλέξτε χειροκίνητα μια εικόνα boot!</string>
<string name="manager_update_title">Νέα Ενημέρωση Magisk Manager Διαθέσιμη!</string>
<string name="manager_download_install">Πιέστε για κατέβασμα και εγκατάσταση</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_notification_title">Ειδοποίηση Ενημέρωσης</string>
<string name="settings_notification_summary">Εμφάνιση ειδοποιήσεων ενημέρωσης όταν είναι διαθέσιμη νέα έκδοση</string>
<string name="settings_clear_cache_title">Εκκαθάριση προσωρινής μνήμης αποθετηρίων</string>
<string name="settings_clear_cache_summary">Καθαρίζει τις κρυφές πληροφορίες για απευθείας συνδεδεμένα αποθετήρια, αναγκάζει την εφαρμογή να κάνει ανανέωση σε απευθείας σύνδεση</string>
<string name="settings_core_only_title">Magisk Λειτουργία Πυρήνα Μόνο</string>
<string name="settings_core_only_summary">Ενεργοποίηση μόνο των λειτουργιών πυρήνα, καμία από τις ενότητες δεν θα ενεργοποιηθεί. Τα MagiskSU, MagiskHide, και systemless hosts θα παραμείνουν ενεργά</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 για εφαρμογές Adblock</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_su_reauth_title">Επανα-πιστοποίηση μετά από αναβάθμιση</string>
<string name="settings_su_reauth_summary">Επανα-πιστοποίηση αδειών υπερχρήστη μετά την αναβάθμιση μίας εφαρμογής</string>
<string name="multiuser_mode">Λειτουργία Πολλών Χρηστών</string>
<string name="settings_owner_only">Μόνο Ιδιοκτήτης Συσκευής</string>
<string name="settings_owner_manage">Διαχειριζόμενη από τον Ιδιοκτήτη</string>
<string name="settings_user_independent">Ανεξάρτητη από τον χρήστη</string>
<string name="owner_only_summary">Μόνο ο ιδιοκτήτης έχει πρόσβαση root</string>
<string name="owner_manage_summary">Μόνο ο ιδιοκτήτης μπορεί να διαχειριστεί την πρόσβαση root και να δεχτεί προτροπές αίτημάτων</string>
<string name="user_indepenent_summary">Κάθε χρήστης έχει τους δικούς του ξεχωριστούς κανόνες root</string>
<string name="multiuser_hint_owner_request">Ένα αίτημα έχει σταλεί στον ιδιοκτήτη της συσκευής. Παρακαλώ αλλάξτε σε ιδιοκτήτη και δώστε την άδεια</string>
<string name="mount_namespace_mode">Λειτουργία προσάρτησης χώρου ονομάτων</string>
<string name="settings_ns_global">Καθολικός Χώρος Ονομάτων</string>
<string name="settings_ns_requester">Κληρονόμησε Χώρο Ονομάτων</string>
<string name="settings_ns_isolate">Απομονωμένος Χώρος Ονομάτων</string>
<string name="global_summary">Όλες οι συνεδρίες root χρησιμοποιούν τον καθολικό χώρο oνομάτων προσάρτησης</string>
<string name="requester_summary">Οι συνεδρίες root θα κληρονομούν το χώρο ονομάτων του αιτούντα τους</string>
<string name="isolate_summary">Κάθε συνεδρία root θα έχει το δικό της απομονωμένο χώρο ονομάτων</string>
<string name="settings_development_category">Ανάπτυξη Εφαρμογής</string>
<string name="settings_developer_logging_title">Ενεργοποίηση προηγμένης καταγραφής ελέγχου σφαλμάτων</string>
<string name="settings_developer_logging_summary">Επιλέξτε αυτό για να ενεργοποιήσετε τη verbose καταγραφή</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">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>

View File

@@ -73,7 +73,7 @@
<string name="app_developers">Desarroladores principales</string>
<string name="app_developers_"><![CDATA[Aplicación creada por <a href="https://github.com/topjohnwu">topjohnwu</a> en colaboración con <a href="https://github.com/d8ahazard">Digitalhigh</a> y <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
<string name="app_changelog">Registro de cambios de la aplicación</string>
<string name="translators">Gawenda, netizen, Deiki, Nosi></string>
<string name="translators">Gawenda, netizen, Deiki, Nosi>, dark-basic</string>
<string name="app_version">Versión de la aplicación</string>
<string name="app_source_code">Código fuente</string>
<string name="donation">Donar</string>
@@ -122,12 +122,14 @@
<string name="settings_general_category">General</string>
<string name="settings_dark_theme_title">Tema oscuro</string>
<string name="settings_dark_theme_summary">Habilita el tema oscuro</string>
<string name="settings_notification_title">Notificar Actualización</string>
<string name="settings_notification_summary">Notificar cuando una nueva versión esté disponible</string>
<string name="settings_clear_cache_title">Limpiar caché del repositorio</string>
<string name="settings_clear_cache_summary">Limpiar la información en caché para los repositorios en línea, fuerza a la aplicación a actualizar en línea</string>
<string name="settings_core_only_title">Magisk Modo Sólo Núcleo</string>
<string name="settings_core_only_summary">Habilitar sólo funciones principales, no se cargarán todos los módulos. MagiskSU, MagiskHide, y hosts fuera de la partición de sistema seguiran habilitados</string>
<string name="settings_magiskhide_summary">Ocultar Magisk de varias detecciones</string>
<string name="settings_busybox_title">Habilitar BusyBox</string>
<string name="settings_busybox_summary">Montar el busybox interno de Magisk en xbin</string>
<string name="settings_hosts_title">Habilitar archivo hosts fuera de la partición de sistema</string>
<string name="settings_hosts_summary">Soporte para aplicaciones de bloqueo de publicidad fuera de la partición de sistema</string>
@@ -144,7 +146,26 @@
<string name="request_timeout">Tiempo de petición</string>
<string name="superuser_notification">Notificación de superusuario</string>
<string name="request_timeout_summary">%1$s segundos</string>
<string name="settings_su_reauth_title">Re-autenticación</string>
<string name="settings_su_reauth_summary">Pedir permisos de superusuario nuevamente si una aplicación es actualizada</string>
<string name="multiuser_mode">Modo MultiUsuario</string>
<string name="settings_owner_only">Solo propietario del dispositivo</string>
<string name="settings_owner_manage">Administrador del dispositivo</string>
<string name="settings_user_independent">Usuario Independiente</string>
<string name="owner_only_summary">Sólo el propietario tiene acceso root</string>
<string name="owner_manage_summary">Sólo el administrador puede supervisar el acceso root y recibir solicitudes</string>
<string name="user_indepenent_summary">Cada usuario tiene separadas sus propias reglas de root </string>
<string name="multiuser_hint_owner_request">Se ha enviado una solicitud al propietario del dispositivo. Por favor, cambie a la sesión del propietario y conceda el permiso</string>
<string name="mount_namespace_mode">Montar Namespace </string>
<string name="settings_ns_global">Global Namespace</string>
<string name="settings_ns_requester">Heredar Namespace</string>
<string name="settings_ns_isolate">Aislar Namespace</string>
<string name="global_summary">Todas las sesiones de root utilizan el soporte Global Namespace</string>
<string name="requester_summary">Las sesiones de root heredarán las peticiones Namespace</string>
<string name="isolate_summary">Cada sesión root tendrá su propia Namespace</string>
<string name="settings_development_category">Desarrollo de la aplicación</string>
<string name="settings_developer_logging_title">Habilitar información avanzada de depuración en el registro</string>
<string name="settings_developer_logging_summary">Activar esto para grabar más información en el registro</string>

View File

@@ -123,7 +123,7 @@
<string name="settings_clear_cache_title">Effacer le cache du dépôt</string>
<string name="settings_clear_cache_summary">Effacer les informations en cache des dépôts en ligne, pour forcer une actualisation de l\'application</string>
<string name="settings_core_only_title">Mode Magisk Core uniquement</string>
<string name="settings_core_only_summary">Activer uniquement les fonctionnalités de base, tous les modules ne seront pas chargés. MagiskSU, MagiskHide, les hosts systemless et busybox restent activés</string>
<string name="settings_core_only_summary">Activer uniquement les fonctionnalités de base, tous les modules ne seront pas chargés. MagiskSU, MagiskHide et les hosts systemless restent activés</string>
<string name="settings_magiskhide_summary">Masquer Magisk de diverses détections</string>
<string name="settings_busybox_title">Activer BusyBox</string>
<string name="settings_busybox_summary">Monter le busybox de Magisk sur xbin</string>

View File

@@ -138,7 +138,7 @@
<string name="settings_clear_cache_summary">Azzera le informazioni nella cache per i repository online, e forza l\'aggiornamento online dell\'app</string>
<string name="settings_core_only_title">Solo modo core Magisk</string>
<string name="settings_core_only_summary">Abilita solo le funzioni principali. Non tutti i moduli verranno caricati. MagiskSU, MagiskHide, host systemless, e busybox rimarranno abilitati</string>
<string name="settings_core_only_summary">Abilita solo le funzioni principali. Non tutti i moduli verranno caricati. MagiskSU, MagiskHide, e host systemless rimarranno abilitati</string>
<string name="settings_magiskhide_summary">Nasconde Magisk da numerose rilevazioni</string>
<string name="settings_busybox_title">Abilita BusyBox</string>
<string name="settings_busybox_summary">Collega il mount della busybox interna di Magisk a xbin</string>

View File

@@ -134,7 +134,7 @@
<string name="settings_clear_cache_summary">オンラインリポジトリのキャッシュされた情報をクリアし、アプリをオンラインで更新する</string>
<string name="settings_core_only_title">Magisk コアモード</string>
<string name="settings_core_only_summary">コア機能のみを有効にすると、すべてのモジュールがロードされなくなります。 MagiskSU、MagiskHide、systemless hosts、busyboxは引き続き有効になります。</string>
<string name="settings_core_only_summary">コア機能のみを有効にすると、すべてのモジュールがロードされなくなります。 MagiskSU、MagiskHide、systemless hostsは引き続き有効になります。</string>
<string name="settings_magiskhide_summary">さまざまな検出からMagiskを隠す</string>
<string name="settings_busybox_title">BusyBoxを有効にする</string>
<string name="settings_busybox_summary">Magiskに搭載するBusyBoxをxbinにバインドする</string>

View File

@@ -133,7 +133,7 @@
<string name="settings_clear_cache_summary">온라인 저장소에 대해 캐시된 정보를 지우고, 온라인에서 정보를 강제로 새로 고칩니다.</string>
<string name="settings_core_only_title">Magisk 핵심 기능 모드</string>
<string name="settings_core_only_summary">핵심 기능만 사용합니다. 모든 모듈은 로드하지 않습니다. MagiskSU, MagiskHide, systemless hosts 및 busybox는 계속 사용할 수 있습니다.</string>
<string name="settings_core_only_summary">핵심 기능만 사용합니다. 모든 모듈은 로드하지 않습니다. MagiskSU, MagiskHide systemless hosts 는 계속 사용할 수 있습니다.</string>
<string name="settings_magiskhide_summary">다양한 감지로부터 Magisk를 숨깁니다.</string>
<string name="settings_busybox_title">BusyBox 사용</string>
<string name="settings_busybox_summary">xbin 디렉터리에 Magisk의 빌트인 busybox를 바인드합니다.</string>

View File

@@ -138,7 +138,7 @@
<string name="settings_clear_cache_summary">Wis de gecachte informatie voor online opslagplaatsen. Dit dwingt de app om online te verversen</string>
<string name="settings_core_only_title">Magisk basismodus</string>
<string name="settings_core_only_summary">Alleen kernfuncties inschakelen. Alle modules worden niet geladen. MagiskSU, MagiskHide, systeemloze hosts, en busybox blijven ingeschakeld</string>
<string name="settings_core_only_summary">Alleen kernfuncties inschakelen. Alle modules worden niet geladen. MagiskSU, MagiskHide, en systeemloze hosts blijven ingeschakeld</string>
<string name="settings_magiskhide_summary">Magisk van verschillende detecties verbergen</string>
<string name="settings_busybox_title">Busybox inschakelen</string>
<string name="settings_busybox_summary">Magisk\'s ingebouwde busybox naar xbin bind mounten</string>

View File

@@ -143,7 +143,7 @@
<string name="settings_clear_cache_summary">Wymusza na aplikacji odświeżenie online repozytorium</string>
<string name="settings_core_only_title">Tylko Tryb Rdzeni Magisk</string>
<string name="settings_core_only_summary">Włącz tylko podstawowe funkcje, wszystkie moduły nie zostaną załadowane. MagiskSU, MagiskHide, systemless hosts i BusyBox nadal będą włączone</string>
<string name="settings_core_only_summary">Włącz tylko podstawowe funkcje, wszystkie moduły nie zostaną załadowane. MagiskSU, MagiskHide i systemless hosts nadal będą włączone</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

@@ -28,12 +28,16 @@
<string name="not_rooted">Sem root</string>
<string name="proper_root">Rooteado</string>
<string name="safetyNet_check_text">Pressione para checar o SafetyNet</string>
<string name="checking_safetyNet_status">Checando status do SafetyNet…</string>
<string name="checking_safetyNet_status">Verificando status do SafetyNet…</string>
<string name="safetyNet_check_success">SafetyNet verificado</string>
<string name="safetyNet_connection_failed">Não é possível conectar-se à API do Google</string>
<string name="safetyNet_connection_suspended">A conexão com API do Google foi suspensa</string>
<string name="safetyNet_no_response">Não é possível verificar o SafetyNet, sem Internet?</string>
<string name="safetyNet_fail">SafetyNet Falhou: CTS profile mismatch</string>
<string name="safetyNet_pass">SafetyNet Passado</string>
<string name="safetyNet_network_loss">Conexão com a rede perdida</string>
<string name="safetyNet_service_disconnected">O serviço foi morto</string>
<string name="safetyNet_res_invalid">A resposta é inválida</string>
<string name="root_info_warning">Funcionalidade muito limitada</string>
<!--Install Fragment-->
@@ -126,6 +130,9 @@
<string name="internal_storage">O zip foi salvo em:\n[Armazenamento interno]%1$s</string>
<string name="zip_process_title">Processando</string>
<string name="manual_boot_image">Por Favor, selecione manualmente a Boot Image</string>
<string name="manager_update_title">Nova atualização do Magisk Manager disponível!</string>
<string name="manager_download_install">Pressione para baixar e instalar</string>
<string name="magisk_updates">Atualizações do Magisk</string>
<!--Settings Fragment -->
<string name="settings_general_category">Geral</string>
@@ -137,7 +144,7 @@
<string name="settings_clear_cache_summary">Limpe as informações armazenadas em cache para repos. online, forçando o aplicativo a atualizar online</string>
<string name="settings_core_only_title">Magisk modo somente Core</string>
<string name="settings_core_only_summary">Ativar somente recursos principais, todos os módulos não serão carregados. MagiskSU, MagiskHide, systemless hosts, e busybox ainda estará ativado</string>
<string name="settings_core_only_summary">Ativar somente recursos principais, todos os módulos não serão carregados. MagiskSU, MagiskHide, e systemless hosts ainda estará ativado</string>
<string name="settings_magiskhide_summary">Ocultar Magisk de várias detecções</string>
<string name="settings_busybox_title">Ativar BusyBox</string>
<string name="settings_busybox_summary">Monta a busybox interna do Magisk\'s para xbin</string>
@@ -157,7 +164,26 @@
<string name="request_timeout">Tempo limite de solicitação</string>
<string name="superuser_notification">Notificação do superusuário</string>
<string name="request_timeout_summary">%1$s segundos</string>
<string name="settings_su_reauth_title">Re-autenticar após a atualização</string>
<string name="settings_su_reauth_summary">Re-autenticar permissões de superusuário após as atualizações de um aplicativo</string>
<string name="multiuser_mode">Modo Multiusuário</string>
<string name="settings_owner_only">Apenas Proprietário do Dispositivo</string>
<string name="settings_owner_manage">Proprietário do dispositivo gerenciado</string>
<string name="settings_user_independent">Usuário Independente</string>
<string name="owner_only_summary">Somente o proprietário possui acesso de root</string>
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso root e receber paineis de solicitações</string>
<string name="user_indepenent_summary">Cada usuário tem suas próprias regras raiz separadas</string>
<string name="multiuser_hint_owner_request">Um pedido foi enviado ao proprietário do dispositivo. Mude para o proprietário e conceda a permissão</string>
<string name="mount_namespace_mode">Modo namespace de montagem</string>
<string name="settings_ns_global">Global namespace</string>
<string name="settings_ns_requester">Herdar namespace</string>
<string name="settings_ns_isolate">Isolar namespace</string>
<string name="global_summary">Todas as sessões raiz usam o namespace de montagem global</string>
<string name="requester_summary">As sessões de raiz herdarão o namespace do seu solicitante</string>
<string name="isolate_summary">Cada sessão raiz terá seu próprio namespace isolado</string>
<string name="settings_development_category">Desenvolvimento</string>
<string name="settings_developer_logging_title">Ativar registro mais detalhado</string>
<string name="settings_developer_logging_summary">Marque essa opção para habilitar um registro mais detalhado</string>

View File

@@ -0,0 +1,224 @@
<resources>
<!--Welcome Activity-->
<string name="navigation_drawer_open">Abrir gaveta de notificação</string>
<string name="navigation_drawer_close">Fechar gaveta de notificação</string>
<string name="modules">Módulos</string>
<string name="downloads">Transferir</string>
<string name="superuser">Super-Utilizador</string>
<string name="log">Registo</string>
<string name="settings">Definições</string>
<string name="status">Estado</string>
<string name="install">Instalar</string>
<!--Status Fragment-->
<string name="magisk_version">Magisk v%1$s Instalado</string>
<string name="magisk_version_core_only">Magisk v%1$s Instalado(Somente em modo Core)</string>
<string name="magisk_version_error">Magisk não instalado</string>
<string name="checking_for_updates">A procurar por atualizações…</string>
<string name="magisk_update_available">Magisk v%1$s disponível!</string>
<string name="cannot_check_updates">Não foi possível verificar atualizações, sem internet?</string>
<string name="up_to_date">Última versão do %1$s instalado</string>
<string name="root_error">Com root mas sem permissão de root, o acesso foi permitido?</string>
<string name="not_rooted">Sem root</string>
<string name="proper_root">Root instalado corretamente</string>
<string name="safetyNet_check_text">Pressione para verificar SafetyNet</string>
<string name="checking_safetyNet_status">A verificar o estado do SafetyNet…</string>
<string name="safetyNet_connection_failed">Não é possível ligar à API do Google</string>
<string name="safetyNet_connection_suspended">A ligação com API do Google foi suspensa</string>
<string name="safetyNet_no_response">Não é possível verificar o SafetyNet, sem Internet?</string>
<string name="safetyNet_fail">SafetyNet Falhou: perfil CTS não corresponde</string>
<string name="safetyNet_pass">SafetyNet Passado</string>
<string name="root_info_warning">Funcionalidade muito limitada</string>
<!--Install Fragment-->
<string name="auto_detect">(Auto) %1$s</string>
<string name="cannot_auto_detect">(Não foi auto detetado)</string>
<string name="boot_image_title">Local da Imagem de Arranque</string>
<string name="detect_button">Detectar</string>
<string name="advanced_settings_title">Definições avançadas</string>
<string name="keep_force_encryption">Manter encriptação forçada</string>
<string name="keep_dm_verity">Manter dm-verity</string>
<string name="current_magisk_title">Versão instalada do Magisk: %1$s</string>
<string name="install_magisk_title">Última versão do Magisk: %1$s</string>
<string name="uninstall">Desinstalar</string>
<string name="reboot_countdown">A reiniciar em %1$d</string>
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
<string name="uninstall_magisk_msg">Isso irá remover todos os módulos, MagiskSU, e Potencialmente encriptar seus dados se estiverem encriptados\nDeseja continuar?</string>
<string name="version_none">(Nenhum)</string>
<!--Module Fragment-->
<string name="no_info_provided">(Nenhuma informação fornecida)</string>
<string name="no_modules_found">Nenhum módulo encontrado</string>
<string name="update_file_created">Módulo será atualizado depois de reiniciar</string>
<string name="remove_file_created">Módulo será removido depois de reiniciar</string>
<string name="remove_file_deleted">Módulo não será removido ao reiniciar</string>
<string name="disable_file_created">Módulo será desativado depois de reiniciar</string>
<string name="disable_file_removed">Módulo será ativado depois de reiniciar</string>
<string name="author">Criado por %1$s</string>
<string name="fab_flash_zip">Instalar Módulo Zip</string>
<!--Repo Fragment-->
<string name="update_available">Atualização disponível</string>
<string name="installed">Instalado</string>
<string name="not_installed">Não Instalado</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Gravar no SD</string>
<string name="menuReload">Recarregar</string>
<string name="menuClearLog">Limpar registo agora</string>
<string name="logs_cleared">Registo limpo com sucesso</string>
<string name="log_is_empty">Registo está vazio</string>
<string name="logs_save_failed">Não foi possível gravar o registo para o cartão SD:</string>
<!--About Activity-->
<string name="about">Sobre</string>
<string name="app_developers">Principais programadores</string>
<string name="app_developers_"><![CDATA[App criado por <a href="https://github.com/topjohnwu">topjohnwu</a> em colaboração com <a href="https://github.com/d8ahazard">Digitalhigh</a> e <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
<string name="app_changelog">Lista de alterações da aplicação</string>
<string name="translators">Bruno Guerreiro</string>
<string name="app_version">Versão do aplicação</string>
<string name="app_source_code">Código fonte</string>
<string name="donation">Doar</string>
<string name="app_translators">Tradutores da Aplicação</string>
<string name="support_thread">Suporte</string>
<!--Toasts, Dialogs-->
<string name="permissionNotGranted">Esta funcionalidade não funcionará sem permissão de escrita do armazenamento externo.</string>
<string name="no_thanks">Não, Obrigado</string>
<string name="yes">Sim</string>
<string name="ok">OK</string>
<string name="close">Fechar</string>
<string name="repo_install_title">Instalar %1$s</string>
<string name="repo_install_msg">Deseja instalar%1$s ?</string>
<string name="download_install">Transferir &amp; instalar</string>
<string name="download">Transferir</string>
<string name="goto_install">Ir para secção instalar</string>
<string name="download_file_error">Erro ao transferir ficheiro</string>
<string name="install_error">Erro na instalação!</string>
<string name="invalid_zip">O zip não é um Módulo Magisk!!</string>
<string name="reboot_title">Instalação bem-sucedida!</string>
<string name="reboot_msg">Deseja reiniciar agora?</string>
<string name="reboot">Reiniciar</string>
<string name="copying_msg">A copiar zip para diretório temporário</string>
<string name="zip_install_progress_title">A instalar</string>
<string name="zip_unzip_msg">A descompactar ficheiro zip …</string>
<string name="zip_process_msg">A processar ficheiro zip …</string>
<string name="zip_install_progress_msg">A instalar %1$s …</string>
<string name="no_magisk_title">Magisk Não Instalado!</string>
<string name="no_magisk_msg">Deseja transferir e instalar o Magisk?</string>
<string name="downloading_toast">A transferir %1$s</string>
<string name="magisk_update_title">Nova atualização do Magisk disponível!</string>
<string name="settings_reboot_toast">Reinicie para aplicar definições</string>
<string name="release_notes">Notas da atualização</string>
<string name="repo_cache_cleared">Cache do repositório apagado</string>
<string name="safetyNet_hide_notice">Esta aplicação usa SafetyNet\nJá manipulado pelo MagiskHide por padrão</string>
<string name="start_magiskhide">A iniciar MagiskHide …</string>
<string name="no_magisksu_title">Não está a usar MagiskSU!</string>
<string name="no_magisksu_msg">Não está root instalado com MagiskSU, Usar somente MagiskHide pode não ser suficiente!\nNão é oficialmente suportado, E precisaria de ferramentas adicionais (ex: suhide) para passar pelo SafetyNet.</string>
<string name="understand">Eu entendo</string>
<string name="process_error">Erro no processo</string>
<string name="internal_storage">O zip foi guardado em:\n[Armazenamento interno]%1$s</string>
<string name="zip_process_title">A processar</string>
<string name="manual_boot_image">Por Favor, selecione manualmente a imagem de Arranque</string>
<!--Settings Fragment -->
<string name="settings_general_category">Geral</string>
<string name="settings_dark_theme_title">Tema escuro</string>
<string name="settings_dark_theme_summary">Ativa o tema escuro</string>
<string name="settings_notification_title">Notificação de Atualização</string>
<string name="settings_notification_summary">Mostrar notificações de atualização quando a nova versão estiver disponível</string>
<string name="settings_clear_cache_title">Apagar Cache de Repositório</string>
<string name="settings_clear_cache_summary">Apaga a informação cache de repositórios online. online, forçando a aplicação a atualizar online</string>
<string name="settings_core_only_title">Magisk somente em Modo Core</string>
<string name="settings_core_only_summary">Ativar somente funcionalidades principais, todos os módulos não serão carregados. MagiskSU, MagiskHide, e systemless hosts ainda estará ativado</string>
<string name="settings_magiskhide_summary">Oculta Magisk de várias deteções</string>
<string name="settings_busybox_title">Ativar BusyBox</string>
<string name="settings_busybox_summary">Ativar systemless hosts</string>
<string name="settings_hosts_title">Ativar systemless hosts</string>
<string name="settings_hosts_summary">Suporte de systemless para aplicações Adblock</string>
<string name="settings_su_app_adb">Aplicações e ADB</string>
<string name="settings_su_app">Somente Aplicações</string>
<string name="settings_su_adb">Somente ADB</string>
<string name="settings_su_disable">Desativado</string>
<string name="settings_su_request_10">10 segundos</string>
<string name="settings_su_request_20">20 segundos</string>
<string name="settings_su_request_30">30 segundos</string>
<string name="settings_su_request_60">60 segundos</string>
<string name="superuser_access">Acesso de Super-Utilizador</string>
<string name="auto_response">Resposta Automática</string>
<string name="request_timeout">Tempo limite de solicitação</string>
<string name="superuser_notification">Notificação de Super-Utilizador</string>
<string name="request_timeout_summary">%1$s segundos</string>
<string name="settings_development_category">Desenvolvimento</string>
<string name="settings_developer_logging_title">Ativar registo mais detalhado</string>
<string name="settings_developer_logging_summary">Marque essa opção para permitir um registo mais detalhado</string>
<string name="settings_shell_logging_title">Ativar registo da linha de comandos</string>
<string name="settings_shell_logging_summary">Marque esta opção para permitir o registo de todos os comandos</string>
<!--Superuser-->
<string name="su_request_title">Pedido de Super-Utilizador</string>
<string name="deny_with_str">Negar%1$s</string>
<string name="deny">Negar</string>
<string name="prompt">Perguntar</string>
<string name="grant">Permitir</string>
<string name="su_warning">Concede acesso total ao seu dispositivo.\nNegue se não tiver certeza!</string>
<string name="forever">Sempre</string>
<string name="once">Uma vez</string>
<string name="tenmin">10 minutos</string>
<string name="twentymin">20 minutos</string>
<string name="thirtymin">30 minutos</string>
<string name="sixtymin">60 minutos</string>
<string name="su_allow_toast">%1$s foi permitido o acesso de Super-Utilizador</string>
<string name="su_deny_toast">%1$s foi negado o acesso de Super-Utilizador</string>
<string name="no_apps_found">Não foram encontrados aplicações</string>
<string name="su_snack_grant">Acesso de Super-Utilizador a %1$s foi permitido</string>
<string name="su_snack_deny">Acesso de Super-Utilizador a %1$s foi negado</string>
<string name="su_snack_notif_on">Notificações de %1$s está ativado</string>
<string name="su_snack_notif_off">Notificações da %1$s está desativado</string>
<string name="su_snack_log_on">Registo de %1$s está ativado</string>
<string name="su_snack_log_off">Registo de %1$s está desativado</string>
<string name="su_snack_revoke">%1$s direitos foram revogados</string>
<string name="su_revoke_title">Revogar?</string>
<string name="su_revoke_msg">Revogar os diretos do %1$s, Confirmar?</string>
<string name="toast">Notificação(pop-up)</string>
<string name="none">Nenhum</string>
<!--Superuser logs-->
<string name="pid">PID:\u0020</string>
<string name="target_uid">Alvo UID:\u0020</string>
<string name="command">Comando:\u0020</string>
<string name="safetyNet_check_success">SafetyNet verificado com sucesso</string>
<string name="safetyNet_network_loss">Perda de ligação</string>
<string name="safetyNet_service_disconnected">Serviço foi interrompido</string>
<string name="safetyNet_res_invalid">A resposta é inválida</string>
<string name="manager_update_title">Nova atualização do Magisk Manager disponível!</string>
<string name="manager_download_install">Pressione para transferir e instalar</string>
<string name="settings_su_reauth_title">Autenticar novamente após atualizar</string>
<string name="settings_su_reauth_summary">Autenticar novamente permissões de Super-Utilizador após atualizar aplicações</string>
<string name="multiuser_mode">Modo Multi-Utilizador</string>
<string name="settings_owner_only">Apenas Proprietário de Dispositivo</string>
<string name="settings_owner_manage">Gerido Proprietário do Dispositivo</string>
<string name="settings_user_independent">Independente de Utilizadores</string>
<string name="owner_only_summary">Apenas o proprietário tem acesso a root</string>
<string name="owner_manage_summary">Apenas o proprietário pode gerir acesso root e receber pedidos</string>
<string name="user_indepenent_summary">Cada utilizador tem suas próprias regras de root separadas</string>
<string name="multiuser_hint_owner_request">Um pedido foi enviado ao proprietário do dispositivo. Mude para o proprietário e conceda a permissão</string>
<string name="mount_namespace_mode">Cada sessão root terá sua própria identificação isolada</string>
<string name="settings_ns_global">Identificação Global</string>
<string name="settings_ns_requester">Herdar Identificação</string>
<string name="settings_ns_isolate">Identificação Isolada</string>
<string name="global_summary">Todas as sessões root usam a identificação de montagem global</string>
<string name="requester_summary">As sessões de root herdarão a identificação do seu solicitante</string>
<string name="isolate_summary">Cada sessão root terá sua própria identificação isolada</string>
</resources>

View File

@@ -134,7 +134,7 @@
<string name="settings_clear_cache_summary">Ștergeți informațiile memorate în cache, forțează actualizarea aplicației online</string>
<string name="settings_core_only_title">Mod de bază</string>
<string name="settings_core_only_summary">Se activează numai caracteristicile principale, toate modulele nu vor fi încărcate. MagiskSU, MagiskHide, systemless hosts şi busybox vor fi în continuare activate</string>
<string name="settings_core_only_summary">Se activează numai caracteristicile principale, toate modulele nu vor fi încărcate. MagiskSU, MagiskHide şi systemless hosts vor fi în continuare activate</string>
<string name="settings_magiskhide_summary">Ascundeţi Magisk de la diferite detectări</string>
<string name="settings_busybox_title">Activare BusyBox</string>
<string name="settings_busybox_summary">Montare busybox Magisk în xbin</string>

View File

@@ -1,66 +1,68 @@
<resources>
<!--Universal-->
<!--Welcome Activity-->
<string name="navigation_drawer_open">Открыть меню навигации</string>
<string name="navigation_drawer_close">Закрыть меню навигации</string>
<string name="modules">Модули</string>
<string name="downloads">Загрузки</string>
<string name="superuser">Суперпользователь</string>
<string name="log">Лог</string>
<string name="log">История</string>
<string name="settings">Настройки</string>
<string name="status">Статус</string>
<string name="status">Состояние</string>
<string name="install">Установка</string>
<!--Status Fragment-->
<string name="magisk_version">Установлен Magisk v%1$s</string>
<string name="magisk_version_core_only">Установлен v%1$s (Базовый режим)</string>
<string name="magisk_version_core_only">Установлен 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$s!</string>
<string name="cannot_check_updates">Невозможно проверить обновления, нет соединения?</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="root_error">Root присутствует, но отсутствует разрешение</string>
<string name="not_rooted">Root отсутствует</string>
<string name="proper_root">Корректный root-доступ</string>
<string name="safetyNet_check_text">Проверить статус SafetyNet</string>
<string name="checking_safetyNet_status">Проверка статуса SafetyNet…</string>
<string name="safetyNet_check_success">Проверка SafetyNet пройдена</string>
<string name="safetyNet_connection_failed">Невозможно соединиться с API Google</string>
<string name="safetyNet_connection_suspended">Соединение с API Google было приостановлено</string>
<string name="safetyNet_no_response">Невозможно выполнить проверку SafetyNet, нет соединения?</string>
<string name="safetyNet_fail">SafetyNet не пройден: несовпадение профиля CTS</string>
<string name="safetyNet_pass">SafetyNet пройден</string>
<string name="safetyNet_network_loss">Потеря сетевого соединения</string>
<string name="safetyNet_connection_failed">Невозможно подключиться к Google API</string>
<string name="safetyNet_connection_suspended">Подключение к Google API было прервано</string>
<string name="safetyNet_no_response">Невозможно выполнить проверку SafetyNet</string>
<string name="safetyNet_fail">Проверка SafetyNet неудачна: несоответствие профиля CTS</string>
<string name="safetyNet_pass">Проверка SafetyNet пройдена</string>
<string name="safetyNet_network_loss">Подключение к интернету прервано</string>
<string name="safetyNet_service_disconnected">Служба была остановлена</string>
<string name="safetyNet_res_invalid">Некорректный ответ</string>
<string name="root_info_warning">Функциональность значительно ограничена</string>
<!--Install Fragment-->
<string name="auto_detect">(Авто) %1$s</string>
<string name="cannot_auto_detect">(Невозможно определить)</string>
<string name="boot_image_title">Местоположение образа Boot</string>
<string name="cannot_auto_detect">(Автоопределение невозможно)</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="advanced_settings_title">Расширенные настройки</string>
<string name="keep_force_encryption">Оставить принуд. шифрование</string>
<string name="keep_dm_verity">Оставить dm-verity</string>
<string name="current_magisk_title">Установленная версия Magisk: %1$s</string>
<string name="current_magisk_title">Текущая версия Magisk: %1$s</string>
<string name="install_magisk_title">Последняя версия Magisk: %1$s</string>
<string name="uninstall">Удалить</string>
<string name="reboot_countdown">Перезагрузка через %1$d</string>
<string name="uninstall_magisk_title">Удалить Magisk</string>
<string name="uninstall_magisk_msg">Это удалит все модули, MagiskSU, и может зашифровать ваши данные, если они не зашифрованы\nПродолжить?</string>
<string name="version_none">(Нет)</string>
<string name="uninstall_magisk_msg">Данное действие приведет к удалению всех модулей, MagiskSU, и может зашифровать данные, если они не зашифрованы.\nУверены, что желаете продолжить?</string>
<string name="version_none">(Нет данных)</string>
<!--Module Fragment-->
<string name="no_info_provided">(Нет информации)</string>
<string name="no_modules_found">Модули не найдены</string>
<string name="update_file_created">Модуль будет обновлён при перезагрузке</string>
<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="disable_file_created">Модуль будет отключен при перезагрузке</string>
<string name="disable_file_removed">Модуль будет включен при перезагрузке</string>
<string name="author">Автор: %1$s</string>
<string name="fab_flash_zip">Прошить zip-архив</string>
<string name="fab_flash_zip">Прошить архив с модулем</string>
<!--Repo Fragment-->
<string name="update_available">Доступно обновление</string>
@@ -68,132 +70,153 @@
<string name="not_installed">Не установлен</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Сохранить на SD-карту</string>
<string name="menuSaveToSd">Сохранить на карту памяти</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>
<string name="menuClearLog">Очистить историю сейчас</string>
<string name="logs_cleared">История успешно очищена</string>
<string name="log_is_empty">История пуста</string>
<string name="logs_save_failed">Не удалось записать файл истории на карту памяти:</string>
<!--About Activity-->
<string name="about">О приложении</string>
<string name="app_developers">Основные разработчики</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="translators" />
<string name="app_version">Версия</string>
<string name="app_source_code">Исходный код</string>
<string name="donation">Пожертвовать</string>
<string name="donation">Поддержать проект</string>
<string name="app_translators">Переводчики</string>
<string name="support_thread">Страница поддержки</string>
<!--Toasts, Dialogs-->
<string name="permissionNotGranted">Это не будет работать без доступа к внешнему хранилищу</string>
<string name="permissionNotGranted">Данная функция не будет работать без разрешения на запись во внешнее хранилище</string>
<string name="no_thanks">Нет, спасибо</string>
<string name="yes">Да</string>
<string name="ok">OK</string>
<string name="close">Закрыть</string>
<string name="repo_install_title">Установить %1$s</string>
<string name="repo_install_msg">Вы хотите установить %1$s ?</string>
<string name="repo_install_msg">Желаете установить %1$s ?</string>
<string name="download_install">Скачать и установить</string>
<string name="download">Скачать</string>
<string name="goto_install">Перейти в раздел «Установка»</string>
<string name="download_file_error">Ошибка при скачивании файла</string>
<string name="install_error">Ошибка при установке!</string>
<string name="invalid_zip">Этот архив не содержит модуль Magisk!!</string>
<string name="goto_install">Перейти в раздел \"Установка\"</string>
<string name="download_file_error">Ошибка скачивания файла</string>
<string name="install_error">Ошибка во время установки!</string>
<string name="invalid_zip">В архив отсутствует модуль Magisk!</string>
<string name="reboot_title">Установка успешна!</string>
<string name="reboot_msg">Вы хотите перезагрузиться?</string>
<string name="reboot_msg">Желаете перезагрузить сейчас?</string>
<string name="reboot">Перезагрузка</string>
<string name="copying_msg">Копирование архива во временную директорию</string>
<string name="copying_msg">Копирование архива во временную папку</string>
<string name="zip_install_progress_title">Установка</string>
<string name="zip_unzip_msg">Распаковка zip-файла</string>
<string name="zip_process_msg">Обработка zip-файла</string>
<string name="zip_install_progress_msg">Установка %1$s…</string>
<string name="zip_unzip_msg">Распаковка архива </string>
<string name="zip_process_msg">Обработка архива </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="no_magisk_msg">Желаете скачать и установить Magisk?</string>
<string name="downloading_toast">Скачивание %1$s</string>
<string name="magisk_update_title">Доступно обновление Magisk!</string>
<string name="settings_reboot_toast">Перезагрузитесь для применения изменений</string>
<string name="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>
<string name="magisk_update_title">Доступно новое обновление Magisk!</string>
<string name="settings_reboot_toast">Для применения настроек выполните перезагрузку</string>
<string name="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">В том случае, если root-доступ получен не с помощью MagiskSU, использования MagiskHide может быть недостаточно!\nОфициально не поддерживается, следовательно, могут понадобиться дополнительные инструменты (например, suhide), для успешного прохождения проверки Safety Net</string>
<string name="understand">Понимаю</string>
<string name="process_error">Ошибка обработки</string>
<string name="internal_storage">Этот архив расположен в:\n[Внутреннее хранилище]%1$s</string>
<string name="internal_storage">Архив расположен:\n[Внутреннее Хранилище]%1$s</string>
<string name="zip_process_title">Обработка</string>
<string name="manual_boot_image">Выберите образ Boot вручную!</string>
<string name="manual_boot_image">Пожалуйста, выберите вручную boot-образ!</string>
<string name="manager_update_title">Доступно новое обновление менеджера Magisk!</string>
<string name="manager_download_install">Нажмите, чтобы скачать и установить</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_notification_title">Уведомления об обновлениях</string>
<string name="settings_notification_summary">Показывать уведомления при наличии новых версий</string>
<string name="settings_clear_cache_title">Очистить кэш репозиториев</string>
<string name="settings_clear_cache_summary">Удалить сохранённую информацию о сетевых репозиториях, чтобы приложение обновило информацию из сети</string>
<string name="settings_dark_theme_summary">Включить тёмное оформление</string>
<string name="settings_notification_title">Уведомление об обновлении</string>
<string name="settings_notification_summary">Показывать уведомления об обновлении, когда доступна новая версия</string>
<string name="settings_clear_cache_title">Очистка кеша</string>
<string name="settings_clear_cache_summary">Очистить сохранённую информацию о сетевых репозиториях, заставляя приложение принудительно обновляться через Интернете</string>
<string name="settings_core_only_title">Базовый режим</string>
<string name="settings_core_only_summary">Включить только основные функции, не загружать модули. MagiskSU, MagiskHide, Systemless hosts, и BusyBox будут включены</string>
<string name="settings_core_only_title">Режим Magisk Core</string>
<string name="settings_core_only_summary">Включить возможности только уровня Core, все модули не будут загружены. MagiskSU, MagiskHide и внесистемные хосты останутся включенными</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_busybox_summary">Монтирование встроенного в Magisk busybox в xbin</string>
<string name="settings_hosts_title">Внесистемные хосты</string>
<string name="settings_hosts_summary">Поддержка внесистемных хостов для приложений блокировки рекламы</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_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="auto_response">Автоответ</string>
<string name="request_timeout">Период запроса</string>
<string name="superuser_notification">Уведомление суперпользователя</string>
<string name="request_timeout_summary">%1$s секунд</string>
<string name="request_timeout_summary">%1$s сек.</string>
<string name="settings_su_reauth_title">Реаутентификация после обновления</string>
<string name="settings_su_reauth_summary">Перевыдача прав суперпользователя после обновлений приложения</string>
<string name="multiuser_mode">Многопользовательский режим</string>
<string name="settings_owner_only">Только владелец</string>
<string name="settings_owner_manage">Регулировка владельцем</string>
<string name="settings_user_independent">Независимый пользователь</string>
<string name="owner_only_summary">Только владелец имеет root-доступ</string>
<string name="owner_manage_summary">Только владелец может управлять root-доступом и обрабатывать запросы на предоставление</string>
<string name="user_indepenent_summary">Каждый пользователь имеет свои собственные правила root-доступа</string>
<string name="multiuser_hint_owner_request">Запрос был отправлен владельцу устройства. Пожалуйста, переключитесь на профиль владельца и предоставьте разрешение</string>
<string name="mount_namespace_mode">Режим монтирования пространства имён</string>
<string name="settings_ns_global">Глобальное пространство имён</string>
<string name="settings_ns_requester">Наследуемое пространство имён</string>
<string name="settings_ns_isolate">Изолированное пространство имён</string>
<string name="global_summary">Все сеансы Суперпользователя используют глобальное пространство имён</string>
<string name="requester_summary">Сессии Суперпользователя наследуют пространство имен запрашивающего</string>
<string name="isolate_summary">Каждая сессия Суперпользователя будет иметь собственное изолированное пространство имен</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>
<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="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="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="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="target_uid">Целевой UID:\u0020</string>
<string name="command">Команда:\u0020</string>
</resources>

View File

@@ -140,7 +140,7 @@
<string name="settings_clear_cache_summary">清除已缓存的在线资源库信息,强制刷新在线数据</string>
<string name="settings_core_only_title">Magisk 核心功能模式</string>
<string name="settings_core_only_summary">仅启用核心功能所有模块将不会被载入。MagiskSU、MagiskHidesystemless hosts 和 busybox 仍会持续运作</string>
<string name="settings_core_only_summary">仅启用核心功能所有模块将不会被载入。MagiskSU、MagiskHidesystemless hosts 仍会持续运作</string>
<string name="settings_magiskhide_summary">隐藏 Magisk 使其不被多种方法检测到</string>
<string name="settings_busybox_title">启用 BusyBox</string>
<string name="settings_busybox_summary">将 Magisk 内置的 Busybox 挂载到 xbin</string>

View File

@@ -192,7 +192,7 @@
<string name="settings_notification_summary">有更新的時候顯示通知</string>
<string name="settings_notification_title">更新通知</string>
<string name="magisk_version_core_only">已安裝 Magisk v%1$s (僅核心功能)</string>
<string name="settings_core_only_summary">僅啟用核心功能所有模組將不會被載入。MagiskSU、MagiskHidesystemless hosts、和 busybox 仍會持續運作</string>
<string name="settings_core_only_summary">僅啟用核心功能所有模組將不會被載入。MagiskSU、MagiskHidesystemless hosts 仍會持續運作</string>
<string name="safetyNet_check_success">SafetyNet 檢查成功</string>
<string name="safetyNet_network_loss">網路斷線</string>
<string name="safetyNet_res_invalid">回傳值無效</string>

View File

@@ -132,6 +132,8 @@
<string name="manual_boot_image">Please manually select a boot image!</string>
<string name="manager_update_title">New Magisk Manager Update Available!</string>
<string name="manager_download_install">Press to download and install</string>
<string name="magisk_updates">Magisk Updates</string>
<string name="flashing">Flashing</string>
<!--Settings Activity -->
<string name="settings_general_category">General</string>
@@ -143,7 +145,7 @@
<string name="settings_clear_cache_summary">Clear the cached information for online repos, forces the app to refresh online</string>
<string name="settings_core_only_title">Magisk Core Only Mode</string>
<string name="settings_core_only_summary">Enable only core features, all modules will not be loaded. MagiskSU, MagiskHide, systemless hosts, and busybox will still be enabled</string>
<string name="settings_core_only_summary">Enable only core features, all modules will not be loaded. MagiskSU, MagiskHide, and systemless hosts will still be enabled</string>
<string name="settings_magiskhide_summary">Hide Magisk from various detections</string>
<string name="settings_busybox_title">Enable BusyBox</string>
<string name="settings_busybox_summary">Bind mount Magisk\'s built-in busybox to xbin</string>

View File

@@ -7,7 +7,7 @@ buildscript {
maven { url "https://maven.google.com" }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-alpha5'
classpath 'com.android.tools.build:gradle:3.0.0-alpha7'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files