Java tutorial
/* Radiobeacon - Openbmap wifi and cell logger Copyright (C) 2013 wish7 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.openbmap.activities; import android.content.ContentUris; import android.content.Intent; import android.database.Cursor; import android.graphics.Color; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.widget.SimpleCursorAdapter; import android.support.v4.widget.SimpleCursorAdapter.ViewBinder; 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.ImageView; import android.widget.ListView; import android.widget.TextView; import org.openbmap.R; import org.openbmap.db.DataHelper; import org.openbmap.db.RadioBeaconContentProvider; import org.openbmap.db.Schema; import org.openbmap.utils.TriToggleButton; //import android.view.ContextMenu; //import android.view.ContextMenu.ContextMenuInfo; //import android.view.MenuInflater; //import android.view.MenuItem; /** * Parent activity for hosting wifi list */ public class WifiListContainer extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> { private static final String TAG = WifiListContainer.class.getSimpleName(); /** * Wifi cursor loader id * must be different from CELL_LOADER_ID ! */ private static final int WIFI_LOADER_ID = 1; /** * By default, sort by wifi ssid */ private static final String DEFAULT_SORT_COLUMN = Schema.COL_TIMESTAMP; /** * Default sort order */ private static final String DEFAULT_SORT_ORDER = " ASC"; /** * Be careful: * All external linking (e.g. to map) must rely on BSSID. * (_id is a pseudo-id as original id can't be used for GROUP BY clauses) */ private CursorLoader mCursorLoader; /** * Adapter for retrieving wifis. */ private SimpleCursorAdapter mAdapter; /** * WHERE clause for loader */ private String mSelection = null; /** * WHERE clause arguments for loader */ private String[] mSelectionArgs = null; /** * Sort order for loader */ private String mSortColumn = DEFAULT_SORT_COLUMN; /** * Sort order for loader */ private String mSortOrder = DEFAULT_SORT_ORDER; /** * Session id */ private int mSession; /** * List header */ private View mHheader; private TriToggleButton sortButton; @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { return inflater.inflate(R.layout.wifilist, container, false); } @Override public final void onActivityCreated(final Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); mHheader = (View) getLayoutInflater(savedInstanceState).inflate(R.layout.wifilistheader, null); this.getListView().addHeaderView(mHheader); registerForContextMenu(mHheader); initUi(); // setup data initData(); getActivity().getSupportLoaderManager().initLoader(WIFI_LOADER_ID, null, this); } /** * Setup Ui controls */ private void initUi() { sortButton = (TriToggleButton) mHheader.findViewById(R.id.triToggleButton1); sortButton.setPositiveImage(getResources().getDrawable(R.drawable.ic_action_up)); sortButton.setNeutralImage(getResources().getDrawable(R.drawable.ic_action_unsorted)); sortButton.setNegativeImage(getResources().getDrawable(R.drawable.ic_action_down)); sortButton.setOnClickListener(new View.OnClickListener() { // Sort button: handler for user clicks @Override public void onClick(final View v) { final int state = sortButton.getState(); try { switch (state) { case 0: mSortOrder = " DESC"; reload(); break; case 1: mSortOrder = DEFAULT_SORT_ORDER; reload(); break; case 2: mSortOrder = " ASC"; reload(); break; default: break; // Should never occur } } catch (final Exception e) { Log.e(TAG, "Error onClick"); } } }); } private void initData() { final DataHelper dataHelper = new DataHelper(getActivity()); mSession = dataHelper.getActiveSessionId(); final String[] from = new String[] { Schema.COL_ID, Schema.COL_BSSID, Schema.COL_SSID, "MAX(" + Schema.COL_LEVEL + ")", /*Schema.COL_IS_NEW_WIFI,*/ Schema.COL_KNOWN_WIFI, Schema.COL_CAPABILITIES }; final int[] to = new int[] { R.id.wifilistfragment_id, R.id.wifilistfragment_bssid, R.id.wifilistfragment_ssid, R.id.wifilistfragment_level, R.id.wifilistfragment_statusicon, R.id.wifilistfragment_capabilities }; mAdapter = new SimpleCursorAdapter(getActivity().getBaseContext(), R.layout.wifilistitems, null, from, to, 0); mAdapter.setViewBinder(new WifiViewBinder()); setListAdapter(mAdapter); } @Override public final void onDestroy() { setListAdapter(null); super.onDestroy(); } public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { inflater.inflate(R.menu.wifilist_context, menu); } /* @Override public final void onCreateContextMenu(final ContextMenu menu, final View v, final ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); //TODO: context menu not yet shown int menuId = R.menu.wifilist_context; MenuInflater inflater = getActivity().getMenuInflater(); inflater.inflate(menuId, menu); } */ @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.menu_sort_timestamp: mSortColumn = DEFAULT_SORT_COLUMN; mSortOrder = " DESC"; sortButton.setState(1); resetFilters(); reload(); return true; case R.id.menu_sort_ssid: mSortColumn = Schema.COL_SSID; mSortOrder = " ASC"; sortButton.setState(1); resetFilters(); reload(); return true; case R.id.menu_display_only_new: mSortColumn = Schema.COL_SSID; mSortOrder = " ASC"; sortButton.setState(1); //setFilters(Schema.COL_IS_NEW_WIFI + " = ?", new String[]{"1"}); setFilters(Schema.COL_KNOWN_WIFI + " = ?", new String[] { "0" }); reload(); return true; case R.id.menu_display_free: mSortColumn = Schema.COL_SSID; mSortOrder = " ASC"; sortButton.setState(1); setFilters(Schema.COL_CAPABILITIES + " = ?", new String[] { "\"[ESS]\"" }); reload(); return true; case R.id.menu_display_all: mSortColumn = Schema.COL_SSID; mSortOrder = " ASC"; sortButton.setState(1); resetFilters(); reload(); return true; default: break; } return super.onOptionsItemSelected(item); } /** * User has clicked on wifi record. * @param lv listview; this * @param iv item clicked * @param position position within list * @param id track ID */ @Override public final void onListItemClick(final ListView lv, final View iv, final int position, final long id) { if (position != 0) { // documentation says call getListView().getItemAtPosition(position) not lv directly // see http://developer.android.com/reference/android/app/ListFragment.html final Cursor row = (Cursor) getListView().getItemAtPosition(position); final String bssid = row.getString(row.getColumnIndex(Schema.COL_BSSID)); final Intent intent = new Intent(); intent.setClass(getActivity(), WifiDetailsActivity.class); intent.putExtra(Schema.COL_BSSID, bssid); intent.putExtra(Schema.COL_SESSION_ID, mSession); startActivity(intent); } } @Override public final Loader<Cursor> onCreateLoader(final int arg0, final Bundle arg1) { final String[] projection = { Schema.COL_ID, Schema.COL_BSSID, Schema.COL_SSID, "MAX(" + Schema.COL_LEVEL + ")", //Schema.COL_IS_NEW_WIFI, Schema.COL_KNOWN_WIFI, Schema.COL_CAPABILITIES }; mCursorLoader = new CursorLoader(getActivity().getBaseContext(), ContentUris.withAppendedId(Uri.withAppendedPath(RadioBeaconContentProvider.CONTENT_URI_WIFI, RadioBeaconContentProvider.CONTENT_URI_OVERVIEW_SUFFIX), mSession), projection, mSelection, mSelectionArgs, mSortColumn + mSortOrder); return mCursorLoader; } @Override public final void onLoadFinished(final Loader<Cursor> loader, final Cursor cursor) { mAdapter.swapCursor(cursor); } @Override public final void onLoaderReset(final Loader<Cursor> loader) { mAdapter.swapCursor(null); } /** * Forces reload */ private void reload() { getLoaderManager().restartLoader(WIFI_LOADER_ID, null, WifiListContainer.this); } /** * Sets loader filters. Won't become effective until next reload * @param selection * @param selectionArgs */ private void setFilters(final String selection, final String[] selectionArgs) { mSelection = selection; mSelectionArgs = selectionArgs; } /** * Clears filters. Won't become effective until next reload */ private void resetFilters() { mSelection = null; mSelectionArgs = null; } /** * Replaces column values with icons and mark free wifis. */ private class WifiViewBinder implements ViewBinder { private final int DEFAULT_TEXT_COLOR = new TextView(getActivity()).getTextColors().getDefaultColor();; public boolean setViewValue(final View view, final Cursor cursor, final int columnIndex) { final ImageView isNew = ((ImageView) ((View) view.getParent()) .findViewById(R.id.wifilistfragment_statusicon)); final TextView ssid = ((TextView) view.findViewById(R.id.wifilistfragment_ssid)); if (columnIndex == cursor.getColumnIndex(Schema.COL_KNOWN_WIFI)) { final int result = cursor.getInt(columnIndex); if (result == 0) { // (+) icon for new wifis isNew.setImageResource(android.R.drawable.stat_notify_more); isNew.setVisibility(View.VISIBLE); } else { isNew.setVisibility(View.INVISIBLE); } return true; } if (columnIndex == cursor.getColumnIndex(Schema.COL_SSID)) { final String encryp = cursor.getString(cursor.getColumnIndex(Schema.COL_CAPABILITIES)); // some devices report no encryption for free wifis, others (e.g. Nexus 4) // report [ESS] if (encryp.length() < 1 || encryp.equals("[ESS]")) { ssid.setTextColor(Color.GREEN); } else { ssid.setTextColor(DEFAULT_TEXT_COLOR); } return false; } return false; } } }