public abstract class BaseModule {
    @NonNull
    private Context mContext;
    private String mModuleId;

    public BaseModule(@NonNull Context context, @NonNull String moduleId) {
        mContext = context;
        mModuleId = moduleId;
    }

    @NonNull
    public Context getContext() {
        return mContext;
    }

    @NonNull
    protected String getModuleId() {
        return mModuleId;
    }

    @NonNull
    protected String getString(@StringRes int stringResId) {
        return mContext.getString(stringResId);
    }

    @NonNull
    public abstract String getName();

    @NonNull
    public abstract String getDescription();

    @NonNull
    public abstract HttpResponse handle(@NonNull HttpRequest request);
} public class Content extends ArrayList<ContentPart> {
    public String toHtml() {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < size(); i++) {
            stringBuilder.append(get(i).toHtml());
        }
        return stringBuilder.toString();
    }
} public class HeadingContentPart extends ContentPart {
    @IntRange(from = 1, to = 6)
    private int mImportance;
    @NonNull
    private final String mTitle;

    public HeadingContentPart(@IntRange(from = 1, to = 6) int importance, @NonNull String title) {
        super();
        mImportance = importance;
        mTitle = title;
    }

    @NonNull
    @Override
    public String toHtml() {
        return "<h" + mImportance + ">" + mTitle + "</h" + mImportance + ">";

    }
} public class Link extends ContentPart {
    private final String mUrl;
    private final String mLabel;

    public Link(String url, String label) {
        super();
        mUrl = url;
        mLabel = label;
    }

    public Link(String url, ContentPart contentPart) {
        this(url, contentPart.toHtml());
    }

    @Override
    public String toHtml() {
        return "<a href=\"" + mUrl + "\">" + mLabel + "</a>";
    }
} public class Page {
    private String mTitle;
    private Content mContent;
    private boolean mShowHomeButton = true;
    private LinksList mLinksList = new LinksList();

    public void setTitle(String title) {
        mTitle = title;
    }

    public Content getContent() {
        return mContent;
    }

    public void setContent(Content content) {
        mContent = content;
    }

    public void setSingleContentPart(ContentPart contentPart) {
        Content content = new Content();
        content.add(contentPart);
        setContent(content);
    }

    public String toHtml() {
        String result = "<html><title>" + mTitle + "</title></head><body>";
        if (mShowHomeButton) {
            mLinksList.add("/", "Back to modules list");
        }
        result += mLinksList.toHtml() + mContent.toHtml() + "</body></html>";
        return result;
    }

    public void showHomeButton(boolean show) {
        mShowHomeButton = show;
    }

    public void addNavigationLink(String url, String label) {
        mLinksList.add(url, label);
    }
} public class RawContentPart extends ContentPart {
    @NonNull
    private final String mContent;

    public RawContentPart(@Nullable String content) {
        super();
        mContent = content == null ? "null" : content;
    }

    @NonNull
    @Override
    public String toHtml() {
        return mContent;
    }
} public class Table extends ContentPart {

    @NonNull
    private Map<CellXY, ContentPart> mContent = new HashMap<>();
    private int mMaxX;
    private int mMaxY;

    public void add(int x, int y, @NonNull ContentPart part) {
        mMaxX = Math.max(mMaxX, x);
        mMaxY = Math.max(mMaxY, y);
        mContent.put(new CellXY(x, y), part);
    }

    @NonNull
    @Override
    public String toHtml() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("<table border=\"#777777\" cellspacing=\"0\" cellpadding=\"5\">");
        for (int y = 0; y < mMaxY + 1; y++) {
            stringBuilder.append("<tr align=\"center\">");
            for (int x = 0; x < mMaxX + 1; x++) {
                stringBuilder.append("<td>");
                ContentPart part = mContent.get(new CellXY(x, y));
                if (part != null) {
                    stringBuilder.append(part.toHtml());
                }
                stringBuilder.append("</td>");
            }
            stringBuilder.append("</tr>");
        }
        stringBuilder.append("</table>");
        return stringBuilder.toString();
    }

    private class CellXY {
        private final int x;
        private final int y;

        CellXY(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public boolean equals(@NonNull Object o) {
            if (this == o) return true;
            if (!(o instanceof CellXY)) return false;
            CellXY key = (CellXY) o;
            return x == key.x && y == key.y;
        }

        @Override
        public int hashCode() {
            int result = x;
            result = 31 * result + y;
            return result;
        }
    }
} public class HttpRequest {
    private Map<String, List<String>> mParameters;
    private Method mMethod;
    private String mUri;

    public HttpRequest(String uri, Method method, Map<String, List<String>> parameters) {
        mUri = uri;
        mMethod = method;
        mParameters = parameters;
    }

    public Map<String, List<String>> getParameters() {
        return mParameters;
    }

    public Method getMethod() {
        return mMethod;
    }

    public String getUri() {
        return mUri;
    }

    public enum Method {
        GET,
        POST
    }
} public class HttpResponse {

    private static final String CONTENT_TYPE_TEXT_HTML = "text/html";

    @NonNull
    private Status mStatus;
    @NonNull
    private String mContentType;
    @Nullable
    private String mContent;
    @Nullable
    private InputStream mStream;
    private long mContentLength;
    @NonNull
    Map<String, String> mHeaders = new HashMap<>();

    public HttpResponse(@NonNull String content) {
        mStatus = Status.OK;
        mContentType = CONTENT_TYPE_TEXT_HTML;
        mContent = content;
    }

    @SuppressWarnings("WeakerAccess")
    public HttpResponse(@NonNull String contentType, @NonNull InputStream stream, long contentLength) {
        mStatus = Status.OK;
        mContentType = contentType;
        mStream = stream;
        mContentLength = contentLength;
    }

    public HttpResponse(@NonNull String contentType, @NonNull InputStream stream) {
        this(contentType, stream, -1);
    }

    public HttpResponse(@NonNull Status status) {
        mStatus = status;
        mContentType = CONTENT_TYPE_TEXT_HTML;
    }

    @Nullable
    public String getContent() {
        return mContent;
    }

    @NonNull
    public String getContentType() {
        return mContentType;
    }

    @NonNull
    public Status getStatus() {
        return mStatus;
    }

    @Nullable
    public InputStream getStream() {
        return mStream;
    }

    public long getContentLength() {
        return mContentLength;
    }

    public void addHeader(@NonNull String name, @NonNull String value) {
        mHeaders.put(name, value);
    }

    @NonNull
    public Map<String, String> getHeaders() {
        return mHeaders;
    }

    public enum Status {
        OK(200, "OK"),
        BAD_REQUEST(400, "Bad request"),
        NOT_FOUND(404, "Not found"),
        INTERNAL_SERVER_ERROR(500, "Internal server error");

        private int mCode;
        private String mDescription;

        Status(int code, String description) {
            mCode = code;
            mDescription = description;
        }

        public int getCode() {
            return mCode;
        }

        public String getDescription() {
            return mDescription;
        }
    }
} public class CommonUtils {
    public static boolean isNumber(@Nullable String str) {
        return str == null || str.matches("-?\\d+");
    }

    @NonNull
    public static String trimFileExtension(@NonNull String fileName) {
        int dot = fileName.lastIndexOf(".");
        if (dot > 0) {
            return fileName.substring(0, dot);
        } else {
            return fileName;
        }
    }

    @Nullable
    public static Activity getCurrentActivity() {
        try {
            Class activityThreadClass = Class.forName("android.app.ActivityThread");
            Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
            Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
            activitiesField.setAccessible(true);

            Map<Object, Object> activities = (Map<Object, Object>) activitiesField.get(activityThread);
            if (activities == null)
                return null;

            for (Object activityRecord : activities.values()) {
                Class activityRecordClass = activityRecord.getClass();
                Field pausedField = activityRecordClass.getDeclaredField("paused");
                pausedField.setAccessible(true);
                if (!pausedField.getBoolean(activityRecord)) {
                    Field activityField = activityRecordClass.getDeclaredField("activity");
                    activityField.setAccessible(true);
                    Activity activity = (Activity) activityField.get(activityRecord);
                    return activity;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Nullable
    public static HttpResponse requestPermissions(@NonNull String ... permissions) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Activity activity = getCurrentActivity();
            if (activity != null && !checkSelfPermissions(activity, permissions)) {
                activity.requestPermissions(permissions, 0);
                return new HttpResponse(new ErrorPage("This module require additional permissions. Please allow it on your smartphone and reload this page.").toHtml());
            }
        }
        return null;
    }

    @TargetApi(Build.VERSION_CODES.M)
    private static boolean checkSelfPermissions(@NonNull Activity activity, @NonNull String[] permissions) {
        for (String permission : permissions) {
            if (activity.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }
} public class HttpUtils {
    @NonNull
    public static Map<String, String> getMapFromParameters(@Nullable Map<String, List<String>> parameters, @Nullable String name) {
        Map<String, String> result = new HashMap<>();
        if (parameters != null && name != null) {
            for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
                if (entry.getKey().startsWith(name + "[")) {
                    result.put(entry.getKey().substring(name.length() + 1, entry.getKey().length() - 1), entry.getValue().get(0));
                }
            }
        }
        return result;
    }

    @NonNull
    public static List<String> getListFromParameters(@Nullable Map<String, List<String>> parameters, @Nullable String name) {
        if (parameters != null && name != null) {
            List<String> values = parameters.get(name + "[]");
            if (values != null) {
                return values;
            }
        }
        return new ArrayList<>();
    }

    @Nullable
    public static String getParameterValue(@Nullable Map<String, List<String>> parameters, @Nullable String key) {
        if (parameters != null && key != null && parameters.get(key) != null) {
            return parameters.get(key).get(0);
        }
        return null;
    }

    @NonNull
    public static String getQueryStringFromArray(@NonNull String paramName, @Nullable String[] array, boolean startWithAmp) {
        if (array != null && array.length > 0) {
            return (startWithAmp ? "&" : "?") +
                    paramName + "[]=" +
                    TextUtils.join("&" + paramName + "[]=", array);
        }
        return "";
    }
}
import android.content.Context;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.webkit.MimeTypeMap;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;
import ru.bartwell.ultradebugger.base.BaseModule;
import ru.bartwell.ultradebugger.base.html.Content;
import ru.bartwell.ultradebugger.base.html.HeadingContentPart;
import ru.bartwell.ultradebugger.base.html.Link;
import ru.bartwell.ultradebugger.base.html.Page;
import ru.bartwell.ultradebugger.base.html.RawContentPart;
import ru.bartwell.ultradebugger.base.html.Table;
import ru.bartwell.ultradebugger.base.model.HttpRequest;
import ru.bartwell.ultradebugger.base.model.HttpResponse;
import ru.bartwell.ultradebugger.base.utils.CommonUtils;
import ru.bartwell.ultradebugger.base.utils.HttpUtils;
package ru.bartwell.ultradebugger.module.files;




/**
 * Created by BArtWell on 24.02.2017.
 */

public class Module extends BaseModule {
    private static final String SIZE_UNITS = "kMGTPE";
    private static final int SIZE_DIVISOR = 1024;
    private static final String PERMISSION_READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
    private static final String PERMISSION_WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";
    private static final String PARAMETER_PATH = "path";
    private static final String PARAMETER_REMOVE = "remove";
    private static final String PATH_PART_DOWNLOAD_FILE = "download";

    public Module(@NonNull Context context, @NonNull String moduleId) {
        super(context, moduleId);
    }

    @NonNull
    @Override
    public String getName() {
        return getString(R.string.files_name);
    }

    @NonNull
    @Override
    public String getDescription() {
        return getString(R.string.files_description);
    }

    @NonNull
    @Override
    public HttpResponse handle(@NonNull HttpRequest request) {