From adab02ef77b78932be87c342d5f48e9f7a6f354b Mon Sep 17 00:00:00 2001
From: Francesco Andreuzzi <andreuzzi.francesco@gmail.com>
Date: Thu, 3 Aug 2017 15:02:40 +0200
Subject: [PATCH] 6.0h

---
 app/build.gradle                              |  7 +-
 .../consolelauncher/LauncherActivity.java     | 34 ++++++-
 .../andre/consolelauncher/MainManager.java    | 69 +++++++++----
 .../ohi/andre/consolelauncher/UIManager.java  | 97 ++++++++++++++-----
 .../commands/CommandTuils.java                | 14 +--
 .../commands/main/raw/config.java             |  9 +-
 .../managers/AliasManager.java                | 78 +++++++++++++--
 .../consolelauncher/managers/AppsManager.java |  2 +
 .../managers/XMLPrefsManager.java             | 53 +++++-----
 .../andre/consolelauncher/tuils/Compare.java  | 89 +++++++++++++----
 .../andre/consolelauncher/tuils/Tuils.java    | 13 ++-
 .../tuils/interfaces/CommandExecuter.java     |  3 +-
 app/src/main/res/values/strings.xml           |  2 +
 build.gradle                                  |  5 -
 14 files changed, 361 insertions(+), 114 deletions(-)

diff --git a/app/build.gradle b/app/build.gradle
index da509ca..3a873f4 100755
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -10,8 +10,8 @@ android {
         minSdkVersion 8
         targetSdkVersion 23
 
-        versionCode 113
-        versionName "6.0g"
+        versionCode 117
+        versionName "6.1c"
     }
 
     buildTypes {
@@ -47,4 +47,7 @@ android {
                     output.outputFile.name.replace("app-release.apk", "${x}/${variant.applicationId}_${variant.versionName}_${new Date().format("dd-MM_hh.mm.ss")}.apk"))
         }
     }
+}
+dependencies {
+    compile files('libs/anrwatchdog-1.3.0.jar')
 }
\ No newline at end of file
diff --git a/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java b/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java
index 5ace3e5..026e473 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java
@@ -11,7 +11,6 @@ import android.content.res.Configuration;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
-import android.provider.Settings;
 import android.support.v4.app.ActivityCompat;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.content.LocalBroadcastManager;
@@ -24,6 +23,9 @@ import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.widget.Toast;
 
+import com.github.anrwatchdog.ANRError;
+import com.github.anrwatchdog.ANRWatchDog;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -65,8 +67,14 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
     private CommandExecuter ex = new CommandExecuter() {
 
         @Override
-        public String exec(String input, String alias) {
-            if(main != null) main.onCommand(input, alias);
+        public String exec(String cmd, String aliasName) {
+            if(main != null) main.onCommand(cmd, aliasName);
+            return null;
+        }
+
+        @Override
+        public String exec(String input) {
+            if(main != null) main.onCommand(input, null);
             return null;
         }
     };
@@ -142,6 +150,19 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
 
     private void finishOnCreate() {
 
+        new ANRWatchDog(5000)
+                .setANRListener(new ANRWatchDog.ANRListener() {
+                    @Override
+                    public void onAppNotResponding(ANRError anrError) {
+                        Tuils.log(anrError);
+                        Tuils.toFile(anrError);
+
+                        Toast.makeText(LauncherActivity.this, R.string.anr, Toast.LENGTH_LONG).show();
+                    }
+                })
+                .setReportMainThreadOnly()
+                .start();
+
         Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
             @Override
             public void uncaughtException(Thread t, Throwable e) {
@@ -195,7 +216,12 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
         if(notifications) {
             LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, new IntentFilter("Msg"));
             if(!Tuils.hasNotificationAccess(this)) {
-                startActivity(new Intent(Build.VERSION.SDK_INT >= 22 ? Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS : "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
+                Intent i = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
+                if(i.resolveActivity(getPackageManager()) == null) {
+                    Toast.makeText(this, R.string.no_notification_access, Toast.LENGTH_LONG).show();
+                } else {
+                    startActivity(i);
+                }
             }
         }
 
diff --git a/app/src/main/java/ohi/andre/consolelauncher/MainManager.java b/app/src/main/java/ohi/andre/consolelauncher/MainManager.java
index 309afe1..23df155 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/MainManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/MainManager.java
@@ -6,7 +6,6 @@ import android.os.Environment;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.style.ForegroundColorSpan;
-import android.util.Log;
 
 import java.io.File;
 import java.util.List;
@@ -90,7 +89,6 @@ public class MainManager {
             new AliasTrigger(),
             new TuiCommandTrigger(),
             new AppTrigger(),
-//            keep this as last trigger
             new SystemCommandTrigger()
     };
     private MainPack mainPack;
@@ -103,6 +101,8 @@ public class MainManager {
     private boolean showAliasValue;
     private boolean showAppHistory;
 
+    private String multipleCmdSeparator;
+
     public static Shell.Interactive interactive;
 
     private Hintable hintable;
@@ -116,6 +116,8 @@ public class MainManager {
         showAliasValue = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.show_alias_content);
         showAppHistory = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.show_launch_history);
 
+        multipleCmdSeparator = XMLPrefsManager.get(String.class, XMLPrefsManager.Behavior.multiple_cmd_separator);
+
         CommandGroup group = new CommandGroup(mContext, COMMANDS_PKG);
 
         ContactManager cont = null;
@@ -125,8 +127,14 @@ public class MainManager {
 
         CommandExecuter executer = new CommandExecuter() {
             @Override
-            public String exec(String input, String alias) {
-                onCommand(input, alias);
+            public String exec(String aliasValue, String alias) {
+                onCommand(aliasValue, alias);
+                return null;
+            }
+
+            @Override
+            public String exec(String input) {
+                onCommand(input, null);
                 return null;
             }
         };
@@ -172,20 +180,29 @@ public class MainManager {
         }
 
         if(alias != null && showAliasValue) {
-            out.onOutput(alias + " --> " + "[" + input + "]");
+            out.onOutput(mainPack.aliasManager.formatLabel(alias, input));
+        }
+
+        String[] cmds;
+        if(multipleCmdSeparator.length() > 0) {
+            cmds = input.split(multipleCmdSeparator);
+        } else {
+            cmds = new String[] {input};
         }
 
-        for (CmdTrigger trigger : triggers) {
-            boolean r;
-            try {
-                r = trigger.trigger(mainPack, input);
-            } catch (Exception e) {
-                out.onOutput(Tuils.getStackTrace(e));
-                return;
+        for(String cmd : cmds) {
+            for (CmdTrigger trigger : triggers) {
+                boolean r;
+                try {
+                    r = trigger.trigger(mainPack, cmd);
+                } catch (Exception e) {
+                    out.onOutput(Tuils.getStackTrace(e));
+                    break;
+                }
+                if (r) {
+                    break;
+                }
             }
-            if (r) {
-                return;
-            } else {}
         }
     }
 
@@ -223,14 +240,23 @@ public class MainManager {
     }
 
     private class AliasTrigger implements CmdTrigger {
+
+
         @Override
-        public boolean trigger(ExecutePack info, String alias) {
-            String aliasValue = mainPack.aliasManager.getAlias(alias);
-            if (aliasValue == null) {
+        public boolean trigger(ExecutePack info, String input) {
+            String alias[] = mainPack.aliasManager.getAlias(input, true);
+
+            String aliasValue = alias[0];
+            if (alias[0] == null) {
                 return false;
             }
 
-            mainPack.executer.exec(aliasValue, alias);
+            String aliasName = alias[1];
+            String residual = alias[2];
+
+            aliasValue = mainPack.aliasManager.format(aliasValue, residual);
+
+            mainPack.executer.exec(aliasValue, aliasName);
 
             return true;
         }
@@ -364,8 +390,9 @@ public class MainManager {
                             }
                         }
                     } catch (Exception e) {
-                        out.onOutput(e.toString());
-                        Log.e("andre", "", e);
+                        out.onOutput(Tuils.getStackTrace(e));
+                        Tuils.log(e);
+                        Tuils.toFile(e);
                     }
                 }
             }.start();
diff --git a/app/src/main/java/ohi/andre/consolelauncher/UIManager.java b/app/src/main/java/ohi/andre/consolelauncher/UIManager.java
index 929af44..58ab51b 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/UIManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/UIManager.java
@@ -82,6 +82,26 @@ public class UIManager implements OnTouchListener {
     String batteryFormat;
 //    boolean batteryCharging;
 
+    private String multipleCmdSeparator;
+
+    private boolean selectFirstSuggestionEnter = false;
+    private OnNewInputListener inputListener = new OnNewInputListener() {
+        @Override
+        public void onNewInput(String input) {
+            if(suggestionsView != null) {
+//                if(suggestionsView.getChildCount() > 0 && selectFirstSuggestionEnter) {
+//                    View v = suggestionsView.getChildAt(0);
+//                    v.performClick();
+//                    return;
+//                }
+                suggestionsView.removeAllViews();
+
+            }
+            trigger.exec(input);
+
+        }
+    };
+
     private Runnable batteryRunnable = new Runnable() {
         @Override
         public void run() {
@@ -306,10 +326,28 @@ public class UIManager implements OnTouchListener {
             boolean execOnClick = suggestion.exec;
 
             String text = suggestion.getText();
+            String input = mTerminalAdapter.getInput();
+
             if(suggestion.type == SuggestionsManager.Suggestion.TYPE_PERMANENT) {
-                mTerminalAdapter.setInput(mTerminalAdapter.getInput() + text);
+                mTerminalAdapter.setInput(input + text);
             } else {
-                mTerminalAdapter.setInput(text);
+                if(multipleCmdSeparator.length() > 0) {
+                    String[] split = input.split(multipleCmdSeparator);
+                    if(split.length == 0) return;
+                    if(split.length == 1) mTerminalAdapter.setInput(text);
+                    else {
+                        split[split.length - 1] = Tuils.EMPTYSTRING;
+
+                        String beforeInputs = Tuils.EMPTYSTRING;
+                        for(int count = 0; count < split.length - 1; count++) {
+                            beforeInputs = beforeInputs + split[count] + multipleCmdSeparator;
+                        }
+
+                        mTerminalAdapter.setInput(beforeInputs + text);
+                    }
+                } else {
+                    mTerminalAdapter.setInput(text);
+                }
             }
 
             if (execOnClick) {
@@ -320,21 +358,12 @@ public class UIManager implements OnTouchListener {
         }
     };
 
-    public void requestSuggestion(String text) {
+    public void requestSuggestion(final String input) {
+
         if (suggestionsView == null || suggestionsManager == null || !showSuggestions) {
             return;
         }
 
-        int lastSpace = text.lastIndexOf(Tuils.SPACE);
-
-        String lastWord = text.substring(lastSpace != -1 ? lastSpace + 1 : 0);
-        String before = text.substring(0, lastSpace != -1 ? lastSpace + 1 : 0);
-
-        requestSuggestion(before, lastWord);
-    }
-
-    private void requestSuggestion(final String before, final String lastWord) {
-
         if (suggestionViewParams == null) {
             suggestionViewParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
             suggestionViewParams.setMargins(SkinManager.SUGGESTION_MARGIN, 0, SkinManager.SUGGESTION_MARGIN, 0);
@@ -368,7 +397,34 @@ public class UIManager implements OnTouchListener {
             public void run() {
                 super.run();
 
-                final SuggestionsManager.Suggestion[] suggestions = suggestionsManager.getSuggestions(info, before, lastWord);
+                String before, lastWord;
+                String lastInput;
+                if(multipleCmdSeparator.length() > 0) {
+                    String[] split = input.split(multipleCmdSeparator);
+                    if(split.length == 0) lastInput = input;
+                    else lastInput = split[split.length - 1];
+                } else {
+                    lastInput = input;
+                }
+
+                int lastSpace = lastInput.lastIndexOf(Tuils.SPACE);
+                if(lastSpace == -1) {
+                    before = Tuils.EMPTYSTRING;
+                    lastWord = lastInput;
+                } else {
+                    before = lastInput.substring(0,lastSpace);
+                    lastWord = lastInput.substring(lastSpace + 1,lastInput.length());
+                }
+
+
+                final SuggestionsManager.Suggestion[] suggestions;
+                try {
+                    suggestions = suggestionsManager.getSuggestions(info, before, lastWord);
+                } catch (Exception e) {
+                    Tuils.log(e);
+                    Tuils.toFile(e);
+                    return;
+                }
 
                 if(suggestions.length == 0) {
                     ((Activity) mContext).runOnUiThread(removeAllSuggestions);
@@ -430,6 +486,9 @@ public class UIManager implements OnTouchListener {
         policy = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
         component = new ComponentName(context, PolicyReceiver.class);
 
+        multipleCmdSeparator = XMLPrefsManager.get(String.class, XMLPrefsManager.Behavior.multiple_cmd_separator);
+        selectFirstSuggestionEnter = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.enter_first_suggestion);
+
         mContext = context;
         this.info = (MainPack) info;
 
@@ -678,15 +737,7 @@ public class UIManager implements OnTouchListener {
         } else initDetector();
 
         mTerminalAdapter = new TerminalManager(terminalView, inputView, prefixView, submitView, backView, nextView, deleteView, pasteView, skinManager, context, mainPack);
-        mTerminalAdapter.setInputListener(new OnNewInputListener() {
-            @Override
-            public void onNewInput(String input) {
-                if(suggestionsView != null) {
-                    suggestionsView.removeAllViews();
-                }
-                trigger.exec(input, null);
-            }
-        });
+        mTerminalAdapter.setInputListener(inputListener);
         if(XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.donation_message)) {
             mTerminalAdapter.addMessager(new TerminalManager.Messager(20, context.getString(R.string.rate_donate_text)));
         }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/CommandTuils.java b/app/src/main/java/ohi/andre/consolelauncher/commands/CommandTuils.java
index d171486..79cdbd8 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/CommandTuils.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/CommandTuils.java
@@ -6,6 +6,7 @@ import android.graphics.Color;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 import ohi.andre.consolelauncher.commands.main.MainPack;
@@ -381,16 +382,17 @@ public class CommandTuils {
 
         if(xmlPrefsEntrys == null) {
             xmlPrefsEntrys = new ArrayList<>();
-            for(XMLPrefsManager.XMLPrefsRoot element : XMLPrefsManager.XMLPrefsRoot.values())
-                for(XMLPrefsManager.XMLPrefsSave save : element.copy)
-                    xmlPrefsEntrys.add(save);
-            for(XMLPrefsManager.XMLPrefsSave save : AppsManager.Options.values()) xmlPrefsEntrys.add(save);
-            for(XMLPrefsManager.XMLPrefsSave save : NotificationManager.Options.values()) xmlPrefsEntrys.add(save);
+
+            for(XMLPrefsManager.XMLPrefsRoot element : XMLPrefsManager.XMLPrefsRoot.values()) Collections.addAll(element.copy);
+            Collections.addAll(xmlPrefsEntrys, AppsManager.Options.values());
+            Collections.addAll(xmlPrefsEntrys, NotificationManager.Options.values());
         }
 
         String candidate = index == -1 ? input : input.substring(0,index);
         for(XMLPrefsManager.XMLPrefsSave xs : xmlPrefsEntrys) {
-            if(xs.is(candidate)) return new ArgInfo(xs, input.substring(index + 1,input.length()), true, 1);
+            if(xs.is(candidate)) {
+                return new ArgInfo(xs, index == -1 ? null : input.substring(index + 1,input.length()), true, 1);
+            }
         }
         return new ArgInfo(null, input, false, 0);
     }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/config.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/config.java
index 47a7e69..c2bfd70 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/config.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/config.java
@@ -57,7 +57,9 @@ public class config extends ParamCommand {
             @Override
             public String exec(ExecutePack pack) {
                 XMLPrefsManager.XMLPrefsSave save = pack.get(XMLPrefsManager.XMLPrefsSave.class, 1);
-                return XMLPrefsManager.get(String.class, save);
+                String s = XMLPrefsManager.get(String.class, save);
+                if(s.length() == 0) return "\"\"";
+                return s;
             }
         };
 
@@ -127,6 +129,11 @@ public class config extends ParamCommand {
 
     @Override
     public String onNotArgEnough(ExecutePack pack, int nArgs) {
+        if(nArgs == 2 && pack.get(ohi.andre.consolelauncher.commands.main.Param.class, 0).equals(Param.set)) {
+            pack.args = new Object[] {pack.args[0], pack.args[1], Tuils.EMPTYSTRING};
+            return Param.set.exec(pack);
+        }
+
         return pack.context.getString(helpRes());
     }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/AliasManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/AliasManager.java
index 57615ac..3c9fb41 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/AliasManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/AliasManager.java
@@ -1,7 +1,5 @@
 package ohi.andre.consolelauncher.managers;
 
-import android.util.Log;
-
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
@@ -14,6 +12,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 import ohi.andre.consolelauncher.tuils.Tuils;
 import ohi.andre.consolelauncher.tuils.interfaces.Reloadable;
@@ -24,8 +23,14 @@ public class AliasManager implements Reloadable {
 
     private Map<String, String> aliases;
 
+    private String paramMarker, paramSeparator, aliasLabelFormat;
+
     public AliasManager() {
         reload();
+
+        paramMarker = XMLPrefsManager.get(String.class, XMLPrefsManager.Behavior.alias_param_marker);
+        paramSeparator = XMLPrefsManager.get(String.class, XMLPrefsManager.Behavior.alias_param_separator);
+        aliasLabelFormat = XMLPrefsManager.get(String.class, XMLPrefsManager.Behavior.alias_content_format);
     }
 
     public String printAliases() {
@@ -37,8 +42,61 @@ public class AliasManager implements Reloadable {
         return output.trim();
     }
 
-    public String getAlias(String s) {
-        return aliases.get(s);
+//    [0] = aliasValue
+//    [1] = aliasName
+//    [2] = residualString
+    public String[] getAlias(String alias, boolean supportSpaces) {
+        if(supportSpaces) {
+
+            String[] split = alias.split(Tuils.SPACE);
+            String name = Tuils.EMPTYSTRING;
+
+            for(int count = 0; count < split.length; count++) {
+                name += Tuils.SPACE + split[count];
+                name = name.trim();
+
+                String a = aliases.get(name);
+
+                if(a != null) {
+                    String residual = Tuils.EMPTYSTRING;
+                    for(int c = count + 1; c < split.length; c++) {
+                        residual += split[c] + Tuils.SPACE;
+                    }
+
+                    return new String[] {a, name, residual.trim()};
+                }
+            }
+
+            return new String[] {null, null, alias};
+        } else {
+            return new String[] {aliases.get(alias), alias, Tuils.EMPTYSTRING};
+        }
+    }
+
+    public String format(String aliasValue, String params) {
+        params = params.trim();
+
+        String quoted = Pattern.quote(paramSeparator);
+
+        if(params.length() == 0) return aliasValue;
+        String[] split = params.split(quoted);
+
+        for(String s : split) {
+            aliasValue = aliasValue.replaceFirst(quoted, s);
+        }
+
+        return aliasValue;
+    }
+
+    private final Pattern pn = Pattern.compile("%n", Pattern.CASE_INSENSITIVE);
+    private final Pattern pv = Pattern.compile("%v", Pattern.CASE_INSENSITIVE);
+    private final Pattern pa = Pattern.compile("%a", Pattern.CASE_INSENSITIVE);
+    public String formatLabel(String aliasName, String aliasValue) {
+        String a = aliasLabelFormat;
+        a = pn.matcher(a).replaceAll(Tuils.NEWLINE);
+        a = pv.matcher(a).replaceAll(aliasValue);
+        a = pa.matcher(a).replaceAll(aliasName);
+        return a;
     }
 
     @Override
@@ -57,13 +115,21 @@ public class AliasManager implements Reloadable {
             while((line = reader.readLine()) != null) {
                 String[] splatted = line.split("=");
                 if(splatted.length < 2) continue;
-                aliases.put(splatted[0], splatted[1]);
+
+                String name, value = Tuils.EMPTYSTRING;
+                name = splatted[0];
+
+                for(int c = 1; c < splatted.length; c++) {
+                    value += splatted[c];
+                    if(c != splatted.length - 1) value += "=";
+                }
+
+                aliases.put(name, value);
             }
         } catch (Exception e) {}
     }
 
     public boolean add(String name, String value) {
-        Log.e("andre", "adding: " + name + " ---> " + value);
 
         FileOutputStream fos;
         try {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/AppsManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/AppsManager.java
index 5c0708c..0ce4670 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/AppsManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/AppsManager.java
@@ -382,6 +382,8 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     private void appUninstalled(String packageName) {
+        if(outputable == null || appsHolder == null || context == null) return;
+
         outputable.onOutput(context.getString(R.string.app_uninstalled) + Tuils.SPACE + packageName);
 
         List<LaunchInfo> infos = AppUtils.findLaunchInfosWithPackage(packageName, appsHolder.getApps());
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/XMLPrefsManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/XMLPrefsManager.java
index 4ed6db6..834cf04 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/XMLPrefsManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/XMLPrefsManager.java
@@ -655,6 +655,36 @@ public class XMLPrefsManager {
             public String defaultValue() {
                 return "@";
             }
+        },
+        alias_param_marker {
+            @Override
+            public String defaultValue() {
+                return "%";
+            }
+        },
+        alias_param_separator {
+            @Override
+            public String defaultValue() {
+                return ",";
+            }
+        },
+        multiple_cmd_separator {
+            @Override
+            public String defaultValue() {
+                return ";";
+            }
+        },
+        alias_content_format {
+            @Override
+            public String defaultValue() {
+                return "%a --> [%v]";
+            }
+        },
+        enter_first_suggestion {
+            @Override
+            public String defaultValue() {
+                return "true";
+            }
         };
 
         @Override
@@ -845,15 +875,6 @@ public class XMLPrefsManager {
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         DocumentBuilder builder = factory.newDocumentBuilder();
 
-//        BufferedReader oldStream = null;
-//        HashMap<XMLPrefsSave, String> oldValues = null;
-//
-//        File old = new File(folder, "settings.txt");
-//        if(old.exists()) {
-//            oldStream = new BufferedReader(new FileReader(old));
-//            oldValues = getOld(oldStream);
-//        }
-
         for(XMLPrefsRoot element : XMLPrefsRoot.values()) {
             File file = new File(folder, element.path);
             if(!file.exists() && !file.createNewFile()) continue;
@@ -925,17 +946,7 @@ public class XMLPrefsManager {
                     if(e.getValue().equals(s)) value = e.getKey();
                 }
                 if(value == null) {
-
-//                    if(oldValues != null) {
-//                        for(Map.Entry<XMLPrefsSave, String> sm : oldValues.entrySet()) {
-//                            if(sm.getKey().equals(s)) {
-//                                value = sm.getValue();
-//                            }
-//                        }
-//                    }
-
-//                    if(value == null)
-                        value = s.defaultValue();
+                    value = s.defaultValue();
                 }
 
                 Element em = d.createElement(s.label());
@@ -947,8 +958,6 @@ public class XMLPrefsManager {
 
             writeTo(d, file);
         }
-
-//        if(old.exists()) old.delete();
     }
 
     public static Object transform(String s, Class<?> c) {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/Compare.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/Compare.java
index 6f6849d..8c4dc89 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/Compare.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/Compare.java
@@ -3,6 +3,8 @@ package ohi.andre.consolelauncher.tuils;
 import java.text.Normalizer;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.regex.Pattern;
 
@@ -13,44 +15,79 @@ import java.util.regex.Pattern;
 public class Compare {
 
     static final char[] allowed_separators = {' ', '-', '_'};
-
     private static final String ACCENTS_PATTERN = "\\p{InCombiningDiacriticalMarks}+";
+
+    static Pattern unconsideredSymbols = Pattern.compile("[\\s_-]");
+    static Pattern accentPattern = Pattern.compile(ACCENTS_PATTERN);
+
     public static String removeAccents(String s) {
         if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
-            Pattern pattern = Pattern.compile(ACCENTS_PATTERN);
             String decomposed = Normalizer.normalize(s, Normalizer.Form.NFD);
-            return pattern.matcher(decomposed).replaceAll(Tuils.EMPTYSTRING);
+            return accentPattern.matcher(decomposed).replaceAll(Tuils.EMPTYSTRING);
         }
 
         return s;
     }
 
     public static int matches(String compared, String comparator, boolean allowSkip) {
+//        Tuils.log("compared: " + compared + ", comparator: " + comparator);
+
         compared = removeAccents(compared).toLowerCase().trim();
         comparator = removeAccents(comparator).toLowerCase().trim();
 
-        List<String> s = new ArrayList<>();
+        double minRate = (double) comparator.length() / 2d;
+//        Tuils.log("min: " + minRate);
+
+        List<ComparePack> s = new ArrayList<>();
         if(allowSkip) {
             for(char sep : allowed_separators) {
                 String[] split = compared.split(String.valueOf(sep));
-                s.addAll(Arrays.asList(split));
+                if(split.length > 1) {
+                    for(int count = 1; count < split.length; count++) {
+                        s.add(new ComparePack(split[count], count, split.length));
+                    }
+                }
             }
         }
-        s.add(compared);
+
+        String unconsidered = unconsideredSymbols.matcher(compared).replaceAll(Tuils.EMPTYSTRING);
+        if(unconsidered.length() != compared.length()) {
+            s.add(new ComparePack(unconsidered, 0, 1));
+        }
+
+        s.add(new ComparePack(compared, 0, 1));
 
         float maxRate = -1;
-        for(String st : s) {
-            float rate = 0;
-            for(int i = 0; i < st.length() && i < comparator.length(); i++) {
-                char c1 = st.charAt(i);
+        Main:
+        for(ComparePack cmp : s) {
+//            Tuils.log("s: " + cmp.s);
+
+            int stop = Math.min(cmp.s.length(), comparator.length());
+            float minus = (float) (0.5 * (comparator.length() / 5));
+
+            float rate = cmp.coefficient() * -1;
+//            Tuils.log("initialRate: " + rate);
+            for(int i = 0; i < stop; i++) {
+                char c1 = cmp.s.charAt(i);
                 char c2 = comparator.charAt(i);
 
                 if(c1 == c2) {
-                    rate += (double) (st.length() - i) / (double) st.length();
+                    rate++;
+                } else {
+                    rate -= minus;
+
+                    if(rate + (stop - 1 - i) < minRate) {
+//                        Tuils.log("continue");
+                        continue Main;
+                    }
                 }
+//                Tuils.log("rate: " + rate);
             }
 
-            if(rate >= (double) comparator.length() / 2d) maxRate = Math.max(maxRate, rate);
+            if(rate >= minRate) {
+                maxRate = Math.max(maxRate, rate);
+//                Tuils.log("maxRate changed");
+            }
         }
 
         return Math.round(maxRate);
@@ -81,12 +118,12 @@ public class Compare {
             if(rate != -1) ms.add(new SimpleMutableEntry<>(s, rate));
         }
 
-//        Collections.sort(ms, new Comparator<SimpleMutableEntry<String, Integer>>() {
-//            @Override
-//            public int compare(SimpleMutableEntry<String, Integer> o1, SimpleMutableEntry<String, Integer> o2) {
-//                return o1.getValue() - o2.getValue();
-//            }
-//        });
+        Collections.sort(ms, new Comparator<SimpleMutableEntry<String, Integer>>() {
+            @Override
+            public int compare(SimpleMutableEntry<String, Integer> o1, SimpleMutableEntry<String, Integer> o2) {
+                return o1.getValue() - o2.getValue();
+            }
+        });
 
         return ms;
     }
@@ -94,4 +131,20 @@ public class Compare {
     public static List<SimpleMutableEntry<String, Integer>> matchesWithRate(String[] compared, String comparator, boolean allowSkip) {
         return matchesWithRate(Arrays.asList(compared), comparator, allowSkip);
     }
+
+    private static class ComparePack {
+        String s;
+        int index;
+        int total;
+
+        public ComparePack(String s, int index, int total) {
+            this.s = s;
+            this.index = index;
+            this.total = total;
+        }
+
+        public int coefficient() {
+            return index;
+        }
+    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/Tuils.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/Tuils.java
index 5b1568a..99a280a 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/Tuils.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/Tuils.java
@@ -267,7 +267,6 @@ public class Tuils {
     public static final int MEGA = 2;
     public static final int KILO = 3;
     public static final int BYTE = 4;
-    public static final int PERCENTAGE = 5;
 
     private static long total = -1;
 
@@ -295,11 +294,15 @@ public class Tuils {
     }
 
     public static double round(double value, int places) {
-        if (places < 0) throw new IllegalArgumentException();
+        if (places < 0) places = 0;
 
-        BigDecimal bd = new BigDecimal(value);
-        bd = bd.setScale(places, RoundingMode.HALF_UP);
-        return bd.doubleValue();
+        try {
+            BigDecimal bd = new BigDecimal(value);
+            bd = bd.setScale(places, RoundingMode.HALF_UP);
+            return bd.doubleValue();
+        } catch (Exception e) {
+            return value;
+        }
     }
 
     public static List<String> getClassesInPackage(String packageName, Context c) throws IOException {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/interfaces/CommandExecuter.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/interfaces/CommandExecuter.java
index ca2fc99..e0d8d0e 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/interfaces/CommandExecuter.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/interfaces/CommandExecuter.java
@@ -5,5 +5,6 @@ package ohi.andre.consolelauncher.tuils.interfaces;
  */
 public interface CommandExecuter {
 
-    String exec(String input, String alias);
+    String exec(String aliasValue, String aliasName);
+    String exec(String input);
 }
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 0f08e26..1134ffe 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -10,6 +10,7 @@
     <string name="output_rate">Thank you!</string>
     <string name="start_notification">T-UI started</string>
     <string name="tui_running">T-UI is running</string>
+    <string name="anr">t-ui is having some issues. Please send to the developer your file crash.txt</string>
 
     <!-- files -->
     <string name="output_error">An unknown error has occurred</string>
@@ -18,6 +19,7 @@
 
     <!-- notifications -->
     <string name="notification_reader">Notification Reader</string>
+    <string name="no_notification_access">Unfortunately t-ui can\'t redirect you to the \"Notification access\" page of your system settings</string>
 
     <!-- helps texts -->
     <string name="rate_donate_text">\nDo you like my work? Rate on Play Store (command: >>rate) or offer me a coffee (command: >>donate). Thank you for using T-UI.
diff --git a/build.gradle b/build.gradle
index e21e380..5954279 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,3 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
 buildscript {
 
     repositories {
@@ -9,9 +7,6 @@ buildscript {
 
     dependencies {
         classpath 'com.android.tools.build:gradle:2.3.1'
-
-        // NOTE: Do not place your application dependencies here; they belong
-        // in the individual module build.gradle files
     }
 }
 
-- 
GitLab