Java tutorial
/* * Androzic - android navigation client that uses OziExplorer maps (ozf2, ozfx3). * Copyright (C) 2010-2014 Andrey Novikov <http://andreynovikov.info/> * * This file is part of Androzic application. * * Androzic 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. * * Androzic 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 Androzic. If not, see <http://www.gnu.org/licenses/>. */ package com.androzic.waypoint; import java.util.Collections; import java.util.Comparator; import java.util.List; import android.annotation.SuppressLint; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.FragmentActivity; import android.support.v4.app.ListFragment; import android.support.v7.app.AlertDialog; 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.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import com.androzic.Androzic; import com.androzic.R; import com.androzic.data.Waypoint; import com.androzic.data.WaypointSet; import com.androzic.ui.FileListDialog; import com.androzic.ui.MarkerFactory; import com.androzic.ui.TooltipManager; import com.androzic.util.Geo; import com.androzic.util.StringFormatter; import com.daimajia.swipe.adapters.BaseSwipeAdapter; import com.daimajia.swipe.util.Attributes; public class WaypointList extends ListFragment implements FileListDialog.OnFileListDialogListener { public static final String TAG = "WaypointList"; private static final int DIALOG_WAYPOINT_PROJECT = 1; private OnWaypointActionListener waypointActionsCallback; private WaypointListAdapter adapter; private int mSortMode = -1; private Handler tooltipCallback = new Handler(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); setHasOptionsMenu(true); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.list_with_empty_view_and_fab, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); TextView emptyView = (TextView) getListView().getEmptyView(); if (emptyView != null) emptyView.setText(R.string.msg_empty_waypoint_list); FloatingActionButton fab = (FloatingActionButton) getView().findViewById(R.id.actionButton); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { waypointActionsCallback.onWaypointEdit(new Waypoint()); } }); adapter = new WaypointListAdapter(getActivity()); setListAdapter(adapter); adapter.setMode(Attributes.Mode.Single); } @Override public void onAttach(Activity activity) { super.onAttach(activity); // This makes sure that the container activity has implemented // the callback interface. If not, it throws an exception try { waypointActionsCallback = (OnWaypointActionListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnWaypointActionListener"); } } @Override public void onStart() { super.onStart(); Androzic application = Androzic.getApplication(); application.saveWaypoints(); application.registerReceiver(broadcastReceiver, new IntentFilter(Androzic.BROADCAST_WAYPOINT_ADDED)); application.registerReceiver(broadcastReceiver, new IntentFilter(Androzic.BROADCAST_WAYPOINT_REMOVED)); SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(application); mSortMode = settings.getInt(getString(R.string.wpt_sort), 0); adapter.sort(mSortMode); } @Override public void onResume() { super.onResume(); adapter.notifyDataSetChanged(); tooltipCallback.postDelayed(showTooltip, TooltipManager.TOOLTIP_DELAY); } @Override public void onPause() { super.onPause(); // Stop showing tooltips tooltipCallback.removeCallbacks(showTooltip); TooltipManager.dismiss(); } @Override public void onStop() { super.onStop(); Androzic application = Androzic.getApplication(); application.unregisterReceiver(broadcastReceiver); } @Override public void onListItemClick(ListView lv, View v, int position, long id) { Androzic application = Androzic.getApplication(); Waypoint waypoint = application.getWaypoint(position); waypointActionsCallback.onWaypointDetails(waypoint); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.waypointlist_menu, menu); super.onCreateOptionsMenu(menu, inflater); } @Override public void onPrepareOptionsMenu(final Menu menu) { Androzic application = Androzic.getApplication(); MenuItem sortItem = menu.findItem(mSortMode == 0 ? R.id.action_sort_alpha : R.id.action_sort_size); sortItem.setChecked(true); Editor editor = PreferenceManager.getDefaultSharedPreferences(application).edit(); editor.putInt(getString(R.string.wpt_sort), mSortMode); editor.commit(); List<WaypointSet> sets = application.getWaypointSets(); if (sets.size() > 1) { menu.setGroupVisible(R.id.group_sets, true); menu.removeGroup(R.id.group_sets); for (int i = 1; i < sets.size(); i++) menu.add(R.id.group_sets, i, Menu.NONE, sets.get(i).name).setChecked(true); menu.setGroupCheckable(R.id.group_sets, true, false); } } @SuppressLint("InflateParams") @Override public boolean onOptionsItemSelected(MenuItem item) { final FragmentActivity activity = getActivity(); switch (item.getItemId()) { case R.id.action_sort_alpha: adapter.sort(0); mSortMode = 0; activity.supportInvalidateOptionsMenu(); return true; case R.id.action_sort_size: adapter.sort(1); mSortMode = 1; activity.supportInvalidateOptionsMenu(); return true; case R.id.action_load_waypoints: WaypointFileList fileListDialog = new WaypointFileList(this); fileListDialog.show(getFragmentManager(), "dialog"); return true; case R.id.action_new_waypoint_set: View view = getActivity().getLayoutInflater().inflate(R.layout.dlg_filename, null); final EditText textEntryView = (EditText) view.findViewById(R.id.name_text); new AlertDialog.Builder(activity).setTitle(R.string.waypointset).setView(view) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String name = textEntryView.getText().toString(); if (!"".equals(name)) { WaypointSet set = new WaypointSet(name); Androzic application = Androzic.getApplication(); application.addWaypointSet(set); activity.supportInvalidateOptionsMenu(); adapter.notifyDataSetChanged(); } } }).setNegativeButton(R.string.cancel, null).create().show(); return true; case R.id.action_project_waypoint: WaypointProject waypointProjectDialog = new WaypointProject(); waypointProjectDialog.setTargetFragment(this, DIALOG_WAYPOINT_PROJECT); waypointProjectDialog.show(getFragmentManager(), "dialog"); return true; default: Androzic application = Androzic.getApplication(); try { application.getWaypointSets().get(item.getItemId()); application.removeWaypointSet(item.getItemId()); activity.supportInvalidateOptionsMenu(); adapter.notifyDataSetChanged(); } catch (IndexOutOfBoundsException e) { return super.onOptionsItemSelected(item); } return true; } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case DIALOG_WAYPOINT_PROJECT: adapter.notifyDataSetChanged(); break; } } final private Runnable showTooltip = new Runnable() { @Override public void run() { long tooltip = TooltipManager.getTooltip(TAG); if (tooltip == 0L) return; if (tooltip == TooltipManager.TOOLTIP_DATA_LIST && !adapter.isEmpty()) TooltipManager.showTooltip(tooltip, getListView().getChildAt(0)); tooltipCallback.postDelayed(this, TooltipManager.TOOLTIP_PERIOD); } }; @Override public void onFileLoaded(int count) { adapter.notifyDataSetChanged(); } private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { adapter.sort(mSortMode); adapter.notifyDataSetChanged(); } }; public class WaypointListAdapter extends BaseSwipeAdapter implements View.OnClickListener { private LayoutInflater mInflater; private int mItemLayout; private float mDensity; private Paint mBorderPaint; private Paint mFillPaint; private int mPointWidth; private Androzic application; private double[] loc; public WaypointListAdapter(Context context) { mItemLayout = R.layout.list_item_waypoint_swipe; mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mDensity = context.getResources().getDisplayMetrics().density; SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); mPointWidth = settings.getInt(context.getString(R.string.pref_waypoint_width), context.getResources().getInteger(R.integer.def_waypoint_width)); mFillPaint = new Paint(); mFillPaint.setAntiAlias(false); mFillPaint.setStrokeWidth(1); mFillPaint.setStyle(Paint.Style.FILL_AND_STROKE); mFillPaint.setColor(settings.getInt(context.getString(R.string.pref_waypoint_color), context.getResources().getColor(R.color.waypoint))); mBorderPaint = new Paint(); mBorderPaint.setAntiAlias(false); mBorderPaint.setStrokeWidth(1); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setColor(context.getResources().getColor(R.color.waypointtext)); mBorderPaint.setColor(settings.getInt(context.getString(R.string.pref_waypoint_namecolor), context.getResources().getColor(R.color.waypointtext))); application = Androzic.getApplication(); loc = application.getLocation(); } @Override public Waypoint getItem(int position) { return application.getWaypoint(position); } @Override public long getItemId(int position) { return position; } @Override public int getCount() { return application.getWaypoints().size(); } @Override public int getSwipeLayoutResourceId(int position) { return R.id.swipe; } @Override public View generateView(int position, ViewGroup parent) { View convertView = mInflater.inflate(mItemLayout, parent, false); return convertView; } @Override public void fillValues(int position, View convertView) { WaypointItemHolder waypointHolder = null; Waypoint wpt = (Waypoint) getItem(position); waypointHolder = (WaypointItemHolder) convertView.getTag(); if (waypointHolder == null) { waypointHolder = new WaypointItemHolder(); waypointHolder.icon = (ImageView) convertView.findViewById(R.id.icon); waypointHolder.actionView = convertView.findViewById(R.id.action_view); waypointHolder.actionNavigate = convertView.findViewById(R.id.action_navigate); waypointHolder.actionEdit = convertView.findViewById(R.id.action_edit); waypointHolder.actionShare = convertView.findViewById(R.id.action_share); waypointHolder.actionDelete = convertView.findViewById(R.id.action_delete); waypointHolder.name = (TextView) convertView.findViewById(R.id.name); waypointHolder.coordinates = (TextView) convertView.findViewById(R.id.coordinates); waypointHolder.distance = (TextView) convertView.findViewById(R.id.distance); convertView.setTag(waypointHolder); } waypointHolder.actionView.setOnClickListener(this); waypointHolder.actionNavigate.setOnClickListener(this); waypointHolder.actionEdit.setOnClickListener(this); waypointHolder.actionShare.setOnClickListener(this); waypointHolder.actionDelete.setOnClickListener(this); waypointHolder.name.setText(wpt.name); String coordinates = StringFormatter.coordinates(" ", wpt.latitude, wpt.longitude); waypointHolder.coordinates.setText(coordinates); double dist = Geo.distance(loc[0], loc[1], wpt.latitude, wpt.longitude); double bearing = Geo.bearing(loc[0], loc[1], wpt.latitude, wpt.longitude); String distance = StringFormatter.distanceH(dist) + " " + StringFormatter.bearingSimpleH(bearing); waypointHolder.distance.setText(distance); Bitmap b = null; if (wpt.drawImage) { b = MarkerFactory.getIcon(application, wpt.marker); } int border = (int) (8 * mDensity); int sizeX = (int) (24 * mDensity); int sizeY = (int) (18 * mDensity); Bitmap bm = Bitmap.createBitmap(sizeX + border * 2, sizeY + border * 2, Config.ARGB_8888); bm.eraseColor(Color.TRANSPARENT); Canvas bc = new Canvas(bm); if (b != null) { int iconWidth = b.getWidth(); int iconHeight = b.getHeight(); Matrix matrix = new Matrix(); if (iconWidth > sizeX || iconHeight > sizeY) { float scaleX = (float) (1. * sizeX / iconWidth); float scaleY = (float) (1. * sizeY / iconHeight); float scale = scaleX > scaleY ? scaleX : scaleY; matrix.postScale(scale, scale); iconWidth = (int) (iconWidth * scale); iconHeight = (int) (iconHeight * scale); } matrix.postTranslate(border + (sizeX - iconWidth) / 2, border + (sizeY - iconHeight) / 2); bc.drawBitmap(b, matrix, null); b.recycle(); } else { int tc = 0, bgc = 0; if (wpt.textcolor != Integer.MIN_VALUE) { tc = mBorderPaint.getColor(); mBorderPaint.setColor(wpt.textcolor); } if (wpt.backcolor != Integer.MIN_VALUE) { bgc = mFillPaint.getColor(); mFillPaint.setColor(wpt.backcolor); } Rect rect = new Rect(0, 0, mPointWidth, mPointWidth); bc.translate(border + (sizeX - mPointWidth) / 2, border + (sizeY - mPointWidth) / 2); bc.drawRect(rect, mBorderPaint); rect.inset(1, 1); bc.drawRect(rect, mFillPaint); if (wpt.textcolor != Integer.MIN_VALUE) { mBorderPaint.setColor(tc); } if (wpt.backcolor != Integer.MIN_VALUE) { mFillPaint.setColor(bgc); } } BitmapDrawable drawable = (BitmapDrawable) waypointHolder.icon.getDrawable(); if (drawable != null) { b = drawable.getBitmap(); if (b != null) b.recycle(); } waypointHolder.icon.setImageBitmap(bm); } @Override public boolean hasStableIds() { return true; } public void sort(final int type) { Collections.sort(application.getWaypoints(), new Comparator<Waypoint>() { @Override public int compare(Waypoint o1, Waypoint o2) { if (type == 1) { // TODO cache distances double dist1 = Geo.distance(loc[0], loc[1], o1.latitude, o1.longitude); double dist2 = Geo.distance(loc[0], loc[1], o2.latitude, o2.longitude); return (Double.compare(dist1, dist2)); } else { return (o1.name.compareToIgnoreCase(o2.name)); } } }); notifyDataSetChanged(); } @Override public void onClick(View v) { ListView lv = getListView(); int position = lv.getPositionForView((View) v.getParent()); closeItem(position); Waypoint waypoint = getItem(position); switch (v.getId()) { case R.id.action_view: waypointActionsCallback.onWaypointView(waypoint); break; case R.id.action_navigate: waypointActionsCallback.onWaypointNavigate(waypoint); break; case R.id.action_edit: waypointActionsCallback.onWaypointEdit(waypoint); break; case R.id.action_share: waypointActionsCallback.onWaypointShare(waypoint); break; case R.id.action_delete: waypointActionsCallback.onWaypointRemove(waypoint); adapter.notifyDataSetChanged(); break; } } } private static class WaypointItemHolder { ImageView icon; TextView name; TextView coordinates; TextView distance; View actionView; View actionNavigate; View actionEdit; View actionShare; View actionDelete; } }