/* * This source is part of the * _____ ___ ____ * __ / / _ \/ _ | / __/___ _______ _ * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / * /___/ * repository. * * Copyright (C) 2015-2017 Carmen Alvarez (c@rmen.ca) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ca.rmen.android.networkmonitor.app.dbops.backend.export; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.text.TextUtils; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import ca.rmen.android.networkmonitor.Constants; import ca.rmen.android.networkmonitor.R; import ca.rmen.android.networkmonitor.app.dbops.ProgressListener; import ca.rmen.android.networkmonitor.app.dbops.ui.Share; import ca.rmen.android.networkmonitor.app.prefs.FilterPreferences; import ca.rmen.android.networkmonitor.app.prefs.NetMonPreferences; import ca.rmen.android.networkmonitor.provider.NetMonColumns; import ca.rmen.android.networkmonitor.provider.UniqueValuesColumns; import ca.rmen.android.networkmonitor.util.IoUtil; import ca.rmen.android.networkmonitor.util.Log; /** * Export the Network Monitor data to a gnuplot file. */ public class GnuplotExport extends FileExport { private static final String TAG = Constants.TAG + GnuplotExport.class.getSimpleName(); private static final String GNUPLOT_FILE = "networkmonitor.gnuplot"; private final String mSeriesField; private final String mYAxisField; private final FilterPreferences.Selection mSelection; private PrintWriter mPrintWriter; private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); public GnuplotExport(Context context) { super(context, Share.getExportFile(context, GNUPLOT_FILE)); NetMonPreferences prefs = NetMonPreferences.getInstance(mContext); mSeriesField = prefs.getExportGnuplotSeriesField(); mYAxisField = prefs.getExportGnuplotYAxisField(); // Get a WHERE clause based on non-null values of the series and y-axis fields, as well // as whatever fields the user chose to filter on, in the FilterColumnActivity. FilterPreferences.Selection filterSelection = FilterPreferences.getSelectionClause(mContext); String seriesAndYAxisSelection = String.format("%s NOT NULL AND %s NOT NULL", mSeriesField, mYAxisField); if (TextUtils.isEmpty(filterSelection.selectionString)) { mSelection = new FilterPreferences.Selection(seriesAndYAxisSelection, null); } else { mSelection = new FilterPreferences.Selection(seriesAndYAxisSelection + " AND " + filterSelection.selectionString, filterSelection.selectionArgs); } } @Override public void execute(ProgressListener listener) { try { mPrintWriter = new PrintWriter(mFile, "utf-8"); String[] projection = new String[]{NetMonColumns.TIMESTAMP, mSeriesField, mYAxisField}; String orderBy = String.format("%s ASC, %s ASC", mSeriesField, NetMonColumns.TIMESTAMP); Cursor c = mContext.getContentResolver().query(NetMonColumns.CONTENT_URI, projection, mSelection.selectionString, mSelection.selectionArgs, orderBy); if (c != null) { if (c.getCount() < 1) { // We have no data to export. Give up. if (listener != null) listener.onError(mContext.getString(R.string.export_notif_error_content)); } else { try { // Write the stuff to the gnuplot script that comes before the actual data // (graph title, axis titles, styles, etc). printGraphConfig(); printSeriesDefinitions(); // Write the actual data. int timestampIndex = c.getColumnIndex(NetMonColumns.TIMESTAMP); int seriesIndex = c.getColumnIndex(mSeriesField); int yAxisIndex = c.getColumnIndex(mYAxisField); String currentSeriesValue = null; while (c.moveToNext() && !isCanceled()) { String seriesValue = c.getString(seriesIndex); double yAxisValue = c.getDouble(yAxisIndex); Date timestamp = new Date(c.getLong(timestampIndex)); mPrintWriter.println(String.format("%s|%s", mDateFormat.format(timestamp), yAxisValue)); // A line with a single "e" in gnuplot signals the end of the data // for the current series. if (c.isLast() || (currentSeriesValue != null && !seriesValue.equals(currentSeriesValue))) { mPrintWriter.println("e"); } if (listener != null) { listener.onProgress(c.getPosition(), c.getCount()); } currentSeriesValue = seriesValue; } } finally { c.close(); } if (listener != null) { if (isCanceled()) { listener.onComplete(mContext.getString(R.string.export_notif_canceled_content)); } else { listener.onComplete(mContext.getString(R.string.export_save_to_external_storage_success, mFile.getAbsolutePath())); } } } } } catch (FileNotFoundException | UnsupportedEncodingException e) { Log.v(TAG, "error exporting gnuplot file: " + e.getMessage(), e); if (listener != null) listener.onError(mContext.getString(R.string.export_notif_error_content)); } IoUtil.closeSilently(mPrintWriter); } /** * Write the first part of the gnuplot script (ex: configuring the chart style) */ private void printGraphConfig() { // Get the first and last dates for the xrange String[] projection = new String[]{ String.format("MIN(%s)", NetMonColumns.TIMESTAMP), String.format("MAX(%s)", NetMonColumns.TIMESTAMP), }; Cursor c = mContext.getContentResolver().query(NetMonColumns.CONTENT_URI, projection, mSelection.selectionString, mSelection.selectionArgs, NetMonColumns.TIMESTAMP + " ASC"); if (c != null) { try { if (c.moveToNext()) { long beginDate = c.getLong(0); long endDate = c.getLong(1); mPrintWriter.println( mContext.getString(R.string.gnuplot_script, NetMonColumns.getColumnLabel(mContext, mYAxisField), NetMonColumns.getColumnLabel(mContext, mSeriesField), mDateFormat.format(new Date(beginDate)), mDateFormat.format(new Date(endDate)) )); } } finally { c.close(); } } } /** * Write a line to the gnuplot script for each series (includes the series name, and style * of the series). */ private void printSeriesDefinitions() { String[] projection = new String[]{UniqueValuesColumns.VALUE}; Uri uri = Uri.withAppendedPath(UniqueValuesColumns.CONTENT_URI, mSeriesField); Cursor c = mContext.getContentResolver().query(uri, projection, mSelection.selectionString, mSelection.selectionArgs, mSeriesField + " ASC"); if (c != null) { try { while (c.moveToNext()) { String seriesName = c.getString(0); seriesName = seriesName.replaceAll("_", "\\\\_"); seriesName = seriesName.replaceAll("&", "\\\\&"); if (TextUtils.isEmpty(seriesName)) seriesName = "?"; mPrintWriter.print(mContext.getString(R.string.gnuplot_series, seriesName)); if (c.isLast()) { mPrintWriter.println(); } else { mPrintWriter.println(", \\"); } } } finally { c.close(); } } } }