Java tutorial
/* * Copyright (C) 2009 Johan Nilsson <http://markupartist.com> * * 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.markupartist.sthlmtraveling; import android.app.Activity; import android.app.AlertDialog; import android.app.DatePickerDialog; import android.app.Dialog; import android.app.TimePickerDialog; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.database.Cursor; import android.graphics.Color; import android.net.Uri; import android.os.Bundle; import android.os.Parcelable; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentTransaction; import android.support.v4.content.CursorLoader; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.text.format.Time; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.CursorAdapter; import android.widget.DatePicker; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.SimpleAdapter; import android.widget.Spinner; import android.widget.TextView; import android.widget.TimePicker; import com.markupartist.sthlmtraveling.provider.HistoryDbAdapter; import com.markupartist.sthlmtraveling.provider.JourneysProvider.Journey.Journeys; import com.markupartist.sthlmtraveling.provider.TransportMode; import com.markupartist.sthlmtraveling.provider.planner.JourneyQuery; import com.markupartist.sthlmtraveling.provider.planner.Planner; import com.markupartist.sthlmtraveling.provider.planner.Planner.Location; import com.markupartist.sthlmtraveling.provider.site.Site; import com.markupartist.sthlmtraveling.ui.view.DelayAutoCompleteTextView; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.HashMap; public class PlannerFragment extends BaseListFragment implements OnCheckedChangeListener { private static final String TAG = "PlannerFragment"; protected static final int REQUEST_CODE_POINT_ON_MAP_START = 0; protected static final int REQUEST_CODE_POINT_ON_MAP_END = 1; private DelayAutoCompleteTextView mStartPointAutoComplete; private DelayAutoCompleteTextView mEndPointAutoComplete; private DelayAutoCompleteTextView mViaPointAutoComplete; private Site mStartPoint = new Site(); private Site mEndPoint = new Site(); private Site mViaPoint = new Site(); private HistoryDbAdapter mHistoryDbAdapter; private boolean mCreateShortcut; private Time mTime; private Button mDateButton; private Button mTimeButton; private LinearLayout mChangeTimeLayout; private Spinner mWhenSpinner; private View mSearchView; private JourneyAdapter mAdapter; /** * The columns needed by the cursor adapter */ private static final String[] PROJECTION = new String[] { Journeys._ID, // 0 Journeys.JOURNEY_DATA, // 1 Journeys.POSITION, // 2 Journeys.STARRED, // 3 }; /** * The index of the id column */ private static final int COLUMN_INDEX_ID = 0; /** * The index of the journey data column */ private static final int COLUMN_INDEX_JOURNEY_DATA = 1; /** * The index of the starred column */ private static final int COLUMN_INDEX_STARRED = 3; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // If the activity was started with the "create shortcut" action, we // remember this to change the behavior upon a search. if (Intent.ACTION_CREATE_SHORTCUT.equals(getActivity().getIntent().getAction())) { mCreateShortcut = true; } if (savedInstanceState != null) { mStackLevel = savedInstanceState.getInt("level"); } CursorLoader cursorLoader = new CursorLoader(getActivity(), Journeys.CONTENT_URI, PROJECTION, null, //selection, null, //selectionArgs, Journeys.HISTORY_SORT_ORDER); Cursor cursor = cursorLoader.loadInBackground(); mAdapter = new JourneyAdapter(getActivity(), cursor); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.planner_list_fragment, container, false); Button searchButton = (Button) rootView.findViewById(R.id.btn_search); if (mCreateShortcut) { searchButton.setText(getText(R.string.create_shortcut_label)); } searchButton.setText(((String) searchButton.getText()).toUpperCase()); searchButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { handleSearchAction(); } }); ImageButton preferenceButton = (ImageButton) rootView.findViewById(R.id.btn_settings); preferenceButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent settingsIntent = new Intent().setClass(getActivity(), SettingsActivity.class); startActivityWithDefaultTransition(settingsIntent); } }); return rootView; } public void initViews() { mSearchView = getActivity().getLayoutInflater().inflate(R.layout.search, null); getListView().addHeaderView(mSearchView, null, false); final TextView historyView = (TextView) getActivity().getLayoutInflater().inflate(R.layout.header, null); historyView.setText(R.string.history_label); historyView.setOnClickListener(null); // Makes the header un-clickable, hack! getListView().addHeaderView(historyView); // Hide dividers on the header view. getListView().setHeaderDividersEnabled(false); if (!mStartPoint.hasName()) { mStartPoint.setName(Site.TYPE_MY_LOCATION); } mStartPointAutoComplete = createAutoCompleteTextView(R.id.from, /*R.id.from_progress*/ -1, mStartPoint); mEndPointAutoComplete = createAutoCompleteTextView(R.id.to, /*R.id.to_progress*/ -1, mEndPoint); mViaPointAutoComplete = createAutoCompleteTextView(R.id.via, /*R.id.via_progress*/ -1, mViaPoint, true); try { mHistoryDbAdapter = new HistoryDbAdapter(getActivity()).open(); } catch (final Exception e) { showDialog(createDialogReinstallApp()); return; } // Setup view for choosing other data for start and end point. final ImageButton fromDialog = (ImageButton) mSearchView.findViewById(R.id.from_menu); fromDialog.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { mStartPointAutoComplete.setError(null); showDialog(createDialogStartPoint()); } }); final ImageButton toDialog = (ImageButton) mSearchView.findViewById(R.id.to_menu); toDialog.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { mEndPointAutoComplete.setError(null); showDialog(createDialogEndPoint()); } }); final ImageButton viaDialog = (ImageButton) mSearchView.findViewById(R.id.via_menu); viaDialog.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { mViaPointAutoComplete.setError(null); showDialog(createDialogViaPoint()); } }); // Views for date and time mChangeTimeLayout = (LinearLayout) mSearchView.findViewById(R.id.planner_change_time_layout); mDateButton = (Button) mSearchView.findViewById(R.id.planner_route_date); mDateButton.setOnClickListener(new OnClickListener() { @Override public void onClick(final View v) { showDialog(createDialogDate()); } }); mTimeButton = (Button) mSearchView.findViewById(R.id.planner_route_time); mTimeButton.setOnClickListener(new OnClickListener() { @Override public void onClick(final View v) { showDialog(createDialogTime()); } }); // Views for radio buttons final RadioButton nowRadioButton = (RadioButton) mSearchView.findViewById(R.id.planner_check_now); nowRadioButton.setOnCheckedChangeListener(this); final RadioButton laterRadioButton = (RadioButton) mSearchView .findViewById(R.id.planner_check_more_choices); laterRadioButton.setOnCheckedChangeListener(this); mWhenSpinner = (Spinner) mSearchView.findViewById(R.id.departure_arrival_choice); final ArrayAdapter<CharSequence> whenChoiceAdapter = ArrayAdapter.createFromResource(getActivity(), R.array.when_choice, android.R.layout.simple_spinner_item); whenChoiceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mWhenSpinner.setAdapter(whenChoiceAdapter); // Handle create shortcut. if (mCreateShortcut) { registerScreen("Planner create shortcut"); getActivity().setTitle(R.string.create_shortcut_label); // Add search label to button RadioGroup chooseTimeGroup = (RadioGroup) mSearchView.findViewById(R.id.planner_choose_time_group); chooseTimeGroup.setVisibility(View.GONE); historyView.setVisibility(View.GONE); // Fake an adapter. This needs to be fixed later on so we can use the history. setListAdapter(new ArrayAdapter<String>(getActivity(), R.layout.journey_history_row)); } else { setListAdapter(mAdapter); } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Log.d(TAG, "PlannerFragment.onActivityCreated()"); restoreState(savedInstanceState); initViews(); } @Override public void onDestroyView() { Log.d(TAG, "PlannerFragment.onDestroyView()"); setListAdapter(null); mHistoryDbAdapter.close(); super.onDestroyView(); } @Override public void onListItemClick(ListView l, View v, int position, long id) { JourneyQuery journeyQuery = getJourneyQuery(mAdapter.getCursor()); Intent routesIntent = new Intent(getActivity(), RoutesActivity.class); routesIntent.putExtra(RoutesActivity.EXTRA_JOURNEY_QUERY, journeyQuery); startActivity(routesIntent); } @Override public void onResume() { super.onResume(); if (mStartPoint != null && !mStartPoint.hasName()) { mStartPointAutoComplete.setText(""); } if (mEndPoint != null && !mEndPoint.hasName()) { mEndPointAutoComplete.setText(""); } if (mViaPoint != null && !mViaPoint.hasName()) { mViaPointAutoComplete.setText(""); } } private Site buildStop(Site site, AutoCompleteTextView auTextView) { if (site.hasName() && site.getName().equals(auTextView.getText().toString())) { return site; } else if (site.isMyLocation() && auTextView.getText().toString().equals(getString(R.string.my_location))) { // Check for my location. return site; } else if (auTextView.getText().toString().equals(getString(R.string.point_on_map))) { // Check for point-on-map. return site; } site.fromSite(null); return site; } @Override public void onSaveInstanceState(Bundle outState) { outState.putInt("level", mStackLevel); if (mStartPoint != null) outState.putParcelable("startPoint", mStartPoint); if (mEndPoint != null) outState.putParcelable("endPoint", mEndPoint); if (mViaPoint != null) outState.putParcelable("viaPoint", mViaPoint); super.onSaveInstanceState(outState); } private void restoreState(Bundle state) { mStartPoint = new Site(); mEndPoint = new Site(); mViaPoint = new Site(); if (state != null) { Site startPoint = state.getParcelable("startPoint"); Site endPoint = state.getParcelable("endPoint"); Site viaPoint = state.getParcelable("viaPoint"); if (startPoint != null) mStartPoint.fromSite(startPoint); if (endPoint != null) mEndPoint.fromSite(endPoint); if (viaPoint != null) mViaPoint.fromSite(viaPoint); } } private DelayAutoCompleteTextView createAutoCompleteTextView(int autoCompleteResId, int progressResId, final Site site) { return createAutoCompleteTextView(autoCompleteResId, progressResId, site, false); } /** * Creates a new {@link AutoCompleteTextView}. * * @param autoCompleteResId * The {@link AutoCompleteTextView} resource id. * @param progressResId * The {@link ProgressBar} resource id. * @param site * The stop. * @param includeAddresses * If addresses should be included. * @return */ private DelayAutoCompleteTextView createAutoCompleteTextView(int autoCompleteResId, int progressResId, final Site site, boolean includeAddresses) { // TODO: Wrap the auto complete view in a custom view... final DelayAutoCompleteTextView autoCompleteTextView = (DelayAutoCompleteTextView) mSearchView .findViewById(autoCompleteResId); //final ProgressBar progress = (ProgressBar) // mSearchView.findViewById(progressResId); final AutoCompleteStopAdapter stopAdapter = new AutoCompleteStopAdapter(getActivity(), R.layout.autocomplete_item_2line, Planner.getInstance(), includeAddresses); autoCompleteTextView.addTextChangedListener( new ReservedNameTextWatcher(getText(R.string.my_location), autoCompleteTextView)); autoCompleteTextView.addTextChangedListener( new ReservedNameTextWatcher(getText(R.string.point_on_map), autoCompleteTextView)); autoCompleteTextView.addTextChangedListener(new UpdateStopTextWatcher(site)); String name = site.getName(); if (site.isMyLocation()) { name = getString(R.string.my_location); } autoCompleteTextView.setText(name); /* stopAdapter.setFilterListener(new FilterListener() { @Override public void onPublishFiltering() { progress.setVisibility(View.INVISIBLE); } @Override public void onPerformFiltering() { progress.setVisibility(View.VISIBLE); } }); */ autoCompleteTextView.setSelectAllOnFocus(true); autoCompleteTextView.setAdapter(stopAdapter); autoCompleteTextView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // Sometime site is not properly set here, where is the reference cleared? Site v = stopAdapter.getValue(position); site.fromSite(v); } }); /* * OLD autoCompleteTextView.setOnTouchListener(new OnTouchListener() { * * @Override public boolean onTouch(View v, MotionEvent event) { int * stop = autoCompleteTextView.getText().length(); * autoCompleteTextView.setSelection(0, stop); return false; } }); */ return autoCompleteTextView; } /** * On date set listener for the date picker. Sets the new date to the time * member and updates views if the date was changed. */ private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { mTime.year = year; mTime.month = monthOfYear; mTime.monthDay = dayOfMonth; onTimeChanged(); } }; /** * On time set listener for the time picker. Sets the new time to the time * member and updates views if the time was changed. */ private TimePickerDialog.OnTimeSetListener mTimeSetListener = new TimePickerDialog.OnTimeSetListener() { @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { mTime.hour = hourOfDay; mTime.minute = minute; onTimeChanged(); } }; private int mStackLevel; /** * Start the search. * * @param startPoint * the start point * @param endPoint * the end point * @param time * the departure time or null to use current time */ private void onSearchRoutes(Site startPoint, Site endPoint, Site viaPoint, Time time) { // TODO: We should not handle point-on-map this way. But for now we just // want it to work. if (!mStartPointAutoComplete.getText().toString().equals(getString(R.string.point_on_map))) { mHistoryDbAdapter.create(HistoryDbAdapter.TYPE_JOURNEY_PLANNER_SITE, startPoint); } if (!mEndPointAutoComplete.getText().toString().equals(getString(R.string.point_on_map))) { mHistoryDbAdapter.create(HistoryDbAdapter.TYPE_JOURNEY_PLANNER_SITE, endPoint); } if (!TextUtils.isEmpty(mViaPointAutoComplete.getText().toString())) { mHistoryDbAdapter.create(HistoryDbAdapter.TYPE_JOURNEY_PLANNER_SITE, endPoint); } boolean alternativeStops = false; boolean isTimeDeparture = true; RadioGroup chooseTimeGroup = (RadioGroup) mSearchView.findViewById(R.id.planner_choose_time_group); int checkedId = chooseTimeGroup.getCheckedRadioButtonId(); if (checkedId == R.id.planner_check_more_choices) { isTimeDeparture = mWhenSpinner.getSelectedItemId() == 0; CheckBox alternativeCheckBox = (CheckBox) getActivity().findViewById(R.id.planner_alternative_stops); alternativeStops = alternativeCheckBox.isChecked(); } else { // User has checked the "now" checkbox, this forces the time to // be set in the RoutesActivity upon search. time = null; } Log.i(TAG, "START POINT: " + startPoint.toDump()); Log.i(TAG, "END POINT: " + endPoint.toDump()); JourneyQuery journeyQuery = new JourneyQuery.Builder().origin(startPoint).destination(endPoint) .via(viaPoint).isTimeDeparture(isTimeDeparture).time(time) .transportModes(getSelectedTransportModes()).alternativeStops(alternativeStops).create(); Intent routesIntent = new Intent(getActivity(), RoutesActivity.class); routesIntent.putExtra(RoutesActivity.EXTRA_JOURNEY_QUERY, journeyQuery); startActivity(routesIntent); /* * Uri routesUri = RoutesActivity.createRoutesUri( startPoint, endPoint, * time, isTimeDeparture); Intent i = new Intent(Intent.ACTION_VIEW, * routesUri, this, RoutesActivity.class); startActivity(i); */ } private ArrayList<String> getSelectedTransportModes() { CheckBox transportBus = (CheckBox) mSearchView.findViewById(R.id.planner_transport_bus); CheckBox transportMetro = (CheckBox) mSearchView.findViewById(R.id.planner_transport_metro); CheckBox transportNar = (CheckBox) mSearchView.findViewById(R.id.planner_transport_nar); CheckBox transportTrain = (CheckBox) mSearchView.findViewById(R.id.planner_transport_train); CheckBox transportTram = (CheckBox) mSearchView.findViewById(R.id.planner_transport_tram); CheckBox transportWax = (CheckBox) mSearchView.findViewById(R.id.planner_transport_wax); ArrayList<String> transportModes = new ArrayList<String>(); if (transportBus.isChecked()) { transportModes.add(TransportMode.BUS); } if (transportMetro.isChecked()) { transportModes.add(TransportMode.METRO); } if (transportNar.isChecked()) { transportModes.add(TransportMode.NAR); } if (transportTrain.isChecked()) { transportModes.add(TransportMode.TRAIN); } if (transportTram.isChecked()) { transportModes.add(TransportMode.TRAM); } if (transportWax.isChecked()) { transportModes.add(TransportMode.WAX); } return transportModes; } /** * Setup a search short cut. * * @param startPoint * the start point * @param endPoint * the end point */ protected void onCreateShortCut(Site startPoint, Site endPoint, String name) { Uri routesUri = RoutesActivity.createRoutesUri(startPoint, endPoint, null, true); Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, routesUri, getActivity(), RoutesActivity.class); shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // Then, set up the container intent (the response to the caller) Intent intent = new Intent(); intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name); Parcelable iconResource = Intent.ShortcutIconResource.fromContext(getActivity(), R.drawable.shortcut); intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); // Now, return the result to the launcher getActivity().setResult(Activity.RESULT_OK, intent); getActivity().finish(); } private void showDialog(Dialog dialog) { mStackLevel++; // DialogFragment.show() will take care of adding the fragment // in a transaction. We also want to remove any currently showing // dialog, so make our own transaction and take care of that here. // FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction(); // Fragment prev = getActivity().getSupportFragmentManager().findFragmentByTag("dialog"); // if (prev != null) { // ft.remove(prev); // } // ft.addToBackStack(null); // // // Create and show the dialog. DialogFragment newFragment = // DialogFragment newFragment = PlannerDialogFragment.newInstance(dialog); // newFragment.show(ft, "dialog"); // TODO: This resolves an issue that raises a IllegalStateException on // ICS, Investigate if the above is really needed. FragmentTransaction ft = getFragmentManager().beginTransaction(); DialogFragment newFragment = PlannerDialogFragment.newInstance(dialog); ft.add(newFragment, null); ft.commit(); } public static class PlannerDialogFragment extends DialogFragment { private static Dialog mDialog; static PlannerDialogFragment newInstance(Dialog dialog) { mDialog = dialog; PlannerDialogFragment f = new PlannerDialogFragment(); return f; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Quick fix to avoid crash when resuming. if (savedInstanceState != null) { this.dismiss(); } return mDialog; } } private Dialog createDialogReinstallApp() { return new AlertDialog.Builder(getActivity()).setIcon(android.R.drawable.ic_dialog_alert) .setTitle(getText(R.string.attention_label)).setMessage(getText(R.string.reinstall_app_message)) .setPositiveButton(android.R.string.ok, null).create(); } private Dialog createDialogShortcutName() { final View chooseShortcutName = getActivity().getLayoutInflater().inflate(R.layout.create_shortcut_name, null); final EditText shortCutName = (EditText) chooseShortcutName.findViewById(R.id.shortcut_name); return new AlertDialog.Builder(getActivity()).setTitle(R.string.create_shortcut_label) .setView(chooseShortcutName) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { onCreateShortCut(mStartPoint, mEndPoint, shortCutName.getText().toString()); } }).create(); } private Dialog createDialogTime() { // TODO: Base 24 hour on locale, same with the format. return new TimePickerDialog(getActivity(), mTimeSetListener, mTime.hour, mTime.minute, true); } private Dialog createDialogDate() { return new DatePickerDialog(getActivity(), mDateSetListener, mTime.year, mTime.month, mTime.monthDay); } private Dialog createDialogNoLocation() { return new AlertDialog.Builder(getActivity()).setIcon(android.R.drawable.ic_dialog_alert) .setTitle(getText(R.string.no_location_title)).setMessage(getText(R.string.no_location_message)) .setPositiveButton(android.R.string.ok, null).create(); } private Dialog createDialogViaPoint() { AlertDialog.Builder viaPointDialogBuilder = new AlertDialog.Builder(getActivity()); viaPointDialogBuilder.setTitle(getText(R.string.via)); final Cursor historyViaCursor = mHistoryDbAdapter.fetchLatest(); getActivity().startManagingCursor(historyViaCursor); final SelectPointAdapter viaPointAdapter = new SelectPointAdapter(getActivity(), historyViaCursor, true, true); getActivity().stopManagingCursor(historyViaCursor); viaPointDialogBuilder.setAdapter(viaPointAdapter, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { default: Site viaPoint = (Site) viaPointAdapter.getItem(which); mViaPoint = viaPoint; mViaPointAutoComplete.setText(mViaPoint.getName()); mViaPointAutoComplete.clearFocus(); } } }); return viaPointDialogBuilder.create(); } private Dialog createDialogEndPoint() { AlertDialog.Builder endPointDialogBuilder = new AlertDialog.Builder(getActivity()); endPointDialogBuilder.setTitle(getText(R.string.choose_end_point_label)); final Cursor historyDestinationCursor = mHistoryDbAdapter.fetchLatest(); getActivity().startManagingCursor(historyDestinationCursor); final SelectPointAdapter endPointAdapter = new SelectPointAdapter(getActivity(), historyDestinationCursor, false, false); getActivity().stopManagingCursor(historyDestinationCursor); endPointDialogBuilder.setAdapter(endPointAdapter, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: mEndPoint.setName(Site.TYPE_MY_LOCATION); mEndPointAutoComplete.setText(getText(R.string.my_location)); mEndPointAutoComplete.clearFocus(); break; case 1: Intent i = new Intent(getActivity(), PointOnMapActivity.class); i.putExtra(PointOnMapActivity.EXTRA_STOP, mEndPoint); i.putExtra(PointOnMapActivity.EXTRA_HELP_TEXT, getString(R.string.tap_your_end_point_on_map)); startActivityForResult(i, REQUEST_CODE_POINT_ON_MAP_END); break; default: Site endPoint = (Site) endPointAdapter.getItem(which); mEndPoint.fromSite(endPoint); mEndPointAutoComplete.setText(mEndPoint.getName()); mEndPointAutoComplete.clearFocus(); } } }); return endPointDialogBuilder.create(); } private Dialog createDialogStartPoint() { AlertDialog.Builder startPointDialogBuilder = new AlertDialog.Builder(getActivity()); startPointDialogBuilder.setTitle(getText(R.string.choose_start_point_label)); final Cursor historyOriginCursor = mHistoryDbAdapter.fetchLatest(); getActivity().startManagingCursor(historyOriginCursor); final SelectPointAdapter startPointAdapter = new SelectPointAdapter(getActivity(), historyOriginCursor, false, false); getActivity().stopManagingCursor(historyOriginCursor); startPointDialogBuilder.setAdapter(startPointAdapter, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: mStartPoint.setName(Site.TYPE_MY_LOCATION); mStartPointAutoComplete.setText(getText(R.string.my_location)); mStartPointAutoComplete.clearFocus(); break; case 1: Intent i = new Intent(getActivity(), PointOnMapActivity.class); i.putExtra(PointOnMapActivity.EXTRA_STOP, mStartPoint); i.putExtra(PointOnMapActivity.EXTRA_HELP_TEXT, getString(R.string.tap_your_start_point_on_map)); startActivityForResult(i, REQUEST_CODE_POINT_ON_MAP_START); break; default: Site startPoint = (Site) startPointAdapter.getItem(which); mStartPoint.fromSite(startPoint); mStartPointAutoComplete.setText(mStartPoint.getName()); mStartPointAutoComplete.clearFocus(); } } }); return startPointDialogBuilder.create(); } /** * Update time on the buttons. */ private void onTimeChanged() { String formattedDate = mTime.format("%x"); String formattedTime = mTime.format("%R"); mDateButton.setText(formattedDate); mTimeButton.setText(formattedTime); } private void handleSearchAction() { if (TextUtils.isEmpty(mStartPointAutoComplete.getText())) { Log.d(TAG, "Start auto was empty"); mStartPointAutoComplete.setError(getText(R.string.empty_value)); } else if (TextUtils.isEmpty(mEndPointAutoComplete.getText())) { Log.d(TAG, "End auto was empty"); mEndPointAutoComplete.setError(getText(R.string.empty_value)); } else { mStartPoint = buildStop(mStartPoint, mStartPointAutoComplete); mEndPoint = buildStop(mEndPoint, mEndPointAutoComplete); boolean looksValid = true; if (!mStartPoint.looksValid()) { Log.d(TAG, "Start was not valid: " + mStartPoint.toDump()); AutoCompleteStopAdapter a = (AutoCompleteStopAdapter) mStartPointAutoComplete.getAdapter(); Site startPoint = a.findSite(mStartPointAutoComplete.getText().toString()); mStartPoint.fromSite(startPoint); if (startPoint == null) { mStartPointAutoComplete.setError(getText(R.string.empty_value)); looksValid = false; } } if (!mEndPoint.looksValid()) { Log.d(TAG, "End was not valid: " + mEndPoint.toDump()); AutoCompleteStopAdapter a = (AutoCompleteStopAdapter) mEndPointAutoComplete.getAdapter(); Site endPoint = a.findSite(mEndPointAutoComplete.getText().toString()); mEndPoint.fromSite(endPoint); if (endPoint == null) { mEndPointAutoComplete.setError(getText(R.string.empty_value)); looksValid = false; } } if (!TextUtils.isEmpty(mViaPointAutoComplete.getText())) { mViaPoint = buildStop(mViaPoint, mViaPointAutoComplete); if (!mViaPoint.looksValid()) { Log.d(TAG, "Via was not valid"); mViaPointAutoComplete.setError(getText(R.string.empty_value)); looksValid = false; } } if (looksValid) { if (mCreateShortcut) { showDialog(createDialogShortcutName()); // onCreateShortCut(mStartPoint, mEndPoint); } else { onSearchRoutes(mStartPoint, mEndPoint, mViaPoint, mTime); } } } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_CODE_POINT_ON_MAP_START: if (resultCode == Activity.RESULT_CANCELED) { Log.d(TAG, "action canceled"); } else { mStartPoint = data.getParcelableExtra(PointOnMapActivity.EXTRA_STOP); mStartPointAutoComplete.setText(getText(R.string.point_on_map)); // mStartPointAutoComplete.setText(mStartPoint.getName()); Log.d(TAG, "Got Stop " + mStartPoint); } break; case REQUEST_CODE_POINT_ON_MAP_END: if (resultCode == Activity.RESULT_CANCELED) { Log.d(TAG, "action canceled"); } else { mEndPoint = data.getParcelableExtra(PointOnMapActivity.EXTRA_STOP); mEndPointAutoComplete.setText(getText(R.string.point_on_map)); // mEndPointAutoComplete.setText(mEndPoint.getName()); Log.d(TAG, "Got Stop " + mEndPoint); } break; } } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // We only check the state for later radio button. if (isChecked && buttonView.getId() == R.id.planner_check_more_choices) { // Set time to now, and notify buttons about the new time. if (mTime == null) { mTime = new Time(); mTime.setToNow(); onTimeChanged(); } mChangeTimeLayout.setVisibility(View.VISIBLE); } else if (!isChecked && buttonView.getId() == R.id.planner_check_more_choices) { mViaPoint = new Site(); mViaPointAutoComplete.setText(""); mChangeTimeLayout.setVisibility(View.GONE); } } private class UpdateStopTextWatcher implements TextWatcher { private final Site mSite; public UpdateStopTextWatcher(Site site) { mSite = site; } @Override public void afterTextChanged(Editable s) { if (!getString(R.string.my_location).equals(s.toString()) || getString(R.string.point_on_map).equals(s.toString())) { if (!s.toString().equals(mSite.getName())) { mSite.setName(s.toString()); mSite.setId(0); mSite.setType(null); mSite.setLocation(null); } } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // Needed by interface, but not used. } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // Needed by interface, but not used. } } private class ReservedNameTextWatcher implements TextWatcher { private final CharSequence mReservedName; private final AutoCompleteTextView mViewToWatch; private boolean mRemoveText = false; private String mNewText; public ReservedNameTextWatcher(CharSequence reservedName, AutoCompleteTextView viewToWatch) { mReservedName = reservedName; mViewToWatch = viewToWatch; } @Override public void afterTextChanged(Editable s) { if (mRemoveText) { mRemoveText = false; if (!mViewToWatch.getText().toString().equals(mNewText)) { mViewToWatch.setText(mNewText); } } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { if (mRemoveText == false && s.toString().equals(mReservedName.toString())) { mRemoveText = true; mViewToWatch.setTextColor(Color.BLACK); } } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mNewText = s.toString().substring(start, start + count); if (s.toString().equals(mReservedName.toString())) { mViewToWatch.setTextColor(0xFF4F94CD); } } } private class SelectPointAdapter extends MultipleListAdapter { private final Context mContext; private SectionedAdapter mHistoryWrapperAdapter = new SectionedAdapter() { @Override protected View getHeaderView(Section section, int index, View convertView, ViewGroup parent) { TextView result = (TextView) convertView; if (convertView == null) { LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); result = (TextView) inflater.inflate(R.layout.header, null); } result.setText(section.caption); return (result); } }; public SelectPointAdapter(Context context, Cursor historyCursor, boolean onlyHistory, boolean isVia) { mContext = context; if (!onlyHistory) { ArrayList<HashMap<String, String>> items = new ArrayList<HashMap<String, String>>(); HashMap<String, String> myLocationItem = new HashMap<String, String>(); myLocationItem.put("item", getString(R.string.my_location)); items.add(myLocationItem); HashMap<String, String> pointOnMapItem = new HashMap<String, String>(); pointOnMapItem.put("item", getString(R.string.point_on_map)); items.add(pointOnMapItem); SimpleAdapter itemsAdapter = new SimpleAdapter(context, items, android.R.layout.simple_list_item_1, new String[] { "item" }, new int[] { android.R.id.text1 }); addAdapter(0, itemsAdapter); } ArrayList<Site> historyList = new ArrayList<Site>(); historyCursor.moveToFirst(); for (int i = 0; i < historyCursor.getCount(); i++) { Site site = new Site(); site.setName(historyCursor.getString(HistoryDbAdapter.INDEX_NAME)); site.setLocation(historyCursor.getInt(HistoryDbAdapter.INDEX_LATITUDE), historyCursor.getInt(HistoryDbAdapter.INDEX_LONGITUDE)); site.setId(historyCursor.getInt(HistoryDbAdapter.INDEX_SITE_ID)); if (isVia) { if (!site.hasLocation()) { historyList.add(site); } } else { historyList.add(site); } historyCursor.moveToNext(); } historyCursor.close(); ArrayAdapter<Site> historyAdapter = new ArrayAdapter<Site>(context, android.R.layout.simple_list_item_1, historyList); mHistoryWrapperAdapter.addSection(0, getString(R.string.history_label), historyAdapter); addAdapter(1, mHistoryWrapperAdapter); } } private class JourneyAdapter extends CursorAdapter { public JourneyAdapter(Context context, Cursor c) { super(context, c); } @Override public void bindView(View view, Context context, Cursor cursor) { JourneyQuery journeyQuery = getJourneyQuery(cursor); if (journeyQuery != null) { inflateView(view, journeyQuery, cursor); } } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { final LayoutInflater inflater = LayoutInflater.from(context); JourneyQuery journeyQuery = getJourneyQuery(cursor); View v; if (journeyQuery != null) { v = inflater.inflate(R.layout.journey_history_row, parent, false); inflateView(v, journeyQuery, cursor); } else { v = new View(getActivity()); } return v; } private View inflateView(View v, JourneyQuery journeyQuery, Cursor c) { TextView originText = (TextView) v.findViewById(R.id.favorite_start_point); if (Location.TYPE_MY_LOCATION.equals(journeyQuery.origin.name)) { originText.setText(getString(R.string.my_location)); } else { originText.setText(journeyQuery.origin.name); } TextView destinationText = (TextView) v.findViewById(R.id.favorite_end_point); if (Location.TYPE_MY_LOCATION.equals(journeyQuery.destination.name)) { destinationText.setText(getString(R.string.my_location)); } else { destinationText.setText(journeyQuery.destination.name); } View viaView = v.findViewById(R.id.via_row); if (journeyQuery.hasVia()) { TextView viaText = (TextView) v.findViewById(R.id.favorite_via_point); viaText.setText(journeyQuery.via.name); viaView.setVisibility(View.VISIBLE); } else { viaView.setVisibility(View.GONE); } addTransportModeViews(journeyQuery, v); CheckBox starred = (CheckBox) v.findViewById(R.id.journey_star_check); boolean isStarred = c.getInt(COLUMN_INDEX_STARRED) == 1 ? true : false; if (isStarred) { starred.setChecked(true); } else { starred.setChecked(false); } final int id = c.getInt(COLUMN_INDEX_ID); // TODO: Refactor so we can re-use the same click listener. // We're using a click listener instead of an checked listener to // avoid callbacks if the list is modified from code. starred.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { boolean isChecked = ((CheckBox) v).isChecked(); Uri uri = ContentUris.withAppendedId(Journeys.CONTENT_URI, id); ContentValues values = new ContentValues(); if (isChecked) { values.put(Journeys.STARRED, 1); } else { values.put(Journeys.STARRED, 0); } getActivity().getContentResolver().update(uri, values, null, null); } }); return v; } private void addTransportModeViews(JourneyQuery journeyQuery, View v) { // this looks crazy! But we need to reset all transport views so // they don't get recycled and then enable them again if they're // selected for the journey. ImageView metroView = (ImageView) v.findViewById(R.id.favorite_transport_mode_metro); metroView.setVisibility(View.GONE); ImageView busView = (ImageView) v.findViewById(R.id.favorite_transport_mode_bus); busView.setVisibility(View.GONE); ImageView trainView = (ImageView) v.findViewById(R.id.favorite_transport_mode_train); trainView.setVisibility(View.GONE); ImageView tramView = (ImageView) v.findViewById(R.id.favorite_transport_mode_tram); tramView.setVisibility(View.GONE); ImageView waxView = (ImageView) v.findViewById(R.id.favorite_transport_mode_wax); waxView.setVisibility(View.GONE); ImageView narView = (ImageView) v.findViewById(R.id.favorite_transport_mode_nar); narView.setVisibility(View.GONE); if (journeyQuery.transportModes != null) { for (String transportMode : journeyQuery.transportModes) { if (transportMode.equals(TransportMode.METRO)) { metroView.setVisibility(View.VISIBLE); } else if (transportMode.equals(TransportMode.BUS)) { busView.setVisibility(View.VISIBLE); } else if (transportMode.equals(TransportMode.TRAIN)) { trainView.setVisibility(View.VISIBLE); } else if (transportMode.equals(TransportMode.TRAM)) { tramView.setVisibility(View.VISIBLE); } else if (transportMode.equals(TransportMode.WAX)) { waxView.setVisibility(View.VISIBLE); } else if (transportMode.equals(TransportMode.NAR)) { narView.setVisibility(View.VISIBLE); } } } else { metroView.setVisibility(View.VISIBLE); busView.setVisibility(View.VISIBLE); trainView.setVisibility(View.VISIBLE); tramView.setVisibility(View.VISIBLE); waxView.setVisibility(View.VISIBLE); } } } private static JourneyQuery getJourneyQuery(Cursor cursor) { String jsonJourneyQuery; try { // TODO: Investigate if we can add some kind of caching here. jsonJourneyQuery = cursor.getString(COLUMN_INDEX_JOURNEY_DATA); } catch (Exception e) { Log.e(TAG, "Failed to retrieve journey data from the cursor."); return null; } JourneyQuery journeyQuery = null; try { journeyQuery = JourneyQuery.fromJson(new JSONObject(jsonJourneyQuery)); } catch (JSONException e) { Log.e(TAG, "Failed to covert to journey from json."); } return journeyQuery; } }