1
mirror of https://github.com/topjohnwu/Magisk synced 2025-10-26 02:22:14 +01:00

Compare commits

...

23 Commits

Author SHA1 Message Date
topjohnwu
0a0ad9a184 Bump to 4.3.1 2017-03-31 13:17:58 +08:00
topjohnwu
234bead59e Bump version 2017-03-31 06:58:47 +08:00
Primokorn
76de310986 Create french strings.xml
Hope it's not too late for the update :)
2017-03-31 03:23:23 +08:00
topjohnwu
817f050bcd Say goodbye to old modules 2017-03-30 06:52:18 +08:00
topjohnwu
60ae685d1e Change disable to Core Only Mode 2017-03-30 05:16:50 +08:00
Wang Han
4c7bdbb284 Fix crashing when selecting release notes on some devices 2017-03-26 23:55:11 +08:00
topjohnwu
435251ca41 Bump version 2017-03-20 06:24:59 +08:00
topjohnwu
324a0dd38f Update uninstall script 2017-03-20 04:17:04 +08:00
topjohnwu
cc77d93918 Fix string.xml(vi) 2017-03-20 03:38:24 +08:00
Nguyễn Thanh Tài
0ea7d8bd8c Added Vietnamese translation 2017-03-20 03:12:03 +08:00
topjohnwu
849b217143 Fix build issues 2017-03-16 14:08:40 +08:00
Fabio
9af6efba59 Update Italian Translation [2/2] 2017-03-16 13:40:52 +08:00
Fatih Fırıncı
079d6f06ef Added turkish language
Please merge it
2017-03-16 13:40:43 +08:00
gargamelek
9cf0757689 Added czech translation 2017-03-16 13:40:30 +08:00
c727
b54c438948 update strings-de 2017-03-16 13:40:10 +08:00
linar10
c3ff4bfdad Update strings pl 2017-03-16 13:39:49 +08:00
topjohnwu
5d62e066e2 Bump version 2017-02-22 05:06:19 +08:00
topjohnwu
e94219c5a3 Add notification settings 2017-02-22 04:58:03 +08:00
topjohnwu
8ed9634adf Fix Samsung crash 2017-02-22 04:13:21 +08:00
topjohnwu
0aefa9599f Version bump 2017-02-21 03:52:35 +08:00
c727
e279cf0575 update strings-de 2017-02-20 13:40:01 -06:00
topjohnwu
a3f0ef8e77 Many improvements and bug fixes
Close #114
2017-02-21 03:38:37 +08:00
topjohnwu
8eba05ed4a Potentially fix Samsung crash and change colors 2017-02-20 20:11:07 +08:00
55 changed files with 1359 additions and 436 deletions

View File

@@ -8,8 +8,8 @@ android {
applicationId "com.topjohnwu.magisk"
minSdkVersion 21
targetSdkVersion 25
versionCode 23
versionName "4.2"
versionCode 28
versionName "4.3.1"
jackOptions {
enabled true
jackInProcess true
@@ -47,10 +47,10 @@ repositories {
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:recyclerview-v7:25.1.1'
compile 'com.android.support:cardview-v7:25.1.1'
compile 'com.android.support:design:25.1.1'
compile 'com.android.support:support-v4:25.1.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.android.support:cardview-v7:25.3.1'
compile 'com.android.support:design:25.3.1'
compile 'com.android.support:support-v4:25.3.1'
compile 'com.jakewharton:butterknife:8.5.1'
compile 'com.github.clans:fab:1.6.4'
compile 'com.thoughtbot:expandablerecyclerview:1.4'

View File

@@ -1,21 +1,20 @@
#!/system/bin/sh
[ -z $BOOTMODE ] && BOOTMODE=false
TMPDIR=/tmp
($BOOTMODE) && TMPDIR=/dev/tmp
BINDIR=/data/magisk
CHROMEDIR=$BINDIR/chromeos
# This path should work in any cases
TMPDIR=/dev/tmp
NEWBOOT=$TMPDIR/boottmp/new-boot.img
UNPACKDIR=$TMPDIR/boottmp/bootunpack
RAMDISK=$TMPDIR/boottmp/ramdisk
BOOTTMP=$TMPDIR/boottmp
MAGISKBIN=/data/magisk
CHROMEDIR=$MAGISKBIN/chromeos
SYSTEMLIB=/system/lib
[ -d /system/lib64 ] && SYSTEMLIB=/system/lib64
ui_print() {
echo "$1"
# Default permissions
umask 022
ui_print_wrapper() {
type ui_print >/dev/null && ui_print "$1" || echo "$1"
}
grep_prop() {
@@ -25,7 +24,7 @@ grep_prop() {
if [ -z "$FILES" ]; then
FILES='/system/build.prop'
fi
cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1
cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1
}
find_boot_image() {
@@ -42,109 +41,93 @@ find_boot_image() {
fi
}
unpack_boot() {
rm -rf $UNPACKDIR $RAMDISK 2>/dev/null
mkdir -p $UNPACKDIR
mkdir -p $RAMDISK
cd $UNPACKDIR
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/bootimgtools --extract $1
cd $RAMDISK
$BINDIR/busybox gunzip -c < $UNPACKDIR/ramdisk.gz | cpio -i
}
repack_boot() {
cd $RAMDISK
find . | cpio -o -H newc 2>/dev/null | gzip -9 > $UNPACKDIR/ramdisk.gz
cd $UNPACKDIR
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/bootimgtools --repack $BOOTIMAGE
if [ -f chromeos ]; then
echo " " > config
echo " " > bootloader
LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack new-boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz new-boot.img --config config --arch arm --bootloader bootloader --flags 0x1
rm -f new-boot.img
mv new-boot.img.signed new-boot.img
fi
if ($SAMSUNG); then
SAMSUNG_CHECK=$(cat new-boot.img | grep SEANDROIDENFORCE)
if [ $? -ne 0 ]; then
echo -n "SEANDROIDENFORCE" >> new-boot.img
fi
fi
if ($LGE_G); then
# Prevent secure boot error on LG G2/G3.
# Just for know, It's a pattern which bootloader verifies at boot. Thanks to LG hackers.
echo -n -e "\x41\xa9\xe4\x67\x74\x4d\x1d\x1b\xa4\x29\xf2\xec\xea\x65\x52\x79" >> new-boot.img
fi
mv new-boot.img $NEWBOOT
}
# Environments
# Set permissions
chmod -R 755 $CHROMEDIR/futility $BINDIR
chmod -R 755 $CHROMEDIR/futility $MAGISKBIN 2>/dev/null
# Temporary busybox for installation
mkdir -p $TMPDIR/busybox
$MAGISKBIN/busybox --install -s $TMPDIR/busybox
rm -f $TMPDIR/busybox/su $TMPDIR/busybox/sh $TMPDIR/busybox/reboot
PATH=$TMPDIR/busybox:$PATH
# Find the boot image
find_boot_image
if [ -z "$BOOTIMAGE" ]; then
ui_print "! Unable to detect boot image"
ui_print_wrapper "! Unable to detect boot image"
exit 1
fi
ui_print "- Found Boot Image: $BOOTIMAGE"
ui_print_wrapper "- Found Boot Image: $BOOTIMAGE"
# Detect special vendors
SAMSUNG=false
SAMSUNG_CHECK=$(cat /system/build.prop | grep "ro.build.fingerprint=" | grep -i "samsung")
if [ $? -eq 0 ]; then
SAMSUNG=true
fi
LGE_G=false
RBRAND=$(grep_prop ro.product.brand)
RMODEL=$(grep_prop ro.product.device)
if [ "$RBRAND" = "lge" ] || [ "$RBRAND" = "LGE" ]; then
if [ "$RMODEL" = "*D80*" ] ||
[ "$RMODEL" = "*S98*" ] ||
[ "$RMODEL" = "*D85*" ] ||
[ "$RMODEL" = "*F40*" ]; then
LGE_G=true
ui_print "! Bump device detected"
fi
rm -rf $BOOTTMP 2>/dev/null
mkdir -p $BOOTTMP
cd $BOOTTMP
ui_print_wrapper "- Unpacking boot image"
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --unpack $BOOTIMAGE
if [ $? -ne 0 ]; then
ui_print_wrapper "! Unable to unpack boot image"
exit 1
fi
# First unpack the boot image
unpack_boot $BOOTIMAGE
# Update our previous backup to new format if exists
if [ -f /data/stock_boot.img ]; then
SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --sha1 /data/stock_boot.img | tail -n 1`
STOCKDUMP=/data/stock_boot_${SHA1}.img
mv /data/stock_boot.img $STOCKDUMP
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --compress $STOCKDUMP
fi
SUPERSU=false
[ -f sbin/launch_daemonsu.sh ] && SUPERSU=true
if ($SUPERSU); then
ui_print "- SuperSU patched image detected"
rm -f magisk sbin/init.magisk.rc sbin/magic_mask.sh
repack_boot
else
if [ -f /data/stock_boot.img ]; then
ui_print "- Boot image backup found!"
NEWBOOT=/data/stock_boot.img
else
ui_print "! Boot image backup unavailable"
if [ -d ".backup" ]; then
ui_print "- Restoring ramdisk with backup"
cp -af .backup/. .
# Detect boot image state
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-test ramdisk.cpio
case $? in
0 )
ui_print_wrapper "! Magisk is not installed!"
ui_print_wrapper "! Nothing to uninstall"
exit
;;
1 )
# Find SHA1 of stock boot image
if [ -z $SHA1 ]; then
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc
SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc`
[ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img
rm -f init.magisk.rc
fi
rm -f magisk sbin/init.magisk.rc sbin/magic_mask.sh
repack_boot
fi
if [ -f ${STOCKDUMP}.gz ]; then
ui_print_wrapper "- Boot image backup found!"
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
else
ui_print_wrapper "! Boot image backup unavailable"
ui_print_wrapper "- Restoring ramdisk with backup"
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-restore ramdisk.cpio
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --repack $BOOTIMAGE stock_boot.img
fi
;;
2 )
ui_print_wrapper "- SuperSU patched image detected"
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-restore ramdisk.cpio
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --repack $BOOTIMAGE stock_boot.img
;;
esac
# Sign chromeos boot
if [ -f chromeos ]; then
echo > config
echo > bootloader
LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack stock_boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz stock_boot.img --config config --arch arm --bootloader bootloader --flags 0x1
rm -f stock_boot.img
mv stock_boot.img.signed stock_boot.img
fi
chmod 644 $NEWBOOT
ui_print "- Flashing stock/reverted image"
ui_print_wrapper "- Flashing stock/reverted image"
[ ! -L "$BOOTIMAGE" ] && dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
dd if=$NEWBOOT of=$BOOTIMAGE bs=4096
dd if=stock_boot.img of=$BOOTIMAGE bs=4096
ui_print "- Removing Magisk files"
ui_print_wrapper "- Removing Magisk files"
rm -rf /cache/magisk.log /cache/last_magisk.log /cache/magiskhide.log /cache/.disable_magisk \
/cache/magisk /cache/magisk_merge /cache/magisk_mount /cache/unblock /cache/magisk_uninstaller.sh \
/data/Magisk.apk /data/magisk.apk /data/magisk.img /data/magisk_merge.img \
/data/busybox /data/magisk /data/custom_ramdisk_patch.sh 2>/dev/null
($BOOTMODE) && reboot
$BOOTMODE && reboot

File diff suppressed because it is too large Load Diff

View File

@@ -71,8 +71,9 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen
}
};
if (getApplication().magiskHideDone.isTriggered)
if (getApplication().magiskHideDone.isTriggered) {
onTrigger(getApplication().magiskHideDone);
}
return view;
}

View File

@@ -162,8 +162,9 @@ public class MagiskLogFragment extends Fragment {
return false;
}
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
return false;
}
Calendar now = Calendar.getInstance();
String filename = String.format(
@@ -175,8 +176,9 @@ public class MagiskLogFragment extends Fragment {
targetFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/MagiskManager/" + filename);
if ((!targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs())
|| (targetFile.exists() && !targetFile.delete()))
|| (targetFile.exists() && !targetFile.delete())) {
return false;
}
List<String> in = Utils.readFile(MAGISK_LOG);
@@ -214,10 +216,11 @@ public class MagiskLogFragment extends Fragment {
break;
case 2:
bool = (boolean) o;
if (bool)
if (bool) {
Toast.makeText(getActivity(), targetFile.toString(), Toast.LENGTH_LONG).show();
else
} else {
Toast.makeText(getActivity(), getString(R.string.logs_save_failed), Toast.LENGTH_LONG).show();
}
break;
}
}

View File

@@ -25,6 +25,7 @@ public class MagiskManager extends Application {
public static final String MAGISK_HIDE_PATH = "/magisk/.core/magiskhide/";
public static final String TMP_FOLDER_PATH = "/dev/tmp";
public static final String MAGISK_PATH = "/magisk";
public static final String INTENT_SECTION = "section";
// Events
public final CallbackEvent<Void> blockDetectionDone = new CallbackEvent<>();
@@ -62,6 +63,8 @@ public class MagiskManager extends Application {
public boolean magiskHide;
public boolean isDarkTheme;
public boolean updateNotification;
public boolean busybox;
public int suRequestTimeout;
public int suLogTimeout = 14;
public int suAccessState;
@@ -91,6 +94,7 @@ public class MagiskManager extends Application {
devLogging = prefs.getBoolean("developer_logging", false);
shellLogging = prefs.getBoolean("shell_logging", false);
magiskHide = prefs.getBoolean("magiskhide", false);
updateNotification = prefs.getBoolean("notification", true);
// Always start a new root shell manually, just for safety
Shell.init();
updateMagiskInfo();
@@ -100,7 +104,8 @@ public class MagiskManager extends Application {
prefs.edit()
.putBoolean("dark_theme", isDarkTheme)
.putBoolean("magiskhide", magiskHide)
.putBoolean("busybox", Utils.commandExists("busybox"))
.putBoolean("notification", updateNotification)
.putBoolean("busybox", busybox)
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
.putString("su_request_timeout", String.valueOf(suRequestTimeout))
@@ -124,9 +129,9 @@ public class MagiskManager extends Application {
}
if (isSuClient) {
ret = Shell.sh("getprop persist.sys.root_access");
if (Utils.isValidShellResponse(ret))
if (Utils.isValidShellResponse(ret)) {
suAccessState = Integer.parseInt(ret.get(0));
else {
} else {
Shell.su(true, "setprop persist.sys.root_access 3");
suAccessState = 3;
}
@@ -146,6 +151,12 @@ public class MagiskManager extends Application {
magiskVersion = Double.POSITIVE_INFINITY;
}
}
ret = Shell.sh("getprop persist.magisk.busybox");
try {
busybox = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
} catch (NumberFormatException e) {
busybox = false;
}
ret = Shell.sh("getprop ro.magisk.disable");
try {
disabled = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
@@ -159,8 +170,9 @@ public class MagiskManager extends Application {
magiskHideStarted = false;
}
if (!magiskHide && magiskHideStarted)
if (magiskHideStarted) {
magiskHide = true;
}
}

View File

@@ -29,8 +29,6 @@ import butterknife.ButterKnife;
public class MainActivity extends Activity
implements NavigationView.OnNavigationItemSelectedListener, CallbackEvent.Listener<Void> {
public static final String SECTION = "section";
private final Handler mDrawerHandler = new Handler();
private SharedPreferences prefs;
private int mDrawerItem;
@@ -79,10 +77,11 @@ public class MainActivity extends Activity
toggle.syncState();
if (savedInstanceState == null)
navigate(getIntent().getStringExtra(SECTION));
navigate(getIntent().getStringExtra(MagiskManager.INTENT_SECTION));
navigationView.setNavigationItemSelectedListener(this);
getApplicationContext().reloadMainActivity.register(this);
getApplicationContext().updateCheckDone.register(this);
}
@@ -95,18 +94,19 @@ public class MainActivity extends Activity
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
navigate(savedInstanceState.getInt(SECTION, R.id.status));
navigate(savedInstanceState.getInt(MagiskManager.INTENT_SECTION, R.id.status));
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(SECTION, mDrawerItem);
outState.putInt(MagiskManager.INTENT_SECTION, mDrawerItem);
}
@Override
protected void onDestroy() {
getApplicationContext().reloadMainActivity.unRegister(this);
getApplicationContext().updateCheckDone.unRegister(this);
super.onDestroy();
}
@@ -128,19 +128,25 @@ public class MainActivity extends Activity
@Override
public void onTrigger(CallbackEvent<Void> event) {
recreate();
if (event == getApplicationContext().reloadMainActivity) {
recreate();
} else if (event == getApplicationContext().updateCheckDone) {
checkHideSection();
}
}
private void checkHideSection() {
Menu menu = navigationView.getMenu();
if (Shell.rootAccess()) {
menu.findItem(R.id.magiskhide).setVisible(
getApplicationContext().magiskVersion >= 8 && prefs.getBoolean("magiskhide", false));
menu.findItem(R.id.modules).setVisible(getApplicationContext().magiskVersion >= 4);
menu.findItem(R.id.downloads).setVisible(getApplicationContext().magiskVersion >= 4);
menu.findItem(R.id.log).setVisible(true);
menu.findItem(R.id.superuser).setVisible(getApplicationContext().isSuClient);
}
menu.findItem(R.id.magiskhide).setVisible(
Shell.rootAccess() && getApplicationContext().magiskVersion >= 8
&& prefs.getBoolean("magiskhide", false));
menu.findItem(R.id.modules).setVisible(
Shell.rootAccess() && getApplicationContext().magiskVersion >= 4);
menu.findItem(R.id.downloads).setVisible(
Shell.rootAccess() && getApplicationContext().magiskVersion >= 4);
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
menu.findItem(R.id.superuser).setVisible(
Shell.rootAccess() && getApplicationContext().isSuClient);
menu.findItem(R.id.install).setVisible(getApplicationContext().remoteMagiskVersion > 0);
}
@@ -181,6 +187,7 @@ public class MainActivity extends Activity
}
public void navigate(int itemId) {
int bak = mDrawerItem;
mDrawerItem = itemId;
navigationView.setCheckedItem(itemId);
switch (itemId) {
@@ -207,9 +214,11 @@ public class MainActivity extends Activity
break;
case R.id.settings:
startActivity(new Intent(this, SettingsActivity.class));
mDrawerItem = bak;
break;
case R.id.app_about:
startActivity(new Intent(this, AboutActivity.class));
mDrawerItem = bak;
break;
}
}

View File

@@ -133,10 +133,11 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener<Vo
for (Repo repo : getApplication().repoMap.values()) {
Module module = getApplication().moduleMap.get(repo.getId());
if (module != null) {
if (repo.getVersionCode() > module.getVersionCode())
if (repo.getVersionCode() > module.getVersionCode()) {
mUpdateRepos.add(repo);
else
} else {
mInstalledRepos.add(repo);
}
} else {
mOthersRepos.add(repo);
}

View File

@@ -89,10 +89,6 @@ public class SettingsActivity extends Activity {
prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
prefScreen = getPreferenceScreen();
SwitchPreference busybox = (SwitchPreference) findPreference("busybox");
SwitchPreference magiskHide = (SwitchPreference) findPreference("magiskhide");
SwitchPreference hosts = (SwitchPreference) findPreference("hosts");
PreferenceCategory magiskCategory = (PreferenceCategory) findPreference("magisk");
PreferenceCategory suCategory = (PreferenceCategory) findPreference("superuser");
@@ -112,14 +108,11 @@ public class SettingsActivity extends Activity {
prefScreen.removePreference(magiskCategory);
prefScreen.removePreference(suCategory);
} else {
if (!getApplication().isSuClient)
if (!getApplication().isSuClient) {
prefScreen.removePreference(suCategory);
if (getApplication().magiskVersion < 11)
}
if (getApplication().magiskVersion < 11) {
prefScreen.removePreference(magiskCategory);
if (getApplication().disabled) {
busybox.setEnabled(false);
magiskHide.setEnabled(false);
hosts.setEnabled(false);
}
}
}
@@ -147,7 +140,6 @@ public class SettingsActivity extends Activity {
if (getApplication().isDarkTheme != enabled) {
getApplication().isDarkTheme = enabled;
getApplication().reloadMainActivity.trigger();
getActivity().finish();
getActivity().recreate();
}
break;
@@ -196,9 +188,12 @@ public class SettingsActivity extends Activity {
.setPositiveButton(R.string.understand, (dialog, which) -> new MagiskHide().enable())
.setCancelable(false)
.show();
} else new MagiskHide().enable();
} else
} else {
new MagiskHide().enable();
}
} else {
new MagiskHide().disable();
}
break;
case "hosts":
enabled = prefs.getBoolean("hosts", false);

View File

@@ -31,7 +31,7 @@ public class SplashActivity extends Activity{
magiskManager.init();
// Initialize the update check service, notify every 3 hours
if (!"install".equals(getIntent().getStringExtra(MainActivity.SECTION))) {
if (!"install".equals(getIntent().getStringExtra(MagiskManager.INTENT_SECTION))) {
ComponentName service = new ComponentName(magiskManager, UpdateCheckService.class);
JobInfo jobInfo = new JobInfo.Builder(UPDATE_SERVICE_ID, service)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
@@ -44,8 +44,8 @@ public class SplashActivity extends Activity{
// Now fire all async tasks
new GetBootBlocks(this).exec();
if (magiskManager.magiskHide && !magiskManager.disabled &&
magiskManager.magiskVersion > 11 && !magiskManager.magiskHideStarted) {
if (magiskManager.magiskHide && magiskManager.magiskVersion > 11 &&
!magiskManager.magiskHideStarted) {
new MagiskHide().enable();
}
new LoadModules(this) {
@@ -60,8 +60,11 @@ public class SplashActivity extends Activity{
@Override
protected void onPostExecute(Void v) {
super.onPostExecute(v);
Intent intent = getIntent().setClass(magiskManager, MainActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION);
Intent intent = new Intent(magiskManager, MainActivity.class);
if (section != null) {
intent.putExtra(MagiskManager.INTENT_SECTION, section);
}
startActivity(intent);
finish();
}

View File

@@ -2,7 +2,6 @@ package com.topjohnwu.magisk;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
@@ -22,6 +21,7 @@ import com.topjohnwu.magisk.utils.Utils;
import butterknife.BindColor;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
public class StatusFragment extends Fragment implements CallbackEvent.Listener<Void> {
@@ -53,7 +53,24 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
@BindColor(R.color.grey500) int colorNeutral;
@BindColor(R.color.blue500) int colorInfo;
@BindColor(android.R.color.transparent) int trans;
int defaultColor;
@OnClick(R.id.safetyNet_container)
public void safetyNet() {
safetyNetProgress.setVisibility(View.VISIBLE);
safetyNetContainer.setBackgroundColor(trans);
safetyNetIcon.setImageResource(0);
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
Utils.checkSafetyNet(getApplication());
}
@OnClick(R.id.magisk_status_container)
public void gotoInstall() {
if (getApplication().remoteMagiskVersion > 0) {
((MainActivity) getActivity()).navigate(R.id.install);
}
}
private int defaultColor;
@Nullable
@Override
@@ -83,37 +100,13 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
new CheckUpdates(getActivity()).exec();
});
safetyNetContainer.setOnClickListener(view -> {
safetyNetProgress.setVisibility(View.VISIBLE);
safetyNetContainer.setBackgroundColor(trans);
safetyNetIcon.setImageResource(0);
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
Utils.checkSafetyNet(getApplication());
});
magiskStatusContainer.setOnClickListener(view -> {
((MainActivity) getActivity()).navigationView.setCheckedItem(R.id.install);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
try {
transaction.replace(R.id.content_frame, new InstallFragment(), "install").commit();
} catch (IllegalStateException ignored) {}
});
if (getApplication().magiskVersion < 0 && Shell.rootAccess() && !noDialog) {
noDialog = true;
new AlertDialogBuilder(getActivity())
.setTitle(R.string.no_magisk_title)
.setMessage(R.string.no_magisk_msg)
.setCancelable(true)
.setPositiveButton(R.string.goto_install, (dialogInterface, i) -> {
((MainActivity) getActivity()).navigationView.setCheckedItem(R.id.install);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
try {
transaction.replace(R.id.content_frame, new InstallFragment(), "install").commit();
} catch (IllegalStateException ignored) {}
})
.setPositiveButton(R.string.goto_install, (d, i) -> gotoInstall())
.setNegativeButton(R.string.no_thanks, null)
.show();
}
@@ -168,7 +161,7 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
if (getApplication().magiskVersion < 0) {
magiskVersionText.setText(R.string.magisk_version_error);
} else if (getApplication().disabled) {
magiskVersionText.setText(getString(R.string.magisk_version_disable, getApplication().magiskVersionString));
magiskVersionText.setText(getString(R.string.magisk_version_core_only, getApplication().magiskVersionString));
} else {
magiskVersionText.setText(getString(R.string.magisk_version, getApplication().magiskVersionString));
}
@@ -221,9 +214,6 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
if (getApplication().magiskVersion < 0) {
color = colorBad;
image = R.drawable.ic_cancel;
} else if (getApplication().disabled) {
color = colorNeutral;
image = R.drawable.ic_cancel;
}
magiskStatusContainer.setBackgroundColor(color);

View File

@@ -109,7 +109,9 @@ public class SuLogAdapter {
@Override
public void onBindGroupViewHolder(LogGroupViewHolder holder, int flatPosition, ExpandableGroup group) {
holder.date.setText(group.getTitle());
if (isGroupExpanded(flatPosition)) holder.expand();
if (isGroupExpanded(flatPosition)) {
holder.expand();
}
}
}

View File

@@ -7,7 +7,7 @@ import android.content.Intent;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.app.NotificationCompat;
import com.topjohnwu.magisk.MainActivity;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.SplashActivity;
import com.topjohnwu.magisk.utils.Utils;
@@ -48,7 +48,8 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
@Override
protected void onPostExecute(Void v) {
if (magiskManager.magiskVersion < magiskManager.remoteMagiskVersion && showNotification) {
if (magiskManager.magiskVersion < magiskManager.remoteMagiskVersion
&& showNotification && magiskManager.updateNotification) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(magiskManager);
builder.setSmallIcon(R.drawable.ic_magisk)
.setContentTitle(magiskManager.getString(R.string.magisk_update_title))
@@ -56,7 +57,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
.setVibrate(new long[]{0, 100, 100, 100})
.setAutoCancel(true);
Intent intent = new Intent(magiskManager, SplashActivity.class);
intent.putExtra(MainActivity.SECTION, "install");
intent.putExtra(MagiskManager.INTENT_SECTION, "install");
TaskStackBuilder stackBuilder = TaskStackBuilder.create(magiskManager);
stackBuilder.addParentStack(SplashActivity.class);
stackBuilder.addNextIntent(intent);

View File

@@ -13,10 +13,9 @@ public class GetBootBlocks extends SerialTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
if (Shell.rootAccess()) {
magiskManager.blockList = Shell.su("ls /dev/block | grep mmc");
if (magiskManager.bootBlock == null)
magiskManager.bootBlock = Utils.detectBootImage();
magiskManager.blockList = Shell.su("ls /dev/block | grep mmc");
if (magiskManager.bootBlock == null) {
magiskManager.bootBlock = Utils.detectBootImage();
}
return null;
}

View File

@@ -22,8 +22,9 @@ public class LoadApps extends ParallelTask<Void, Void, Void> {
List<ApplicationInfo> list = pm.getInstalledApplications(0);
for (Iterator<ApplicationInfo> i = list.iterator(); i.hasNext(); ) {
ApplicationInfo info = i.next();
if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled)
if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled) {
i.remove();
}
}
Collections.sort(list, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
.compareTo(b.loadLabel(pm).toString().toLowerCase()));

View File

@@ -57,12 +57,10 @@ public class LoadRepos extends ParallelTask<Void, Void, Void> {
String etag = prefs.getString(ETAG_KEY, "");
header.put("If-None-Match", etag);
magiskManager.repoMap = new ValueSortedMap<>();
// Make a request to main URL for repo info
String jsonString = WebService.request(REPO_URL, WebService.GET, null, header, false);
ValueSortedMap<String, Repo> cached = dbHelper.getRepoMap();
ValueSortedMap<String, Repo> cached = dbHelper.getRepoMap(false), fetched = new ValueSortedMap<>();
if (!TextUtils.isEmpty(jsonString)) {
try {
@@ -96,27 +94,25 @@ public class LoadRepos extends ParallelTask<Void, Void, Void> {
Logger.dev("LoadRepos: Update cached repo " + id);
repo.update(updatedDate);
}
if (repo.getId() != null)
magiskManager.repoMap.put(id, repo);
if (repo.getId() != null) {
fetched.put(id, repo);
}
} catch (BaseModule.CacheModException ignored) {}
// Update the database
dbHelper.addRepoMap(fetched);
// The leftover cached are those removed remote, cleanup db
dbHelper.removeRepo(cached);
// Update ETag
prefs.edit().putString(ETAG_KEY, etag).apply();
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
// Use cached if no internet or no updates
Logger.dev("LoadRepos: No updates, use cached");
magiskManager.repoMap.putAll(cached);
cached.clear();
}
// Update the database
dbHelper.addRepoMap(magiskManager.repoMap);
// The leftover cached are those removed remote, cleanup db
dbHelper.removeRepo(cached);
// Update ETag
prefs.edit().putString(ETAG_KEY, etag).apply();
magiskManager.repoMap = dbHelper.getRepoMap();
Logger.dev("LoadRepos: Repo load done");
return null;

View File

@@ -21,15 +21,17 @@ public class MagiskHide extends SerialTask<Object, Void, Void> {
protected Void doInBackground(Object... params) {
String command = (String) params[0];
List<String> ret = Shell.su(MagiskManager.MAGISK_HIDE_PATH + command);
if (isList)
if (isList) {
magiskManager.magiskHideList = ret;
}
return null;
}
@Override
protected void onPostExecute(Void v) {
if (isList)
if (isList) {
magiskManager.magiskHideDone.trigger();
}
}
public void add(CharSequence packageName) {
@@ -50,8 +52,7 @@ public class MagiskHide extends SerialTask<Object, Void, Void> {
public void list() {
isList = true;
if (magiskManager == null)
return;
if (magiskManager == null) return;
exec("list");
}

View File

@@ -45,7 +45,8 @@ public class ProcessMagiskZip extends ParallelTask<Void, Void, Boolean> {
ZipUtils.unzip(magiskManager.getContentResolver().openInputStream(mUri), tempdir);
// Running in parallel mode, open new shell
Shell.su(true,
"echo \"BOOTIMAGE=/dev/block/" + mBoot + "\" > /dev/.magisk",
"rm -f /dev/.magisk",
(mBoot != null) ? "echo \"BOOTIMAGE=/dev/block/" + mBoot + "\" >> /dev/.magisk" : "",
"echo \"KEEPFORCEENCRYPT=" + String.valueOf(mEnc) + "\" >> /dev/.magisk",
"echo \"KEEPVERITY=" + String.valueOf(mVerity) + "\" >> /dev/.magisk",
"mkdir -p " + MagiskManager.TMP_FOLDER_PATH,
@@ -66,13 +67,14 @@ public class ProcessMagiskZip extends ParallelTask<Void, Void, Boolean> {
@Override
protected void onPostExecute(Boolean result) {
progressDialog.dismiss();
if (result)
if (result) {
new FlashZip(activity, mUri) {
@Override
protected boolean unzipAndCheck() throws Exception {
// Don't need to check, as it is downloaded in correct form
return true;
}
@Override
protected void onSuccess() {
new SerialTask<Void, Void, Void>(activity) {
@@ -87,7 +89,8 @@ public class ProcessMagiskZip extends ParallelTask<Void, Void, Boolean> {
super.onSuccess();
}
}.exec();
else
} else {
Utils.showUriSnack(activity, mUri);
}
}
}

View File

@@ -103,10 +103,11 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
protected void onPostExecute(Boolean result) {
progressDialog.dismiss();
if (result) {
if (Shell.rootAccess() && mInstall)
if (Shell.rootAccess() && mInstall) {
new FlashZip(activity, mUri).exec();
else
} else {
Utils.showUriSnack(activity, mUri);
}
} else {
Toast.makeText(activity, R.string.process_error, Toast.LENGTH_LONG).show();

View File

@@ -8,6 +8,6 @@ public class Activity extends AppCompatActivity {
@Override
public MagiskManager getApplicationContext() {
return (MagiskManager) getApplication();
return (MagiskManager) super.getApplicationContext();
}
}

View File

@@ -93,8 +93,9 @@ public class AlertDialogBuilder extends AlertDialog.Builder {
positive.setText(text);
positiveListener = listener;
positive.setOnClickListener((v) -> {
if (positiveListener != null)
if (positiveListener != null) {
positiveListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
}
dialog.dismiss();
});
return this;
@@ -112,8 +113,9 @@ public class AlertDialogBuilder extends AlertDialog.Builder {
negative.setText(text);
negativeListener = listener;
negative.setOnClickListener((v) -> {
if (negativeListener != null)
if (negativeListener != null) {
negativeListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
}
dialog.dismiss();
});
return this;
@@ -131,8 +133,9 @@ public class AlertDialogBuilder extends AlertDialog.Builder {
neutral.setText(text);
neutralListener = listener;
neutral.setOnClickListener((v) -> {
if (neutralListener != null)
if (neutralListener != null) {
neutralListener.onClick(dialog, DialogInterface.BUTTON_NEUTRAL);
}
dialog.dismiss();
});
return this;

View File

@@ -3,7 +3,6 @@ package com.topjohnwu.magisk.components;
import android.app.Activity;
import android.support.annotation.StringRes;
import android.support.design.widget.Snackbar;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
@@ -34,8 +33,7 @@ public class SnackbarMaker {
private static void setup(Snackbar snack) {
TextView text = ButterKnife.findById(snack.getView(), android.support.design.R.id.snackbar_text);
text.setMaxLines(2);
text.setEllipsize(TextUtils.TruncateAt.START);
text.setMaxLines(Integer.MAX_VALUE);
}
}

View File

@@ -13,7 +13,7 @@ import java.util.Collection;
public class RepoDatabaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VER = 1;
private static final int DATABASE_VER = 2;
private static final String TABLE_NAME = "repos";
public RepoDatabaseHelper(Context context) {
@@ -33,15 +33,20 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
"(id TEXT, name TEXT, version TEXT, versionCode INT, " +
"author TEXT, description TEXT, repo_name TEXT, last_update INT, " +
"PRIMARY KEY(id))");
oldVersion++;
}
if (oldVersion == 1) {
db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD template INT");
oldVersion++;
}
// No upgrades yet
}
public void addRepoMap(ValueSortedMap<String, Repo> map) {
SQLiteDatabase db = getWritableDatabase();
Collection<Repo> list = map.values();
for (Repo repo : list)
for (Repo repo : list) {
db.replace(TABLE_NAME, null, repo.getContentValues());
}
db.close();
}
@@ -54,12 +59,17 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
public void removeRepo(ValueSortedMap<String, Repo> map) {
SQLiteDatabase db = getWritableDatabase();
Collection<Repo> list = map.values();
for (Repo repo : list)
for (Repo repo : list) {
db.delete(TABLE_NAME, "id=?", new String[] { repo.getId() });
}
db.close();
}
public ValueSortedMap<String, Repo> getRepoMap() {
return getRepoMap(true);
}
public ValueSortedMap<String, Repo> getRepoMap(boolean filtered) {
ValueSortedMap<String, Repo> ret = new ValueSortedMap<>();
SQLiteDatabase db = getReadableDatabase();
Repo repo;
@@ -67,6 +77,10 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
while (c.moveToNext()) {
repo = new Repo(c);
Logger.dev("Load from cache: " + repo.getId());
if (repo.getTemplateVersion() < 3 && filtered) {
Logger.dev("Outdated repo: " + repo.getId());
continue;
}
ret.put(repo.getId(), repo);
}
}

View File

@@ -22,15 +22,18 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " +
"(uid INT, package_name TEXT, app_name TEXT, policy INT, " +
"until INT, logging INT, notification INT, " +
"PRIMARY KEY(uid))");
onUpgrade(db, 0, DATABASE_VER);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion == 0) {
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " +
"(uid INT, package_name TEXT, app_name TEXT, policy INT, " +
"until INT, logging INT, notification INT, " +
"PRIMARY KEY(uid))");
}
// Currently new database, no upgrading
}
@@ -45,8 +48,9 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
Policy policy = null;
SQLiteDatabase db = getReadableDatabase();
try (Cursor c = db.query(TABLE_NAME, null, "uid=?", new String[] { String.valueOf(uid) }, null, null, null)) {
if (c.moveToNext())
if (c.moveToNext()) {
policy = new Policy(c);
}
}
db.close();
return policy;

View File

@@ -25,14 +25,17 @@ public class SuLogDatabaseHelper extends SQLiteOpenHelper {
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, " +
"to_uid INT, action INT, time INT, command TEXT)");
onUpgrade(db, 0, DATABASE_VER);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion == 0) {
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, " +
"to_uid INT, action INT, time INT, command TEXT)");
}
// Currently new database, no upgrading
}
@@ -63,8 +66,9 @@ public class SuLogDatabaseHelper extends SQLiteOpenHelper {
db.delete(TABLE_NAME, "time < ?", new String[] { String.valueOf(
System.currentTimeMillis() / 1000 - magiskManager.suLogTimeout * 86400) });
try (Cursor c = db.query(TABLE_NAME, null, selection, null, null, null, "time DESC")) {
while (c.moveToNext())
while (c.moveToNext()) {
ret.add(new SuLogEntry(c));
}
}
db.close();
return ret;

View File

@@ -11,7 +11,7 @@ import java.util.List;
public abstract class BaseModule implements Comparable<BaseModule> {
private String mId, mName, mVersion, mAuthor, mDescription;
private int mVersionCode = 0;
private int mVersionCode = 0, templateVersion = 0;
protected BaseModule() {}
@@ -22,6 +22,7 @@ public abstract class BaseModule implements Comparable<BaseModule> {
mVersionCode = c.getInt(c.getColumnIndex("versionCode"));
mAuthor = c.getString(c.getColumnIndex("author"));
mDescription = c.getString(c.getColumnIndex("description"));
templateVersion = c.getInt(c.getColumnIndex("template"));
}
protected void parseProps(List<String> props) throws CacheModException { parseProps(props.toArray(new String[props.size()])); }
@@ -57,6 +58,10 @@ public abstract class BaseModule implements Comparable<BaseModule> {
case "description":
mDescription = prop[1];
break;
case "template":
try {
templateVersion = Integer.parseInt(prop[1]);
} catch (NumberFormatException ignored) {}
case "cacheModule":
if (Boolean.parseBoolean(prop[1]))
throw new CacheModException(mId);
@@ -99,6 +104,10 @@ public abstract class BaseModule implements Comparable<BaseModule> {
return mVersionCode;
}
public int getTemplateVersion() {
return templateVersion;
}
public static class CacheModException extends Exception {
public CacheModException(String id) {
Logger.error("Cache mods are no longer supported! id: " + id);

View File

@@ -21,8 +21,9 @@ public class Module extends BaseModule {
setId(path.substring(sep + 1));
}
if (getName() == null)
if (getName() == null) {
setName(getId());
}
Logger.dev("Creating Module, id: " + getId());

View File

@@ -53,6 +53,7 @@ public class Repo extends BaseModule {
values.put("description", getDescription());
values.put("repo_name", repoName);
values.put("last_update", mLastUpdate.getTime());
values.put("template", getTemplateVersion());
return values;
}
@@ -60,10 +61,6 @@ public class Repo extends BaseModule {
return String.format(ZIP_URL, repoName);
}
public String getLogUrl() {
return String.format(FILE_URL, repoName, "changelog.txt");
}
public String getManifestUrl() {
return String.format(FILE_URL, repoName, "module.prop");
}

View File

@@ -12,6 +12,7 @@ public class UpdateCheckService extends JobService {
@Override
protected Void doInBackground(Void... voids) {
magiskManager.updateMagiskInfo();
magiskManager.updateNotification = magiskManager.prefs.getBoolean("notification", true);
return super.doInBackground(voids);
}

View File

@@ -38,10 +38,12 @@ public class SuReceiver extends BroadcastReceiver {
SuDatabaseHelper suDbHelper = new SuDatabaseHelper(context);
policy = suDbHelper.getPolicy(fromUid);
if (policy == null) try {
policy = new Policy(fromUid, context.getPackageManager());
} catch (Throwable throwable) {
return;
if (policy == null) {
try {
policy = new Policy(fromUid, context.getPackageManager());
} catch (Throwable throwable) {
return;
}
}
magiskManager.initSuConfigs();

View File

@@ -76,8 +76,9 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
@Override
public void onEvent(int fileEvent, String path) {
if (fileEvent == FileObserver.DELETE_SELF) {
if (event != null)
if (event != null) {
event.trigger();
}
finish();
}
}
@@ -147,8 +148,9 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
public void onTrigger(CallbackEvent<Policy> event) {
Policy policy = event.getResult();
String response = "socket:DENY";
if (policy != null &&policy.policy == Policy.ALLOW )
if (policy != null &&policy.policy == Policy.ALLOW ) {
response = "socket:ALLOW";
}
try {
socket.getOutputStream().write((response).getBytes());
} catch (Exception ignored) {}
@@ -176,7 +178,7 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
@Override
protected Boolean doInBackground(Void... params) {
try{
try {
socket = new LocalSocket();
socket.connect(new LocalSocketAddress(socketPath, LocalSocketAddress.Namespace.FILESYSTEM));

View File

@@ -10,8 +10,9 @@ public class CallbackEvent<Result> {
private Set<Listener<Result>> listeners;
public void register(Listener<Result> l) {
if (listeners == null)
if (listeners == null) {
listeners = new HashSet<>();
}
listeners.add(l);
}
@@ -20,8 +21,9 @@ public class CallbackEvent<Result> {
}
public void unRegister(Listener<Result> l) {
if (listeners != null)
if (listeners != null) {
listeners.remove(l);
}
}
public void trigger() {
@@ -32,8 +34,9 @@ public class CallbackEvent<Result> {
result = r;
isTriggered = true;
if (listeners != null) {
for (Listener<Result> listener : listeners)
for (Listener<Result> listener : listeners) {
listener.onTrigger(this);
}
}
}

Some files were not shown because too many files have changed in this diff Show More