Search in sources :

Example 1 with SortPreferences

use of ca.rmen.android.networkmonitor.app.prefs.SortPreferences in project network-monitor by caarmen.

the class LogActivity method loadHTMLFile.

/**
 * Read the data from the DB, export it to an HTML file, and load the HTML file in the WebView.
 */
// only loading local files, it's ok.
@SuppressLint("SetJavaScriptEnabled")
private void loadHTMLFile() {
    Log.v(TAG, "loadHTMLFile");
    final ProgressBar progressBar = findViewById(R.id.progress_bar);
    assert progressBar != null;
    progressBar.setVisibility(View.VISIBLE);
    startRefreshIconAnimation();
    final boolean freezeHeader = NetMonPreferences.getInstance(this).getFreezeHtmlTableHeader();
    final String fixedTableHeight;
    if (freezeHeader) {
        // I've come to the following calculation by trial and error.
        // I've noticed that when entering the web view, the density is equal to the scale/zoom, but I'm
        // not sure if it's the density or zoom which really matters in this calculation.
        // We subtract 100px from the scaled webview height to account for the table header.
        fixedTableHeight = ((mWebView.getHeight() / getResources().getDisplayMetrics().density) - 100) + "px";
    } else {
        fixedTableHeight = null;
    }
    AsyncTask.execute(() -> {
        Log.v(TAG, "loadHTMLFile:doInBackground");
        // Export the DB to the HTML file.
        HTMLExport htmlExport = new HTMLExport(LogActivity.this, false, fixedTableHeight);
        int recordCount = NetMonPreferences.getInstance(LogActivity.this).getFilterRecordCount();
        File result = htmlExport.export(recordCount, null);
        runOnUiThread(() -> {
            Log.v(TAG, "loadHTMLFile:onPostExecute, result=" + result);
            if (isFinishing()) {
                Log.v(TAG, "finishing, ignoring loadHTMLFile result");
                return;
            }
            WebView webView = mWebView;
            if (webView == null) {
                Log.v(TAG, "Must be destroyed or destroying, we have no webview, ignoring loadHTMLFile result");
                return;
            }
            if (result == null) {
                Snackbar.make(webView, R.string.error_reading_log, Snackbar.LENGTH_LONG).show();
                return;
            }
            // Load the exported HTML file into the WebView.
            // Save our current horizontal scroll position so we can keep our
            // horizontal position after reloading the page.
            final int oldScrollX = webView.getScrollX();
            webView.getSettings().setUseWideViewPort(true);
            webView.getSettings().setBuiltInZoomControls(true);
            webView.getSettings().setJavaScriptEnabled(true);
            webView.loadUrl("file://" + result.getAbsolutePath());
            webView.setWebViewClient(new WebViewClient() {

                @Override
                public void onPageStarted(WebView view, String url, Bitmap favicon) {
                    super.onPageStarted(view, url, favicon);
                    Log.v(TAG, "onPageStarted");
                    // http://stackoverflow.com/questions/6855715/maintain-webview-content-scroll-position-on-orientation-change
                    if (oldScrollX > 0) {
                        String jsScrollX = "javascript:window:scrollTo(" + oldScrollX + " / window.devicePixelRatio,0);";
                        view.loadUrl(jsScrollX);
                    }
                }

                @Override
                public void onPageFinished(WebView view, String url) {
                    super.onPageFinished(view, url);
                    progressBar.setVisibility(View.GONE);
                    stopRefreshIconAnimation();
                }

                @Override
                @TargetApi(Build.VERSION_CODES.N)
                public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                    return loadUrl(request.getUrl().toString()) || super.shouldOverrideUrlLoading(view, request);
                }

                @SuppressWarnings("deprecation")
                @Override
                public boolean shouldOverrideUrlLoading(WebView view, String url) {
                    return loadUrl(url) || super.shouldOverrideUrlLoading(view, url);
                }

                private boolean loadUrl(String url) {
                    Log.v(TAG, "url: " + url);
                    // the sorting preference (column name, ascending or descending order).
                    if (url.startsWith(HTMLExport.URL_SORT)) {
                        NetMonPreferences prefs = NetMonPreferences.getInstance(LogActivity.this);
                        SortPreferences oldSortPreferences = prefs.getSortPreferences();
                        // The new column used for sorting will be the one the user tapped on.
                        String newSortColumnName = url.substring(HTMLExport.URL_SORT.length());
                        SortPreferences.SortOrder newSortOrder = oldSortPreferences.sortOrder;
                        // toggle the sort order between ascending and descending.
                        if (newSortColumnName.equals(oldSortPreferences.sortColumnName)) {
                            if (oldSortPreferences.sortOrder == SortPreferences.SortOrder.DESC)
                                newSortOrder = SortPreferences.SortOrder.ASC;
                            else
                                newSortOrder = SortPreferences.SortOrder.DESC;
                        }
                        // Update the sorting preferences (our shared preference change listener will be notified
                        // and reload the page).
                        prefs.setSortPreferences(new SortPreferences(newSortColumnName, newSortOrder));
                        return true;
                    } else // If the user clicked on the filter icon, start the filter activity for this column.
                    if (url.startsWith(HTMLExport.URL_FILTER)) {
                        Intent intent = new Intent(LogActivity.this, FilterColumnActivity.class);
                        String columnName = url.substring(HTMLExport.URL_FILTER.length());
                        intent.putExtra(FilterColumnActivity.EXTRA_COLUMN_NAME, columnName);
                        startActivityForResult(intent, REQUEST_CODE_FILTER_COLUMN);
                        return true;
                    } else {
                        return false;
                    }
                }
            });
        });
    });
}
Also used : HTMLExport(ca.rmen.android.networkmonitor.app.dbops.backend.export.HTMLExport) WebResourceRequest(android.webkit.WebResourceRequest) Intent(android.content.Intent) SuppressLint(android.annotation.SuppressLint) NetMonPreferences(ca.rmen.android.networkmonitor.app.prefs.NetMonPreferences) SortPreferences(ca.rmen.android.networkmonitor.app.prefs.SortPreferences) Bitmap(android.graphics.Bitmap) WebView(android.webkit.WebView) ProgressBar(android.widget.ProgressBar) File(java.io.File) TargetApi(android.annotation.TargetApi) WebViewClient(android.webkit.WebViewClient) SuppressLint(android.annotation.SuppressLint)

Example 2 with SortPreferences

use of ca.rmen.android.networkmonitor.app.prefs.SortPreferences in project network-monitor by caarmen.

the class HTMLExport method writeHeader.

@Override
void writeHeader(String[] columnLabels) {
    try {
        mPrintWriter = new PrintWriter(mFile, "utf-8");
    } catch (FileNotFoundException | UnsupportedEncodingException e) {
        Log.e(TAG, "writeHeader Could not initialize print writer", e);
        return;
    }
    mPrintWriter.println("<!DOCTYPE html>");
    mPrintWriter.println("<html>");
    mPrintWriter.println("  <head>");
    mPrintWriter.println("    <title>" + mContext.getString(R.string.app_name) + "</title>");
    String columnCss = mContext.getString(R.string.css_template, getColumnCss());
    mPrintWriter.println(mContext.getString(R.string.css));
    mPrintWriter.println(mContext.getString(R.string.css_api_level_custom));
    mPrintWriter.println(mContext.getString(R.string.css_themed));
    mPrintWriter.println(columnCss);
    if (mFixedTableHeight != null) {
        String fixedHeaderCss = mContext.getString(R.string.fixed_header_css, mFixedTableHeight);
        mPrintWriter.println(fixedHeaderCss);
    }
    mPrintWriter.println("  </head><body>");
    mPrintWriter.println("<table class='main-table'>");
    mPrintWriter.println(getColgroup(columnLabels.length));
    mPrintWriter.println("  <thead><tr>");
    SortPreferences sortPreferences = NetMonPreferences.getInstance(mContext).getSortPreferences();
    mPrintWriter.println("    <th></th>");
    for (String columnLabel : columnLabels) {
        String dbColumnName = NetMonColumns.getColumnName(mContext, columnLabel);
        if (dbColumnName != null) {
            String labelClass = "column_heading";
            // Indicate if this is the sorting column: specify a particular css style
            // for the label, and show an up or down arrow depending on if we're
            // sorting ascending or descending.
            String sortIconCharacter = "";
            if (dbColumnName.equals(sortPreferences.sortColumnName)) {
                labelClass += " sort_column";
                if (sortPreferences.sortOrder == SortOrder.DESC)
                    sortIconCharacter = mContext.getString(R.string.icon_sort_desc);
                else
                    sortIconCharacter = mContext.getString(R.string.icon_sort_asc);
            }
            // Indicate if this is a filtered column: specify a particular css style
            // for the label, and show the filter on or off icon.
            boolean isFilterable = NetMonColumns.isColumnFilterable(mContext, dbColumnName);
            String filterIconClass = "filter_icon";
            String filterIconCharacter = isFilterable ? mContext.getString(R.string.icon_filter_off) : "";
            if (isFilterable) {
                List<String> columnFilterValues = NetMonPreferences.getInstance(mContext).getColumnFilterValues(dbColumnName);
                if (columnFilterValues != null && columnFilterValues.size() > 0) {
                    labelClass += " filtered_column_label";
                    filterIconCharacter = mContext.getString(R.string.icon_filter_on);
                }
            }
            // One cell for the sort icon and column label.
            String sort = sortIconCharacter + "<a class=\"" + labelClass + "\" href=\"" + URL_SORT + dbColumnName + "\">" + columnLabel + "</a>";
            // One cell for the filter icon.
            String filter = "<a class=\"" + filterIconClass + "\" href=\"" + URL_FILTER + dbColumnName + "\">" + filterIconCharacter + "</a>";
            // Write out the table cell for this column header.
            mPrintWriter.println("    <th>" + sort + filter + "</th>");
        } else {
            mPrintWriter.println("    <th></th>");
        }
    }
    mPrintWriter.println("  </tr></thead><tbody>");
    mPrintWriter.println("  <tr>");
    // container-container?  :( Wish I could do this more cleanly/simply.
    mPrintWriter.println("    <td class='table-data-container-container' colspan='" + (columnLabels.length + 1) + "'>");
    mPrintWriter.println("      <div class='table-data-container'>");
    mPrintWriter.println("        <table class='table-data'>");
    mPrintWriter.println(getColgroup(columnLabels.length));
}
Also used : SortPreferences(ca.rmen.android.networkmonitor.app.prefs.SortPreferences) FileNotFoundException(java.io.FileNotFoundException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) PrintWriter(java.io.PrintWriter)

Example 3 with SortPreferences

use of ca.rmen.android.networkmonitor.app.prefs.SortPreferences in project network-monitor by caarmen.

the class TableFileExport method export.

/**
 * @param recordCount export at most this number of records. If recordCount is 0 or less, all records will be exported.
 * @return the file if it was correctly exported, null otherwise.
 */
public File export(int recordCount, ProgressListener listener) {
    Log.v(TAG, "export " + (recordCount <= 0 ? "all" : recordCount) + " records");
    String[] usedColumnNames = (String[]) NetMonPreferences.getInstance(mContext).getSelectedColumns().toArray();
    Formatter formatter = FormatterFactory.getFormatter(mFormatterStyle, mContext);
    // Order and filter the results based on the user's preferences.
    SortPreferences sortPreferences = NetMonPreferences.getInstance(mContext).getSortPreferences();
    Selection selection = FilterPreferences.getSelectionClause(mContext);
    Uri uri = NetMonColumns.CONTENT_URI;
    if (recordCount > 0)
        uri = uri.buildUpon().appendQueryParameter(NetMonProvider.QUERY_PARAMETER_LIMIT, String.valueOf(recordCount)).build();
    Cursor c = mContext.getContentResolver().query(uri, usedColumnNames, selection.selectionString, selection.selectionArgs, sortPreferences.getOrderByClause());
    if (c != null) {
        try {
            for (int i = 0; i < usedColumnNames.length; i++) usedColumnNames[i] = NetMonColumns.getColumnLabel(mContext, usedColumnNames[i]);
            Log.v(TAG, "Column names: " + Arrays.toString(usedColumnNames));
            // Write the table rows to the file.
            int rowsAvailable = c.getCount();
            // Start writing to the file.
            writeHeader(usedColumnNames);
            while (c.moveToNext() && !isCanceled()) {
                String[] cellValues = new String[c.getColumnCount()];
                for (int i = 0; i < c.getColumnCount(); i++) cellValues[i] = formatter.format(c, i);
                writeRow(c.getPosition(), cellValues);
                // Notify the listener of our progress (progress is 1-based)
                if (listener != null)
                    listener.onProgress(c.getPosition() + 1, rowsAvailable);
                // Some file exports need to create the whole file in memory
                // before saving it. (This is currently the case with
                // the Excel export, whether we use jexcelapi or poi).
                // On some devices, with large exports, we may not
                // have enough memory to export the whole file.
                // Here we detect a low memory situation, and stop
                // creating rows.
                long maxMemory = Runtime.getRuntime().maxMemory();
                long allocatedMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
                long pctFreeMemory = ((maxMemory - allocatedMemory) * 100) / maxMemory;
                if (c.getPosition() % 100 == 0) {
                    Log.v(TAG, "pctFreeMemory:" + pctFreeMemory);
                }
                if (pctFreeMemory < THRESHOLD_LOW_MEMORY_PCT) {
                    Log.v(TAG, "Not enough memory to export the whole file");
                    if (listener != null) {
                        listener.onWarning(mContext.getString(R.string.export_warning_file_too_big_message));
                    }
                    break;
                }
            }
            // Write the footer and clean up the file.
            writeFooter();
            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()));
                }
            }
            return mFile;
        } catch (IOException e) {
            Log.e(TAG, "export Could not export file " + mFile + ": " + e.getMessage(), e);
        } finally {
            c.close();
        }
    }
    if (listener != null)
        listener.onError(mContext.getString(R.string.export_notif_error_content));
    return null;
}
Also used : SortPreferences(ca.rmen.android.networkmonitor.app.prefs.SortPreferences) Selection(ca.rmen.android.networkmonitor.app.prefs.FilterPreferences.Selection) IOException(java.io.IOException) Cursor(android.database.Cursor) Uri(android.net.Uri)

Aggregations

SortPreferences (ca.rmen.android.networkmonitor.app.prefs.SortPreferences)3 SuppressLint (android.annotation.SuppressLint)1 TargetApi (android.annotation.TargetApi)1 Intent (android.content.Intent)1 Cursor (android.database.Cursor)1 Bitmap (android.graphics.Bitmap)1 Uri (android.net.Uri)1 WebResourceRequest (android.webkit.WebResourceRequest)1 WebView (android.webkit.WebView)1 WebViewClient (android.webkit.WebViewClient)1 ProgressBar (android.widget.ProgressBar)1 HTMLExport (ca.rmen.android.networkmonitor.app.dbops.backend.export.HTMLExport)1 Selection (ca.rmen.android.networkmonitor.app.prefs.FilterPreferences.Selection)1 NetMonPreferences (ca.rmen.android.networkmonitor.app.prefs.NetMonPreferences)1 File (java.io.File)1 FileNotFoundException (java.io.FileNotFoundException)1 IOException (java.io.IOException)1 PrintWriter (java.io.PrintWriter)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1