Android Open Source - WsprNetViewer Wspr Fragment






From Project

Back to project page WsprNetViewer.

License

The source code is released under:

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUC...

If you think the Android project WsprNetViewer listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2014 Joseph D. Glandorf
 *// ww w .  ja  v  a 2 s  .  c o m
 * 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 com.glandorf1.joe.wsprnetviewer.app;

import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.glandorf1.joe.wsprnetviewer.app.data.WsprNetContract;
import com.glandorf1.joe.wsprnetviewer.app.sync.WsprNetViewerSyncAdapter;

/**
 * Encapsulates getting the wspr data and displaying it in a ListView layout.
 */
public class WsprFragment extends Fragment implements LoaderCallbacks<Cursor> {
    private final String LOG_TAG = MainActivity.class.getSimpleName();
    private static final String SELECTED_KEY = "selected_position";
    private WsprAdapter mWsprAdapter;
    private static final int WSPR_LOADER = 0;
    private String mSelection, mGridsquare, mFilterTxCallsign, mFilterRxCallsign, mFilterTxGridsquare, mFilterRxGridsquare;
    private boolean mFilterAnd, mFiltered;
    private int mLastNumItems = -1;
    private ListView mListView;
    private TextView mTVGridCallHeader;
    private int mPosition = ListView.INVALID_POSITION;  // selected item's position
    private boolean mDualPane; // provision for putting the details fragment next to this fragment for wider screens

    // For the wspr view, show only a subset of the stored data.
    // Specify the columns we need; this is the 'projection' parameter passed to query().
    private static final String[] WSPR_COLUMNS = {
            // Fully qualify the id with a table name in case the content provider joins the
            // gridsquare & wspr tables in the background--both have an _id column.
            WsprNetContract.SignalReportEntry.TABLE_NAME + "." + WsprNetContract.SignalReportEntry._ID,
            WsprNetContract.SignalReportEntry.COLUMN_TIMESTAMPTEXT,
            WsprNetContract.SignalReportEntry.COLUMN_TX_CALLSIGN,
            WsprNetContract.SignalReportEntry.COLUMN_TX_FREQ_MHZ,
            WsprNetContract.SignalReportEntry.COLUMN_RX_SNR,
            WsprNetContract.SignalReportEntry.COLUMN_RX_DRIFT,
            WsprNetContract.SignalReportEntry.COLUMN_TX_GRIDSQUARE,
            WsprNetContract.SignalReportEntry.COLUMN_TX_POWER,
            WsprNetContract.SignalReportEntry.COLUMN_RX_CALLSIGN,
            WsprNetContract.SignalReportEntry.COLUMN_RX_GRIDSQUARE,
            WsprNetContract.SignalReportEntry.COLUMN_DISTANCE,
            WsprNetContract.SignalReportEntry.COLUMN_AZIMUTH
    };

    // These indices are tied to WSPR_COLUMNS.  If WSPR_COLUMNS changes, these must change.
    public static final int COL_WSPR_ID = 0;
    public static final int COL_WSPR_TIMESTAMP     = 1;
    public static final int COL_WSPR_TX_CALLSIGN   = 2;
    public static final int COL_WSPR_TX_FREQ_MHZ   = 3;
    public static final int COL_WSPR_RX_SNR        = 4;
    public static final int COL_WSPR_RX_DRIFT      = 5;
    public static final int COL_WSPR_TX_GRIDSQUARE = 6;
    public static final int COL_WSPR_TX_POWER      = 7;
    public static final int COL_WSPR_RX_CALLSIGN   = 8;
    public static final int COL_WSPR_RX_GRIDSQUARE = 9;
    public static final int COL_WSPR_DISTANCE      =10;
    public static final int COL_WSPR_AZIMUTH       =11;
    public static final int COL_WSPR_CITY_NAME     =12;
    public static final int COL_WSPR_COUNTRY_NAME  =13;
    public static final int COL_WSPR_COORD_LAT     =14;
    public static final int COL_WSPR_COORD_LONG    =15;

    /**
     * A callback interface that all activities containing this fragment must
     * implement. This mechanism allows activities to be notified of item
     * selections.
     */
    public interface Callback {
        /**
         * DetailFragmentCallback for when an item has been selected.
         */
        public void onItemSelected(String timestamp);
    }

    public WsprFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Enable this fragment to handle menu events.
        setHasOptionsMenu(true);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.wsprfragment, menu);
        if (BuildConfig.DEBUG == true) {
            menu.findItem(R.id.action_debug).setVisible(true);
            menu.findItem(R.id.action_debug).setEnabled(true);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        // The action_debug menu (refresh, dump_db, clear_db) is only turned on for BuildConfig.DEBUG.
        if (id == R.id.action_refresh) {
            updateWspr();
            return true;
        }
        if (id == R.id.action_dumpdb) {
            Utility.exportDB(getActivity());
            return true;
        }
        if (id == R.id.action_cleardb) {
            Utility.deleteAllRecords(getActivity());
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        if (mPosition != ListView.INVALID_POSITION) {
            outState.putInt(SELECTED_KEY, mPosition);
        }
        super.onSaveInstanceState(outState);
    }

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

        // The ArrayAdapter will take data from a source and
        // use it to populate the ListView it's attached to.
        mWsprAdapter = new WsprAdapter(getActivity(), null, 0);

        View rootView = inflater.inflate(R.layout.fragment_main, container, false);

        // Get a reference to the grid/call header
        mTVGridCallHeader = (TextView) rootView.findViewById(R.id.textview_list_header_gridsquare);

        // Get a reference to the ListView, and attach this adapter to it.
        mListView = (ListView) rootView.findViewById(R.id.listview_wspr);
        mListView.setAdapter(mWsprAdapter);
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
                Cursor cursor = mWsprAdapter.getCursor();
                if (cursor != null && cursor.moveToPosition(position)) {
                    ((Callback) getActivity())
                            .onItemSelected(cursor.getString(COL_WSPR_ID)); // TODO: change to record ID!!
                }
                mPosition = position;
            }
        });

        // Get previously-selected position from bundle, restore list selection during onLoadFinished.
        if (savedInstanceState != null && savedInstanceState.containsKey(SELECTED_KEY)) {
            mPosition = savedInstanceState.getInt(SELECTED_KEY);
        }
        mWsprAdapter.setUseDualPane(mDualPane);
        return rootView;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        getLoaderManager().initLoader(WSPR_LOADER, null, this);
        super.onActivityCreated(savedInstanceState);
    }

    private void updateWspr() {
      // invoke the sync adapter service
        WsprNetViewerSyncAdapter.syncImmediately(getActivity());
    }

    @Override
    public void onResume() {
        super.onResume();
        boolean filterOn = Utility.isFiltered(getActivity());
        // Restart the loader if some of the preferences have changed.
        if (filterOn // and filter settings have changed
                    && (   ((mFilterTxCallsign   != null) && !mFilterTxCallsign.equals((Utility.getFilterCallsign(getActivity(),  true))))
                        || ((mFilterRxCallsign   != null) && !mFilterRxCallsign.equals((Utility.getFilterCallsign(getActivity(), false))))
                        || ((mFilterTxGridsquare != null) && !mFilterTxGridsquare.equals((Utility.getFilterGridsquare(getActivity(), true))))
                        || ((mFilterRxGridsquare != null) && !mFilterRxGridsquare.equals((Utility.getFilterGridsquare(getActivity(), false))))
                        || (mFilterAnd != Utility.isFilterAnd(getActivity()))
                       )
            || (mFiltered != Utility.isFiltered(getActivity())) // or filter on/off has changed
            || (mWsprAdapter.mainDisplayFormat !=  Utility.getMainDisplayPreference(getActivity())) // or layout has changed
           ) {
            mLastNumItems = -1; // reset so that notification will appear
            getLoaderManager().restartLoader(WSPR_LOADER, null, this);
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // This is called when a new Loader needs to be created.  This
        // fragment only uses one loader, so we don't care about checking the id.

        // TODO: Filter the query to only return data from today and the previous N days.
//        Calendar cal = Calendar.getInstance();
//        cal.setTime(new Date());
//        cal.add(Calendar.DATE, -7); // N= 7
//        Date cutoffDate = cal.getTime();
//        String startTimestamp = WsprNetContract.getDbTimestampString(cutoffDate);

        // Sort order:  Descending, by timestamp.
        String sortOrder = WsprNetContract.SignalReportEntry.COLUMN_TIMESTAMPTEXT + " DESC";
        String txCall = Utility.getFilterCallsign(getActivity(), true),
               rxCall = Utility.getFilterCallsign(getActivity(), false);
        String txGridsquare = Utility.getFilterGridsquare(getActivity(),  true),
               rxGridsquare = Utility.getFilterGridsquare(getActivity(), false);
        txCall = Utility.filterCleanupForSQL(txCall);
        rxCall = Utility.filterCleanupForSQL(rxCall);
        txGridsquare = Utility.filterCleanupForSQL(txGridsquare);
        rxGridsquare = Utility.filterCleanupForSQL(rxGridsquare);
        mSelection = "";
        if (Utility.isFiltered(getActivity())) {
            // When adding filters, be sure to update onResume(), and save the preference value below, too.
            String prefAndOr = Utility.isFilterAnd(getActivity()) ? " and " : " or ";
            String sAndOr = " ";
            if (txCall.length() > 0) {
                sAndOr = (mSelection.length() > 0) ? prefAndOr : "";
                mSelection += sAndOr + "(" + WsprNetContract.SignalReportEntry.COLUMN_TX_CALLSIGN + " like '" + txCall + "')";
            }
            if (rxCall.length() > 0) {
                sAndOr = (mSelection.length() > 0) ? prefAndOr : "";
                mSelection += sAndOr + "(" + WsprNetContract.SignalReportEntry.COLUMN_RX_CALLSIGN + " like '" + rxCall + "')";
            }
            if (txGridsquare.length() > 0) {
                sAndOr = (mSelection.length() > 0) ? prefAndOr : "";
                mSelection += sAndOr + "(" + WsprNetContract.SignalReportEntry.COLUMN_TX_GRIDSQUARE + " like '" + txGridsquare + "')";
            }
            if (rxGridsquare.length() > 0) {
                sAndOr = (mSelection.length() > 0) ? prefAndOr : "";
                mSelection += sAndOr + "(" + WsprNetContract.SignalReportEntry.COLUMN_RX_GRIDSQUARE + " like '" + rxGridsquare + "')";
            }
            // Examples of resulting 'selection' clause:
            //   tx_callsign like 'D%'
            //   (tx_gridsquare like 'D%') and (rx_callsign like 'N%')
            //   (tx_gridsquare like 'D%') or (rx_callsign like 'N%')
            if (mSelection.length() > 0) {
                // Remind user that items are filtered, in case the result is not what they expect.
                Toast.makeText(getActivity(), getActivity().getString(R.string.toast_filter_items), Toast.LENGTH_LONG).show();
            }
        }

        int mainDisplayPreference = Utility.getMainDisplayPreference(getActivity());
        if (mWsprAdapter.mainDisplayFormat != mainDisplayPreference) {
            // Update the gridsquare/callsign heading text based on the display layout.
            switch (mainDisplayPreference) {
                case Utility.MAIN_DISPLAY_CALLSIGN: // fit everything into 2 lines of display
                    mTVGridCallHeader.setText(getActivity().getString(R.string.callsign));
                    mTVGridCallHeader.setTextColor(getResources().getColor(R.color.wspr_brown));
                    break;
                case Utility.MAIN_DISPLAY_GRIDCALL: // fit everything into 4 lines of display
                    String g = getActivity().getString(R.string.grid);
                    String c = getActivity().getString(R.string.call);
                    Spannable s = new SpannableString(g + "/" + c);
                    // In "Grid/Call", make "grid" black, "Call" brown, and "/" somewhere between.
                    // Release: For "Grid", set the span to be 1 extra character.
                    s.setSpan(new ForegroundColorSpan(Color.BLACK), 0, g.length()+0, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    // Debug: For the "/", set the span to be 2 characters; it will won't display in the color if the span is only 1 character.
                    s.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.wspr_brown2)), g.length()+0, g.length()+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    s.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.wspr_brown)), g.length()+1, s.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    mTVGridCallHeader.setText(s);
                    break;
                case Utility.MAIN_DISPLAY_GRIDSQUARE: // fit everything into 2 lines of display
                default:
                    mTVGridCallHeader.setText(getActivity().getString(R.string.gridsquare));
                    mTVGridCallHeader.setTextColor(Color.BLACK);
            }

        }


        // Save some of the preferences to detect if they've changed in onResume().
        mGridsquare = Utility.getPreferredGridsquare(getActivity());
        mWsprAdapter.mainDisplayFormat = mainDisplayPreference;
        mFilterTxCallsign = Utility.getFilterCallsign(getActivity(), true);
        mFilterRxCallsign = Utility.getFilterCallsign(getActivity(), false);
        mFilterTxGridsquare = Utility.getFilterGridsquare(getActivity(), true);
        mFilterRxGridsquare = Utility.getFilterGridsquare(getActivity(), false);
        mFilterAnd = Utility.isFilterAnd(getActivity());
        mFiltered = Utility.isFiltered(getActivity());
        Uri wsprUri;
        wsprUri = WsprNetContract.SignalReportEntry.buildWspr();

        // Create and return a CursorLoader that will take care of creating a Cursor for the data being displayed.
        return new CursorLoader(
                getActivity(), // context
                wsprUri,       // URI
                WSPR_COLUMNS,  // String[] projection
                mSelection,    // String selection
                null,          // String[] selectionArgs
                sortOrder      // String sortOrder
        );
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        Integer n = data.getCount();
        Log.v(LOG_TAG, "WsprFragment: onLoadFinished:  data.getCount()= " + n.toString());
        if ((n == 0) && (mLastNumItems != 0)) {
            // only do this once if there are no items
            Toast.makeText(getActivity(), getActivity().getString(R.string.toast_no_items), Toast.LENGTH_LONG).show();
            WsprNetViewerSyncAdapter.syncImmediately(getActivity());
        } else if (n > 0) {
            String msg = getActivity().getString(R.string.toast_num_items, n);
            Toast.makeText(getActivity(), msg, Toast.LENGTH_LONG).show();
        }
        mWsprAdapter.swapCursor(data);
        if (mPosition != ListView.INVALID_POSITION) {
            mListView.smoothScrollToPosition(mPosition);
        }
        mLastNumItems = n;

    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mWsprAdapter.swapCursor(null);
    }

    public void setDualPane(boolean dualPane) {
        mDualPane = dualPane;
        if (mWsprAdapter != null) {
            mWsprAdapter.setUseDualPane(mDualPane);
        }
    }
}




Java Source Code List

com.glandorf1.joe.wsprnetviewer.app.ApplicationTest.java
com.glandorf1.joe.wsprnetviewer.app.DetailActivity.java
com.glandorf1.joe.wsprnetviewer.app.DetailFragment.java
com.glandorf1.joe.wsprnetviewer.app.FullTestSuite.java
com.glandorf1.joe.wsprnetviewer.app.MainActivity.java
com.glandorf1.joe.wsprnetviewer.app.SettingsActivity.java
com.glandorf1.joe.wsprnetviewer.app.SimpleEula.java
com.glandorf1.joe.wsprnetviewer.app.TestDb.java
com.glandorf1.joe.wsprnetviewer.app.TestProvider.java
com.glandorf1.joe.wsprnetviewer.app.Utility.java
com.glandorf1.joe.wsprnetviewer.app.WsprAdapter.java
com.glandorf1.joe.wsprnetviewer.app.WsprFragment.java
com.glandorf1.joe.wsprnetviewer.app.data.WsprNetContract.java
com.glandorf1.joe.wsprnetviewer.app.data.WsprNetCustomView.java
com.glandorf1.joe.wsprnetviewer.app.data.WsprNetDbHelper.java
com.glandorf1.joe.wsprnetviewer.app.data.WsprNetProvider.java
com.glandorf1.joe.wsprnetviewer.app.sync.WsprNetViewerAuthenticatorService.java
com.glandorf1.joe.wsprnetviewer.app.sync.WsprNetViewerAuthenticator.java
com.glandorf1.joe.wsprnetviewer.app.sync.WsprNetViewerSyncAdapter.java
com.glandorf1.joe.wsprnetviewer.app.sync.WsprNetViewerSyncService.java