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.route; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.FragmentManager; import android.support.v4.app.ListFragment; import android.support.v7.app.AppCompatActivity; import android.support.v7.internal.view.SupportMenuInflater; import android.support.v7.internal.view.menu.MenuBuilder; import android.support.v7.internal.view.menu.MenuPopupHelper; import android.support.v7.internal.view.menu.MenuPresenter; 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.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.androzic.Androzic; import com.androzic.FragmentHolder; import com.androzic.R; import com.androzic.data.Route; import com.androzic.data.Waypoint; import com.androzic.navigation.NavigationService; import com.androzic.util.StringFormatter; import com.androzic.waypoint.OnWaypointActionListener; public class RouteDetails extends ListFragment implements OnSharedPreferenceChangeListener, MenuBuilder.Callback, MenuPresenter.Callback { private static final String TAG = "RouteDetails"; Androzic application; private FragmentHolder fragmentHolderCallback; private OnRouteActionListener routeActionsCallback; private OnWaypointActionListener waypointActionsCallback; private WaypointListAdapter adapter; private int selectedKey; private Drawable selectedBackground; private int accentColor; private Route route; private boolean navigation; public RouteDetails() { application = Androzic.getApplication(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); setRetainInstance(true); accentColor = getResources().getColor(R.color.theme_accent_color); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.list_with_empty_view, container, false); } @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 { fragmentHolderCallback = (FragmentHolder) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement FragmentHolder"); } try { routeActionsCallback = (OnRouteActionListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnRouteActionListener"); } try { waypointActionsCallback = (OnWaypointActionListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnWaypointActionListener"); } } @Override public void onStart() { super.onStart(); if (route == null) { Bundle args = getArguments(); if (args != null) setRoute(application.getRoute(args.getInt("index"))); } if (route != null) updateRouteDetails(); } @Override public void onResume() { super.onResume(); if (navigation) { application.registerReceiver(navigationReceiver, new IntentFilter(NavigationService.BROADCAST_NAVIGATION_STATUS)); application.registerReceiver(navigationReceiver, new IntentFilter(NavigationService.BROADCAST_NAVIGATION_STATE)); } else { fragmentHolderCallback.enableActionButton().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { routeActionsCallback.onRouteNavigate(route); } }); } SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getActivity()); onSharedPreferenceChanged(settings, getString(R.string.pref_wakelock)); PreferenceManager.getDefaultSharedPreferences(application).registerOnSharedPreferenceChangeListener(this); adapter.notifyDataSetChanged(); } @Override public void onPause() { super.onPause(); if (navigation) { application.unregisterReceiver(navigationReceiver); } else { fragmentHolderCallback.disableActionButton(); } PreferenceManager.getDefaultSharedPreferences(application).unregisterOnSharedPreferenceChangeListener(this); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.route_menu, menu); } @Override public void onPrepareOptionsMenu(final Menu menu) { menu.findItem(R.id.action_navigate).setVisible(false); if (navigation) { menu.findItem(R.id.action_edit).setVisible(false); menu.findItem(R.id.action_edit_path).setVisible(false); menu.findItem(R.id.action_save).setVisible(false); menu.findItem(R.id.action_remove).setVisible(false); } } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.action_edit: routeActionsCallback.onRouteEdit(route); return true; case R.id.action_edit_path: routeActionsCallback.onRouteEditPath(route); return true; case R.id.action_save: routeActionsCallback.onRouteSave(route); return true; case R.id.action_remove: Androzic application = Androzic.getApplication(); application.removeRoute(route); // "Close" fragment getFragmentManager().popBackStack(); return true; } return false; } @Override public void onListItemClick(ListView lv, View v, int position, long id) { v.setTag("selected"); selectedKey = position; selectedBackground = v.getBackground(); v.setBackgroundColor(accentColor); // https://gist.github.com/mediavrog/9345938#file-iconizedmenu-java-L55 MenuBuilder menu = new MenuBuilder(getActivity()); menu.setCallback(this); MenuPopupHelper popup = new MenuPopupHelper(getActivity(), menu, v.findViewById(R.id.name)); popup.setForceShowIcon(true); popup.setCallback(this); new SupportMenuInflater(getActivity()) .inflate(navigation ? R.menu.routewaypointnavigation_menu : R.menu.routewaypoint_menu, menu); popup.show(); } @Override public boolean onMenuItemSelected(MenuBuilder builder, MenuItem item) { switch (item.getItemId()) { case R.id.action_view: route.show = true; waypointActionsCallback.onWaypointView(route.getWaypoint(selectedKey)); //TODO Sometimes we have to close it manually, sometimes not. Should investigate it. FragmentManager fm = getFragmentManager(); if (fm != null) fm.popBackStack(); return true; case R.id.action_navigate: if (navigation) { if (application.navigationService.navDirection == NavigationService.DIRECTION_REVERSE) selectedKey = route.length() - selectedKey - 1; application.navigationService.setRouteWaypoint(selectedKey); adapter.notifyDataSetChanged(); } return true; case R.id.action_edit: routeActionsCallback.onRouteWaypointEdit(route, route.getWaypoint(selectedKey)); return true; } return false; } @Override public void onMenuModeChange(MenuBuilder builder) { } @SuppressWarnings("deprecation") @Override public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { try { ListView lv = getListView(); if (allMenusAreClosing && lv != null) { View v = lv.findViewWithTag("selected"); if (v != null) { v.setBackgroundDrawable(selectedBackground); v.setTag(null); } } } catch (IllegalStateException ignore) { // Ignore dismissing view after list view was destroyed } } @Override public boolean onOpenSubMenu(MenuBuilder menu) { return false; } public void setRoute(Route route) { this.route = route; navigation = application.isNavigatingViaRoute() && application.navigationService.navRoute == route; if (isVisible()) updateRouteDetails(); } private void updateRouteDetails() { AppCompatActivity activity = (AppCompatActivity) getActivity(); activity.getSupportActionBar().setTitle(navigation ? "\u21d2 " + route.name : route.name); adapter = new WaypointListAdapter(activity, route); setListAdapter(adapter); if (navigation) getListView().setSelection(application.navigationService.navRouteCurrentIndex()); activity.supportInvalidateOptionsMenu(); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { Resources resources = getResources(); if (getString(R.string.pref_wakelock).equals(key)) { getListView().setKeepScreenOn( navigation && sharedPreferences.getBoolean(key, resources.getBoolean(R.bool.def_wakelock))); } } private BroadcastReceiver navigationReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.e(TAG, "Broadcast: " + intent.getAction()); if (intent.getAction().equals(NavigationService.BROADCAST_NAVIGATION_STATE)) { final int state = intent.getExtras().getInt("state"); if (state == NavigationService.STATE_REACHED) { Toast.makeText(getActivity(), R.string.arrived, Toast.LENGTH_LONG).show(); navigation = false; getActivity().supportInvalidateOptionsMenu(); } adapter.notifyDataSetChanged(); } if (intent.getAction().equals(NavigationService.BROADCAST_NAVIGATION_STATUS)) { adapter.notifyDataSetChanged(); } } }; public class WaypointListAdapter extends BaseAdapter { private LayoutInflater mInflater; private int mItemLayout; private Route mRoute; public WaypointListAdapter(Context context, Route route) { mItemLayout = R.layout.list_item_route_waypoint; mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mRoute = route; } public Waypoint getItem(int position) { if (navigation && application.navigationService.navDirection == NavigationService.DIRECTION_REVERSE) position = mRoute.length() - position - 1; return mRoute.getWaypoint(position); } @Override public long getItemId(int position) { if (navigation && application.navigationService.navDirection == NavigationService.DIRECTION_REVERSE) position = mRoute.length() - position - 1; return position; } @Override public int getCount() { return mRoute.length(); } @Override public View getView(int position, View convertView, ViewGroup parent) { View v; if (convertView == null) { v = mInflater.inflate(mItemLayout, parent, false); } else { v = convertView; v = mInflater.inflate(mItemLayout, parent, false); } Waypoint wpt = getItem(position); TextView text = (TextView) v.findViewById(R.id.name); if (text != null) { text.setText(wpt.name); } if (navigation && application.navigationService.isNavigatingViaRoute()) { int progress = position - application.navigationService.navRouteCurrentIndex(); if (position > 0) { double dist = progress == 0 ? application.navigationService.navDistance : mRoute.distanceBetween(position - 1, position); String distance = StringFormatter.distanceH(dist); text = (TextView) v.findViewById(R.id.distance); if (text != null) { text.setText(distance); // if (progress == 0) // text.setTextAppearance(RouteDetails.this, resid); } double crs; if (progress == 0) crs = application.navigationService.navBearing; else if (application.navigationService.navDirection == NavigationService.DIRECTION_FORWARD) crs = mRoute.course(position - 1, position); else crs = mRoute.course(position, position - 1); String course = StringFormatter.angleH(crs); text = (TextView) v.findViewById(R.id.course); if (text != null) { text.setText(course); } } if (progress >= 0) { double dist = application.navigationService.navDistance; if (progress > 0) dist += application.navigationService.navRouteDistanceLeftTo(position); String distance = StringFormatter.distanceH(dist); text = (TextView) v.findViewById(R.id.total_distance); if (text != null) { text.setText(distance); } int ete = progress == 0 ? application.navigationService.navETE : application.navigationService.navRouteWaypointETE(position); String s = StringFormatter.timeR(ete); text = (TextView) v.findViewById(R.id.ete); if (text != null) { text.setText(s); } int eta = application.navigationService.navETE; if (progress > 0 && eta < Integer.MAX_VALUE) { int t = application.navigationService.navRouteETETo(position); if (t < Integer.MAX_VALUE) eta += t; } s = StringFormatter.timeR(eta); text = (TextView) v.findViewById(R.id.eta); if (text != null) { text.setText(s); } if (progress == 0) { text = (TextView) v.findViewById(R.id.name); text.setText("\u2192 " + text.getText()); } } else { text = (TextView) v.findViewById(R.id.name); text.setTextColor(text.getTextColors().withAlpha(128)); text = (TextView) v.findViewById(R.id.distance); text.setTextColor(text.getTextColors().withAlpha(128)); text = (TextView) v.findViewById(R.id.course); text.setTextColor(text.getTextColors().withAlpha(128)); } } else { if (position > 0) { double dist = mRoute.distanceBetween(position - 1, position); String distance = StringFormatter.distanceH(dist); text = (TextView) v.findViewById(R.id.distance); if (text != null) { text.setText(distance); } double crs = mRoute.course(position - 1, position); String course = StringFormatter.angleH(crs); text = (TextView) v.findViewById(R.id.course); if (text != null) { text.setText(course); } } double dist = position > 0 ? mRoute.distanceBetween(0, position) : 0.; String distance = StringFormatter.distanceH(dist); text = (TextView) v.findViewById(R.id.total_distance); if (text != null) { text.setText(distance); } } return v; } @Override public boolean hasStableIds() { return true; } } }