Java tutorial
/* * 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.graphics.Color; 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.TextView; import org.json.JSONArray; import org.json.JSONObject; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; 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 Dashboard extends Fragment implements SwipeRefreshLayout.OnRefreshListener, RecyclerTouchListener.OnItemClickListener, RefreshTimer.OnTimeoutListener, ControllerTask.ControllerTaskListener { private DashboardCache mModuleCache; private JSONObject mServiceStatus; private static final List<DashboardEntry> mDashboardList = new ArrayList<>(); private RefreshTimer mTimer; private int mRefreshTimeout = 10; private SwipeRefreshLayout swipeRefresh; private DashboardEntryRecyclerAdapter mAdapter; private String mLastError; private TextView tvCritical; private TextView tvError; private TextView tvWarning; private HashMap<String, String> mModuleNames; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.dashboard, container, false); swipeRefresh = view.findViewById(R.id.swipeRefresh); swipeRefresh.setOnRefreshListener(this); tvCritical = view.findViewById(R.id.critical); tvError = view.findViewById(R.id.error); tvWarning = view.findViewById(R.id.warning); RecyclerView rvDashboard = view.findViewById(R.id.recyclerViewDashboard); rvDashboard.setLayoutManager(new LinearLayoutManager(getActivity())); rvDashboard.setItemAnimator(new DefaultItemAnimator()); rvDashboard.addItemDecoration(new RecyclerDivider(getActivity(), LinearLayoutManager.VERTICAL)); mAdapter = new DashboardEntryRecyclerAdapter(mDashboardList); rvDashboard.setAdapter(mAdapter); rvDashboard.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), this)); mModuleNames = new HashMap<String, String>() { { put("system", getString(R.string.System)); put("pf", getString(R.string.PacketFilter)); put("dhcpd", getString(R.string.DHCPServer)); put("named", getString(R.string.DNSServer)); put("openssh", getString(R.string.OpenSSH)); put("ftp-proxy", getString(R.string.FTPProxy)); put("httpd", getString(R.string.WebServer)); put("symon", getString(R.string.Symon)); put("symux", getString(R.string.Symux)); } }; if (cache.dashboard == null) { cache.dashboard = new DashboardCache(); } mModuleCache = cache.dashboard; return view; } @Override public void onPause() { super.onPause(); mModuleCache.mServiceStatus = mServiceStatus; // ATTENTION: It is very important to cancel the timer mTimer.cancel(); } @Override public void onResume() { super.onResume(); fragment = this; mServiceStatus = mModuleCache.mServiceStatus; if (mServiceStatus == null) { getStatus(); } else { updateStatus(); } // Schedule the timer here, not in onCreateView(), because mRefreshTimeout may be updated in getStatus() mTimer = new RefreshTimer((MainActivity) getActivity(), this); mTimer.start(mRefreshTimeout); } @Override public void onTimeout() { getStatus(); } @Override public void onItemClick(View view) { TextView tvModule = view.findViewById(R.id.module); TextView tvErrors = view.findViewById(R.id.errors); int lines = 10; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { if (tvModule.getMaxLines() != 1) { lines = 1; } } tvModule.setMaxLines(lines); tvErrors.setMaxLines(lines); } @Override public void executePreTask() { } @Override public void preExecute() { swipeRefresh.setRefreshing(true); } @Override public boolean executeTask() { try { String output = controller.execute("system", "GetServiceStatus"); JSONArray jsonArray = new JSONArray(output); mServiceStatus = new JSONObject(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); return false; } return true; } @Override public void postExecute(boolean result) { if (result) { updateStatus(); } else { showMessage(this, "Error: " + mLastError); } swipeRefresh.setRefreshing(false); } @Override public void executeOnCancelled() { swipeRefresh.setRefreshing(false); } private void getStatus() { ControllerTask.run(this, this); } private void updateStatus() { try { mDashboardList.clear(); int critical = 0; int error = 0; int warning = 0; Iterator<String> modules = mServiceStatus.keys(); while (modules.hasNext()) { String module = modules.next(); JSONObject jsonModuleStatus = mServiceStatus.getJSONObject(module); mDashboardList.add(DashboardEntry.newInstance(mModuleNames.get(module), jsonModuleStatus)); critical += jsonModuleStatus.getInt("Critical"); error += jsonModuleStatus.getInt("Error"); warning += jsonModuleStatus.getInt("Warning"); } tvCritical.setText("" + critical); tvError.setText("" + error); tvWarning.setText("" + warning); mAdapter.notifyDataSetChanged(); } catch (Exception e) { e.printStackTrace(); logger.warning("updateStatus exception: " + e.toString()); } } @Override public void onRefresh() { getStatus(); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.menuRefresh) { getStatus(); return true; } return super.onOptionsItemSelected(item); } } class DashboardEntry { String status; String errorStatus; String module; String errors; static DashboardEntry newInstance(String module, JSONObject jsonModuleStatus) { DashboardEntry dashboardEntry = new DashboardEntry(); try { dashboardEntry.module = module; dashboardEntry.status = jsonModuleStatus.getString("Status"); dashboardEntry.errorStatus = jsonModuleStatus.getString("ErrorStatus"); int critical = jsonModuleStatus.getInt("Critical"); int error = jsonModuleStatus.getInt("Error"); int warning = jsonModuleStatus.getInt("Warning"); String errors = ""; if (critical > 0) { errors += "Critical: " + critical; } if (error > 0) { if (critical > 0) { errors += ", "; } errors += "Error: " + error; } if (warning > 0) { if (critical > 0 || error > 0) { errors += ", "; } errors += "Warning: " + warning; } dashboardEntry.errors = errors; } catch (Exception e) { e.printStackTrace(); logger.warning("DashboardEntry newInstance exception= " + e.toString()); } return dashboardEntry; } } class DashboardEntryRecyclerAdapter extends RecyclerView.Adapter<DashboardEntryRecyclerAdapter.DashboardEntryViewHolder> { private final List<DashboardEntry> dashboardEntryList; class DashboardEntryViewHolder extends RecyclerView.ViewHolder { final TextView status; final TextView errorStatus; final TextView module; final TextView errors; DashboardEntryViewHolder(View view) { super(view); status = view.findViewById(R.id.status); errorStatus = view.findViewById(R.id.errorStatus); module = view.findViewById(R.id.module); errors = view.findViewById(R.id.errors); } } DashboardEntryRecyclerAdapter(List<DashboardEntry> list) { this.dashboardEntryList = list; } @Override public DashboardEntryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.dashboard_module_status, parent, false); return new DashboardEntryViewHolder(itemView); } @Override public void onBindViewHolder(DashboardEntryViewHolder holder, int position) { DashboardEntry dashboardEntry = dashboardEntryList.get(position); // Use position as id, so we know the dashboardEntry that the user clicks on holder.itemView.setId(position); holder.module.setText(dashboardEntry.module); holder.errors.setText(dashboardEntry.errors); int image; if (dashboardEntry.status.contains("R")) { image = R.mipmap.running; holder.status.setTextColor(Color.WHITE); } else { image = R.drawable.stopped; } holder.status.setBackgroundResource(image); holder.status.setText(dashboardEntry.status); if (dashboardEntry.errorStatus.contains("C")) { image = R.drawable.critical; } else if (dashboardEntry.errorStatus.contains("E")) { image = R.drawable.error; } else if (dashboardEntry.errorStatus.contains("W")) { image = R.mipmap.warning; } else { image = R.drawable.noerror; } holder.errorStatus.setBackgroundResource(image); holder.errorStatus.setText(dashboardEntry.errorStatus); } @Override public int getItemCount() { return dashboardEntryList.size(); } } class DashboardCache { JSONObject mServiceStatus; }