org.comixwall.pffw.InfoSystem.java Source code

Java tutorial

Introduction

Here is the source code for org.comixwall.pffw.InfoSystem.java

Source

/*
 * Copyright (C) 2017-2018 Soner Tari
 *
 * This file is part of PFFW.
 *
 * PFFW 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 3 of the License, or
 * (at your option) any later version.
 *
 * PFFW 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 PFFW.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.comixwall.pffw;

import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import org.json.JSONArray;

import java.util.ArrayList;
import java.util.List;

import static org.comixwall.pffw.MainActivity.cache;
import static org.comixwall.pffw.MainActivity.controller;
import static org.comixwall.pffw.MainActivity.fragment;
import static org.comixwall.pffw.MainActivity.logger;
import static org.comixwall.pffw.Utils.processException;
import static org.comixwall.pffw.Utils.showMessage;

public class InfoSystem extends Fragment
        implements SwipeRefreshLayout.OnRefreshListener, RefreshTimer.OnTimeoutListener,
        RecyclerTouchListener.OnItemClickListener, ControllerTask.ControllerTaskListener {

    private InfoSystemCache mModuleCache;

    private RefreshTimer mTimer;
    private int mRefreshTimeout = 10;

    private SwipeRefreshLayout swipeRefresh;

    private String mSymonStatus;
    private String mSymuxStatus;

    private TextView tvSymonStatus;
    private TextView tvSymuxStatus;

    private ImageView ivSymonStatus;
    private ImageView ivSymuxStatus;

    private JSONArray mSymonJsonArray;
    private final List<Process> mSymonList = new ArrayList<>();
    private ProcessRecyclerAdapter mSymonAdapter;

    private JSONArray mSymuxJsonArray;
    private final List<Process> mSymuxList = new ArrayList<>();
    private ProcessRecyclerAdapter mSymuxAdapter;

    private JSONArray mSystemJsonArray;
    private final List<Process> mSystemList = new ArrayList<>();
    private ProcessRecyclerAdapter mSystemAdapter;

    private String mLastError;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.info_system, container, false);

        swipeRefresh = view.findViewById(R.id.swipeRefresh);
        swipeRefresh.setOnRefreshListener(this);

        tvSymonStatus = view.findViewById(R.id.symonStatus);
        tvSymuxStatus = view.findViewById(R.id.symuxStatus);

        ivSymonStatus = view.findViewById(R.id.imageViewSymonStatus);
        ivSymuxStatus = view.findViewById(R.id.imageViewSymuxStatus);

        RecyclerView rvSymon = view.findViewById(R.id.recyclerViewSymon);
        rvSymon.setLayoutManager(new LinearLayoutManager(getActivity()));
        rvSymon.setItemAnimator(new DefaultItemAnimator());
        rvSymon.addItemDecoration(new RecyclerDivider(getActivity(), LinearLayoutManager.VERTICAL));
        mSymonAdapter = new ProcessRecyclerAdapter(mSymonList);
        rvSymon.setAdapter(mSymonAdapter);
        rvSymon.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), this));

        RecyclerView rvSymux = view.findViewById(R.id.recyclerViewSymux);
        rvSymux.setLayoutManager(new LinearLayoutManager(getActivity()));
        rvSymux.setItemAnimator(new DefaultItemAnimator());
        rvSymux.addItemDecoration(new RecyclerDivider(getActivity(), LinearLayoutManager.VERTICAL));
        mSymuxAdapter = new ProcessRecyclerAdapter(mSymuxList);
        rvSymux.setAdapter(mSymuxAdapter);
        rvSymux.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), this));

        RecyclerView rvSystem = view.findViewById(R.id.recyclerViewSystem);
        rvSystem.setLayoutManager(new LinearLayoutManager(getActivity()));
        rvSystem.setItemAnimator(new DefaultItemAnimator());
        rvSystem.addItemDecoration(new RecyclerDivider(getActivity(), LinearLayoutManager.VERTICAL));
        mSystemAdapter = new ProcessRecyclerAdapter(mSystemList);
        rvSystem.setAdapter(mSystemAdapter);
        rvSystem.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), this));

        if (cache.infoSystem == null) {
            cache.infoSystem = new InfoSystemCache();
        }
        mModuleCache = cache.infoSystem;

        return view;
    }

    @Override
    public void onPause() {
        super.onPause();

        mModuleCache.bundle.putString("mSymonStatus", mSymonStatus);
        mModuleCache.bundle.putString("mSymuxStatus", mSymuxStatus);

        mModuleCache.mSymonJsonArray = mSymonJsonArray;
        mModuleCache.mSymuxJsonArray = mSymuxJsonArray;
        mModuleCache.mSystemJsonArray = mSystemJsonArray;

        // ATTENTION: It is very important to cancel the timer
        mTimer.cancel();
    }

    @Override
    public void onResume() {
        super.onResume();

        fragment = this;
        mSymonStatus = mModuleCache.bundle.getString("mSymonStatus");

        if (mSymonStatus == null) {
            getInfo();
        } else {
            mSymuxStatus = mModuleCache.bundle.getString("mSymuxStatus");

            mSymonJsonArray = mModuleCache.mSymonJsonArray;
            mSymuxJsonArray = mModuleCache.mSymuxJsonArray;
            mSystemJsonArray = mModuleCache.mSystemJsonArray;

            updateInfo();
        }

        mTimer = new RefreshTimer((MainActivity) getActivity(), this);
        mTimer.start(mRefreshTimeout);
    }

    @Override
    public void onTimeout() {
        getInfo();
    }

    @Override
    public void executePreTask() {
    }

    @Override
    public void preExecute() {
        swipeRefresh.setRefreshing(true);
    }

    @Override
    public boolean executeTask() {
        Boolean retval = true;
        try {
            String output = controller.execute("symon", "IsRunning");

            mSymonStatus = new JSONArray(output).get(2).toString();

            output = controller.execute("symon", "GetProcList");

            JSONArray jsonArray = new JSONArray(output);
            mSymonJsonArray = new JSONArray(jsonArray.get(0).toString());

            output = controller.execute("symux", "IsRunning");

            mSymuxStatus = new JSONArray(output).get(2).toString();

            output = controller.execute("symux", "GetProcList");

            jsonArray = new JSONArray(output);
            mSymuxJsonArray = new JSONArray(jsonArray.get(0).toString());

            output = controller.execute("system", "GetProcList");

            jsonArray = new JSONArray(output);
            mSystemJsonArray = new JSONArray(jsonArray.get(0).toString());

            output = controller.execute("pf", "GetReloadRate");

            int timeout = Integer.parseInt(new JSONArray(output).get(0).toString());
            mRefreshTimeout = timeout < 10 ? 10 : timeout;

        } catch (Exception e) {
            mLastError = processException(e);
            retval = false;
        }
        return retval;
    }

    @Override
    public void postExecute(boolean result) {
        if (result) {
            updateInfo();
        } else {
            showMessage(this, "Error: " + mLastError);
        }

        swipeRefresh.setRefreshing(false);
    }

    @Override
    public void executeOnCancelled() {
        swipeRefresh.setRefreshing(false);
    }

    private void getInfo() {
        ControllerTask.run(this, this);
    }

    private void updateInfo() {

        Utils.updateStatusViews(mSymonStatus, ivSymonStatus, tvSymonStatus, "Symon");

        updateProcList(mSymonJsonArray, mSymonList);
        mSymonAdapter.notifyDataSetChanged();

        Utils.updateStatusViews(mSymuxStatus, ivSymuxStatus, tvSymuxStatus, "Symux");

        updateProcList(mSymuxJsonArray, mSymuxList);
        mSymuxAdapter.notifyDataSetChanged();

        updateProcList(mSystemJsonArray, mSystemList);
        mSystemAdapter.notifyDataSetChanged();
    }

    private void updateProcList(JSONArray jsonArray, List<Process> list) {
        try {
            list.clear();

            int i = 0;
            while (i < jsonArray.length()) {
                list.add(Process.newInstance(jsonArray.getJSONArray(i++)));
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.warning("updateProcList exception: " + e.toString());
        }
    }

    @Override
    public void onRefresh() {
        getInfo();
    }

    @Override
    public void onItemClick(View view) {
        TextView tvCommand = view.findViewById(R.id.command);
        TextView tvOthers = view.findViewById(R.id.others);

        int lines = 10;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            if (tvCommand.getMaxLines() != 1) {
                lines = 1;
            }
        }

        tvCommand.setMaxLines(lines);
        tvOthers.setMaxLines(lines);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.menuRefresh) {
            getInfo();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

class Process {
    String pid;
    String started;
    String cpu;
    public String time;
    String mem;
    String rss;
    String vsz;
    String stat;
    String pri;
    String ni;
    String user;
    String group;
    String command;

    static Process newInstance(JSONArray procLine) {
        Process proc = new Process();
        try {
            proc.pid = procLine.getString(0);
            proc.started = procLine.getString(1);
            proc.cpu = procLine.getString(2);
            proc.time = procLine.getString(3);
            proc.mem = procLine.getString(4);
            proc.rss = procLine.getString(5);
            proc.vsz = procLine.getString(6);
            proc.stat = procLine.getString(7);
            proc.pri = procLine.getString(8);
            proc.ni = procLine.getString(9);
            proc.user = procLine.getString(10);
            proc.group = procLine.getString(11);
            proc.command = procLine.getString(12);
        } catch (Exception e) {
            e.printStackTrace();
            logger.warning("Process newInstance exception: " + e.toString());
        }
        return proc;
    }
}

class ProcessRecyclerAdapter extends RecyclerView.Adapter<ProcessRecyclerAdapter.ProcessViewHolder> {

    private final List<Process> procsList;

    class ProcessViewHolder extends RecyclerView.ViewHolder {
        final TextView cpuMemTime;
        final TextView command;
        final TextView pid;
        final TextView others;
        final TextView started;
        final TextView image;

        ProcessViewHolder(View view) {
            super(view);
            cpuMemTime = view.findViewById(R.id.cpuMemTime);
            command = view.findViewById(R.id.command);
            pid = view.findViewById(R.id.pid);
            others = view.findViewById(R.id.others);
            started = view.findViewById(R.id.started);
            image = view.findViewById(R.id.image);
        }
    }

    ProcessRecyclerAdapter(List<Process> list) {
        this.procsList = list;
    }

    @Override
    public ProcessViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.process, parent, false);

        return new ProcessViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(ProcessViewHolder holder, int position) {

        Process proc = procsList.get(position);

        holder.cpuMemTime.setText(String.format(holder.cpuMemTime.getResources().getString(R.string.cpu_mem_time),
                proc.cpu, proc.mem, proc.time));
        holder.command.setText(proc.command);
        holder.pid.setText(proc.pid);
        holder.others.setText("rss: " + proc.rss + ", vsz: " + proc.vsz + ", " + proc.user + ":" + proc.group
                + ", stat: " + proc.stat + ", pri: " + proc.pri + ", ni: " + proc.ni);
        holder.started.setText(proc.started);

        int pri = Integer.parseInt(proc.pri);

        int image;
        String caption;

        if (pri > 20) {
            image = R.drawable.block;
            caption = "H";
        } else if (pri > 10) {
            image = R.drawable.pass;
            caption = "M";
        } else {
            image = R.drawable.match;
            caption = "L";
        }

        holder.image.setBackgroundResource(image);
        holder.image.setText(caption);
    }

    @Override
    public int getItemCount() {
        return procsList.size();
    }
}

class InfoSystemCache {
    public final Bundle bundle = new Bundle();

    JSONArray mSymonJsonArray;
    JSONArray mSymuxJsonArray;
    JSONArray mSystemJsonArray;
}