From f47ac1735aa3f6ee1cbcb3df35f84604248b3750 Mon Sep 17 00:00:00 2001
From: Francesco Andreuzzi <andreuzzi.francesco@gmail.com>
Date: Sat, 26 Aug 2017 00:09:27 +0200
Subject: [PATCH] 6.2a

---
 app/build.gradle                              |   4 +-
 app/google-services.json                      |  55 ++
 app/src/main/AndroidManifest.xml              |   2 +
 .../consolelauncher/LauncherActivity.java     |  93 ++-
 .../andre/consolelauncher/MainManager.java    |  51 +-
 .../ohi/andre/consolelauncher/UIManager.java  |   2 +-
 .../consolelauncher/commands/Command.java     |  28 +-
 .../commands/CommandAbstraction.java          |   7 +-
 .../commands/CommandTuils.java                |  19 +-
 .../commands/main/MainPack.java               |  55 +-
 .../consolelauncher/commands/main/Param.java  |   3 +
 .../commands/main/raw/airplane.java           |   5 -
 .../commands/main/raw/alias.java              |  30 +-
 .../commands/main/raw/apps.java               | 174 +++++-
 .../commands/main/raw/beep.java               |   5 -
 .../commands/main/raw/bluetooth.java          |   5 -
 .../commands/main/raw/calc.java               |   5 -
 .../commands/main/raw/call.java               |   5 -
 .../commands/main/raw/clear.java              |   5 -
 .../commands/main/raw/cntcts.java             |  45 +-
 .../commands/main/raw/config.java             |  46 +-
 .../commands/main/raw/ctrlc.java              |   5 -
 .../commands/main/raw/data.java               |   5 -
 .../commands/main/raw/devutils.java           | 110 ++++
 .../commands/main/raw/donate.java             |   5 -
 .../commands/main/raw/exit.java               |   5 -
 .../commands/main/raw/flash.java              | 216 +++----
 .../commands/main/raw/help.java               |   5 -
 .../commands/main/raw/location.java           |   5 -
 .../commands/main/raw/music.java              |  40 +-
 .../commands/main/raw/notifications.java      |  73 ++-
 .../commands/main/raw/open.java               |   5 -
 .../commands/main/raw/rate.java               |   5 -
 .../commands/main/raw/refresh.java            |   5 -
 .../commands/main/raw/restart.java            |   5 -
 .../commands/main/raw/search.java             | 116 ++--
 .../commands/main/raw/share.java              |   5 -
 .../commands/main/raw/shellcommands.java      |  10 +-
 .../commands/main/raw/sms.java                |   5 -
 .../commands/main/raw/status.java             |   5 -
 .../commands/main/raw/theme.java              | 118 ++++
 .../commands/main/raw/time.java               |   5 -
 .../commands/main/raw/tui.java                |  32 +-
 .../commands/main/raw/tuixt.java              |   5 -
 .../commands/main/raw/tutorial.java           |   5 -
 .../commands/main/raw/uninstall.java          |   5 -
 .../commands/main/raw/vibrate.java            |   5 -
 .../commands/main/raw/wifi.java               |   5 -
 .../commands/specific/ParamCommand.java       |  15 +
 .../commands/tuixt/TuixtActivity.java         |   2 +-
 .../commands/tuixt/raw/exit.java              |   5 -
 .../commands/tuixt/raw/help.java              |   5 -
 .../commands/tuixt/raw/save.java              |   5 -
 .../consolelauncher/managers/AppsManager.java | 535 ++++++++++++++----
 .../managers/ContactManager.java              |   8 +-
 .../consolelauncher/managers/SkinManager.java |   2 +-
 .../managers/ThemesManager.java               | 145 +++++
 .../managers/XMLPrefsManager.java             | 179 ++++--
 .../managers/flashlight/Constants.java        |  49 ++
 .../managers/flashlight/Device.java           |  44 ++
 .../managers/flashlight/DeviceListener.java   |  27 +
 .../managers/flashlight/Flashlight.java       |  34 ++
 .../managers/flashlight/Flashlight1.java      | 107 ++++
 .../managers/flashlight/Flashlight2.java      |  98 ++++
 .../managers/flashlight/OutputDevice.java     |  74 +++
 .../flashlight/OutputDeviceListener.java      |  27 +
 .../managers/flashlight/Torch.java            |  32 ++
 .../managers/flashlight/TorchManager.java     |  69 +++
 .../managers/music/MusicManager2.java         |  17 +-
 .../consolelauncher/managers/music/Song.java  |   9 +-
 .../notifications/NotificationManager.java    |  39 +-
 .../notifications/NotificationService.java    |  43 +-
 .../suggestions/SuggestionRunnable.java       |  65 ++-
 .../suggestions/SuggestionsManager.java       | 222 ++++----
 .../andre/consolelauncher/tuils/Compare.java  |  28 +
 .../andre/consolelauncher/tuils/Tuils.java    |  26 +-
 app/src/main/res/values/strings.xml           |  43 +-
 77 files changed, 2553 insertions(+), 855 deletions(-)
 create mode 100644 app/google-services.json
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/devutils.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/theme.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/managers/ThemesManager.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Constants.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Device.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/DeviceListener.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight1.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight2.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/OutputDevice.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/OutputDeviceListener.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Torch.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/TorchManager.java

diff --git a/app/build.gradle b/app/build.gradle
index f228dd0..a15995c 100755
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,8 +11,8 @@ android {
         minSdkVersion 9
         targetSdkVersion 23
 
-        versionCode 122
-        versionName "6.2b"
+        versionCode 125
+        versionName "6.3b"
     }
 
     buildTypes {
diff --git a/app/google-services.json b/app/google-services.json
new file mode 100644
index 0000000..c42f8ef
--- /dev/null
+++ b/app/google-services.json
@@ -0,0 +1,55 @@
+{
+  "project_info": {
+    "project_number": "461882303040",
+    "firebase_url": "https://voltaic-charter-154600.firebaseio.com",
+    "project_id": "voltaic-charter-154600",
+    "storage_bucket": "voltaic-charter-154600.appspot.com"
+  },
+  "client": [
+    {
+      "client_info": {
+        "mobilesdk_app_id": "1:461882303040:android:fb35e978c4e587f5",
+        "android_client_info": {
+          "package_name": "ohi.andre.consolelauncher"
+        }
+      },
+      "oauth_client": [
+        {
+          "client_id": "461882303040-hh2aic16bg8c6ivhrmkogrfus5cfdhfb.apps.googleusercontent.com",
+          "client_type": 1,
+          "android_info": {
+            "package_name": "ohi.andre.consolelauncher",
+            "certificate_hash": "5b330e846d1dc49302993131a5bec9187936dba0"
+          }
+        },
+        {
+          "client_id": "461882303040-oe3oiuegut9vvub3jmt53v57lk9q2rk6.apps.googleusercontent.com",
+          "client_type": 3
+        }
+      ],
+      "api_key": [
+        {
+          "current_key": "AIzaSyDSnTQXJPlRBb1KwnPJ2nQXiKzJNfN7l10"
+        }
+      ],
+      "services": {
+        "analytics_service": {
+          "status": 1
+        },
+        "appinvite_service": {
+          "status": 2,
+          "other_platform_oauth_client": [
+            {
+              "client_id": "461882303040-oe3oiuegut9vvub3jmt53v57lk9q2rk6.apps.googleusercontent.com",
+              "client_type": 3
+            }
+          ]
+        },
+        "ads_service": {
+          "status": 2
+        }
+      }
+    }
+  ],
+  "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a13b89d..0beffc5 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -10,6 +10,8 @@
         android:smallScreens="true" />
 
     <!-- permissions -->
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.FLASHLIGHT" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java b/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java
index 274e505..1df632d 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java
@@ -20,12 +20,16 @@ import android.view.KeyEvent;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.Window;
 import android.view.WindowManager;
 import android.widget.Toast;
 
 import com.github.anrwatchdog.ANRError;
 import com.github.anrwatchdog.ANRWatchDog;
 
+import java.util.LinkedList;
+import java.util.Queue;
+
 import ohi.andre.consolelauncher.commands.main.MainPack;
 import ohi.andre.consolelauncher.commands.tuixt.TuixtActivity;
 import ohi.andre.consolelauncher.managers.ContactManager;
@@ -37,6 +41,7 @@ import ohi.andre.consolelauncher.managers.suggestions.SuggestionsManager;
 import ohi.andre.consolelauncher.tuils.Assist;
 import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
 import ohi.andre.consolelauncher.tuils.KeeperService;
+import ohi.andre.consolelauncher.tuils.SimpleMutableEntry;
 import ohi.andre.consolelauncher.tuils.TimeManager;
 import ohi.andre.consolelauncher.tuils.Tuils;
 import ohi.andre.consolelauncher.tuils.interfaces.CommandExecuter;
@@ -113,19 +118,74 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
 
     private Outputable out = new Outputable() {
 
+        private final int DELAY = 500;
+
+        Queue<SimpleMutableEntry<CharSequence,Integer>> textColor = new LinkedList<>();
+        Queue<SimpleMutableEntry<CharSequence,Integer>> textCategory = new LinkedList<>();
+
+        boolean charged = false;
+        Handler handler = new Handler();
+        Runnable r = new Runnable() {
+            @Override
+            public void run() {
+                if(ui == null) {
+                    handler.postDelayed(this, DELAY);
+                    return;
+                }
+
+                SimpleMutableEntry<CharSequence,Integer> sm;
+                while ((sm = textCategory.poll()) != null) {
+                    ui.setOutput(sm.getKey(), sm.getValue());
+                }
+
+                while ((sm = textColor.poll()) != null) {
+                    ui.setOutput(sm.getValue(), sm.getKey());
+                }
+
+                textCategory = null;
+                textColor = null;
+                handler = null;
+                r = null;
+            }
+        };
+
         @Override
         public void onOutput(CharSequence output) {
             if(ui != null) ui.setOutput(output, TerminalManager.CATEGORY_OUTPUT);
+            else {
+                textCategory.add(new SimpleMutableEntry<>(output, TerminalManager.CATEGORY_OUTPUT));
+
+                if(!charged) {
+                    charged = true;
+                    handler.postDelayed(r, DELAY);
+                }
+            }
         }
 
         @Override
         public void onOutput(CharSequence output, int category) {
             if(ui != null) ui.setOutput(output, category);
+            else {
+                textCategory.add(new SimpleMutableEntry<>(output, category));
+
+                if(!charged) {
+                    charged = true;
+                    handler.postDelayed(r, DELAY);
+                }
+            }
         }
 
         @Override
         public void onOutput(int color, CharSequence output) {
-            ui.setOutput(color, output);
+            if(ui != null) ui.setOutput(color, output);
+            else {
+                textColor.add(new SimpleMutableEntry<>(output, color));
+
+                if(!charged) {
+                    charged = true;
+                    handler.postDelayed(r, DELAY);
+                }
+            }
         }
     };
 
@@ -178,8 +238,15 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
             }
         });
 
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(InputOutputReceiver.ACTION_CMD);
+        filter.addAction(InputOutputReceiver.ACTION_OUTPUT);
+
+        InputOutputReceiver inputOutputReceiver = new InputOutputReceiver(ex, out);
+        getApplicationContext().registerReceiver(inputOutputReceiver, filter);
+
         try {
-            XMLPrefsManager.create();
+            XMLPrefsManager.create(this);
             TimeManager.create();
         } catch (Exception e) {
             Tuils.log(Tuils.getStackTrace(e));
@@ -187,6 +254,16 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
             return;
         }
 
+        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !XMLPrefsManager.get(boolean.class, XMLPrefsManager.Ui.ignore_bar_color)) {
+            Window window = getWindow();
+
+            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
+            window.setStatusBarColor(XMLPrefsManager.getColor(XMLPrefsManager.Theme.statusbar_color));
+            window.setNavigationBarColor(XMLPrefsManager.getColor(XMLPrefsManager.Theme.navigationbar_color));
+        }
+
         boolean showNotification = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.tui_notification);
         Intent keeperIntent = new Intent(this, KeeperService.class);
         if (showNotification) {
@@ -215,11 +292,14 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
         }
 
         try {
-            NotificationManager.create();
+            NotificationManager.create(this);
         } catch (Exception e) {
             Tuils.toFile(e);
         }
+
         boolean notifications = XMLPrefsManager.get(boolean.class, NotificationManager.Options.show_notifications);
+        if(!notifications) notifications = XMLPrefsManager.get(String.class, NotificationManager.Options.show_notifications).equalsIgnoreCase("enabled");
+
         if(notifications) {
             LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, new IntentFilter("Msg"));
             if(!Tuils.hasNotificationAccess(this)) {
@@ -262,13 +342,6 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
             ui.setInput("tutorial");
         }
 
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(InputOutputReceiver.ACTION_CMD);
-        filter.addAction(InputOutputReceiver.ACTION_OUTPUT);
-
-        InputOutputReceiver inputOutputReceiver = new InputOutputReceiver(ex, out);
-        getApplicationContext().registerReceiver(inputOutputReceiver, filter);
-
         System.gc();
     }
 
diff --git a/app/src/main/java/ohi/andre/consolelauncher/MainManager.java b/app/src/main/java/ohi/andre/consolelauncher/MainManager.java
index 3a97b3b..24568dc 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/MainManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/MainManager.java
@@ -21,9 +21,9 @@ import ohi.andre.consolelauncher.managers.AliasManager;
 import ohi.andre.consolelauncher.managers.AppsManager;
 import ohi.andre.consolelauncher.managers.ContactManager;
 import ohi.andre.consolelauncher.managers.TerminalManager;
-import ohi.andre.consolelauncher.managers.ThemesManager;
 import ohi.andre.consolelauncher.managers.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.music.MusicManager2;
+import ohi.andre.consolelauncher.tuils.Compare;
 import ohi.andre.consolelauncher.tuils.StoppableThread;
 import ohi.andre.consolelauncher.tuils.TimeManager;
 import ohi.andre.consolelauncher.tuils.Tuils;
@@ -86,7 +86,8 @@ public class MainManager {
 
     private final String COMMANDS_PKG = "ohi.andre.consolelauncher.commands.main.raw";
 
-    private CmdTrigger[] triggers = new CmdTrigger[]{
+    private CmdTrigger[] triggers = new CmdTrigger[] {
+            new GroupTrigger(),
             new AliasTrigger(),
             new TuiCommandTrigger(),
             new AppTrigger(),
@@ -101,6 +102,7 @@ public class MainManager {
 
     private boolean showAliasValue;
     private boolean showAppHistory;
+    private int aliasContentColor;
 
     private String multipleCmdSeparator;
 
@@ -116,11 +118,10 @@ public class MainManager {
 
         showAliasValue = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.show_alias_content);
         showAppHistory = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.show_launch_history);
+        aliasContentColor = XMLPrefsManager.getColor(XMLPrefsManager.Theme.alias_content_color);
 
         multipleCmdSeparator = XMLPrefsManager.get(String.class, XMLPrefsManager.Behavior.multiple_cmd_separator);
 
-        new ThemesManager();
-
         CommandGroup group = new CommandGroup(mContext, COMMANDS_PKG);
 
         ContactManager cont = null;
@@ -155,7 +156,7 @@ public class MainManager {
         }
 
         if(alias != null && showAliasValue) {
-            out.onOutput(mainPack.aliasManager.formatLabel(alias, input));
+            out.onOutput(aliasContentColor, mainPack.aliasManager.formatLabel(alias, input));
         }
 
         String[] cmds;
@@ -225,7 +226,6 @@ public class MainManager {
 
     private class AliasTrigger implements CmdTrigger {
 
-
         @Override
         public boolean trigger(ExecutePack info, String input) {
             String alias[] = mainPack.aliasManager.getAlias(input, true);
@@ -246,6 +246,39 @@ public class MainManager {
         }
     }
 
+    private class GroupTrigger implements CmdTrigger {
+
+        @Override
+        public boolean trigger(ExecutePack info, String input) throws Exception {
+            int index = input.indexOf(Tuils.SPACE);
+            String name;
+
+            if(index != -1) {
+                name = input.substring(0,index);
+                input = input.substring(index + 1);
+            } else {
+                name = input;
+                input = null;
+            }
+
+            List<? extends Group> appGroups = AppsManager.groups;
+            if(appGroups != null) {
+                for(Group g : appGroups) {
+                    if(name.equals(g.name())) {
+                        if(input == null) {
+                            out.onOutput(AppsManager.AppUtils.printApps(AppsManager.AppUtils.labelList((List<AppsManager.LaunchInfo>) g.members(), false)));
+                            return true;
+                        } else {
+                            return g.use(mainPack, input);
+                        }
+                    }
+                }
+            }
+
+            return false;
+        }
+    }
+
     private class SystemCommandTrigger implements CmdTrigger {
 
         final int CD_CODE = 10;
@@ -375,4 +408,10 @@ public class MainManager {
             return true;
         }
     }
+
+    public interface Group {
+        List<? extends Compare.Stringable> members();
+        boolean use(MainPack mainPack, String input);
+        String name();
+    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/UIManager.java b/app/src/main/java/ohi/andre/consolelauncher/UIManager.java
index 7947c4d..df46d31 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/UIManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/UIManager.java
@@ -727,7 +727,7 @@ public class UIManager implements OnTouchListener {
             this.clickListener = null;
         }
 
-        lockOnDbTap = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.double_tap_closes);
+        lockOnDbTap = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.double_tap_lock);
         doubleTapCmd = XMLPrefsManager.get(String.class, XMLPrefsManager.Behavior.double_tap_cmd);
         if(!lockOnDbTap && doubleTapCmd == null) {
             policy = null;
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/Command.java b/app/src/main/java/ohi/andre/consolelauncher/commands/Command.java
index 977ed03..d0033bd 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/Command.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/Command.java
@@ -18,11 +18,11 @@ public class Command {
     public String exec(Resources resources, ExecutePack info) throws Exception {
         info.set(mArgs);
 
-        if (indexNotFound != -1) {
-            return cmd.onArgNotFound(info, indexNotFound);
-        }
-
         if(cmd instanceof ParamCommand) {
+            if(indexNotFound == 0) {
+                return cmd.onArgNotFound(info, indexNotFound);
+            }
+
             ParamCommand pCmd = (ParamCommand) cmd;
 
             if(mArgs == null || mArgs.length == 0) {
@@ -30,29 +30,33 @@ public class Command {
             }
 
             int[] args = info.get(Param.class, 0).args();
-            if(args == null) return resources.getString(R.string.output_invalid_param) + Tuils.SPACE + mArgs[0];
+            if(args == null || !(mArgs[0] instanceof Param)) return resources.getString(R.string.output_invalid_param) + Tuils.SPACE + mArgs[0];
+
+            Param param = (Param) mArgs[0];
+
+            if(indexNotFound != -1) {
+                param.onArgNotFound(info, indexNotFound);
+            }
 
             if(pCmd.supportDefaultParam()) {
-                if(args.length + 1 > nArgs + 1) {
-                    return cmd.onNotArgEnough(info, nArgs);
+                if(args.length > nArgs) {
+                    return param.onNotArgEnough(info, nArgs);
                 }
             } else {
                 if(args.length + 1 > nArgs) {
-                    return cmd.onNotArgEnough(info, nArgs);
+                    return param.onNotArgEnough(info, nArgs);
                 }
             }
         } else if (nArgs < cmd.minArgs() || (mArgs == null && cmd.minArgs() > 0)) {
             return cmd.onNotArgEnough(info, nArgs);
         }
 
-        if (cmd.maxArgs() != CommandAbstraction.UNDEFINIED && nArgs > cmd.maxArgs()) {
-            return resources.getString(R.string.output_toomanyargs);
+        if(indexNotFound != -1) {
+            return cmd.onArgNotFound(info, indexNotFound);
         }
 
         String output = cmd.exec(info);
-
         info.clear();
-
         return output;
     }
 
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/CommandAbstraction.java b/app/src/main/java/ohi/andre/consolelauncher/commands/CommandAbstraction.java
index 1b2f4c1..5a118f1 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/CommandAbstraction.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/CommandAbstraction.java
@@ -2,9 +2,6 @@ package ohi.andre.consolelauncher.commands;
 
 public interface CommandAbstraction {
 
-    //	undefinied n of arguments
-    int UNDEFINIED = -1;
-
     //	arg type
     int PLAIN_TEXT = 10;
     int FILE = 11;
@@ -23,13 +20,13 @@ public interface CommandAbstraction {
     int INT = 24;
     int DEFAULT_APP = 25;
     int ALL_PACKAGES = 26;
+    int NO_SPACE_STRING = 27;
+    int APP_GROUP = 28;
 
     String exec(ExecutePack pack) throws Exception;
 
     int minArgs();
 
-    int maxArgs();
-
     int[] argType();
 
     int priority();
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 922fbeb..a3cda5a 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/CommandTuils.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/CommandTuils.java
@@ -159,6 +159,10 @@ public class CommandTuils {
             return defaultApp(input, ((MainPack) info).appsManager);
         } else if(type == CommandAbstraction.ALL_PACKAGES) {
             return allPackages(input, ((MainPack) info).appsManager);
+        } else if(type == CommandAbstraction.NO_SPACE_STRING) {
+            return noSpaceString(input);
+        } else if(type == CommandAbstraction.APP_GROUP) {
+            return noSpaceString(input);
         }
 
         return null;
@@ -212,6 +216,15 @@ public class CommandTuils {
         return new ArgInfo(arg, null, true, arg.size());
     }
 
+    private static ArgInfo noSpaceString(String input) {
+        if(input == null) return null;
+
+        int index = input.indexOf(Tuils.SPACE);
+        if(index == -1) index = input.length();
+
+        return new ArgInfo(input.substring(0,index), input.length() > index ? input.substring(index + 1) : null, true, 1);
+    }
+
     private static ArgInfo command(String string, CommandGroup active) {
         CommandAbstraction abstraction = null;
         try {
@@ -380,10 +393,14 @@ public class CommandTuils {
     private static ArgInfo configEntry(String input) {
         int index = input.indexOf(Tuils.SPACE);
 
+        Tuils.log(input);
+
         if(xmlPrefsEntrys == null) {
             xmlPrefsEntrys = new ArrayList<>();
 
-            for(XMLPrefsManager.XMLPrefsRoot element : XMLPrefsManager.XMLPrefsRoot.values()) Collections.addAll(element.copy);
+            for(XMLPrefsManager.XMLPrefsRoot element : XMLPrefsManager.XMLPrefsRoot.values()) {
+                xmlPrefsEntrys.addAll(element.copy);
+            }
             Collections.addAll(xmlPrefsEntrys, AppsManager.Options.values());
             Collections.addAll(xmlPrefsEntrys, NotificationManager.Options.values());
         }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/MainPack.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/MainPack.java
index c5de9b4..5fa04a6 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/MainPack.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/MainPack.java
@@ -7,21 +7,19 @@ import android.hardware.Camera;
 import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
-import android.os.Build;
 import android.os.Environment;
 
 import java.io.File;
 import java.lang.reflect.Method;
-import java.util.List;
 
 import ohi.andre.consolelauncher.commands.CommandGroup;
 import ohi.andre.consolelauncher.commands.CommandsPreferences;
 import ohi.andre.consolelauncher.commands.ExecutePack;
-import ohi.andre.consolelauncher.commands.main.raw.flash;
 import ohi.andre.consolelauncher.managers.AliasManager;
 import ohi.andre.consolelauncher.managers.AppsManager;
 import ohi.andre.consolelauncher.managers.ContactManager;
 import ohi.andre.consolelauncher.managers.SkinManager;
+import ohi.andre.consolelauncher.managers.flashlight.TorchManager;
 import ohi.andre.consolelauncher.managers.music.MusicManager2;
 import ohi.andre.consolelauncher.tuils.interfaces.CommandExecuter;
 import ohi.andre.consolelauncher.tuils.interfaces.Redirectator;
@@ -113,32 +111,35 @@ public class MainPack extends ExecutePack {
         this.redirectator = redirectator;
     }
 
-    public void initCamera() {
-        try {
-            this.camera = Camera.open();
-            this.parameters = this.camera.getParameters();
-            List<Camera.Size> sizes = this.parameters.getSupportedPreviewSizes();
-            if(sizes != null && sizes.size() > 0) {
-                this.parameters.setPreviewSize(sizes.get(0).width, sizes.get(0).height);
-            }
-        } catch (Exception e) {
-            this.camera = null;
-            this.parameters = null;
-        }
-    }
+//    public void initCamera() {
+//        try {
+//            this.camera = Camera.open();
+//            this.parameters = this.camera.getParameters();
+//            List<Camera.Size> sizes = this.parameters.getSupportedPreviewSizes();
+//            if(sizes != null && sizes.size() > 0) {
+//                this.parameters.setPreviewSize(sizes.get(0).width, sizes.get(0).height);
+//            }
+//        } catch (Exception e) {
+//            this.camera = null;
+//            this.parameters = null;
+//        }
+//    }
 
     public void dispose() {
-        if (this.camera == null || this.isFlashOn)
-            return;
-
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            flash.detachSurfaceTexture(null);
-        }
-
-        this.camera.stopPreview();
-        this.camera.release();
-        this.camera = null;
-        this.parameters = null;
+//        if (this.camera == null || this.isFlashOn)
+//            return;
+//
+//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+//            flash.detachSurfaceTexture(null);
+//        }
+
+//        this.camera.stopPreview();
+//        this.camera.release();
+//        this.camera = null;
+//        this.parameters = null;
+
+        TorchManager mgr = TorchManager.getInstance();
+        if(mgr.isOn()) mgr.turnOff();
     }
 
     public void destroy() {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/Param.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/Param.java
index c7c4cfe..14adb8c 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/Param.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/Param.java
@@ -11,4 +11,7 @@ public interface Param {
     int[] args();
     String exec(ExecutePack pack);
     String label();
+
+    String onNotArgEnough(ExecutePack pack, int n);
+    String onArgNotFound(ExecutePack pack, int index);
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/airplane.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/airplane.java
index 07c61cc..aed3878 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/airplane.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/airplane.java
@@ -45,11 +45,6 @@ public class airplane extends APICommand {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/alias.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/alias.java
index a3855aa..e524b51 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/alias.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/alias.java
@@ -98,6 +98,16 @@ public class alias extends ParamCommand {
         public String label() {
             return Tuils.MINUS + name();
         }
+
+        @Override
+        public String onNotArgEnough(ExecutePack pack, int index) {
+            return pack.context.getString(R.string.help_alias);
+        }
+
+        @Override
+        public String onArgNotFound(ExecutePack pack, int index) {
+            return null;
+        }
     }
 
 
@@ -121,28 +131,8 @@ public class alias extends ParamCommand {
         return R.string.help_alias;
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
-    @Override
-    public int maxArgs() {
-        return CommandAbstraction.UNDEFINIED;
-    }
-
     @Override
     public int priority() {
         return 2;
     }
-
-    @Override
-    public String onNotArgEnough(ExecutePack info, int nArgs) {
-        return ((MainPack) info).aliasManager.printAliases();
-    }
-
-    @Override
-    public String onArgNotFound(ExecutePack info, int index) {
-        return null;
-    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/apps.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/apps.java
index 27d74d7..36bd6e8 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/apps.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/apps.java
@@ -21,6 +21,17 @@ public class apps extends ParamCommand {
 
     private enum Param implements ohi.andre.consolelauncher.commands.main.Param {
 
+        ls {
+            @Override
+            public int[] args() {
+                return new int[0];
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                return ((MainPack) pack).appsManager.printApps(AppsManager.SHOWN_APPS);
+            }
+        },
         lsh {
             @Override
             public int[] args() {
@@ -116,6 +127,15 @@ public class apps extends ParamCommand {
                     return pack.context.getString(R.string.invalid_integer);
                 }
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                int res;
+                if(index == 1) res = R.string.invalid_integer;
+                else res = R.string.output_appnotfound;
+
+                return pack.context.getString(res);
+            }
         },
         st {
             @Override
@@ -154,6 +174,127 @@ public class apps extends ParamCommand {
                 pack.context.startActivity(Tuils.openFile(new File(Tuils.getFolder(), AppsManager.PATH)));
                 return null;
             }
+        },
+        mkgp {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.NO_SPACE_STRING};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                String name = pack.get(String.class, 1);
+                return ((MainPack) pack).appsManager.createGroup(name);
+            }
+        },
+        rmgp {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.APP_GROUP};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                String name = pack.get(String.class, 1);
+                return ((MainPack) pack).appsManager.removeGroup(name);
+            }
+        },
+        gp_bg_color {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.APP_GROUP, CommandAbstraction.COLOR};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                String name = pack.get(String.class, 1);
+                String color = pack.get(String.class, 2);
+                return ((MainPack) pack).appsManager.groupBgColor(name, color);
+            }
+
+            @Override
+            public String onNotArgEnough(ExecutePack pack, int n) {
+                if(n == 2) {
+                    String name = pack.get(String.class, 1);
+                    return ((MainPack) pack).appsManager.groupBgColor(name, Tuils.EMPTYSTRING);
+                }
+                return super.onNotArgEnough(pack, n);
+            }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.output_invalidcolor);
+            }
+        },
+        gp_fore_color {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.APP_GROUP, CommandAbstraction.COLOR};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                String name = pack.get(String.class, 1);
+                String color = pack.get(String.class, 2);
+                return ((MainPack) pack).appsManager.groupForeColor(name, color);
+            }
+
+            @Override
+            public String onNotArgEnough(ExecutePack pack, int n) {
+                if(n == 2) {
+                    String name = pack.get(String.class, 1);
+                    return ((MainPack) pack).appsManager.groupForeColor(name, Tuils.EMPTYSTRING);
+                }
+                return super.onNotArgEnough(pack, n);
+            }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.output_invalidcolor);
+            }
+        },
+        lsgp {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.APP_GROUP};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                String name = pack.get(String.class, 1);
+                return ((MainPack) pack).appsManager.listGroup(name);
+            }
+
+            @Override
+            public String onNotArgEnough(ExecutePack pack, int n) {
+                return ((MainPack) pack).appsManager.listGroups();
+            }
+        },
+        addtogp {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.APP_GROUP, CommandAbstraction.VISIBLE_PACKAGE};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                String name = pack.get(String.class, 1);
+                AppsManager.LaunchInfo app = pack.get(AppsManager.LaunchInfo.class, 2);
+                return ((MainPack) pack).appsManager.addAppToGroup(name, app);
+            }
+        },
+        rmfromgp {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.APP_GROUP, CommandAbstraction.VISIBLE_PACKAGE};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                String name = pack.get(String.class, 1);
+                AppsManager.LaunchInfo app = pack.get(AppsManager.LaunchInfo.class, 2);
+                return ((MainPack) pack).appsManager.removeAppFromGroup(name, app);
+            }
         };
 
         static Param get(String p) {
@@ -180,6 +321,16 @@ public class apps extends ParamCommand {
         public String label() {
             return Tuils.MINUS + name();
         }
+
+        @Override
+        public String onNotArgEnough(ExecutePack pack, int n) {
+            return pack.context.getString(R.string.help_apps);
+        }
+
+        @Override
+        public String onArgNotFound(ExecutePack pack, int index) {
+            return pack.context.getString(R.string.output_appnotfound);
+        }
     }
 
     @Override
@@ -209,34 +360,11 @@ public class apps extends ParamCommand {
         return R.string.help_apps;
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
-    @Override
-    public int maxArgs() {
-        return 3;
-    }
-
     @Override
     public int priority() {
         return 4;
     }
 
-    @Override
-    public String onNotArgEnough(ExecutePack info, int nArgs) {
-        MainPack pack = (MainPack) info;
-        if (nArgs > 0) return pack.res.getString(helpRes());
-        return pack.appsManager.printApps(AppsManager.SHOWN_APPS);
-    }
-
-    @Override
-    public String onArgNotFound(ExecutePack info, int index) {
-        MainPack pack = (MainPack) info;
-        return pack.res.getString(R.string.output_appnotfound);
-    }
-
     @Override
     public String[] params() {
         return Param.labels();
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/beep.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/beep.java
index c2f3852..b3b7f0a 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/beep.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/beep.java
@@ -31,11 +31,6 @@ public class beep implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/bluetooth.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/bluetooth.java
index e0d78c9..7b53c49 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/bluetooth.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/bluetooth.java
@@ -33,11 +33,6 @@ public class bluetooth implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/calc.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/calc.java
index d4b549a..f524cdd 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/calc.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/calc.java
@@ -27,11 +27,6 @@ public class calc extends PermanentSuggestionCommand {
         return 1;
     }
 
-    @Override
-    public int maxArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[] {CommandAbstraction.PLAIN_TEXT};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/call.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/call.java
index 60c24f1..50e5d3d 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/call.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/call.java
@@ -56,11 +56,6 @@ public class call implements CommandAbstraction {
         return 1;
     }
 
-    @Override
-    public int maxArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[]{CommandAbstraction.CONTACTNUMBER};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/clear.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/clear.java
index 8d45ee4..ec09b4f 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/clear.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/clear.java
@@ -21,11 +21,6 @@ public class clear implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/cntcts.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/cntcts.java
index 13d5355..a5354bb 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/cntcts.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/cntcts.java
@@ -71,6 +71,11 @@ public class cntcts extends ParamCommand {
             public int[] args() {
                 return new int[] {CommandAbstraction.CONTACTNUMBER};
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.output_numbernotfound);
+            }
         },
         edit {
             @Override
@@ -86,6 +91,11 @@ public class cntcts extends ParamCommand {
             public int[] args() {
                 return new int[] {CommandAbstraction.CONTACTNUMBER};
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.output_numbernotfound);
+            }
         },
         l {
             @Override
@@ -105,6 +115,11 @@ public class cntcts extends ParamCommand {
             public int[] args() {
                 return new int[] {CommandAbstraction.CONTACTNUMBER};
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.output_numbernotfound);
+            }
         };
 
         static Param get(String p) {
@@ -131,6 +146,16 @@ public class cntcts extends ParamCommand {
         public String label() {
             return Tuils.MINUS + name();
         }
+
+        @Override
+        public String onArgNotFound(ExecutePack pack, int index) {
+            return null;
+        }
+
+        @Override
+        public String onNotArgEnough(ExecutePack pack, int n) {
+            return pack.context.getString(R.string.help_cntcts);
+        }
     }
 
     @Override
@@ -152,16 +177,6 @@ public class cntcts extends ParamCommand {
         return null;
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
-    @Override
-    public int maxArgs() {
-        return 2;
-    }
-
     @Override
     public int priority() {
         return 3;
@@ -171,14 +186,4 @@ public class cntcts extends ParamCommand {
     public int helpRes() {
         return R.string.help_cntcts;
     }
-
-    @Override
-    public String onArgNotFound(ExecutePack pack, int indexNotFound) {
-        return pack.context.getString(R.string.output_numbernotfound);
-    }
-
-    @Override
-    public String onNotArgEnough(ExecutePack pack, int nArgs) {
-        return pack.context.getString(helpRes());
-    }
 }
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 b67edce..60a2da7 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
@@ -34,6 +34,12 @@ public class config extends ParamCommand {
                 }
                 return null;
             }
+
+            @Override
+            public String onNotArgEnough(ExecutePack pack, int n) {
+                pack.args = new Object[] {pack.args[0], pack.args[1], Tuils.EMPTYSTRING};
+                return set.exec(pack);
+            }
         },
         open {
             @Override
@@ -47,6 +53,11 @@ public class config extends ParamCommand {
                 pack.context.startActivity(Tuils.openFile(file));
                 return null;
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.output_filenotfound);
+            }
         },
         get {
             @Override
@@ -98,6 +109,16 @@ public class config extends ParamCommand {
         public String label() {
             return Tuils.MINUS + name();
         }
+
+        @Override
+        public String onNotArgEnough(ExecutePack pack, int n) {
+            return pack.context.getString(R.string.help_config);
+        }
+
+        @Override
+        public String onArgNotFound(ExecutePack pack, int index) {
+            return pack.context.getString(R.string.output_invalidarg);
+        }
     }
 
     @Override
@@ -115,16 +136,6 @@ public class config extends ParamCommand {
         return null;
     }
 
-    @Override
-    public int minArgs() {
-        return 2;
-    }
-
-    @Override
-    public int maxArgs() {
-        return 3;
-    }
-
     @Override
     public int priority() {
         return 4;
@@ -134,19 +145,4 @@ public class config extends ParamCommand {
     public int helpRes() {
         return R.string.help_config;
     }
-
-    @Override
-    public String onArgNotFound(ExecutePack pack, int indexNotFound) {
-        return pack.context.getString(R.string.output_invalidarg);
-    }
-
-    @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/commands/main/raw/ctrlc.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/ctrlc.java
index 99d95cd..ecff729 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/ctrlc.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/ctrlc.java
@@ -37,11 +37,6 @@ public class ctrlc implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/data.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/data.java
index f8a5fe1..c1263a2 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/data.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/data.java
@@ -74,11 +74,6 @@ public class data extends APICommand {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/devutils.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/devutils.java
new file mode 100644
index 0000000..26fd109
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/devutils.java
@@ -0,0 +1,110 @@
+package ohi.andre.consolelauncher.commands.main.raw;
+
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationManagerCompat;
+
+import java.util.List;
+
+import ohi.andre.consolelauncher.R;
+import ohi.andre.consolelauncher.commands.CommandAbstraction;
+import ohi.andre.consolelauncher.commands.ExecutePack;
+import ohi.andre.consolelauncher.commands.main.MainPack;
+import ohi.andre.consolelauncher.commands.specific.ParamCommand;
+import ohi.andre.consolelauncher.tuils.Tuils;
+
+/**
+ * Created by francescoandreuzzi on 22/08/2017.
+ */
+
+public class devutils extends ParamCommand {
+
+    private enum Param implements ohi.andre.consolelauncher.commands.main.Param {
+        notify {
+            @Override
+            public String exec(ExecutePack pack) {
+                List<String> text = pack.get(List.class, 1);
+
+                String title, txt = null;
+                if(text.size() == 0) return null;
+                else {
+                    title = text.remove(0);
+                    if(text.size() >= 2) txt = Tuils.toPlanString(text, Tuils.SPACE);
+                }
+
+                NotificationManagerCompat.from(pack.context).notify(200,
+                        new NotificationCompat.Builder(pack.context)
+                            .setSmallIcon(R.mipmap.ic_launcher)
+                            .setContentTitle(title)
+                            .setContentText(txt)
+                            .build());
+
+                return null;
+            }
+
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.TEXTLIST};
+            }
+        };
+
+        static Param get(String p) {
+            p = p.toLowerCase();
+            Param[] ps = values();
+            for (Param p1 : ps)
+                if (p.endsWith(p1.label()))
+                    return p1;
+            return null;
+        }
+
+        static String[] labels() {
+            Param[] ps = values();
+            String[] ss = new String[ps.length];
+
+            for (int count = 0; count < ps.length; count++) {
+                ss[count] = ps[count].label();
+            }
+
+            return ss;
+        }
+
+        @Override
+        public String label() {
+            return Tuils.MINUS + name();
+        }
+
+        @Override
+        public String onNotArgEnough(ExecutePack pack, int n) {
+            return pack.context.getString(R.string.help_devutils);
+        }
+
+        @Override
+        public String onArgNotFound(ExecutePack pack, int index) {
+            return null;
+        }
+    }
+
+    @Override
+    protected ohi.andre.consolelauncher.commands.main.Param paramForString(MainPack pack, String param) {
+        return Param.get(param);
+    }
+
+    @Override
+    public int priority() {
+        return 2;
+    }
+
+    @Override
+    public int helpRes() {
+        return R.string.help_devutils;
+    }
+
+    @Override
+    public String[] params() {
+        return Param.labels();
+    }
+
+    @Override
+    protected String doThings(ExecutePack pack) {
+        return null;
+    }
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/donate.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/donate.java
index daeca62..4af9b04 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/donate.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/donate.java
@@ -39,11 +39,6 @@ public class donate implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/exit.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/exit.java
index 812d7b3..889db6a 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/exit.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/exit.java
@@ -21,11 +21,6 @@ public class exit implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/flash.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/flash.java
index a782794..6e1d05f 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/flash.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/flash.java
@@ -1,121 +1,128 @@
 package ohi.andre.consolelauncher.commands.main.raw;
 
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.hardware.Camera;
-import android.graphics.SurfaceTexture;
-import android.hardware.Camera.Parameters;
-import android.hardware.camera2.CameraManager;
-import android.os.Build;
+import android.Manifest;
+import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
 
+import ohi.andre.consolelauncher.LauncherActivity;
 import ohi.andre.consolelauncher.R;
 import ohi.andre.consolelauncher.commands.CommandAbstraction;
 import ohi.andre.consolelauncher.commands.ExecutePack;
-import ohi.andre.consolelauncher.commands.main.MainPack;
+import ohi.andre.consolelauncher.managers.flashlight.TorchManager;
 
-@SuppressWarnings("deprecation")
 public class flash implements CommandAbstraction {
 
     @Override
     public String exec(ExecutePack pack) {
-        final MainPack info = (MainPack) pack;
-        if (!info.canUseFlash) {
-            return info.res.getString(R.string.output_flashlightnotavailable);
-        }
-
-        final boolean flashOn = info.isFlashOn;
-        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
-            info.initCamera();
-
-            if(info.camera == null) {
-                return info.res.getString(R.string.output_problemcamera);
-            }
-
-            new Thread() {
-                @Override
-                public void run() {
-                    super.run();
-
-                    if (!flashOn) {
-                        info.parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
-                        info.camera.setParameters(info.parameters);
-
-                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-                            setSurfaceTexture(info.camera);
-                        }
+        if (ContextCompat.checkSelfPermission(pack.context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
 
-                        try {
-                            info.camera.startPreview();
-                        } catch (Exception e) {
-                            info.camera.release();
-                        }
-                    } else {
-                        info.parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
-                        info.camera.setParameters(info.parameters);
-
-                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-                            detachSurfaceTexture(info.camera);
-                        }
-
-                        try {
-                            info.camera.stopPreview();
-                        } catch (Exception e) {
-                            info.camera.release();
-                        }
-                    }
-                }
-            }.start();
-        } else {
-            if(!flashOn) {
-                flashOnMarshy(info.context);
-            } else {
-                flashOffMarshy(info.context);
-            }
-        }
-
-        info.isFlashOn = !flashOn;
-        if (info.isFlashOn) {
-            return info.res.getString(R.string.output_flashon);
-        } else {
-            return info.res.getString(R.string.output_flashoff);
+            ActivityCompat.requestPermissions((Activity) pack.context, new String[]{Manifest.permission.CAMERA}, LauncherActivity.COMMAND_REQUEST_PERMISSION);
+            return pack.context.getString(R.string.output_waitingpermission);
         }
-    }
 
-    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
-    public static void setSurfaceTexture(Camera camera) {
-        try {
-            camera.setPreviewTexture(new SurfaceTexture(0));
-        } catch (Exception e) {}
-    }
-
-    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
-    public static void detachSurfaceTexture(Camera camera) {
-        try {
-            camera.setPreviewTexture(null);
-        } catch (Exception e) {}
+        TorchManager.getInstance().toggle(pack.context);
+
+//        final MainPack info = (MainPack) pack;
+//        if (!info.canUseFlash) {
+//            return info.res.getString(R.string.output_flashlightnotavailable);
+//        }
+//
+//        final boolean flashOn = info.isFlashOn;
+//        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+//            info.initCamera();
+//
+//            if(info.camera == null) {
+//                return info.res.getString(R.string.output_problemcamera);
+//            }
+//
+//            new Thread() {
+//                @Override
+//                public void run() {
+//                    super.run();
+//
+//                    if (!flashOn) {
+//                        info.parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
+//                        info.camera.setParameters(info.parameters);
+//
+//                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+//                            setSurfaceTexture(info.camera);
+//                        }
+//
+//                        try {
+//                            info.camera.startPreview();
+//                        } catch (Exception e) {
+//                            info.camera.release();
+//                        }
+//                    } else {
+//                        info.parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
+//                        info.camera.setParameters(info.parameters);
+//
+//                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+//                            detachSurfaceTexture(info.camera);
+//                        }
+//
+//                        try {
+//                            info.camera.stopPreview();
+//                        } catch (Exception e) {
+//                            info.camera.release();
+//                        }
+//                    }
+//                }
+//            }.start();
+//        } else {
+//            if(!flashOn) {
+//                flashOnMarshy(info.context);
+//            } else {
+//                flashOffMarshy(info.context);
+//            }
+//        }
+//
+//        info.isFlashOn = !flashOn;
+//        if (info.isFlashOn) {
+//            return info.res.getString(R.string.output_flashon);
+//        } else {
+//            return info.res.getString(R.string.output_flashoff);
+//        }
+        return null;
     }
 
-    @TargetApi(Build.VERSION_CODES.M)
-    private boolean flashOnMarshy(Context context) {
-        try {
-            CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
-            manager.setTorchMode(manager.getCameraIdList()[0], true);
-            return true;
-        } catch (Exception e) {
-            return false;
-        }
-    }
-
-    @TargetApi(Build.VERSION_CODES.M)
-    private boolean flashOffMarshy(Context context) {
-        try {
-            CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
-            manager.setTorchMode(manager.getCameraIdList()[0], false);
-            return true;
-        } catch (Exception e) {
-            return false;
-        }
-    }
+//    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+//    public static void setSurfaceTexture(Camera camera) {
+//        try {
+//            camera.setPreviewTexture(new SurfaceTexture(0));
+//        } catch (Exception e) {}
+//    }
+//
+//    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+//    public static void detachSurfaceTexture(Camera camera) {
+//        try {
+//            camera.setPreviewTexture(null);
+//        } catch (Exception e) {}
+//    }
+//
+//    @TargetApi(Build.VERSION_CODES.M)
+//    private boolean flashOnMarshy(Context context) {
+//        try {
+//            CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
+//            manager.setTorchMode(manager.getCameraIdList()[0], true);
+//            return true;
+//        } catch (Exception e) {
+//            return false;
+//        }
+//    }
+//
+//    @TargetApi(Build.VERSION_CODES.M)
+//    private boolean flashOffMarshy(Context context) {
+//        try {
+//            CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
+//            manager.setTorchMode(manager.getCameraIdList()[0], false);
+//            return true;
+//        } catch (Exception e) {
+//            return false;
+//        }
+//    }
 
     @Override
     public int helpRes() {
@@ -127,11 +134,6 @@ public class flash implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/help.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/help.java
index 465f71f..21f5be3 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/help.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/help.java
@@ -32,11 +32,6 @@ public class help implements CommandAbstraction {
         return 1;
     }
 
-    @Override
-    public int maxArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[]{CommandAbstraction.COMMAND};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/location.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/location.java
index aebce88..22c45d4 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/location.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/location.java
@@ -81,11 +81,6 @@ public class location extends APICommand {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/music.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/music.java
index 36ea9e2..e684d70 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/music.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/music.java
@@ -86,6 +86,11 @@ public class music extends ParamCommand {
                 ((MainPack) pack).player.select(s);
                 return null;
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int indexNotFound) {
+                return pack.context.getString(R.string.output_songnotfound);
+            }
         },
         info {
             @Override
@@ -133,6 +138,11 @@ public class music extends ParamCommand {
                 ((MainPack) pack).player.seekTo(pack.get(int.class, 1) * 1000);
                 return null;
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int indexNotFound) {
+                return pack.context.getString(R.string.invalid_integer);
+            }
         };
 
         static Param get(String p) {
@@ -159,21 +169,21 @@ public class music extends ParamCommand {
         public String label() {
             return Tuils.MINUS + name();
         }
-    }
 
-    @Override
-    protected ohi.andre.consolelauncher.commands.main.Param paramForString(MainPack pack, String param) {
-        return Param.get(param);
-    }
+        @Override
+        public String onArgNotFound(ExecutePack pack, int indexNotFound) {
+            return null;
+        }
 
-    @Override
-    public int minArgs() {
-        return 0;
+        @Override
+        public String onNotArgEnough(ExecutePack pack, int n) {
+            return pack.context.getString(R.string.help_music);
+        }
     }
 
     @Override
-    public int maxArgs() {
-        return 2;
+    protected ohi.andre.consolelauncher.commands.main.Param paramForString(MainPack pack, String param) {
+        return Param.get(param);
     }
 
     @Override
@@ -186,16 +196,6 @@ public class music extends ParamCommand {
         return R.string.help_music;
     }
 
-    @Override
-    public String onArgNotFound(ExecutePack pack, int indexNotFound) {
-        return pack.context.getString(R.string.output_songnotfound);
-    }
-
-    @Override
-    public String onNotArgEnough(ExecutePack pack, int nArgs) {
-        return pack.context.getString(helpRes());
-    }
-
     @Override
     public String[] params() {
         return Param.labels();
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/notifications.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/notifications.java
index d6c570d..4fa7fcb 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/notifications.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/notifications.java
@@ -32,6 +32,11 @@ public class notifications extends ParamCommand {
             public int[] args() {
                 return new int[] {CommandAbstraction.VISIBLE_PACKAGE};
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.output_appnotfound);
+            }
         },
         exc {
             @Override
@@ -44,11 +49,15 @@ public class notifications extends ParamCommand {
             public int[] args() {
                 return new int[] {CommandAbstraction.VISIBLE_PACKAGE};
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.output_appnotfound);
+            }
         },
         clr {
             @Override
             public String exec(ExecutePack pack) {
-                if(pack.args.length < 3) return ((MainPack) pack).context.getString(R.string.help_notifications);
                 try {
                     NotificationManager.notificationsChangeFor(new NotificationManager.NotificatedApp(pack.get(AppsManager.LaunchInfo.class, 2).componentName.getPackageName(), pack.get(String.class, 1), true));
                 } catch (Exception e) {}
@@ -59,6 +68,15 @@ public class notifications extends ParamCommand {
             public int[] args() {
                 return new int[] {CommandAbstraction.COLOR, CommandAbstraction.VISIBLE_PACKAGE};
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                int res;
+                if(index == 1) res = R.string.output_invalidcolor;
+                else res = R.string.output_appnotfound;
+
+                return pack.context.getString(res);
+            }
         },
         title_filter {
             @Override
@@ -72,6 +90,11 @@ public class notifications extends ParamCommand {
             public int[] args() {
                 return new int[] {CommandAbstraction.INT, CommandAbstraction.PLAIN_TEXT};
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.invalid_integer);
+            }
         },
         text_filter {
             @Override
@@ -85,6 +108,11 @@ public class notifications extends ParamCommand {
             public int[] args() {
                 return new int[] {CommandAbstraction.INT, CommandAbstraction.PLAIN_TEXT};
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.invalid_integer);
+            }
         },
         apply_filter {
             @Override
@@ -98,6 +126,15 @@ public class notifications extends ParamCommand {
                 NotificationManager.applyFilter(id, pack.get(AppsManager.LaunchInfo.class, 2).componentName.getPackageName());
                 return null;
             }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                int res;
+                if(index == 1) res = R.string.invalid_integer;
+                else res = R.string.output_appnotfound;
+
+                return pack.context.getString(res);
+            }
         },
         file {
             @Override
@@ -152,6 +189,16 @@ public class notifications extends ParamCommand {
         public String label() {
             return Tuils.MINUS + name();
         }
+
+        @Override
+        public String onArgNotFound(ExecutePack pack, int index) {
+            return null;
+        }
+
+        @Override
+        public String onNotArgEnough(ExecutePack pack, int n) {
+            return pack.context.getString(R.string.help_notifications);
+        }
     }
 
     @Override
@@ -169,16 +216,6 @@ public class notifications extends ParamCommand {
         return Param.labels();
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
-    @Override
-    public int maxArgs() {
-        return 3;
-    }
-
     @Override
     public int priority() {
         return 3;
@@ -188,18 +225,4 @@ public class notifications extends ParamCommand {
     public int helpRes() {
         return R.string.help_notifications;
     }
-
-    @Override
-    public String onArgNotFound(ExecutePack pack, int index) {
-        String arg = pack.get(String.class, 0).toLowerCase();
-        if(index == 1 && (arg.equals(Param.title_filter.label()) || arg.equals(Param.text_filter.label()) || arg.equals(Param.apply_filter.label()))) {
-            return ((MainPack) pack).context.getString(R.string.invalid_integer);
-        }
-        return ((MainPack) pack).context.getString(R.string.output_appnotfound);
-    }
-
-    @Override
-    public String onNotArgEnough(ExecutePack pack, int nArgs) {
-        return ((MainPack) pack).context.getString(helpRes());
-    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/open.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/open.java
index 66fbf66..4652f03 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/open.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/open.java
@@ -36,11 +36,6 @@ public class open implements CommandAbstraction {
         return 1;
     }
 
-    @Override
-    public int maxArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[]{CommandAbstraction.FILE};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rate.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rate.java
index 1483462..a04db5a 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rate.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rate.java
@@ -47,11 +47,6 @@ public class rate implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/refresh.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/refresh.java
index 452dcfb..78d761e 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/refresh.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/refresh.java
@@ -28,11 +28,6 @@ public class refresh implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/restart.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/restart.java
index d99b9bf..4a4016c 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/restart.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/restart.java
@@ -19,11 +19,6 @@ public class restart implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/search.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/search.java
index afceeb9..f56dac2 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/search.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/search.java
@@ -2,10 +2,8 @@ package ohi.andre.consolelauncher.commands.main.raw;
 
 import android.content.Context;
 import android.content.Intent;
-import android.content.res.Resources;
 import android.net.Uri;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -15,7 +13,6 @@ import ohi.andre.consolelauncher.commands.ExecutePack;
 import ohi.andre.consolelauncher.commands.main.MainPack;
 import ohi.andre.consolelauncher.commands.specific.ParamCommand;
 import ohi.andre.consolelauncher.tuils.Tuils;
-import ohi.andre.consolelauncher.tuils.interfaces.Outputable;
 
 public class search extends ParamCommand {
 
@@ -100,6 +97,16 @@ public class search extends ParamCommand {
         public String label() {
             return Tuils.MINUS + name();
         }
+
+        @Override
+        public String onNotArgEnough(ExecutePack pack, int n) {
+            return pack.context.getString(R.string.help_search);
+        }
+
+        @Override
+        public String onArgNotFound(ExecutePack pack, int index) {
+            return null;
+        }
     }
 
     @Override
@@ -166,47 +173,47 @@ public class search extends ParamCommand {
         return Tuils.EMPTYSTRING;
     }
 
-    private static String file(final List<String> args, final File cd, final Resources res, final Outputable outputable) {
-        new Thread() {
-            @Override
-            public void run() {
-                super.run();
-
-                String name = Tuils.toPlanString(args);
-                List<String> paths = rightPaths(cd, name);
-                if(paths.size() == 0) {
-                    outputable.onOutput(res.getString(R.string.output_nothing_found));
-                } else {
-                    outputable.onOutput(Tuils.toPlanString(paths, Tuils.NEWLINE));
-                }
-            }
-        };
-
-        return Tuils.EMPTYSTRING;
-    }
-
-    private static List<String> rightPaths(File dir, String name) {
-        File[] files = dir.listFiles();
-        List<String> rightPaths = new ArrayList<>(files.length);
-
-        boolean check = false;
-        for (File file : files) {
-            if (fileMatch(file, name)) {
-                if (!check)
-                    rightPaths.add(dir.getAbsolutePath());
-                check = true;
-                rightPaths.add(Tuils.NEWLINE + Tuils.DOUBLE_SPACE + file.getAbsolutePath());
-            }
-            if (file.isDirectory())
-                rightPaths.addAll(rightPaths(file, name));
-        }
-
-        return rightPaths;
-    }
-
-    private static boolean fileMatch(File f, String name) {
-        return f.getName().equalsIgnoreCase(name);
-    }
+//    private static String file(final List<String> args, final File cd, final Resources res, final Outputable outputable) {
+//        new Thread() {
+//            @Override
+//            public void run() {
+//                super.run();
+//
+//                String name = Tuils.toPlanString(args);
+//                List<String> paths = rightPaths(cd, name);
+//                if(paths.size() == 0) {
+//                    outputable.onOutput(res.getString(R.string.output_nothing_found));
+//                } else {
+//                    outputable.onOutput(Tuils.toPlanString(paths, Tuils.NEWLINE));
+//                }
+//            }
+//        };
+//
+//        return Tuils.EMPTYSTRING;
+//    }
+//
+//    private static List<String> rightPaths(File dir, String name) {
+//        File[] files = dir.listFiles();
+//        List<String> rightPaths = new ArrayList<>(files.length);
+//
+//        boolean check = false;
+//        for (File file : files) {
+//            if (fileMatch(file, name)) {
+//                if (!check)
+//                    rightPaths.add(dir.getAbsolutePath());
+//                check = true;
+//                rightPaths.add(Tuils.NEWLINE + Tuils.DOUBLE_SPACE + file.getAbsolutePath());
+//            }
+//            if (file.isDirectory())
+//                rightPaths.addAll(rightPaths(file, name));
+//        }
+//
+//        return rightPaths;
+//    }
+//
+//    private static boolean fileMatch(File f, String name) {
+//        return f.getName().equalsIgnoreCase(name);
+//    }
 
     private static String youTube(List<String> args, Context c) {
         String toSearch = Tuils.toPlanString(args, "+");
@@ -222,29 +229,8 @@ public class search extends ParamCommand {
         return R.string.help_search;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
-    @Override
-    public int maxArgs() {
-        return CommandAbstraction.UNDEFINIED;
-    }
-
     @Override
     public int priority() {
         return 4;
     }
-
-    @Override
-    public String onNotArgEnough(ExecutePack pack, int nArgs) {
-        return pack.context.getString(helpRes());
-    }
-
-    @Override
-    public String onArgNotFound(ExecutePack pack, int index) {
-//        use default param
-        return pack.context.getString(helpRes());
-    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/share.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/share.java
index 11fa366..c4dc508 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/share.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/share.java
@@ -35,11 +35,6 @@ public class share implements CommandAbstraction {
         return 1;
     }
 
-    @Override
-    public int maxArgs() {
-        return CommandAbstraction.UNDEFINIED;
-    }
-
     @Override
     public int[] argType() {
         return new int[]{CommandAbstraction.FILE};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/shellcommands.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/shellcommands.java
index 2a99036..70fae98 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/shellcommands.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/shellcommands.java
@@ -48,7 +48,10 @@ public class shellcommands implements CommandAbstraction {
         Set<String> commands = new HashSet<>();
 
         for (String s : path) {
-            commands.addAll(Arrays.asList(new File(s).list()));
+            String[] f = new File(s).list();
+            if(f != null) {
+                commands.addAll(Arrays.asList(f));
+            }
         }
 
         return commands;
@@ -59,11 +62,6 @@ public class shellcommands implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/sms.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/sms.java
index 13a51a9..5f2da41 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/sms.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/sms.java
@@ -45,11 +45,6 @@ public class sms extends RedirectCommand {
         return 1;
     }
 
-    @Override
-    public int maxArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[] {CommandAbstraction.CONTACTNUMBER};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/status.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/status.java
index d0f47f7..1fbf0e5 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/status.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/status.java
@@ -58,11 +58,6 @@ public class status implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/theme.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/theme.java
new file mode 100644
index 0000000..fc05a0e
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/theme.java
@@ -0,0 +1,118 @@
+package ohi.andre.consolelauncher.commands.main.raw;
+
+import ohi.andre.consolelauncher.R;
+import ohi.andre.consolelauncher.commands.CommandAbstraction;
+import ohi.andre.consolelauncher.commands.ExecutePack;
+import ohi.andre.consolelauncher.commands.main.MainPack;
+import ohi.andre.consolelauncher.commands.specific.ParamCommand;
+import ohi.andre.consolelauncher.tuils.Tuils;
+
+/**
+ * Created by francescoandreuzzi on 20/08/2017.
+ */
+
+public class theme extends ParamCommand {
+
+    private enum Param implements ohi.andre.consolelauncher.commands.main.Param {
+
+        apply {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.PLAIN_TEXT};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                return "Hehehehe you wanted! Wait some days...";
+
+//                String theme = pack.get(String.class, 1);
+//                ThemesManager.apply(pack.context, theme);
+//                return null;
+            }
+        },
+        view {
+            @Override
+            public int[] args() {
+                return new int[0];
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                pack.context.startActivity(Tuils.webPage("http://tui-launcher.surge.sh/"));
+                return null;
+            }
+        },
+        create {
+            @Override
+            public int[] args() {
+                return new int[0];
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                pack.context.startActivity(Tuils.webPage("http://tui-launcher.surge.sh/create"));
+                return null;
+            }
+        };
+
+        static Param get(String p) {
+            p = p.toLowerCase();
+            Param[] ps = values();
+            for (Param p1 : ps)
+                if (p.endsWith(p1.label()))
+                    return p1;
+            return null;
+        }
+
+        static String[] labels() {
+            Param[] ps = values();
+            String[] ss = new String[ps.length];
+
+            for (int count = 0; count < ps.length; count++) {
+                ss[count] = ps[count].label();
+            }
+
+            return ss;
+        }
+
+        @Override
+        public String label() {
+            return Tuils.MINUS + name();
+        }
+
+        @Override
+        public String onNotArgEnough(ExecutePack pack, int n) {
+            return pack.context.getString(R.string.help_theme);
+        }
+
+        @Override
+        public String onArgNotFound(ExecutePack pack, int index) {
+            return null;
+        }
+    }
+
+    @Override
+    public String[] params() {
+        return Param.labels();
+    };
+
+    @Override
+    protected ohi.andre.consolelauncher.commands.main.Param paramForString(MainPack pack, String param) {
+        return Param.get(param);
+    }
+
+    @Override
+    public int priority() {
+        return 4;
+    }
+
+    @Override
+    public int helpRes() {
+        return R.string.help_theme;
+    }
+
+    @Override
+    protected String doThings(ExecutePack pack) {
+        return null;
+    }
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/time.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/time.java
index c9ab955..2f5277d 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/time.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/time.java
@@ -20,11 +20,6 @@ public class time implements CommandAbstraction {
         return 1;
     }
 
-    @Override
-    public int maxArgs() {
-        return 1;
-    }
-
     @Override
     public int priority() {
         return 4;
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tui.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tui.java
index 01da49d..78e1f40 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tui.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tui.java
@@ -69,7 +69,7 @@ public class tui extends ParamCommand {
         reset {
             @Override
             public String exec(ExecutePack pack) {
-                Tuils.getFolder().delete();
+                Tuils.delete(Tuils.getFolder());
                 return null;
             }
         },
@@ -120,6 +120,16 @@ public class tui extends ParamCommand {
         public String label() {
             return Tuils.MINUS + name();
         }
+
+        @Override
+        public String onArgNotFound(ExecutePack pack, int index) {
+            return null;
+        }
+
+        @Override
+        public String onNotArgEnough(ExecutePack pack, int n) {
+            return null;
+        }
     }
 
     @Override
@@ -137,16 +147,6 @@ public class tui extends ParamCommand {
         return Param.labels();
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
-    @Override
-    public int maxArgs() {
-        return 1;
-    }
-
     @Override
     public int priority() {
         return 4;
@@ -156,14 +156,4 @@ public class tui extends ParamCommand {
     public int helpRes() {
         return R.string.help_tui;
     }
-
-    @Override
-    public String onArgNotFound(ExecutePack pack, int indexNotFound) {
-        return null;
-    }
-
-    @Override
-    public String onNotArgEnough(ExecutePack pack, int nArgs) {
-        return ((MainPack) pack).context.getString(helpRes());
-    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tuixt.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tuixt.java
index 8ec7bb8..9872dd3 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tuixt.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tuixt.java
@@ -43,11 +43,6 @@ public class tuixt implements CommandAbstraction {
         return 1;
     }
 
-    @Override
-    public int maxArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[] {CommandAbstraction.FILE};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tutorial.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tutorial.java
index 68bfa4e..1cab1a6 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tutorial.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tutorial.java
@@ -27,11 +27,6 @@ public class tutorial implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/uninstall.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/uninstall.java
index b338b9c..23b25e6 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/uninstall.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/uninstall.java
@@ -35,11 +35,6 @@ public class uninstall implements CommandAbstraction {
         return 1;
     }
 
-    @Override
-    public int maxArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[]{CommandAbstraction.VISIBLE_PACKAGE};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/vibrate.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/vibrate.java
index 6bb0393..e1f513c 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/vibrate.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/vibrate.java
@@ -40,11 +40,6 @@ public class vibrate implements CommandAbstraction {
         return 1;
     }
 
-    @Override
-    public int maxArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[] {CommandAbstraction.PLAIN_TEXT};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/wifi.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/wifi.java
index 9a0fe0f..d82ff97 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/wifi.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/wifi.java
@@ -30,11 +30,6 @@ public class wifi implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/specific/ParamCommand.java b/app/src/main/java/ohi/andre/consolelauncher/commands/specific/ParamCommand.java
index c87cc1a..a202895 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/specific/ParamCommand.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/specific/ParamCommand.java
@@ -20,6 +20,11 @@ public abstract class ParamCommand implements CommandAbstraction {
         return new int[] {CommandAbstraction.PARAM};
     }
 
+    @Override
+    public int minArgs() {
+        return -1;
+    }
+
     @Override
     public final String exec(ExecutePack pack) throws Exception {
         String o = doThings(pack);
@@ -44,6 +49,16 @@ public abstract class ParamCommand implements CommandAbstraction {
         return def;
     }
 
+    @Override
+    public String onNotArgEnough(ExecutePack pack, int nArgs) {
+        return pack.context.getString(helpRes());
+    }
+
+    @Override
+    public String onArgNotFound(ExecutePack pack, int indexNotFound) {
+        return pack.context.getString(helpRes());
+    }
+
     public abstract String[] params();
     protected abstract Param paramForString(MainPack pack, String param);
     protected abstract String doThings(ExecutePack pack);
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/TuixtActivity.java b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/TuixtActivity.java
index d6d3a88..cc7bd3d 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/TuixtActivity.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/TuixtActivity.java
@@ -118,7 +118,7 @@ public class TuixtActivity extends Activity {
         prefixView.setTypeface(skinManager.systemFont ? Typeface.DEFAULT : lucidaConsole);
         prefixView.setTextColor(skinManager.inputColor);
         prefixView.setTextSize(skinManager.getTextSize());
-        prefixView.setText(prefix);
+        prefixView.setText(prefix.endsWith(Tuils.SPACE) ? prefix : prefix + Tuils.SPACE);
 
         if (submitView != null) {
             submitView.setColorFilter(skinManager.inputColor);
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/exit.java b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/exit.java
index 9f8a5d0..b6fb29f 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/exit.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/exit.java
@@ -26,11 +26,6 @@ public class exit implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/help.java b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/help.java
index 8383a33..2548e5b 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/help.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/help.java
@@ -32,11 +32,6 @@ public class help implements CommandAbstraction {
         return 1;
     }
 
-    @Override
-    public int maxArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[] {CommandAbstraction.COMMAND};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/save.java b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/save.java
index 1887458..cb891f1 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/save.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/save.java
@@ -31,11 +31,6 @@ public class save implements CommandAbstraction {
         return 0;
     }
 
-    @Override
-    public int maxArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
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 b809176..6e7a87a 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/AppsManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/AppsManager.java
@@ -11,6 +11,7 @@ import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.graphics.Color;
 import android.os.Build;
 import android.support.annotation.NonNull;
 
@@ -28,10 +29,10 @@ import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
 
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
+import ohi.andre.consolelauncher.MainManager;
 import ohi.andre.consolelauncher.R;
+import ohi.andre.consolelauncher.commands.main.MainPack;
+import ohi.andre.consolelauncher.tuils.Compare;
 import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
 import ohi.andre.consolelauncher.tuils.TimeManager;
 import ohi.andre.consolelauncher.tuils.Tuils;
@@ -49,11 +50,15 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
 
     public static final String PATH = "apps.xml";
     private final String NAME = "APPS";
+    private File file;
 
     private final String SHOW_ATTRIBUTE = "show";
+    private final String APPS_ATTRIBUTE = "apps";
+    private final String BGCOLOR_ATTRIBUTE = "bgColor";
+    private final String FORECOLOR_ATTRIBUTE = "foreColor";
+    private static final String APPS_SEPARATOR = ";";
 
     private Context context;
-    private File folder;
 
     private AppsHolder appsHolder;
     private List<LaunchInfo> hiddenApps;
@@ -66,6 +71,8 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
 
     private XMLPrefsManager.XMLPrefsList defaultApps;
 
+    public static List<Group> groups;
+
     public enum Options implements XMLPrefsManager.XMLPrefsSave {
 
         default_app_n1 {
@@ -152,10 +159,13 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
 
         this.context = context;
 
+        this.file = new File(Tuils.getFolder(), PATH);
+
         this.preferences = context.getSharedPreferences(PREFS, 0);
         this.editor = preferences.edit();
 
-        this.folder = Tuils.getFolder();
+        this.groups = new ArrayList<>();
+
         initAppListener(context);
 
         new Thread() {
@@ -179,40 +189,39 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public void fill() {
-        List<LaunchInfo> allApps = createAppMap(context.getPackageManager());
+        final List<LaunchInfo> allApps = createAppMap(context.getPackageManager());
         hiddenApps = new ArrayList<>();
 
-        try {
+        groups.clear();
 
+        try {
             defaultApps = new XMLPrefsManager.XMLPrefsList();
 
-            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-            DocumentBuilder builder = factory.newDocumentBuilder();
-
-            File file = new File(folder, PATH);
-            if (!file.exists() && !file.createNewFile()) return;
-
-            Document d;
-            try {
-                d = builder.parse(file);
-            } catch (Exception e) {
+            if(!file.exists()) {
                 resetFile(file, NAME);
-                d = builder.parse(file);
             }
 
-            List<AppsManager.Options> enums = new ArrayList<>(Arrays.asList(AppsManager.Options.values()));
-
-            Element root = (Element) d.getElementsByTagName(NAME).item(0);
-            if (root == null) {
-                resetFile(file, NAME);
+            Object[] o;
+            try {
+                o = XMLPrefsManager.buildDocument(file, NAME);
+            } catch (Exception e) {
+                Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                intent.putExtra(InputOutputReceiver.TEXT, context.getString(R.string.output_xmlproblem1) + Tuils.SPACE + NAME + context.getString(R.string.output_xmlproblem2) +
+                        Tuils.NEWLINE + context.getString(R.string.output_errorlabel) + e.toString());
+                intent.putExtra(InputOutputReceiver.COLOR, Color.parseColor("#ff0000"));
+                context.sendBroadcast(intent);
 
-                d = builder.parse(file);
-                root = (Element) d.getElementsByTagName(NAME).item(0);
+                return;
             }
 
+            Document d = (Document) o[0];
+            Element root = (Element) o[1];
+
+            List<AppsManager.Options> enums = new ArrayList<>(Arrays.asList(AppsManager.Options.values()));
             NodeList nodes = root.getElementsByTagName("*");
+
             for (int count = 0; count < nodes.getLength(); count++) {
-                Node node = nodes.item(count);
+                final Node node = nodes.item(count);
 
                 String nn = node.getNodeName();
                 int nodeIndex = Tuils.find(nn, (List) enums);
@@ -229,35 +238,100 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
 //                todo support delete
                 else {
                     if (node.getNodeType() == Node.ELEMENT_NODE) {
-                        Element e = (Element) node;
-
-                        boolean shown = !e.hasAttribute(SHOW_ATTRIBUTE) || Boolean.parseBoolean(e.getAttribute(SHOW_ATTRIBUTE));
-                        if (!shown) {
-                            ComponentName name = null;
-
-                            String[] split = nn.split("-");
-                            if (split.length >= 2) {
-                                name = new ComponentName(split[0], split[1]);
-                            } else if (split.length == 1) {
-                                if (split[0].contains("Activity")) {
-                                    for (LaunchInfo i : allApps) {
-                                        if (i.componentName.getClassName().equals(split[0]))
-                                            name = i.componentName;
+                        final Element e = (Element) node;
+
+                        if(e.hasAttribute(APPS_ATTRIBUTE)) {
+                            final String name = e.getNodeName();
+                            if(name.contains(Tuils.SPACE)) {
+                                Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                                intent.putExtra(InputOutputReceiver.TEXT, PATH + ": " + context.getString(R.string.output_groupspace) + ": " + name);
+                                intent.putExtra(InputOutputReceiver.COLOR, Color.parseColor("#ff0000"));
+                                context.sendBroadcast(intent);
+                                continue;
+                            }
+
+                            new Thread() {
+                                @Override
+                                public void run() {
+                                    super.run();
+
+                                    Group g = new Group(name);
+
+                                    String apps = e.getAttribute(APPS_ATTRIBUTE);
+                                    String[] split = apps.split(APPS_SEPARATOR);
+
+                                    List<LaunchInfo> as = new ArrayList<>(allApps);
+
+                                    External:
+                                    for(String s : split) {
+                                        for(int c = 0; c < as.size(); c++) {
+                                            if(as.get(c).equals(s)) {
+                                                g.add(as.remove(c));
+                                                continue External;
+                                            }
+                                        }
+                                    }
+
+                                    if(e.hasAttribute(BGCOLOR_ATTRIBUTE)) {
+                                        String c = e.getAttribute(BGCOLOR_ATTRIBUTE);
+                                        if(c.length() > 0) {
+                                            try {
+                                                g.setBgColor(Color.parseColor(c));
+                                            } catch (Exception e) {
+                                                Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                                                intent.putExtra(InputOutputReceiver.TEXT, PATH + ": " + context.getString(R.string.output_invalidcolor) + ": " + c);
+                                                intent.putExtra(InputOutputReceiver.COLOR, Color.parseColor("#ff0000"));
+                                                context.sendBroadcast(intent);
+                                            }
+                                        }
                                     }
-                                } else {
-                                    for (LaunchInfo i : allApps) {
-                                        if (i.componentName.getPackageName().equals(split[0]))
-                                            name = i.componentName;
+
+                                    if(e.hasAttribute(FORECOLOR_ATTRIBUTE)) {
+                                        String c = e.getAttribute(FORECOLOR_ATTRIBUTE);
+                                        if(c.length() > 0) {
+                                            try {
+                                                g.setForeColor(Color.parseColor(c));
+                                            } catch (Exception e) {
+                                                Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                                                intent.putExtra(InputOutputReceiver.TEXT, PATH + ": " + context.getString(R.string.output_invalidcolor) + ": " + c);
+                                                intent.putExtra(InputOutputReceiver.COLOR, Color.parseColor("#ff0000"));
+                                                context.sendBroadcast(intent);
+                                            }
+                                        }
+                                    }
+
+                                    groups.add(g);
+                                }
+                            }.start();
+                        } else {
+                            boolean shown = !e.hasAttribute(SHOW_ATTRIBUTE) || Boolean.parseBoolean(e.getAttribute(SHOW_ATTRIBUTE));
+                            if (!shown) {
+                                ComponentName name = null;
+
+                                String[] split = nn.split("-");
+                                if (split.length >= 2) {
+                                    name = new ComponentName(split[0], split[1]);
+                                } else if (split.length == 1) {
+                                    if (split[0].contains("Activity")) {
+                                        for (LaunchInfo i : allApps) {
+                                            if (i.componentName.getClassName().equals(split[0]))
+                                                name = i.componentName;
+                                        }
+                                    } else {
+                                        for (LaunchInfo i : allApps) {
+                                            if (i.componentName.getPackageName().equals(split[0]))
+                                                name = i.componentName;
+                                        }
                                     }
                                 }
-                            }
 
-                            if (name == null) continue;
+                                if (name == null) continue;
 
-                            LaunchInfo removed = AppUtils.findLaunchInfoWithComponent(allApps, name);
-                            if (removed != null) {
-                                allApps.remove(removed);
-                                hiddenApps.add(removed);
+                                LaunchInfo removed = AppUtils.findLaunchInfoWithComponent(allApps, name);
+                                if (removed != null) {
+                                    allApps.remove(removed);
+                                    hiddenApps.add(removed);
+                                }
                             }
                         }
                     }
@@ -393,7 +467,7 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public String hideActivity(LaunchInfo info) {
-        set(new File(folder, PATH), NAME, info.componentName.getPackageName() + "-" + info.componentName.getClassName(), new String[] {SHOW_ATTRIBUTE}, new String[] {false + Tuils.EMPTYSTRING});
+        set(file, NAME, info.write(), new String[] {SHOW_ATTRIBUTE}, new String[] {false + Tuils.EMPTYSTRING});
 
         appsHolder.remove(info);
         appsHolder.update(true);
@@ -404,7 +478,7 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public String showActivity(LaunchInfo info) {
-        set(new File(folder, PATH), NAME, info.componentName.getPackageName() + "-" + info.componentName.getClassName(), new String[] {SHOW_ATTRIBUTE}, new String[] {true + Tuils.EMPTYSTRING});
+        set(file, NAME, info.write(), new String[]{SHOW_ATTRIBUTE}, new String[]{true + Tuils.EMPTYSTRING});
 
         hiddenApps.remove(info);
         appsHolder.add(info);
@@ -413,24 +487,184 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
         return info.publicLabel;
     }
 
-    public List<String> getAppLabels() {
-        if(appsHolder != null) {
-            return appsHolder.getAppLabels();
-        } return new ArrayList<>();
+    public String createGroup(String name) {
+        return XMLPrefsManager.set(file, NAME, name, new String[]{APPS_ATTRIBUTE}, new String[]{Tuils.EMPTYSTRING});
+    }
+
+    public String groupBgColor(String name, String color) {
+        return XMLPrefsManager.set(file, NAME, name, new String[]{BGCOLOR_ATTRIBUTE}, new String[]{color});
+    }
+
+    public String groupForeColor(String name, String color) {
+        return XMLPrefsManager.set(file, NAME, name, new String[]{FORECOLOR_ATTRIBUTE}, new String[]{color});
     }
 
-    public List<String> getHiddenAppsLabels() {
-        return AppUtils.labelList(hiddenApps, true);
+    public String removeGroup(String name) {
+        String output = XMLPrefsManager.removeNode(file, NAME, name);
+
+        if(output == null) return null;
+        if(output.length() == 0) return context.getString(R.string.output_groupnotfound);
+        return output;
     }
 
-    public String[] getSuggestedApps() {
-        if(appsHolder == null) return new String[0];
+    public String addAppToGroup(String group, LaunchInfo app) {
+        Object[] o;
+        try {
+            o = XMLPrefsManager.buildDocument(file, NAME);
+        } catch (Exception e) {
+            return e.toString();
+        }
+
+        Document d = (Document) o[0];
+        Element root = (Element) o[1];
+
+        Node node = XMLPrefsManager.findNode(root, group);
+        if(node == null) return context.getString(R.string.output_groupnotfound);
+
+        Element e = (Element) node;
+        String apps = e.getAttribute(APPS_ATTRIBUTE);
+
+        if(apps != null && app.isInside(apps)) return null;
+
+        apps = apps + APPS_SEPARATOR + app.write();
+        if(apps.startsWith(APPS_SEPARATOR)) apps = apps.substring(1);
+
+        e.setAttribute(APPS_ATTRIBUTE, apps);
+
+        XMLPrefsManager.writeTo(d, file);
+        return null;
+    }
+
+    public String removeAppFromGroup(String group, LaunchInfo app) {
+        Object[] o;
+        try {
+            o = XMLPrefsManager.buildDocument(file, NAME);
+        } catch (Exception e) {
+            return e.toString();
+        }
+
+        Document d = (Document) o[0];
+        Element root = (Element) o[1];
+
+        Node node = XMLPrefsManager.findNode(root, group);
+        if(node == null) return context.getString(R.string.output_groupnotfound);
+
+        Element e = (Element) node;
+
+        String apps = e.getAttribute(APPS_ATTRIBUTE);
+        if(apps == null) return null;
+
+        if(!app.isInside(apps)) return null;
+
+        String temp = apps.replaceAll(app.write(), Tuils.EMPTYSTRING);
+        if(temp.length() < apps.length()) apps = temp;
+        else apps = apps.replaceAll(app.componentName.getPackageName(), Tuils.EMPTYSTRING);
+
+        apps = apps.replaceAll(APPS_SEPARATOR + APPS_SEPARATOR, APPS_SEPARATOR);
+        if(apps.startsWith(APPS_SEPARATOR)) apps = apps.substring(1);
+        if(apps.endsWith(APPS_SEPARATOR)) apps = apps.substring(0, apps.length() - 1);
+
+        e.setAttribute(APPS_ATTRIBUTE, apps);
+
+        XMLPrefsManager.writeTo(d, file);
+        return null;
+    }
+
+    public String listGroup(String group) {
+        Object[] o;
+        try {
+            o = XMLPrefsManager.buildDocument(file, NAME);
+        } catch (Exception e) {
+            return e.toString();
+        }
+
+        Element root = (Element) o[1];
+
+        Node node = XMLPrefsManager.findNode(root, group);
+        if(node == null) return context.getString(R.string.output_groupnotfound);
+
+        Element e = (Element) node;
+
+        String apps = e.getAttribute(APPS_ATTRIBUTE);
+        if(apps == null) return "[]";
+
+        String labels = Tuils.EMPTYSTRING;
+
+        PackageManager manager = context.getPackageManager();
+        String[] split = apps.split(APPS_SEPARATOR);
+        for(String s : split) {
+            if(s.length() == 0) continue;
+
+            String label;
+
+            ComponentName name = LaunchInfo.componentInfo(s);
+            if(name == null) {
+                try {
+                    label = manager.getApplicationInfo(s, 0).loadLabel(manager).toString();
+                } catch (Exception e1) {
+                    continue;
+                }
+            } else {
+                try {
+                    label = manager.getActivityInfo(name, 0).loadLabel(manager).toString();
+                } catch (Exception e1) {
+                    continue;
+                }
+            }
+
+            labels = labels + Tuils.NEWLINE + label;
+        }
+
+        return labels.trim();
+    }
+
+    public String listGroups() {
+        Object[] o;
+        try {
+            o = XMLPrefsManager.buildDocument(file, NAME);
+        } catch (Exception e) {
+            return e.toString();
+        }
+
+        Element root = (Element) o[1];
+
+        String groups = Tuils.EMPTYSTRING;
+
+        NodeList list = root.getElementsByTagName("*");
+        for(int count = 0; count < list.getLength(); count++) {
+            Node node = list.item(count);
+            if(! (node instanceof Element)) continue;
+
+            Element e = (Element) node;
+            if(!e.hasAttribute(APPS_ATTRIBUTE)) continue;
+
+            groups = groups + Tuils.NEWLINE + e.getNodeName();
+        }
+
+        if(groups.length() == 0) return "[]";
+        return groups.trim();
+    }
+
+    public List<LaunchInfo> shownApps() {
+        return appsHolder.getApps();
+    }
+
+    public List<LaunchInfo> hiddenApps() {
+        return hiddenApps;
+    }
+
+    public LaunchInfo[] getSuggestedApps() {
+        if(appsHolder == null) return new LaunchInfo[0];
         return appsHolder.getSuggestedApps();
     }
 
     public String printApps(int type) {
-        List<String> labels = type == SHOWN_APPS ? appsHolder.appLabels : AppUtils.labelList(hiddenApps, true);
-        return AppUtils.printApps(labels);
+        try {
+            List<String> labels = AppUtils.labelList(type == SHOWN_APPS ? appsHolder.getApps() : hiddenApps, true);
+            return AppUtils.printApps(labels);
+        } catch (NullPointerException e) {
+            return "[]";
+        }
     }
 
     public void unregisterReceiver(Context context) {
@@ -441,7 +675,88 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
         unregisterReceiver(context);
     }
 
-    public static class LaunchInfo {
+    public static class Group implements MainManager.Group {
+        List<LaunchInfo> apps;
+
+        int bgColor = SkinManager.COLOR_NOT_SET;
+        int foreColor = SkinManager.COLOR_NOT_SET;
+
+        String name;
+
+        public Group(String name) {
+            this.name = name;
+            apps = new ArrayList<>();
+        }
+
+        public void add(LaunchInfo info) {
+            apps.add(info);
+        }
+
+        public boolean contains(LaunchInfo info) {
+            return apps.contains(info);
+        }
+
+        public int getBgColor() {
+            return bgColor;
+        }
+
+        public void setBgColor(int color) {
+            this.bgColor = color;
+        }
+
+        public int getForeColor() {
+            return foreColor;
+        }
+
+        public void setForeColor(int foreColor) {
+            this.foreColor = foreColor;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public List<? extends Compare.Stringable> members() {
+            return apps;
+        }
+
+        @Override
+        public boolean use(MainPack mainPack, String input) {
+            LaunchInfo info = AppUtils.findLaunchInfoWithLabel(apps, input);
+            if(info == null) return false;
+
+            info.launchedTimes++;
+
+            Intent intent = new Intent(Intent.ACTION_MAIN);
+            intent.setComponent(info.componentName);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            mainPack.context.startActivity(intent);
+
+            return true;
+        }
+
+        @Override
+        public String name() {
+            return name;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if(obj instanceof Group) {
+                return name.equals(((Group) obj).name());
+            } else if(obj instanceof String) {
+                return obj.equals(name);
+            }
+
+            return false;
+        }
+    }
+
+    public static class LaunchInfo implements Compare.Stringable {
+
+        private static final String COMPONENT_SEPARATOR = "-";
 
         public ComponentName componentName;
 
@@ -450,10 +765,40 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
 
         public LaunchInfo(String packageName, String activityName, String label) {
             this.componentName = new ComponentName(packageName, activityName);
-
             this.publicLabel = label;
         }
 
+        public boolean isInside(String apps) {
+            String[] split = apps.split(AppsManager.APPS_SEPARATOR);
+            for(String s : split) {
+                if(is(s)) return true;
+            }
+
+            return false;
+        }
+
+        public boolean is(String app) {
+            String[] split2 = app.split(COMPONENT_SEPARATOR);
+
+            if(split2.length == 1) {
+                if(componentName.getPackageName().equals(split2[0])) return true;
+            } else {
+                if(componentName.getPackageName().equals(split2[0]) && componentName.getClassName().equals(split2[1])) return true;
+            }
+
+            return false;
+        }
+
+        public static ComponentName componentInfo(String app) {
+            String[] split2 = app.split(COMPONENT_SEPARATOR);
+
+            if(split2.length == 1) {
+                return null;
+            } else {
+                return new ComponentName(split2[0], split2[1]);
+            }
+        }
+
         @Override
         public boolean equals(Object o) {
             if(o == null) {
@@ -472,7 +817,7 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
                 return this.componentName.equals(o);
             }
             else if(o instanceof String) {
-                return this.componentName.getClassName().equals(o);
+                return is((String) o) || this.componentName.getClassName().equals(o);
             }
 
             return false;
@@ -482,6 +827,15 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
         public String toString() {
             return componentName.getPackageName() + " - " + componentName.getClassName() + " --> " + publicLabel + ", n=" + launchedTimes;
         }
+
+        public String write() {
+            return this.componentName.getPackageName() + COMPONENT_SEPARATOR + this.componentName.getClassName();
+        }
+
+        @Override
+        public String getString() {
+            return publicLabel;
+        }
     }
 
     private class AppsHolder {
@@ -489,7 +843,6 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
         final int MOST_USED = 10, NULL = 11, USER_DEFINIED = 12;
 
         private List<LaunchInfo> infos;
-        private List<String> appLabels;
         private XMLPrefsManager.XMLPrefsList values;
 
         private SuggestedAppMgr suggestedAppMgr;
@@ -534,8 +887,6 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
                 }
 
                 sort();
-
-//                handler.postDelayed(runnable, 1000 * 60 * 5);
             }
 
             public int size() {
@@ -588,7 +939,7 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
                 sort();
             }
 
-            public List<String> labels() {
+            public List<LaunchInfo> apps() {
                 List<LaunchInfo> list = new ArrayList<>();
 
                 List<SuggestedApp> cp = new ArrayList<>(suggested);
@@ -603,27 +954,26 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
                     SuggestedApp app = cp.get(count);
                     if(app.type != NULL && app.app != null) list.add(app.app);
                 }
-                return AppUtils.labelList(list, false);
+                return list;
             }
 
-//            private Handler handler = new Handler();
-//            private Runnable runnable = new Runnable() {
-//                @Override
-//                public void run() {
-//                    if(duplicates()) {
-//                        fillSuggestions();
+//            public List<String> labels() {
+//                List<LaunchInfo> list = new ArrayList<>();
+//
+//                List<SuggestedApp> cp = new ArrayList<>(suggested);
+//                Collections.sort(cp, new Comparator<SuggestedApp>() {
+//                    @Override
+//                    public int compare(SuggestedApp o1, SuggestedApp o2) {
+//                        return o1.index - o2.index;
 //                    }
-//                    handler.postDelayed(runnable, 1000 * 60 * 2);
-//                }
+//                });
 //
-//                private boolean duplicates() {
-//                    for (int count =0; count < size(); count++)
-//                        for (int count2 = count+1 ; count2 < size(); count2++)
-//                            if (count != count2 && get(count) == get(count2))
-//                                return true;
-//                    return false;
+//                for(int count = 0; count < cp.size(); count++) {
+//                    SuggestedApp app = cp.get(count);
+//                    if(app.type != NULL && app.app != null) list.add(app.app);
 //                }
-//            };
+//                return AppUtils.labelList(list, false);
+//            }
 
             private class SuggestedApp implements Comparable {
                 int type;
@@ -712,10 +1062,6 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
             } catch (NullPointerException e) {}
         }
 
-        private void fillLabels() {
-            appLabels = AppUtils.labelList(infos, true);
-        }
-
         private void fillSuggestions() {
             suggestedAppMgr = new SuggestedAppMgr(values, getApps());
             for(LaunchInfo info : infos) {
@@ -730,23 +1076,18 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
         private void update(boolean refreshSuggestions) {
             AppUtils.checkEquality(infos);
             sort();
-            fillLabels();
             if(refreshSuggestions) {
                 fillSuggestions();
             }
         }
 
-        public List<String> getAppLabels() {
-            return appLabels;
-        }
-
         public List<LaunchInfo> getApps() {
             return infos;
         }
 
-        public String[] getSuggestedApps() {
-            List<String> ls = suggestedAppMgr.labels();
-            return ls.toArray(new String[ls.size()]);
+        public LaunchInfo[] getSuggestedApps() {
+            List<LaunchInfo> apps = suggestedAppMgr.apps();
+            return apps.toArray(new LaunchInfo[apps.size()]);
         }
     }
 
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/ContactManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/ContactManager.java
index 94c988d..c92139d 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/ContactManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/ContactManager.java
@@ -16,6 +16,7 @@ import java.util.Collections;
 import java.util.List;
 
 import ohi.andre.consolelauncher.LauncherActivity;
+import ohi.andre.consolelauncher.tuils.Compare;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
 public class ContactManager {
@@ -269,7 +270,7 @@ public class ContactManager {
         return ContactsContract.Contacts.getLookupUri(mCurrentId, mCurrentLookupKey);
     }
 
-    public static class Contact implements Comparable<Contact> {
+    public static class Contact implements Comparable<Contact>, Compare.Stringable {
         public String name;
         public List<String> numbers = new ArrayList<>();
 
@@ -303,5 +304,10 @@ public class ContactManager {
 
             return tf - of;
         }
+
+        @Override
+        public String getString() {
+            return name;
+        }
     }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/SkinManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/SkinManager.java
index 4708be1..5409825 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/SkinManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/SkinManager.java
@@ -162,7 +162,7 @@ public class SkinManager implements Parcelable {
             return new ColorDrawable(Color.TRANSPARENT);
         } else {
             switch (type) {
-                case SuggestionsManager.Suggestion.TYPE_APP:
+                case SuggestionsManager.Suggestion.TYPE_APP:case SuggestionsManager.Suggestion.TYPE_APPGROUP:
                     return new ColorDrawable(suggAppBg);
                 case SuggestionsManager.Suggestion.TYPE_ALIAS:
                     return new ColorDrawable(suggAliasBg);
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/ThemesManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/ThemesManager.java
new file mode 100644
index 0000000..565aeea
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/ThemesManager.java
@@ -0,0 +1,145 @@
+package ohi.andre.consolelauncher.managers;
+
+import android.content.Context;
+import android.content.Intent;
+
+import com.google.firebase.database.DataSnapshot;
+import com.google.firebase.database.DatabaseError;
+import com.google.firebase.database.FirebaseDatabase;
+import com.google.firebase.database.ValueEventListener;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import ohi.andre.consolelauncher.R;
+import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
+import ohi.andre.consolelauncher.tuils.Tuils;
+
+/**
+ * Created by francescoandreuzzi on 19/08/2017.
+ */
+
+public class ThemesManager {
+
+    static DocumentBuilderFactory factory;
+    static DocumentBuilder builder;
+
+    static {
+        factory = DocumentBuilderFactory.newInstance();
+        try {
+            builder = factory.newDocumentBuilder();
+        } catch (ParserConfigurationException e) {}
+    }
+
+    public static void apply(final Context context, final String name) {
+        FirebaseDatabase.getInstance().getReference().addListenerForSingleValueEvent(new ValueEventListener() {
+            @Override
+            public void onDataChange(DataSnapshot dataSnapshot) {
+
+                DataSnapshot theme = dataSnapshot.child("themes").child(name);
+                if(theme != null && theme.exists()) {
+
+                    File currentTheme = new File(Tuils.getFolder(), "theme.xml");
+                    File currentSuggestions = new File(Tuils.getFolder(), "suggestions.xml");
+
+                    String themePath = currentTheme.getAbsolutePath();
+                    String suggestionsPath = currentSuggestions.getAbsolutePath();
+
+                    File old = new File(Tuils.getFolder(), "old");
+                    if(old.exists()) Tuils.delete(old);
+                    old.mkdir();
+
+                    currentTheme.renameTo(new File(old, "theme.xml"));
+                    currentSuggestions.renameTo(new File(old, "suggestions.xml"));
+
+                    theme = theme.child("files");
+                    DataSnapshot t = theme.child("THEME");
+                    DataSnapshot s = theme.child("SUGGESTIONS");
+
+                    createFile(themePath, "THEME", t);
+                    createFile(suggestionsPath, "SUGGESTIONS", s);
+
+                    Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                    intent.putExtra(InputOutputReceiver.TEXT, context.getString(R.string.theme_done));
+                    context.sendBroadcast(intent);
+                } else {
+                    Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                    intent.putExtra(InputOutputReceiver.TEXT, context.getString(R.string.theme_not_found));
+                    context.sendBroadcast(intent);
+                }
+            }
+
+            @Override
+            public void onCancelled(DatabaseError databaseError) {}
+        });
+    }
+
+    private static Pattern rgbaExtractor = Pattern.compile("rgba\\(([0-9]+),([0-9]+),([0-9]+),([0-9]+)\\)");
+
+    private static void createFile(String path, String root, DataSnapshot s) {
+        File file = new File(path);
+        XMLPrefsManager.resetFile(file, root);
+
+        try {
+            Document document = builder.parse(file);
+            Element r = (Element) document.getElementsByTagName(root).item(0);
+
+            for(DataSnapshot ds : s.getChildren()) {
+                String value = ds.getValue().toString();
+                if(value.startsWith("rgba(")) value = rgbaToHex(value);
+
+                Element em = document.createElement(ds.getKey());
+                em.setAttribute(XMLPrefsManager.VALUE_ATTRIBUTE, value);
+                r.appendChild(em);
+            }
+
+            XMLPrefsManager.writeTo(document, file);
+
+        } catch (Exception e) {
+            Tuils.log(e);
+        }
+    }
+
+    private static String rgbaToHex(String value) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("#");
+
+        Matcher matcher = rgbaExtractor.matcher(value);
+        if(matcher.find()) {
+            try {
+                String redString = matcher.group(1);
+                String greenString = matcher.group(2);
+                String blueString = matcher.group(3);
+                String alphaString = matcher.group(4);
+
+                int alpha = (int) (Float.parseFloat(alphaString) * 255);
+
+                String redHex = Integer.toHexString(Integer.parseInt(redString));
+                if(redHex.length() == 1) redHex = "0" + redHex;
+
+                String greenHex = Integer.toHexString(Integer.parseInt(greenString));
+                if(greenHex.length() == 1) greenHex = "0" + greenHex;
+
+                String blueHex = Integer.toHexString(Integer.parseInt(blueString));
+                if(blueHex.length() == 1) blueHex = "0" + blueHex;
+
+                String alphaHex = Integer.toHexString(alpha);
+                if(alphaHex.length() == 1) alphaHex = "0" + alphaHex;
+
+                builder.append(alphaHex).append(redHex).append(greenHex).append(blueHex);
+            } catch (Exception e) {
+                return null;
+            }
+        }
+
+        return builder.toString();
+    }
+}
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 e3b3249..f86d92a 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/XMLPrefsManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/XMLPrefsManager.java
@@ -1,5 +1,7 @@
 package ohi.andre.consolelauncher.managers;
 
+import android.content.Context;
+import android.content.Intent;
 import android.graphics.Color;
 
 import org.w3c.dom.Document;
@@ -17,19 +19,31 @@ import java.util.regex.Pattern;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
+import ohi.andre.consolelauncher.R;
+import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
 public class XMLPrefsManager {
 
     public static final String XML_DEFAULT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
-
     public static final String VALUE_ATTRIBUTE = "value";
 
+    private static DocumentBuilderFactory factory;
+    private static DocumentBuilder builder;
+
+    static {
+        factory = DocumentBuilderFactory.newInstance();
+        try {
+            builder = factory.newDocumentBuilder();
+        } catch (ParserConfigurationException e) {}
+    }
+
     public interface XMLPrefsSave {
         String defaultValue();
         String label();
@@ -122,6 +136,24 @@ public class XMLPrefsManager {
             public String defaultValue() {
                 return "#80000000";
             }
+        },
+        alias_content_color {
+            @Override
+            public String defaultValue() {
+                return "#1DE9B6";
+            }
+        },
+        statusbar_color {
+            @Override
+            public String defaultValue() {
+                return "#000000";
+            }
+        },
+        navigationbar_color {
+            @Override
+            public String defaultValue() {
+                return "#000000";
+            }
         };
 
         @Override
@@ -291,6 +323,12 @@ public class XMLPrefsManager {
             public String defaultValue() {
                 return "0";
             }
+        },
+        ignore_bar_color {
+            @Override
+            public String defaultValue() {
+                return "false";
+            }
         };
 
         @Override
@@ -438,6 +476,12 @@ public class XMLPrefsManager {
                 return "true";
             }
         },
+        suggest_appgp_default {
+            @Override
+            public String defaultValue() {
+                return "true";
+            }
+        },
         click_to_launch {
             @Override
             public String defaultValue() {
@@ -463,7 +507,7 @@ public class XMLPrefsManager {
 
     public enum Behavior implements XMLPrefsSave {
 
-        double_tap_closes {
+        double_tap_lock {
             @Override
             public String defaultValue() {
                 return "true";
@@ -720,7 +764,7 @@ public class XMLPrefsManager {
         BEHAVIOR("behavior.xml", Behavior.values()) {
             @Override
             public String[] deleted() {
-                return new String[0];
+                return new String[] {"double_tap_closes"};
             }
         },
         SUGGESTIONS("suggestions.xml", Suggestions.values()) {
@@ -822,32 +866,37 @@ public class XMLPrefsManager {
 
     private XMLPrefsManager() {}
 
-    public static void create() throws Exception {
+    public static void create(Context context) throws Exception {
         File folder = Tuils.getFolder();
 
-        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-        DocumentBuilder builder = factory.newDocumentBuilder();
-
         for(XMLPrefsRoot element : XMLPrefsRoot.values()) {
             File file = new File(folder, element.path);
-            if(!file.exists() && !file.createNewFile()) continue;
+            if(!file.exists()) {
+                resetFile(file, element.name());
+            }
 
-            Document d;
+            Object[] o;
             try {
-                d = builder.parse(file);
+                o = buildDocument(file, element.name());
             } catch (Exception e) {
-                resetFile(file, element.name());
+                Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                intent.putExtra(InputOutputReceiver.TEXT, context.getString(R.string.output_xmlproblem1) + Tuils.SPACE + element.name() + context.getString(R.string.output_xmlproblem2) +
+                        Tuils.NEWLINE + context.getString(R.string.output_errorlabel) + e.toString());
+                intent.putExtra(InputOutputReceiver.COLOR, Color.parseColor("#ff0000"));
+                context.sendBroadcast(intent);
 
-                d = builder.parse(file);
+                continue;
             }
 
+            Document d = (Document) o[0];
+            Element root = (Element) o[1];
+
             List<XMLPrefsSave> enums = element.enums;
             if(enums == null) continue;
 
             String[] deleted = element.deleted();
             boolean needToWrite = false;
 
-            Element root = (Element) d.getElementsByTagName(element.name()).item(0);
             if(root == null) {
                 resetFile(file, element.name());
                 d = builder.parse(file);
@@ -898,6 +947,8 @@ public class XMLPrefsManager {
     }
 
     public static Object transform(String s, Class<?> c) throws Exception {
+        if(s == null) throw new UnsupportedOperationException();
+
         if(c == int.class) return Integer.parseInt(s);
         if(c == Color.class) return Color.parseColor(s);
         if(c == boolean.class) return Boolean.parseBoolean(s);
@@ -920,6 +971,15 @@ public class XMLPrefsManager {
         return s;
     }
 
+//    [0] = document
+//    [1] = root
+    public static Object[] buildDocument(File file, String root) throws Exception {
+        Document d = builder.parse(file);
+        Element r = (Element) d.getElementsByTagName(root).item(0);
+
+        return new Object[] {d, r};
+    }
+
     public static void writeTo(Document d, File f) {
         try {
             TransformerFactory transformerFactory = TransformerFactory.newInstance();
@@ -942,17 +1002,15 @@ public class XMLPrefsManager {
 
     public static String add(File file, String rootName, String elementName, String[] attributeNames, String[] attributeValues) {
         try {
-            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-            DocumentBuilder builder = factory.newDocumentBuilder();
-
-            Document d;
+            Object[] o;
             try {
-                d = builder.parse(file);
+                o = buildDocument(file, rootName);
             } catch (Exception e) {
                 return e.toString();
             }
 
-            Element root = (Element) d.getElementsByTagName(rootName).item(0);
+            Document d = (Document) o[0];
+            Element root = (Element) o[1];
 
             Element element = d.createElement(elementName);
             for(int c = 0; c < attributeNames.length; c++) {
@@ -977,17 +1035,16 @@ public class XMLPrefsManager {
 
     public static String setMany(File file, String rootName, String elementNames[], String[] attributeNames, String[][] attributeValues) {
         try {
-            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-            DocumentBuilder builder = factory.newDocumentBuilder();
-
-            Document d;
+            Object[] o;
             try {
-                d = builder.parse(file);
+                o = buildDocument(file, rootName);
             } catch (Exception e) {
                 return e.toString();
             }
 
-            Element root = (Element) d.getElementsByTagName(rootName).item(0);
+            Document d = (Document) o[0];
+            Element root = (Element) o[1];
+
             NodeList nodes = root.getElementsByTagName("*");
 
             for(int count = 0; count < nodes.getLength(); count++) {
@@ -1026,48 +1083,74 @@ public class XMLPrefsManager {
         return null;
     }
 
-    public static boolean removeNode(File file, String rootName, String nodeName) {
+    public static String removeNode(File file, String rootName, String nodeName) {
         try {
-            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-            DocumentBuilder builder = factory.newDocumentBuilder();
+            Object[] o;
+            try {
+                o = buildDocument(file, rootName);
+            } catch (Exception e) {
+                return e.toString();
+            }
+
+            Document d = (Document) o[0];
+            Element root = (Element) o[1];
+
+            Node node = findNode(root, nodeName);
 
-            Document d;
+            if(node == null) return Tuils.EMPTYSTRING;
+
+            root.removeChild(node);
+            writeTo(d, file);
+            return null;
+        } catch (Exception e) {
+            return e.toString();
+        }
+    }
+
+    public static Node findNode(File file, String rootName, String nodeName) {
+        try {
+            Object[] o;
             try {
-                d = builder.parse(file);
+                o = buildDocument(file, rootName);
             } catch (Exception e) {
-                return false;
+                return null;
             }
 
-            Element root = (Element) d.getElementsByTagName(rootName).item(0);
-            NodeList nodes = root.getElementsByTagName("*");
+            Element root = (Element) o[1];
 
-            for(int count = 0; count < nodes.getLength(); count++) {
-                Node node = nodes.item(count);
+            findNode(root, nodeName);
+        } catch (Exception e) {
+            return null;
+        }
 
-                if(node.getNodeName().equalsIgnoreCase(nodeName)) {
-                    root.removeChild(node);
-                    writeTo(d, file);
-                    return true;
-                }
+        return null;
+    }
+
+    public static Node findNode(Element root, String nodeName) {
+        NodeList nodes = root.getElementsByTagName("*");
+
+        for(int count = 0; count < nodes.getLength(); count++) {
+            Node node = nodes.item(count);
+
+            if(node.getNodeName().equalsIgnoreCase(nodeName)) {
+                return node;
             }
-        } catch (Exception e) {}
+        }
 
-        return false;
+        return null;
     }
 
     public static String[] getAttrValues(File file, String rootName, String nodeName, String[] attrNames) {
         try {
-            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-            DocumentBuilder builder = factory.newDocumentBuilder();
-
-            Document d;
+            Object[] o;
             try {
-                d = builder.parse(file);
+                o = buildDocument(file, rootName);
             } catch (Exception e) {
                 return null;
             }
 
-            Element root = (Element) d.getElementsByTagName(rootName).item(0);
+            Element root = (Element) o[1];
+
             NodeList nodes = root.getElementsByTagName("*");
 
             for(int count = 0; count < nodes.getLength(); count++) {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Constants.java b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Constants.java
new file mode 100755
index 0000000..4043cd6
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Constants.java
@@ -0,0 +1,49 @@
+/*
+ *     Copyright (C) 2016  Merbin J Anselm <merbinjanselm@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package ohi.andre.consolelauncher.managers.flashlight;
+
+/**
+ * Created by I327891 on 19-Feb-17.
+ */
+
+public class Constants {
+    public final static String ID_DEVICE = "0";
+
+    public final static String ID_DEVICE_OUTPUT = "1";
+    public final static String ID_DEVICE_OUTPUT_TORCH = "10";
+    public final static String ID_DEVICE_OUTPUT_TORCH_FLASH = "11";
+    public final static String ID_DEVICE_OUTPUT_TORCH_FLASH_LEGACY = "12";
+    public final static String ID_DEVICE_OUTPUT_TORCH_FLASH_NEW = "13";
+    public final static String ID_DEVICE_OUTPUT_TORCH_SCREEN = "14";
+    public final static String ID_DEVICE_OUTPUT_VIBRATOR = "15";
+
+    public final static String ID_DEVICE_INPUT = "2";
+    public final static String ID_DEVICE_INPUT_VOLUMEKEY = "20";
+    public final static String ID_DEVICE_INPUT_VOLUMEKEY_NATIVE = "21";
+    public final static String ID_DEVICE_INPUT_VOLUMEKEY_ROCKER = "22";
+    public final static String ID_DEVICE_INPUT_PROXIMITY = "23";
+
+    public final static String PLAY_URI = "https://play.google.com/store/apps/details?id=in.blogspot.anselmbros.torchie";
+    public final static String WEB_URI = "https://torchieapp.wordpress.com";
+    public final static String ABOUTANSELM_URI = "http://anselmbros.blogspot.in/p/about-us.html";
+    public final static String COMMUNITY_URI = "https://plus.google.com/communities/114100054385968340083";
+    public final static String FACEBOOK_URI = "https://facebook.com/torchieapp";
+    public final static String GOOGLEPLUS_URI = "https://plus.google.com/111668132285982978436";
+    public final static String WEB_DONATE_URI = "https://torchieapp.wordpress.com/donate/";
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Device.java b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Device.java
new file mode 100755
index 0000000..7ba987f
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Device.java
@@ -0,0 +1,44 @@
+/*
+ *     Copyright (C) 2016  Merbin J Anselm <merbinjanselm@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package ohi.andre.consolelauncher.managers.flashlight;
+
+import android.content.Context;
+
+/**
+ * Created by I327891 on 04-Feb-17.
+ */
+
+public abstract class Device {
+
+    protected final Context mContext;
+    protected boolean isEnabled;
+
+    public Device(Context context) {
+        this.mContext = context;
+        isEnabled = false;
+    }
+
+    public boolean isEnabled() {
+        return isEnabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        isEnabled = enabled;
+    }
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/DeviceListener.java b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/DeviceListener.java
new file mode 100755
index 0000000..72c2f4b
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/DeviceListener.java
@@ -0,0 +1,27 @@
+/*
+ *     Copyright (C) 2016  Merbin J Anselm <merbinjanselm@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package ohi.andre.consolelauncher.managers.flashlight;
+
+/**
+ * Created by I327891 on 04-Feb-17.
+ */
+
+public interface DeviceListener {
+    void onError(String error);
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight.java b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight.java
new file mode 100755
index 0000000..b5125bc
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight.java
@@ -0,0 +1,34 @@
+/*
+ *     Copyright (C) 2016  Merbin J Anselm <merbinjanselm@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package ohi.andre.consolelauncher.managers.flashlight;
+
+import android.content.Context;
+
+/**
+ * Created by I327891 on 06-Feb-17.
+ */
+
+public abstract class Flashlight extends Torch {
+
+    public static final String TYPE = Constants.ID_DEVICE_OUTPUT_TORCH_FLASH;
+
+    public Flashlight(Context context) {
+        super(context);
+    }
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight1.java b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight1.java
new file mode 100644
index 0000000..e2d1a10
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight1.java
@@ -0,0 +1,107 @@
+package ohi.andre.consolelauncher.managers.flashlight;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.os.Build;
+
+import java.util.List;
+
+import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
+
+/**
+ * Created by francescoandreuzzi on 20/08/2017.
+ */
+
+public class Flashlight1 extends Flashlight {
+
+    private Camera mCamera;
+    private boolean flashSupported;
+
+    public Flashlight1(Context context) {
+        super(context);
+        this.flashSupported = false;
+    }
+
+    @Override
+    protected void turnOn() {
+        if (this.ready() && !this.getStatus()) {
+            try {
+
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+                    this.mCamera.setPreviewTexture(new SurfaceTexture(0));
+                    this.mCamera.startPreview();
+                    this.updateStatus(true);
+                } else {
+                    Camera.Parameters parameters = mCamera.getParameters();
+                    parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
+                    mCamera.setParameters(parameters);
+                }
+            } catch (Exception e) {
+                if (this.mCamera != null) {
+                    try {
+                        this.mCamera.release();
+                        this.mCamera = null;
+                    } catch (Exception ex) {}
+                }
+
+                Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                intent.putExtra(InputOutputReceiver.TEXT, e.toString());
+                mContext.sendBroadcast(intent);
+            }
+        }
+    }
+
+    @Override
+    protected void turnOff() {
+        if (this.getStatus() && this.mCamera != null) {
+            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+                this.mCamera.stopPreview();
+                this.mCamera.release();
+                this.mCamera = null;
+            } else {
+                Camera.Parameters parameters = mCamera.getParameters();
+                parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
+                mCamera.setParameters(parameters);
+            }
+            this.updateStatus(false);
+        }
+    }
+
+    private boolean ready() {
+        if (this.mCamera == null) {
+            try {
+                this.mCamera = Camera.open();
+            } catch (Exception e) {
+                Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                intent.putExtra(InputOutputReceiver.TEXT, e.toString());
+                mContext.sendBroadcast(intent);
+                return false;
+            }
+        }
+        Camera.Parameters mCameraParameters = this.mCamera.getParameters();
+        List<String> supportedFlashModes = mCameraParameters.getSupportedFlashModes();
+        if (supportedFlashModes != null) {
+            if (supportedFlashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
+                this.flashSupported = true;
+                mCameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
+            } else if (supportedFlashModes.contains(Camera.Parameters.FLASH_MODE_ON)) {
+                this.flashSupported = true;
+                mCameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
+            }
+        }
+        if (this.flashSupported) {
+            try {
+                mCamera.setParameters(mCameraParameters);
+            } catch (RuntimeException e) {
+                Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                intent.putExtra(InputOutputReceiver.TEXT, e.toString());
+                mContext.sendBroadcast(intent);
+                return false;
+            }
+        }
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight2.java b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight2.java
new file mode 100755
index 0000000..3a29eed
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Flashlight2.java
@@ -0,0 +1,98 @@
+/*
+ *     Copyright (C) 2016  Merbin J Anselm <merbinjanselm@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package ohi.andre.consolelauncher.managers.flashlight;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+
+import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
+
+/**
+ * Created by I327891 on 04-Feb-17.
+ */
+
+@TargetApi(23)
+public class Flashlight2 extends Flashlight {
+
+    public static final String TYPE = Constants.ID_DEVICE_OUTPUT_TORCH_FLASH_NEW;
+
+    private String[] mCameraIDList;
+    private boolean flashSupported;
+
+    public Flashlight2(Context context) {
+        super(context);
+        flashSupported = false;
+    }
+
+    @Override
+    protected void turnOn() {
+        if (!this.getStatus()) {
+            CameraManager mCameraManager = (CameraManager) this.mContext.getSystemService(Context.CAMERA_SERVICE);
+            try {
+                this.mCameraIDList = mCameraManager.getCameraIdList();
+            } catch (CameraAccessException e) {
+                Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                intent.putExtra(InputOutputReceiver.TEXT, e.toString());
+                mContext.sendBroadcast(intent);
+                return;
+            }
+            try {
+                CameraCharacteristics mCameraParameters = mCameraManager.getCameraCharacteristics(this.mCameraIDList[0]);
+                this.flashSupported = mCameraParameters.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
+            } catch (Exception e) {
+                Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                intent.putExtra(InputOutputReceiver.TEXT, e.toString());
+                mContext.sendBroadcast(intent);
+                return;
+            }
+            if (this.flashSupported) {
+                try {
+                    mCameraManager.setTorchMode(this.mCameraIDList[0], true);
+                    this.updateStatus(true);
+                } catch (CameraAccessException e) {
+                    Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                    intent.putExtra(InputOutputReceiver.TEXT, e.toString());
+                    mContext.sendBroadcast(intent);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void turnOff() {
+        if (this.getStatus()) {
+            if (this.mCameraIDList != null && this.flashSupported) {
+                CameraManager mCameraManager = (CameraManager) this.mContext.getSystemService(Context.CAMERA_SERVICE);
+                try {
+                    mCameraManager.setTorchMode(mCameraIDList[0], false);
+                } catch (CameraAccessException e) {
+                    Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                    intent.putExtra(InputOutputReceiver.TEXT, e.toString());
+                    mContext.sendBroadcast(intent);
+                    return;
+                }
+                this.updateStatus(false);
+            }
+        }
+    }
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/OutputDevice.java b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/OutputDevice.java
new file mode 100755
index 0000000..67b7cb4
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/OutputDevice.java
@@ -0,0 +1,74 @@
+/*
+ *     Copyright (C) 2016  Merbin J Anselm <merbinjanselm@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package ohi.andre.consolelauncher.managers.flashlight;
+
+import android.content.Context;
+
+/**
+ * Created by I327891 on 04-Feb-17.
+ */
+
+public abstract class OutputDevice extends Device {
+
+    private boolean mStatus;
+    private OutputDeviceListener mListener;
+
+    public OutputDevice(Context context) {
+        super(context);
+        this.mStatus = false;
+    }
+
+    protected abstract void turnOn();
+
+    protected abstract void turnOff();
+
+    public final void start(boolean status) {
+        if (this.isEnabled) {
+            if (status && !this.mStatus)
+                this.turnOn();
+            else if (!status && this.mStatus)
+                this.turnOff();
+        }
+    }
+
+    public final void toggle() {
+        this.start(!this.mStatus);
+    }
+
+    public final boolean getStatus() {
+        return this.mStatus;
+    }
+
+    public final void setListener(OutputDeviceListener listener) {
+        this.mListener = listener;
+    }
+
+    protected final void updateStatus(boolean status) {
+        this.mStatus = status;
+        if (this.mListener != null) {
+            this.mListener.onStatusChanged(status);
+        }
+    }
+
+    protected final void updateError(String error) {
+        if (this.mListener != null) {
+            this.mListener.onError(error);
+        }
+    }
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/OutputDeviceListener.java b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/OutputDeviceListener.java
new file mode 100755
index 0000000..7048c6d
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/OutputDeviceListener.java
@@ -0,0 +1,27 @@
+/*
+ *     Copyright (C) 2016  Merbin J Anselm <merbinjanselm@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package ohi.andre.consolelauncher.managers.flashlight;
+
+/**
+ * Created by I327891 on 04-Feb-17.
+ */
+
+public interface OutputDeviceListener extends DeviceListener {
+    void onStatusChanged(boolean status);
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Torch.java b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Torch.java
new file mode 100755
index 0000000..d863b52
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/Torch.java
@@ -0,0 +1,32 @@
+/*
+ *     Copyright (C) 2016  Merbin J Anselm <merbinjanselm@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package ohi.andre.consolelauncher.managers.flashlight;
+
+import android.content.Context;
+
+/**
+ * Created by I327891 on 05-Feb-17.
+ */
+
+public abstract class Torch extends OutputDevice {
+
+    public Torch(Context context) {
+        super(context);
+    }
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/TorchManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/TorchManager.java
new file mode 100644
index 0000000..3925060
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/flashlight/TorchManager.java
@@ -0,0 +1,69 @@
+package ohi.andre.consolelauncher.managers.flashlight;
+
+import android.content.Context;
+import android.os.Build;
+
+/**
+ * Created by francescoandreuzzi on 20/08/2017.
+ */
+
+public class TorchManager {
+
+    private static TorchManager mInstance;
+    private final String flashType;
+    private Torch mTorch;
+    private String torchType;
+
+    private TorchManager() {
+        this.flashType = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ? Flashlight2.TYPE : Flashlight1.TYPE;
+        this.setTorchType(Constants.ID_DEVICE_OUTPUT_TORCH_FLASH);
+    }
+
+    public static TorchManager getInstance() {
+        if (mInstance == null) {
+            mInstance = new TorchManager();
+        }
+        return mInstance;
+    }
+
+    public boolean isOn() {
+        return this.mTorch != null;
+    }
+
+    public void setTorchType(String torchType) {
+        this.torchType = torchType;
+    }
+
+    public void turnOn(Context context) {
+        if (this.mTorch == null) {
+            if (this.torchType.equals(Flashlight.TYPE)) {
+                if (this.flashType.equals(Flashlight1.TYPE)) {
+                    this.mTorch = new Flashlight1(context);
+                } else if (this.flashType.equals(Flashlight2.TYPE)) {
+                    this.mTorch = new Flashlight2(context);
+                }
+            }
+        }
+        this.mTorch.setEnabled(true);
+        this.mTorch.start(true);
+    }
+
+    public void turnOff() {
+        if (this.mTorch != null) {
+            this.mTorch.start(false);
+            this.mTorch = null;
+        }
+    }
+
+    public void toggle(Context context) {
+        if (this.mTorch == null) {
+            this.turnOn(context);
+        } else {
+            if (this.mTorch.getStatus()) {
+                this.turnOff();
+            } else {
+                this.turnOn(context);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicManager2.java b/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicManager2.java
index 0a73ed8..fc26322 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicManager2.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicManager2.java
@@ -32,7 +32,6 @@ public class MusicManager2 implements MediaController.MediaPlayerControl {
     Context mContext;
 
     List<Song> songs;
-    List<String> titles;
 
     MusicService musicSrv;
     boolean musicBound=false;
@@ -153,9 +152,6 @@ public class MusicManager2 implements MediaController.MediaPlayerControl {
                     if(songs == null) songs = new ArrayList<>();
                     else songs.clear();
 
-                    if(titles == null) titles = new ArrayList<>();
-                    else titles.clear();
-
                     if(XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.songs_from_mediastore)) {
                         ContentResolver musicResolver = mContext.getContentResolver();
                         Uri musicUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
@@ -167,7 +163,6 @@ public class MusicManager2 implements MediaController.MediaPlayerControl {
                                 long thisId = musicCursor.getLong(idColumn);
                                 String thisTitle = musicCursor.getString(titleColumn);
                                 songs.add(new Song(thisId, thisTitle));
-                                titles.add(thisTitle);
                             }
                             while (musicCursor.moveToNext());
                         }
@@ -177,10 +172,6 @@ public class MusicManager2 implements MediaController.MediaPlayerControl {
                         if(path.length() > 0) {
                             File dir = new File(path);
                             if(dir.isDirectory()) songs.addAll(Tuils.getSongsInFolder(dir));
-
-                            for(Song s : songs) {
-                                titles.add(s.getTitle());
-                            }
                         }
                     }
                 } catch (Exception e) {
@@ -324,12 +315,12 @@ public class MusicManager2 implements MediaController.MediaPlayerControl {
         musicSrv.playSong();
     }
 
-    public List<String> getTitles() {
-        return titles;
-    }
-
     @Override
     public void start() {
         musicSrv.go();
     }
+
+    public List<Song> getSongs() {
+        return songs;
+    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/music/Song.java b/app/src/main/java/ohi/andre/consolelauncher/managers/music/Song.java
index 27f64cd..e1653e1 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/music/Song.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/music/Song.java
@@ -2,11 +2,13 @@ package ohi.andre.consolelauncher.managers.music;
 
 import java.io.File;
 
+import ohi.andre.consolelauncher.tuils.Compare;
+
 /**
  * Created by francescoandreuzzi on 17/08/2017.
  */
 
-public class Song {
+public class Song implements Compare.Stringable {
 
     private long id;
     private String title, path;
@@ -37,5 +39,10 @@ public class Song {
     public String getPath() {
         return path;
     }
+
+    @Override
+    public String getString() {
+        return title;
+    }
 }
 
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationManager.java
index e043b6e..7842f2a 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationManager.java
@@ -1,6 +1,9 @@
 package ohi.andre.consolelauncher.managers.notifications;
 
 import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
 import android.os.Build;
 import android.util.SparseArray;
 
@@ -19,11 +22,10 @@ import java.util.Collections;
 import java.util.List;
 import java.util.regex.Pattern;
 
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
 import ohi.andre.consolelauncher.BuildConfig;
+import ohi.andre.consolelauncher.R;
 import ohi.andre.consolelauncher.managers.XMLPrefsManager;
+import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
 import static ohi.andre.consolelauncher.managers.XMLPrefsManager.VALUE_ATTRIBUTE;
@@ -125,7 +127,7 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
 
     private NotificationManager() {}
 
-    public static void create() {
+    public static void create(Context context) {
         instance = new NotificationManager();
 
         if(created) return;
@@ -137,29 +139,28 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
         values = new XMLPrefsManager.XMLPrefsList();
 
         try {
-            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-            DocumentBuilder builder = factory.newDocumentBuilder();
-
             File file = new File(Tuils.getFolder(), PATH);
-            if(!file.exists() && !file.createNewFile()) return;
+            if(!file.exists()) {
+                resetFile(file, NAME);
+            }
 
-            Document d;
+            Object[] o;
             try {
-                d = builder.parse(file);
+                o = XMLPrefsManager.buildDocument(file, NAME);
             } catch (Exception e) {
-                resetFile(file, NAME);
+                Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+                intent.putExtra(InputOutputReceiver.TEXT, context.getString(R.string.output_xmlproblem1) + Tuils.SPACE + NAME + context.getString(R.string.output_xmlproblem2) +
+                        Tuils.NEWLINE + context.getString(R.string.output_errorlabel) + e.toString());
+                intent.putExtra(InputOutputReceiver.COLOR, Color.parseColor("#ff0000"));
+                context.sendBroadcast(intent);
 
-                d = builder.parse(file);
+                return;
             }
 
-            List<Options> enums = new ArrayList<>(Arrays.asList(Options.values()));
+            Document d = (Document) o[0];
+            Element root = (Element) o[1];
 
-            Element root = (Element) d.getElementsByTagName(NAME).item(0);
-            if(root == null) {
-                resetFile(file, NAME);
-                d = builder.parse(file);
-                root = (Element) d.getElementsByTagName(NAME).item(0);
-            }
+            List<Options> enums = new ArrayList<>(Arrays.asList(Options.values()));
             NodeList nodes = root.getElementsByTagName("*");
 
             String[] deleted = instance.deleted();
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationService.java b/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationService.java
index cbc02dc..701a726 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationService.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationService.java
@@ -10,9 +10,11 @@ import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.graphics.Color;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Handler;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
+import android.support.v4.app.NotificationCompat;
 import android.support.v4.content.LocalBroadcastManager;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -38,17 +40,20 @@ public class NotificationService extends NotificationListenerService {
 
     private final int UPDATE_TIME = 1500;
 
-    Map<String, Long> recentNotifications = new HashMap<>();
+    Map<Integer, Long> recentNotifications = new HashMap<>();
     Handler handler = new Handler();
 
     @Override
     public void onCreate() {
         super.onCreate();
 
-        NotificationManager.create();
+        NotificationManager.create(this);
+
+        manager = getPackageManager();
+        format = NotificationManager.getFormat();
+        timeColor = XMLPrefsManager.getColor(XMLPrefsManager.Theme.time_color);
 
         if(NotificationManager.apps() == 0) {
-//            some nice apps
             NotificationManager.notificationsChangeFor(new ArrayList<>(Arrays.asList(
                     new NotificatedApp("com.whatsapp", "#25D366", true),
                     new NotificatedApp("com.google.android.apps.inbox", "#03A9F4", true),
@@ -63,10 +68,10 @@ public class NotificationService extends NotificationListenerService {
         handler.post(new Runnable() {
             @Override
             public void run() {
-                Map<String, Long> copy = new HashMap<>(recentNotifications);
+                Map<Integer, Long> copy = new HashMap<>(recentNotifications);
 
                 long time = System.currentTimeMillis();
-                for(Map.Entry<String, Long> entry : copy.entrySet()) {
+                for(Map.Entry<Integer, Long> entry : copy.entrySet()) {
                     if(time - entry.getValue() > 1500) recentNotifications.remove(entry.getKey());
                 }
 
@@ -99,20 +104,14 @@ public class NotificationService extends NotificationListenerService {
     @Override
     public void onNotificationPosted(StatusBarNotification sbn) {
 
-        if(recentNotifications.containsKey(sbn.getPackageName())) return;
-        recentNotifications.put(sbn.getPackageName(), System.currentTimeMillis());
+        if (recentNotifications.containsKey(sbn.getId())) return;
+        recentNotifications.put(sbn.getId(), System.currentTimeMillis());
 
         Notification notification = sbn.getNotification();
         if (notification == null) {
             return;
         }
 
-        if(format == null) {
-            manager = getPackageManager();
-            format = NotificationManager.getFormat();
-            timeColor = XMLPrefsManager.getColor(XMLPrefsManager.Theme.time_color);
-        }
-
         String pack = sbn.getPackageName();
 
         String appName;
@@ -123,19 +122,27 @@ public class NotificationService extends NotificationListenerService {
         }
 
         NotificatedApp nApp = NotificationManager.getAppState(pack);
-        if( (nApp != null && !nApp.enabled)) {
+        if ((nApp != null && !nApp.enabled)) {
             return;
         }
 
-        if(nApp == null && !NotificationManager.default_app_state) {
+        if (nApp == null && !NotificationManager.default_app_state) {
             return;
         }
 
         CharSequence textSequence = null, titleSequence = null;
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
-            textSequence = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
-            titleSequence = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
+        Bundle bundle = NotificationCompat.getExtras(notification);
+        if(bundle != null) {
+            textSequence = bundle.getCharSequence(NotificationCompat.EXTRA_TEXT);
+            titleSequence = bundle.getCharSequence(NotificationCompat.EXTRA_TITLE);
+
+            if (textSequence == null) {
+                CharSequence[] charText = (CharSequence[]) bundle.get(NotificationCompat.EXTRA_TEXT_LINES);
+                if (charText != null && charText.length > 0) {
+                    textSequence = charText[charText.length - 1].toString();
+                }
+            }
         } else {
             textSequence = notification.tickerText;
         }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionRunnable.java b/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionRunnable.java
index b12ecdd..1c014a9 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionRunnable.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionRunnable.java
@@ -22,6 +22,7 @@ import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import ohi.andre.consolelauncher.R;
+import ohi.andre.consolelauncher.managers.AppsManager;
 import ohi.andre.consolelauncher.managers.SkinManager;
 
 public class SuggestionRunnable implements Runnable {
@@ -94,8 +95,36 @@ public class SuggestionRunnable implements Runnable {
                 toRecycle[count].setTag(R.id.suggestion_id, suggestions[count]);
 
                 toRecycle[count].setText(s);
-                toRecycle[count].setBackgroundDrawable(skinManager.getSuggestionBg(suggestions[count].type));
-                toRecycle[count].setTextColor(skinManager.getSuggestionTextColor(suggestions[count].type));
+
+//                bg and fore
+                int bgColor = SkinManager.COLOR_NOT_SET;
+                int foreColor = SkinManager.COLOR_NOT_SET;
+                if(suggestions[count].type == SuggestionsManager.Suggestion.TYPE_APP ||
+                        suggestions[count].type == SuggestionsManager.Suggestion.TYPE_APPGROUP) {
+
+                    Object o = suggestions[count].object;
+                    if(o != null && o instanceof AppsManager.LaunchInfo) {
+                        AppsManager.LaunchInfo i = (AppsManager.LaunchInfo) o;
+
+                        for(AppsManager.Group g : AppsManager.groups) {
+                            if(g.contains(i)) {
+                                o = g;
+                                break;
+                            }
+                        }
+                    }
+
+                    if(o != null && o instanceof AppsManager.Group) {
+                        bgColor = ((AppsManager.Group) o).getBgColor();
+                        foreColor = ((AppsManager.Group) o).getForeColor();
+                    }
+                }
+
+                if(bgColor != SkinManager.COLOR_NOT_SET) toRecycle[count].setBackgroundColor(bgColor);
+                else toRecycle[count].setBackgroundDrawable(skinManager.getSuggestionBg(suggestions[count].type));
+                if(foreColor != SkinManager.COLOR_NOT_SET) toRecycle[count].setTextColor(foreColor);
+                else toRecycle[count].setTextColor(skinManager.getSuggestionTextColor(suggestions[count].type));
+//                end bg and fore
 
                 if(suggestions[count].type == SuggestionsManager.Suggestion.TYPE_CONTACT) {
                     toRecycle[count].setLongClickable(true);
@@ -110,8 +139,36 @@ public class SuggestionRunnable implements Runnable {
                     toAdd[space].setTag(R.id.suggestion_id, suggestions[count]);
 
                     toAdd[space].setText(s);
-                    toAdd[space].setBackgroundDrawable(skinManager.getSuggestionBg(suggestions[count].type));
-                    toAdd[space].setTextColor(skinManager.getSuggestionTextColor(suggestions[count].type));
+
+//                    bg and fore
+                    int bgColor = SkinManager.COLOR_NOT_SET;
+                    int foreColor = SkinManager.COLOR_NOT_SET;
+                    if(suggestions[count].type == SuggestionsManager.Suggestion.TYPE_APP ||
+                            suggestions[count].type == SuggestionsManager.Suggestion.TYPE_APPGROUP) {
+
+                        Object o = suggestions[count].object;
+                        if(o != null && o instanceof AppsManager.LaunchInfo) {
+                            AppsManager.LaunchInfo i = (AppsManager.LaunchInfo) o;
+
+                            for(AppsManager.Group g : AppsManager.groups) {
+                                if(g.contains(i)) {
+                                    o = g;
+                                    break;
+                                }
+                            }
+                        }
+
+                        if(o != null && o instanceof AppsManager.Group) {
+                            bgColor = ((AppsManager.Group) o).getBgColor();
+                            foreColor = ((AppsManager.Group) o).getForeColor();
+                        }
+                    }
+
+                    if(bgColor != SkinManager.COLOR_NOT_SET) toAdd[space].setBackgroundColor(bgColor);
+                    else toAdd[space].setBackgroundDrawable(skinManager.getSuggestionBg(suggestions[count].type));
+                    if(foreColor != SkinManager.COLOR_NOT_SET) toAdd[space].setTextColor(foreColor);
+                    else toAdd[space].setTextColor(skinManager.getSuggestionTextColor(suggestions[count].type));
+//                    end bg and fore
 
                     if(toAdd[space].getParent() == null) {
                         suggestionsView.addView(toAdd[space], suggestionViewParams);
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionsManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionsManager.java
index 29e40c3..acd15e1 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionsManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionsManager.java
@@ -18,6 +18,7 @@ import ohi.andre.consolelauncher.managers.AppsManager;
 import ohi.andre.consolelauncher.managers.ContactManager;
 import ohi.andre.consolelauncher.managers.FileManager;
 import ohi.andre.consolelauncher.managers.XMLPrefsManager;
+import ohi.andre.consolelauncher.managers.music.Song;
 import ohi.andre.consolelauncher.managers.notifications.NotificationManager;
 import ohi.andre.consolelauncher.tuils.Compare;
 import ohi.andre.consolelauncher.tuils.SimpleMutableEntry;
@@ -33,24 +34,18 @@ public class SuggestionsManager {
 
     private final int MIN_COMMAND_PRIORITY = 5;
 
-//    private int min_command_rate = 4;
-//    private int min_apps_rate = 2;
-//    private int min_contacts_rate = 2;
-//    private int min_file_rate = 2;
-//    private int min_songs_rate = 2;
-
-//    use to place something at the top
     private final int MAX_RATE = 100;
     private final int NO_RATE = -1;
 
     private final int FIRST_INTERVAL = 6;
 
-    private boolean showAliasDefault, set = false, clickToLaunch;
+    private boolean showAliasDefault, set = false, clickToLaunch, showAppsGpDefault;
 
     public Suggestion[] getSuggestions(MainPack info, String before, String lastWord) {
 
         if(!set) {
             showAliasDefault = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Suggestions.suggest_alias_default);
+            showAppsGpDefault = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Suggestions.suggest_appgp_default);
             set = true;
             clickToLaunch = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Suggestions.click_to_launch);
         }
@@ -65,7 +60,7 @@ public class SuggestionsManager {
 //            lastword = 0 && before = 0
 
             if (before.length() == 0) {
-                String[] apps = info.appsManager.getSuggestedApps();
+                AppsManager.LaunchInfo[] apps = info.appsManager.getSuggestedApps();
                 if (apps != null) {
                     for(int count = 0; count < apps.length; count++) {
                         if(apps[count] == null) {
@@ -74,11 +69,12 @@ public class SuggestionsManager {
 
                         float shift = count + 1;
                         float rate = 1f / shift;
-                        suggestionList.add(new Suggestion(before, apps[count], clickToLaunch, (int) Math.ceil(rate), Suggestion.TYPE_APP));
+                        suggestionList.add(new Suggestion(before, apps[count].getString(), clickToLaunch, (int) Math.ceil(rate), Suggestion.TYPE_APP, apps[count]));
                     }
                 }
 
                 if(showAliasDefault) suggestAlias(info.aliasManager, suggestionList, lastWord);
+                if(showAppsGpDefault) suggestAppGroup(suggestionList, lastWord, before);
 
                 return suggestionList.toArray(new Suggestion[suggestionList.size()]);
             }
@@ -97,7 +93,7 @@ public class SuggestionsManager {
                         suggestPermanentSuggestions(suggestionList, (PermanentSuggestionCommand) cmd.cmd);
                     }
 
-                    if (cmd.nArgs == cmd.cmd.maxArgs() || (cmd.mArgs != null && cmd.mArgs.length > 0 && cmd.cmd instanceof ParamCommand && cmd.nArgs >= 1 && ((Param) cmd.mArgs[0]).args().length + 1 == cmd.nArgs)) {
+                    if (cmd.mArgs != null && cmd.mArgs.length > 0 && cmd.cmd instanceof ParamCommand && cmd.nArgs >= 1 && ((Param) cmd.mArgs[0]).args().length + 1 == cmd.nArgs) {
                         return new Suggestion[0];
                     }
 
@@ -128,14 +124,13 @@ public class SuggestionsManager {
                         suggestFile(info, suggestionList, Tuils.EMPTYSTRING, before);
                     } else {
 //                        ==> app
-                        suggestApp(info, suggestionList, before, Tuils.EMPTYSTRING);
+                        suggestApp(info, suggestionList, before + Tuils.SPACE, Tuils.EMPTYSTRING);
                     }
 
                 }
             }
         }
 
-
 //        lastWord > 0
         else {
 
@@ -151,11 +146,11 @@ public class SuggestionsManager {
                         suggestPermanentSuggestions(suggestionList, (PermanentSuggestionCommand) cmd.cmd);
                     }
 
-                    if (cmd.cmd.maxArgs() == 1 && before.contains(Tuils.SPACE)) {
-                        int index = cmd.cmd.getClass().getSimpleName().length() + 1;
-
-                        lastWord = before.substring(index) + lastWord;
-                    }
+//                    if (cmd.cmd.maxArgs() == 1 && before.contains(Tuils.SPACE)) {
+//                        int index = cmd.cmd.getClass().getSimpleName().length() + 1;
+//
+//                        lastWord = before.substring(index) + lastWord;
+//                    }
 
                     if(cmd.cmd instanceof ParamCommand && (cmd.mArgs == null || cmd.mArgs.length == 0)) {
                         suggestParams(info, suggestionList, (ParamCommand) cmd.cmd, before, lastWord);
@@ -174,7 +169,7 @@ public class SuggestionsManager {
                     if(isShellCmd) {
                         suggestFile(info, suggestionList, lastWord, before);
                     } else {
-                        suggestApp(info, suggestionList, before + lastWord, Tuils.EMPTYSTRING);
+                        suggestApp(info, suggestionList, before + Tuils.SPACE + lastWord, Tuils.EMPTYSTRING);
                     }
                 }
 
@@ -183,6 +178,7 @@ public class SuggestionsManager {
                 suggestCommand(info, suggestionList, lastWord, before);
                 suggestAlias(info.aliasManager, suggestionList, lastWord);
                 suggestApp(info, suggestionList, lastWord, Tuils.EMPTYSTRING);
+                suggestAppGroup(suggestionList, lastWord, before);
             }
         }
 
@@ -272,6 +268,9 @@ public class SuggestionsManager {
             case CommandAbstraction.ALL_PACKAGES:
                 suggestAllPackages(info, suggestions, prev, before);
                 break;
+            case CommandAbstraction.APP_GROUP:
+                suggestAppGroup(suggestions, prev, before);
+                break;
         }
     }
 
@@ -354,22 +353,14 @@ public class SuggestionsManager {
     }
 
     private void suggestContact(MainPack info, List<Suggestion> suggestions, String prev, String before) {
+        List<ContactManager.Contact> contacts = info.contacts.getContacts();
+        if(contacts == null) return;
+
         if (prev == null || prev.length() == 0) {
-            for (ContactManager.Contact contact : info.contacts.getContacts())
-                suggestions.add(new Suggestion(before, contact.name, true, NO_RATE, Suggestion.TYPE_CONTACT, contact));
+            for (ContactManager.Contact contact : contacts) suggestions.add(new Suggestion(before, contact.name, true, NO_RATE, Suggestion.TYPE_CONTACT, contact));
         }
-
-//        else if(prev.length() <= FIRST_INTERVAL) {
-//            prev = prev.trim().toLowerCase();
-//
-//            for (ContactManager.Contact contact : info.contacts.getContacts())
-//                if(contact.name.toLowerCase().trim().startsWith(prev)) {
-//                    suggestions.add(new Suggestion(before, contact.name, true, NO_RATE, Suggestion.TYPE_CONTACT, contact));
-//                }
-//        }
-
         else {
-            for(ContactManager.Contact contact : info.contacts.getContacts()) {
+            for(ContactManager.Contact contact : contacts) {
                 if(Thread.currentThread().isInterrupted()) return;
 
                 int rate = Compare.matches(contact.name, prev, true);
@@ -381,16 +372,18 @@ public class SuggestionsManager {
     }
 
     private void suggestSong(MainPack info, List<Suggestion> suggestions, String prev, String before) {
-        Tuils.log(info.player.getTitles().toString());
+        List<Song> songs = info.player.getSongs();
+        if(songs == null) return;
+
         if (prev == null || prev.length() == 0) {
-            for (String s : info.player.getTitles()) {
-                suggestions.add(new Suggestion(before, s, clickToLaunch, NO_RATE, Suggestion.TYPE_SONG));
+            for (Song s : songs) {
+                suggestions.add(new Suggestion(before, s.getTitle(), clickToLaunch, NO_RATE, Suggestion.TYPE_SONG));
             }
         }
         else {
-            List<SimpleMutableEntry<String, Integer>> infos = Compare.matchesWithRate(info.player.getTitles(), prev, true);
-            for(SimpleMutableEntry<String, Integer> i : infos) {
-                suggestions.add(new Suggestion(before, i.getKey(), clickToLaunch, i.getValue(), Suggestion.TYPE_SONG));
+            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(songs, true, prev);
+            for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
+                suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_SONG));
             }
         }
     }
@@ -403,7 +396,10 @@ public class SuggestionsManager {
 
         if(prev.length() <= FIRST_INTERVAL) {
             prev = prev.toLowerCase().trim();
+
             String[] cmds = info.commandGroup.getCommandNames();
+            if(cmds == null) return;
+
             for (String s : cmds) {
                 if(Thread.currentThread().isInterrupted()) return;
 
@@ -424,7 +420,10 @@ public class SuggestionsManager {
     }
 
     private void suggestCommand(MainPack info, List<Suggestion> suggestions, String before) {
-        for (String s : info.commandGroup.getCommandNames()) {
+        String[] cmds = info.commandGroup.getCommandNames();
+        if(cmds == null) return;
+
+        for (String s : cmds) {
             if(Thread.currentThread().isInterrupted()) return;
 
             CommandAbstraction cmd = info.commandGroup.getCommandByName(s);
@@ -437,63 +436,84 @@ public class SuggestionsManager {
     }
 
     private void suggestApp(MainPack info, List<Suggestion> suggestions, String prev, String before) {
-        List<String> names = info.appsManager.getAppLabels();
-        if (prev == null || prev.length() == 0) {
-            for (String s : names) {
-                suggestions.add(new Suggestion(before, s, clickToLaunch, NO_RATE, Suggestion.TYPE_APP));
+//        try to find a group only if it was called outside a command
+        int index = prev.indexOf(Tuils.SPACE);
+        if(before.length() == 0 && index != -1) {
+            String temp = prev;
+
+            String gpName = prev.substring(0,index);
+            prev = prev.substring(index + 1);
+
+            int gpIndex = Tuils.find(gpName, AppsManager.groups);
+            if(gpIndex != -1) {
+                AppsManager.Group g = AppsManager.groups.get(gpIndex);
+
+                List<? extends Compare.Stringable> apps = g.members();
+                if(apps != null && apps.size() > 0) {
+                    if (prev.length() == 0) {
+                        for (Compare.Stringable s : apps) {
+                            suggestions.add(new Suggestion(before, s.getString(), clickToLaunch, NO_RATE, Suggestion.TYPE_APP, s));
+                        }
+                    }
+                    else {
+                        List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, prev);
+                        for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
+                            suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
+                        }
+                    }
+                    return;
+                }
+            }
+
+            prev = temp;
+        }
+
+//        group not found...
+        List<AppsManager.LaunchInfo> apps = info.appsManager.shownApps();
+        if(apps == null) return;
+
+        if (prev.length() == 0) {
+            for (AppsManager.LaunchInfo l : apps) {
+                suggestions.add(new Suggestion(before, l.publicLabel, clickToLaunch, NO_RATE, Suggestion.TYPE_APP, l));
             }
         }
-//        else if(prev.length() <= FIRST_INTERVAL) {
-//            prev = prev.trim().toLowerCase();
-//            for (String n : names) {
-//                if(n.toLowerCase().trim().startsWith(prev)) {
-//                    suggestions.add(new Suggestion(before, n, true, MAX_RATE, Suggestion.TYPE_APP));
-//                }
-//            }
-//        }
         else {
-            List<SimpleMutableEntry<String, Integer>> infos = Compare.matchesWithRate(names, prev, true);
-            for(SimpleMutableEntry<String, Integer> i : infos) {
-                suggestions.add(new Suggestion(before, i.getKey(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP));
+            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, prev);
+            for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
+                suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
             }
         }
     }
 
     private void suggestHiddenApp(MainPack info, List<Suggestion> suggestions, String prev, String before) {
-        List<String> names = info.appsManager.getHiddenAppsLabels();
+        List<AppsManager.LaunchInfo> apps = info.appsManager.hiddenApps();
+        if(apps == null) return;
+
         if (prev == null || prev.length() == 0) {
-            for (String s : names) {
-                suggestions.add(new Suggestion(before, s, clickToLaunch, NO_RATE, Suggestion.TYPE_APP));
+            for (AppsManager.LaunchInfo a : apps) {
+                suggestions.add(new Suggestion(before, a.publicLabel, clickToLaunch, NO_RATE, Suggestion.TYPE_APP));
             }
         }
-//        else if(prev.length() <= FIRST_INTERVAL) {
-//            prev = prev.trim().toLowerCase();
-//            for (String n : names) {
-//                if(n.toLowerCase().trim().startsWith(prev)) {
-//                    suggestions.add(new Suggestion(before, n, true, MAX_RATE, Suggestion.TYPE_APP));
-//                }
-//            }
-//        }
         else {
-            List<SimpleMutableEntry<String, Integer>> infos = Compare.matchesWithRate(names, prev, true);
-            for(SimpleMutableEntry<String, Integer> i : infos) {
-                suggestions.add(new Suggestion(before, i.getKey(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP));
+            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, prev);
+            for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
+                suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP));
             }
         }
     }
 
     private void suggestAllPackages(MainPack info, List<Suggestion> suggestions, String prev, String before) {
-        List<String> apps = info.appsManager.getHiddenAppsLabels();
-        apps.addAll(info.appsManager.getAppLabels());
+        List<AppsManager.LaunchInfo> apps = new ArrayList<>(info.appsManager.shownApps());
+        apps.addAll(info.appsManager.hiddenApps());
 
         if (prev == null || prev.length() == 0) {
-            for (String s : apps) {
-                suggestions.add(new Suggestion(before, s, clickToLaunch, NO_RATE, Suggestion.TYPE_APP));
+            for (AppsManager.LaunchInfo a : apps) {
+                suggestions.add(new Suggestion(before, a.publicLabel, clickToLaunch, NO_RATE, Suggestion.TYPE_APP, a));
             }
         } else {
-            List<SimpleMutableEntry<String, Integer>> infos = Compare.matchesWithRate(apps, prev, true);
-            for(SimpleMutableEntry<String, Integer> i : infos) {
-                suggestions.add(new Suggestion(before, i.getKey(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP));
+            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, prev);
+            for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
+                suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
             }
         }
     }
@@ -502,24 +522,18 @@ public class SuggestionsManager {
         suggestions.add(new Suggestion(before, "most_used", false, MAX_RATE, Suggestion.TYPE_PERMANENT));
         suggestions.add(new Suggestion(before, "null", false, MAX_RATE, Suggestion.TYPE_PERMANENT));
 
-        List<String> names = info.appsManager.getAppLabels();
+        List<AppsManager.LaunchInfo> apps = info.appsManager.shownApps();
+        if(apps == null) return;
+
         if (prev == null || prev.length() == 0) {
-            for (String s : names) {
-                suggestions.add(new Suggestion(before, s, clickToLaunch, NO_RATE, Suggestion.TYPE_APP));
+            for (AppsManager.LaunchInfo a : apps) {
+                suggestions.add(new Suggestion(before, a.publicLabel, clickToLaunch, NO_RATE, Suggestion.TYPE_APP, a));
             }
         }
-//        else if(prev.length() <= FIRST_INTERVAL) {
-//            prev = prev.trim().toLowerCase();
-//            for (String n : names) {
-//                if(n.toLowerCase().trim().startsWith(prev)) {
-//                    suggestions.add(new Suggestion(before, n, true, MAX_RATE, Suggestion.TYPE_APP));
-//                }
-//            }
-//        }
         else {
-            List<SimpleMutableEntry<String, Integer>> infos = Compare.matchesWithRate(names, prev, true);
-            for(SimpleMutableEntry<String, Integer> i : infos) {
-                suggestions.add(new Suggestion(before, i.getKey(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP));
+            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, prev);
+            for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
+                suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
             }
         }
     }
@@ -540,15 +554,6 @@ public class SuggestionsManager {
                 suggestions.add(sg);
             }
         }
-//        else if(prev.length() <= FIRST_INTERVAL) {
-//            prev = prev.trim().toLowerCase();
-//            for (XMLPrefsManager.XMLPrefsSave s : xmlPrefsEntrys) {
-//                String label = s.label();
-//                if(label.startsWith(prev)) {
-//                    suggestions.add(new Suggestion(before, label, false, MAX_RATE, Suggestion.TYPE_COMMAND));
-//                }
-//            }
-//        }
         else {
             for (XMLPrefsManager.XMLPrefsSave s : xmlPrefsEntrys) {
                 if(Thread.currentThread().isInterrupted()) return;
@@ -588,6 +593,26 @@ public class SuggestionsManager {
         }
     }
 
+    private void suggestAppGroup(List<Suggestion> suggestions, String prev, String before) {
+        List<AppsManager.Group> groups = AppsManager.groups;
+
+        if(prev == null || prev.length() == 0) {
+            for(AppsManager.Group g : groups) {
+                Suggestion sg = new Suggestion(before, g.getName(), false, NO_RATE, Suggestion.TYPE_APPGROUP, g);
+                suggestions.add(sg);
+            }
+        }
+        else {
+            for(AppsManager.Group g : groups) {
+                String label = g.getName();
+                int rate = Compare.matches(label, prev, true);
+                if(rate != -1) {
+                    suggestions.add(new Suggestion(before, label, false, rate, Suggestion.TYPE_APPGROUP, g));
+                }
+            }
+        }
+    }
+
     public class Suggestion implements Comparable<Suggestion> {
 
         public static final int TYPE_APP = 10;
@@ -599,6 +624,7 @@ public class SuggestionsManager {
         public static final int TYPE_BOOLEAN = 16;
         public static final int TYPE_COLOR = 17;
         public static final int TYPE_PERMANENT = 18;
+        public static final int TYPE_APPGROUP = 19;
 
         public String text;
         public String textBefore;
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 8c4dc89..4775c36 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/Compare.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/Compare.java
@@ -132,6 +132,30 @@ public class Compare {
         return matchesWithRate(Arrays.asList(compared), comparator, allowSkip);
     }
 
+    public static List<SimpleMutableEntry<Stringable, Integer>> matchesWithRate(List<? extends Stringable> compared, boolean allowSkip, String comparator) {
+        List<SimpleMutableEntry<Stringable, Integer>> ms = new ArrayList<>();
+
+        for(Stringable s : compared) {
+            if(Thread.currentThread().isInterrupted()) return ms;
+
+            int rate = matches(s.getString(), comparator, allowSkip);
+            if(rate != -1) ms.add(new SimpleMutableEntry<>(s, rate));
+        }
+
+        Collections.sort(ms, new Comparator<SimpleMutableEntry<Stringable, Integer>>() {
+            @Override
+            public int compare(SimpleMutableEntry<Stringable, Integer> o1, SimpleMutableEntry<Stringable, Integer> o2) {
+                return o1.getValue() - o2.getValue();
+            }
+        });
+
+        return ms;
+    }
+
+    public static List<SimpleMutableEntry<Stringable, Integer>> matchesWithRate(Stringable[] compared, boolean allowSkip, String comparator) {
+        return matchesWithRate(Arrays.asList(compared), allowSkip, comparator);
+    }
+
     private static class ComparePack {
         String s;
         int index;
@@ -147,4 +171,8 @@ public class Compare {
             return index;
         }
     }
+
+    public interface Stringable {
+        String getString();
+    }
 }
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 6c7e8dc..5ce0c46 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/Tuils.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/Tuils.java
@@ -258,6 +258,14 @@ public class Tuils {
         return round(result, 2);
     }
 
+    public static void delete(File dir) {
+        for(File f : dir.listFiles()) {
+            if(f.isDirectory()) delete(f);
+            f.delete();
+        }
+        dir.delete();
+    }
+
     public static void deepView(View v) {
         Tuils.log(v.toString());
 
@@ -431,11 +439,10 @@ public class Tuils {
             return Tuils.EMPTYSTRING;
         }
 
-        String output = "";
+        String output = Tuils.EMPTYSTRING;
         for (int count = 0; count < strings.length; count++) {
             output = output.concat(strings[count]);
-            if (count < strings.length - 1)
-                output = output.concat(separator);
+            if (count < strings.length - 1) output = output.concat(separator);
         }
         return output;
     }
@@ -447,6 +454,19 @@ public class Tuils {
         return Tuils.EMPTYSTRING;
     }
 
+    public static String toPlanString(String separator, List<? extends Compare.Stringable> strings) {
+        if(strings == null) {
+            return Tuils.EMPTYSTRING;
+        }
+
+        String output = Tuils.EMPTYSTRING;
+        for (int count = 0; count < strings.size(); count++) {
+            output = output.concat(strings.get(count).getString());
+            if (count < strings.size() - 1) output = output.concat(separator);
+        }
+        return output;
+    }
+
     public static void log(Object o) {
         if(o instanceof Throwable) {
             Log.e("andre", "", (Throwable) o);
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 786ae14..c77adc7 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -5,7 +5,9 @@
     <string name="version_label">Version:</string>
     <string name="location_off">Turn on GPS or network location</string>
     <string name="share_label">Share</string>
-    <string name="output_about">Francesco Andreuzzi (Italy)\n\t-> Programmer</string>
+    <string name="output_about">Francesco Andreuzzi (Italy)\n\t-> Programmer
+        \n\nLuke Winward (USA)\n\t-> Idea and design
+        \n\nAlexander King (Australia)\n\t-> t-ui theme website and db management</string>
     <string name="output_refresh">Refresh: apps, alias, music, contacts</string>
     <string name="output_rate">Thank you!</string>
     <string name="start_notification">T-UI started</string>
@@ -13,13 +15,17 @@
     <string name="anr">t-ui is having some issues. Please send to the developer your file crash.txt in the "t-ui" folder</string>
     <string name="admin_permission">Lock the screen on double tap</string>
 
+    <!-- theme -->
+    <string name="theme_done">Done</string>
+    <string name="theme_not_found">Theme not found</string>
+
     <!-- files -->
     <string name="output_error">An unknown error has occurred</string>
     <string name="output_isdirectory">This is a directory</string>
     <string name="output_filenotfound">File not found</string>
 
     <!-- notifications -->
-    <string name="notification_reader">Notification Reader</string>
+    <string name="notification_reader">T-UI 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 -->
@@ -48,6 +54,12 @@
     <string name="output_lessarg">Less arguments than expected</string>
     <string name="invalid_integer">Invalid integer</string>
     <string name="output_nothing_found">Nothing was found</string>
+    <string name="output_xmlproblem1">There was an XML problem with your file</string>
+    <string name="output_xmlproblem2">, t-ui will use default values.\nFix or delete the file to recover your options</string>
+    <string name="output_errorlabel">Error:</string>
+    <string name="output_invalidcolor">Invalid color</string>
+    <string name="output_groupnotfound">Group not found</string>
+    <string name="output_groupspace">Spaces are not allowed inside group names</string>
 
     <!-- alias -->
     <string name="output_aliasnotfound">Alias not found:</string>
@@ -84,7 +96,6 @@
 
     <!-- command/args -->
     <string name="output_commandnotfound">Command not found.\nTry to use \">>help\" or \">>tutorial\"</string>
-    <string name="output_toomanyargs">More arguments than expected</string>
     <string name="output_invalid_param">Invalid option:</string>
 
     <!-- flash -->
@@ -114,7 +125,8 @@
     </string>
     <string name="help_apps">Manage your apps
         \n\nUsage:
-        \n-lsh -> show hidden apps
+        \n-ls -> list your apps
+        \n-lsh -> list your hidden apps
         \n-show [appName] -> re-show an hidden app
         \n-hide [appName] -> hide an app
         \n-l [appName] -> show details about an app
@@ -123,6 +135,12 @@
         \n-default_app [index] [appName or most_used or null] -> set the default_app at the specified index
         \n-frc [appName] -> force t-ui to launch an app
         \n-file -> open apps.xml
+        \n-mkgp [groupName] -> create a new group with the given name
+        \n-rmgp [groupName] -> delete the group with the given name
+        \n-gpcolor [groupName] [color] -> set the color for the given group
+        \n-addtogp [groupName] [appName] -> add the given app to the given group
+        \n-rmfromgp [groupName] [appName] -> remove the given app from the given group
+        \n-lsgp [OPTIONAL: groupName] -> list your groups, or list the content of the given group
     </string>
     <string name="help_bluetooth">Toggle bluetooth</string>
     <string name="help_clear">Clear the screen</string>
@@ -130,8 +148,6 @@
         \nExample:
         \n\n>>calc 4+2-5
         \n1
-        \n\n>>calc 7 % 3
-        \n1
         \n\n>>calc 2 ^ (2*2)
         \n16
         \n\n>>calc sqrt25
@@ -148,17 +164,14 @@
         \n-reset [option] -> reset the value of an option
     </string>
     <string name="help_data">Toggle mobile data</string>
+    <string name="help_devutils">Usage:
+        \nnotify [title] [text]</string>
     <string name="help_donate">Offer a coffee to the developer (PayPal only)</string>
     <string name="help_flash">Toggle the flashlight</string>
     <string name="help_help">Print a list of the available commands, or info about a command
         \nUsage:
         \n>>help [command]
     </string>
-    <string name="help_next">Play the next track in the queue</string>
-    <string name="help_listen">Play a specific track
-        \nUsage:
-        \n>>listen [songName]
-    </string>
     <string name="help_music">Usage:
         \n-next -> play the next song in the queue
         \n-previous -> play the previous song in the queue
@@ -168,7 +181,6 @@
         \n-select [song] -> play the selected song
         \n-info -> get info about the current song
         \n-seekto [seconds] -> seek to the selected part of the current song</string>
-    <string name="help_previous">Play the last played track</string>
     <string name="help_rate">Leave a feedback on the Play Store page</string>
     <string name="help_refresh">Refresh apps, alias, music, contacts</string>
     <string name="help_restart">Restart t-ui and load modified values</string>
@@ -186,12 +198,13 @@
     </string>
     <string name="help_shellcommands">Print the commands in /system/bin and /system/xbin</string>
     <string name="help_status">Get info about battery charge, wifi status and mobile data</string>
-    <string name="help_stop">Stop the player</string>
+    <string name="help_theme">Usage:
+        \n-apply [theme] -> apply the selected theme (case sensitive)
+        \n-view -> view the available themes
+        \n-create -> create a new theme</string>
     <string name="help_time">Print the current time with the given format
         \n\nUsage:
         \n$ time [index] (index means the index of the desired time_format</string>
-    <string name="help_track">Print info about the current track</string>
-    <string name="help_tracks">Print a list of the tracks in your music folder</string>
     <string name="help_tuixt">Open the text editor.
         \nUsage:
         \n>>tuixt [textFile]
-- 
GitLab