From d3f36a805d43028f7f938948157ae9269112ffb3 Mon Sep 17 00:00:00 2001
From: Francesco Andreuzzi <andreuzzi.francesco@gmail.com>
Date: Sat, 19 Aug 2017 00:20:41 +0200
Subject: [PATCH] 6.2a

---
 app/libs/anrwatchdog-1.3.0.jar                | Bin 0 -> 9369 bytes
 .../commands/main/raw/music.java              | 208 +++++++++++
 .../managers/music/MusicController.java       |  14 +
 .../managers/music/MusicManager2.java         | 335 ++++++++++++++++++
 .../managers/music/MusicService.java          | 245 +++++++++++++
 .../consolelauncher/managers/music/Song.java  |  41 +++
 .../tuils/InputOutputReceiver.java            |  64 ++++
 .../tuils/libsuperuser/ShellHolder.java       |  37 ++
 8 files changed, 944 insertions(+)
 create mode 100644 app/libs/anrwatchdog-1.3.0.jar
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/music.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicController.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicManager2.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicService.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/managers/music/Song.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/tuils/InputOutputReceiver.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/tuils/libsuperuser/ShellHolder.java

diff --git a/app/libs/anrwatchdog-1.3.0.jar b/app/libs/anrwatchdog-1.3.0.jar
new file mode 100644
index 0000000000000000000000000000000000000000..b8ff41bc9b51d130ca4e0f0220f7c6c0864fee1f
GIT binary patch
literal 9369
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

literal 0
HcmV?d00001

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
new file mode 100755
index 0000000..36ea9e2
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/music.java
@@ -0,0 +1,208 @@
+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.managers.music.MusicManager2;
+import ohi.andre.consolelauncher.managers.music.Song;
+import ohi.andre.consolelauncher.tuils.Tuils;
+
+public class music extends ParamCommand {
+
+    private enum Param implements ohi.andre.consolelauncher.commands.main.Param {
+        next {
+            @Override
+            public int[] args() {
+                return new int[0];
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                String title = ((MainPack) pack).player.playNext();
+                if(title != null) return pack.context.getString(R.string.output_playing) + Tuils.SPACE + title;
+                return null;
+            }
+        },
+        previous {
+            @Override
+            public int[] args() {
+                return new int[0];
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                String title = ((MainPack) pack).player.playPrev();
+                if(title != null) return pack.context.getString(R.string.output_playing) + Tuils.SPACE + title;
+                return null;
+            }
+        },
+        ls {
+            @Override
+            public int[] args() {
+                return new int[0];
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                return ((MainPack) pack).player.lsSongs();
+            }
+        },
+        play {
+            @Override
+            public int[] args() {
+                return new int[0];
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                String title = ((MainPack) pack).player.play();
+                if(title == null) return null;
+                return pack.context.getString(R.string.output_playing) + Tuils.SPACE + title;
+            }
+        },
+        stop {
+            @Override
+            public int[] args() {
+                return new int[0];
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                ((MainPack) pack).player.stop();
+                return null;
+            }
+        },
+        select {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.SONG};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                String s = pack.get(String.class, 1);
+                ((MainPack) pack).player.select(s);
+                return null;
+            }
+        },
+        info {
+            @Override
+            public int[] args() {
+                return new int[0];
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                StringBuilder builder = new StringBuilder();
+
+                MusicManager2 m = ((MainPack) pack).player;
+                Song song = m.get(m.getSongIndex());
+
+                builder.append("Name: " + song.getTitle()).append(Tuils.NEWLINE);
+                if(song.getID() == -1) builder.append("Path: " + song.getPath()).append(Tuils.NEWLINE);
+                builder.append(Tuils.NEWLINE);
+
+                int curS = m.getCurrentPosition() / 1000;
+                int curMin = 0;
+                if(curS >= 60) {
+                    curMin = curS / 60;
+                    curS = curS % 60;
+                }
+
+                int s = m.getDuration() / 1000;
+                int min = 0;
+                if(s >= 60) {
+                    min = s / 60;
+                    s = s % 60;
+                }
+
+                builder.append((curMin > 0 ? curMin + "." + curS : curS + "s") + " of " + (min > 0 ? min + "." + s : s + "s") + " (" + (Tuils.percentage(m.getCurrentPosition(), m.getDuration())) + "%)");
+                return builder.toString();
+            }
+        },
+        seekto {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.INT};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                ((MainPack) pack).player.seekTo(pack.get(int.class, 1) * 1000);
+                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
+    protected ohi.andre.consolelauncher.commands.main.Param paramForString(MainPack pack, String param) {
+        return Param.get(param);
+    }
+
+    @Override
+    public int minArgs() {
+        return 0;
+    }
+
+    @Override
+    public int maxArgs() {
+        return 2;
+    }
+
+    @Override
+    public int priority() {
+        return 4;
+    }
+
+    @Override
+    public int helpRes() {
+        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();
+    }
+
+    @Override
+    protected String doThings(ExecutePack pack) {
+        return null;
+    }
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicController.java b/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicController.java
new file mode 100644
index 0000000..fd7858d
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicController.java
@@ -0,0 +1,14 @@
+package ohi.andre.consolelauncher.managers.music;
+
+import android.content.Context;
+import android.widget.MediaController;
+
+public class MusicController extends MediaController {
+
+    public MusicController(Context c){
+        super(c);
+    }
+
+    public void hide(){}
+}
+
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
new file mode 100644
index 0000000..0a73ed8
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicManager2.java
@@ -0,0 +1,335 @@
+package ohi.andre.consolelauncher.managers.music;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.IBinder;
+import android.provider.MediaStore;
+import android.widget.MediaController;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import ohi.andre.consolelauncher.managers.XMLPrefsManager;
+import ohi.andre.consolelauncher.tuils.Tuils;
+
+/**
+ * Created by francescoandreuzzi on 17/08/2017.
+ */
+
+public class MusicManager2 implements MediaController.MediaPlayerControl {
+
+    public static final String[] MUSIC_EXTENSIONS = {".mp3", ".wav", ".ogg", ".flac"};
+
+    final int WAITING_NEXT = 10, WAITING_PREVIOUS = 11, WAITING_PLAY = 12, WAITING_LISTEN = 13;
+
+    Context mContext;
+
+    List<Song> songs;
+    List<String> titles;
+
+    MusicService musicSrv;
+    boolean musicBound=false;
+    Intent playIntent;
+
+    boolean playbackPaused=true, stopped = true;
+
+    Thread loader;
+
+    int waitingMethod = 0;
+    String savedParam;
+
+    public MusicManager2(Context c) {
+        mContext = c;
+        updateSongs();
+
+        init();
+    }
+
+    public void init() {
+        playIntent = new Intent(mContext, MusicService.class);
+        mContext.bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
+        mContext.startService(playIntent);
+    }
+
+    public void refresh() {
+        destroy();
+        updateSongs();
+    }
+
+    public void destroy() {
+        if(musicSrv != null && musicBound) {
+            musicSrv.stop();
+            mContext.unbindService(musicConnection);
+            mContext.stopService(playIntent);
+            musicSrv = null;
+        }
+
+        musicBound = false;
+        playbackPaused = true;
+        stopped = true;
+    }
+
+    public String playNext() {
+        if(!musicBound) {
+            init();
+            waitingMethod = WAITING_NEXT;
+
+            return null;
+        }
+
+        playbackPaused=false;
+        stopped = false;
+
+        return musicSrv.playNext();
+    }
+
+    public String playPrev() {
+        if(!musicBound) {
+            init();
+            waitingMethod = WAITING_PREVIOUS;
+
+            return null;
+        }
+
+        playbackPaused = false;
+        stopped = false;
+
+        return musicSrv.playPrev();
+    }
+
+    @Override
+    public void pause() {
+        if(musicSrv == null) return;
+
+        playbackPaused=true;
+        musicSrv.pausePlayer();
+    }
+
+    public String play() {
+        if(!musicBound) {
+            init();
+            waitingMethod = WAITING_PLAY;
+
+            return null;
+        }
+
+        if(stopped) {
+            musicSrv.playSong();
+            playbackPaused = false;
+            stopped = false;
+        } else if(playbackPaused) {
+            playbackPaused = false;
+            musicSrv.playPlayer();
+        } else pause();
+
+        return null;
+    }
+
+    public String lsSongs() {
+        List<String> ss = new ArrayList<>();
+        for(Song s : songs) {
+            ss.add(s.getTitle());
+        }
+
+        Collections.sort(ss);
+        Tuils.addPrefix(ss, Tuils.DOUBLE_SPACE);
+        Tuils.insertHeaders(ss, false);
+
+        return Tuils.toPlanString(ss, Tuils.NEWLINE);
+    }
+
+    public void updateSongs() {
+        loader = new Thread() {
+            @Override
+            public void run() {
+                try {
+                    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;
+                        Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);
+                        if(musicCursor!=null && musicCursor.moveToFirst()){
+                            int titleColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
+                            int idColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media._ID);
+                            do {
+                                long thisId = musicCursor.getLong(idColumn);
+                                String thisTitle = musicCursor.getString(titleColumn);
+                                songs.add(new Song(thisId, thisTitle));
+                                titles.add(thisTitle);
+                            }
+                            while (musicCursor.moveToNext());
+                        }
+                        musicCursor.close();
+                    } else {
+                        String path = XMLPrefsManager.get(String.class, XMLPrefsManager.Behavior.songs_folder);
+                        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) {
+                    Tuils.toFile(e);
+                }
+
+                synchronized (songs) {
+                    songs.notify();
+                }
+            }
+        };
+        loader.start();
+    }
+
+    private ServiceConnection musicConnection = new ServiceConnection(){
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            MusicService.MusicBinder binder = (MusicService.MusicBinder)service;
+            musicSrv = binder.getService();
+            musicSrv.setShuffle(XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.random_play));
+
+            if(songs == null || loader.isAlive()) {
+                synchronized (songs) {
+                    try {
+                        songs.wait();
+                    } catch (InterruptedException e) {}
+                }
+            }
+            musicSrv.setList(songs);
+            musicBound = true;
+
+            switch (waitingMethod) {
+                case WAITING_NEXT:
+                    playNext();
+                    break;
+                case WAITING_PREVIOUS:
+                    playPrev();
+                    break;
+                case WAITING_PLAY:
+                    play();
+                    break;
+                case WAITING_LISTEN:
+                    select(savedParam);
+                    break;
+            }
+
+            waitingMethod = 0;
+            savedParam = null;
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            musicBound = false;
+        }
+    };
+
+    @Override
+    public boolean canPause() {
+        return true;
+    }
+
+    @Override
+    public boolean canSeekBackward() {
+        return true;
+    }
+
+    @Override
+    public boolean canSeekForward() {
+        return true;
+    }
+
+    @Override
+    public int getAudioSessionId() {
+        return 0;
+    }
+
+    @Override
+    public int getBufferPercentage() {
+        return 0;
+    }
+
+    @Override
+    public int getCurrentPosition() {
+        if(musicSrv != null && musicBound && musicSrv.isPng())
+            return musicSrv.getPosn();
+        else return -1;
+    }
+
+    @Override
+    public int getDuration() {
+        if(musicSrv != null && musicBound && musicSrv.isPng())
+            return musicSrv.getDur();
+        else return -1;
+    }
+
+    public int getSongIndex() {
+        if(musicSrv != null) return musicSrv.getSongIndex();
+        return -1;
+    }
+
+    @Override
+    public boolean isPlaying() {
+        if(musicSrv != null && musicBound)
+            return musicSrv.isPng();
+        return false;
+    }
+
+    public void stop() {
+        destroy();
+    }
+
+    public Song get(int index) {
+        return songs.get(index);
+    }
+
+    @Override
+    public void seekTo(int pos) {
+        musicSrv.seek(pos);
+    }
+
+    public void select(String song) {
+        if(!musicBound) {
+            init();
+            waitingMethod = WAITING_LISTEN;
+            savedParam = song;
+
+            return;
+        }
+
+        int i = -1;
+        for(int index = 0; index < songs.size(); index++) {
+            if(songs.get(index).getTitle().equals(song)) i = index;
+        }
+
+        if(i == -1) {
+            return;
+        }
+
+        musicSrv.setSong(i);
+        musicSrv.playSong();
+    }
+
+    public List<String> getTitles() {
+        return titles;
+    }
+
+    @Override
+    public void start() {
+        musicSrv.go();
+    }
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicService.java b/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicService.java
new file mode 100644
index 0000000..f01971b
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicService.java
@@ -0,0 +1,245 @@
+package ohi.andre.consolelauncher.managers.music;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Build;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.RemoteInput;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Random;
+
+import ohi.andre.consolelauncher.LauncherActivity;
+import ohi.andre.consolelauncher.R;
+import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
+import ohi.andre.consolelauncher.tuils.Tuils;
+
+public class MusicService extends Service implements
+        MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener,
+        MediaPlayer.OnCompletionListener {
+
+    public static final int NOTIFY_ID=100001;
+
+    public static final String SONGTITLE_KEY = "songTitle";
+
+    private MediaPlayer player;
+    private List<Song> songs;
+    private int songPosn;
+    private final IBinder musicBind = new MusicBinder();
+    private String songTitle="";
+    private boolean shuffle=false;
+    private Random rand;
+
+    public void onCreate(){
+        super.onCreate();
+        songPosn=0;
+        rand=new Random();
+        player = new MediaPlayer();
+        initMusicPlayer();
+    }
+
+    public void initMusicPlayer(){
+        player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
+        player.setAudioStreamType(AudioManager.STREAM_MUSIC);
+        player.setOnPreparedListener(this);
+        player.setOnCompletionListener(this);
+        player.setOnErrorListener(this);
+    }
+
+    public void setList(List<Song> theSongs){
+        songs=theSongs;
+    }
+
+    public class MusicBinder extends Binder {
+        MusicService getService() {
+            return MusicService.this;
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return musicBind;
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent){
+        return super.onUnbind(intent);
+    }
+
+    public String playSong(){
+        try {
+            player.reset();
+        } catch (Exception e) {}
+
+        Song playSong = songs.get(songPosn);
+
+        long id = playSong.getID();
+        if(id == -1) {
+            String path = playSong.getPath();
+            try {
+                player.setDataSource(path);
+            } catch (IOException e) {
+                Tuils.log(e);
+                Tuils.toFile(e);
+                return null;
+            }
+        } else {
+            songTitle=playSong.getTitle();
+            long currSong = playSong.getID();
+            Uri trackUri = ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, currSong);
+            try {
+                player.setDataSource(getApplicationContext(), trackUri);
+            }
+            catch(Exception e) {
+                Tuils.log(e);
+                Tuils.toFile(e);
+                return null;
+            }
+        }
+        player.prepareAsync();
+
+        return playSong.getTitle();
+    }
+
+    public void setSong(int songIndex){
+        songPosn=songIndex;
+    }
+
+    @Override
+    public void onCompletion(MediaPlayer mp) {
+        if(player.getCurrentPosition()>0){
+            mp.reset();
+            playNext();
+        }
+    }
+
+    @Override
+    public boolean onError(MediaPlayer mp, int what, int extra) {
+        mp.reset();
+        return false;
+    }
+
+    @Override
+    public void onPrepared(MediaPlayer mp) {
+        mp.start();
+        startForeground(NOTIFY_ID, buildNotification(this.getApplicationContext(), songTitle));
+    }
+
+    public static Notification buildNotification(Context context, String songTitle) {
+        Intent notIntent = new Intent(context, LauncherActivity.class);
+        PendingIntent pendInt = PendingIntent.getActivity(context, 0, notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+        Notification not;
+        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
+        builder.setContentIntent(pendInt)
+                .setSmallIcon(R.mipmap.ic_launcher)
+                .setTicker(songTitle)
+                .setOngoing(true)
+                .setContentTitle("Playing")
+                .setContentText(songTitle);
+
+        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            String label = "cmd";
+            RemoteInput remoteInput = new RemoteInput.Builder(InputOutputReceiver.TEXT)
+                    .setLabel(label)
+                    .build();
+
+            Intent i = new Intent(InputOutputReceiver.ACTION_CMD);
+            i.putExtra(InputOutputReceiver.WAS_KEY, InputOutputReceiver.WAS_MUSIC_SERVICE);
+
+            NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, label,
+                    PendingIntent.getBroadcast(context.getApplicationContext(), 10, i, PendingIntent.FLAG_UPDATE_CURRENT))
+                    .addRemoteInput(remoteInput)
+                    .build();
+
+            builder.addAction(action);
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) not = builder.build();
+        else not = builder.getNotification();
+
+        return not;
+    }
+
+    public int getPosn(){
+        return player.getCurrentPosition();
+    }
+
+    public int getDur(){
+        return player.getDuration();
+    }
+
+    public boolean isPng(){
+        return player.isPlaying();
+    }
+
+    public void pausePlayer(){
+        player.pause();
+    }
+
+    public void stop() {
+        player.stop();
+        player.release();
+        setSong(0);
+    }
+
+    public void playPlayer() {
+        player.start();
+    }
+
+    public void seek(int posn){
+        player.seekTo(posn);
+    }
+
+    public void go(){
+        player.start();
+    }
+
+    public String playPrev(){
+        songPosn--;
+        if(songPosn<0) songPosn=songs.size()-1;
+        return playSong();
+    }
+
+    public String playNext(){
+        if(shuffle){
+            int newSong = songPosn;
+            while(newSong==songPosn){
+                newSong=rand.nextInt(songs.size());
+            }
+            songPosn=newSong;
+        }
+        else{
+            songPosn++;
+            if(songPosn>=songs.size()) songPosn=0;
+        }
+
+        return playSong();
+    }
+
+    public int getSongIndex() {
+        return songPosn;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopForeground(true);
+    }
+
+    public void setShuffle(boolean shuffle){
+        this.shuffle = shuffle;
+    }
+
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..27f64cd
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/music/Song.java
@@ -0,0 +1,41 @@
+package ohi.andre.consolelauncher.managers.music;
+
+import java.io.File;
+
+/**
+ * Created by francescoandreuzzi on 17/08/2017.
+ */
+
+public class Song {
+
+    private long id;
+    private String title, path;
+
+    public Song(long songID, String songTitle) {
+        id = songID;
+        title = songTitle;
+    }
+
+    public Song(File file) {
+        String name = file.getName();
+        int dot = name.lastIndexOf(".");
+        name = name.substring(0,dot);
+
+        this.title = name;
+        this.path = file.getAbsolutePath();
+        this.id = -1;
+    }
+
+    public long getID() {
+        return id;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public String getPath() {
+        return path;
+    }
+}
+
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/InputOutputReceiver.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/InputOutputReceiver.java
new file mode 100644
index 0000000..122374d
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/InputOutputReceiver.java
@@ -0,0 +1,64 @@
+package ohi.andre.consolelauncher.tuils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.NotificationManagerCompat;
+import android.support.v4.app.RemoteInput;
+
+import ohi.andre.consolelauncher.managers.SkinManager;
+import ohi.andre.consolelauncher.tuils.interfaces.CommandExecuter;
+import ohi.andre.consolelauncher.tuils.interfaces.Outputable;
+
+/**
+ * Created by francescoandreuzzi on 18/08/2017.
+ */
+
+public class InputOutputReceiver extends BroadcastReceiver {
+
+    public static final int WAS_MUSIC_SERVICE = 10;
+    public static final int WAS_KEEPER_SERVICE = 11;
+
+    public static final String WAS_KEY = "was";
+
+    public static final String ACTION_CMD = "ohi.andre.consolelauncher.action_cmd";
+    public static final String ACTION_OUTPUT = "ohi.andre.consolelauncher.action_output";
+    public static final String TEXT = "ohi.andre.consolelauncher.text";
+    public static final String COLOR = "ohi.andre.consolelauncher.color";
+
+    CommandExecuter executer;
+    Outputable outputable;
+
+    public InputOutputReceiver(CommandExecuter executer, Outputable outputable) {
+        this.executer = executer;
+        this.outputable = outputable;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
+        if(remoteInput == null || remoteInput.size() == 0) {
+            CharSequence text = intent.getCharSequenceExtra(TEXT);
+            if(text == null) text = intent.getStringExtra(TEXT);
+            if(text == null) return;
+
+            if(intent.getAction().equals(ACTION_CMD)) {
+                executer.exec(text.toString());
+            } else {
+                int color = intent.getIntExtra(COLOR, SkinManager.COLOR_NOT_SET);
+                outputable.onOutput(color, text);
+            }
+        } else {
+            String cmd = remoteInput.getString(TEXT);
+            executer.exec(cmd, true);
+
+            int was = intent.getIntExtra(WAS_KEY, 0);
+            if(was == WAS_KEEPER_SERVICE) {
+                NotificationManagerCompat.from(context).notify(KeeperService.ONGOING_NOTIFICATION_ID, KeeperService.buildNotification(context));
+            } else if(was == WAS_MUSIC_SERVICE) {
+//                do nothing
+            }
+        }
+    }
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/libsuperuser/ShellHolder.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/libsuperuser/ShellHolder.java
new file mode 100644
index 0000000..73cbbe9
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/libsuperuser/ShellHolder.java
@@ -0,0 +1,37 @@
+package ohi.andre.consolelauncher.tuils.libsuperuser;
+
+import android.os.Environment;
+
+import ohi.andre.consolelauncher.tuils.interfaces.Outputable;
+
+/**
+ * Created by francescoandreuzzi on 18/08/2017.
+ */
+
+public class ShellHolder {
+
+    private Outputable outputable;
+
+    public ShellHolder(Outputable outputable) {
+        this.outputable = outputable;
+    }
+
+    public Shell.Interactive build() {
+        Shell.Interactive interactive = new Shell.Builder()
+                .setOnSTDOUTLineListener(new StreamGobbler.OnLineListener() {
+                    @Override
+                    public void onLine(String line) {
+                        outputable.onOutput(line);
+                    }
+                })
+                .setOnSTDERRLineListener(new StreamGobbler.OnLineListener() {
+                    @Override
+                    public void onLine(String line) {
+                        outputable.onOutput(line);
+                    }
+                })
+                .open();
+        interactive.addCommand("cd " + Environment.getExternalStorageDirectory().getAbsolutePath());
+        return interactive;
+    }
+}
-- 
GitLab