Java tutorial
/* BusTO - Arrival times for Turin public transports. Copyright (C) 2014 Valerio Bozzolan This program 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. 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package it.reyboz.bustorino; import it.reyboz.bustorino.backend.Stop; import it.reyboz.bustorino.middleware.StopAdapter; import it.reyboz.bustorino.middleware.StopsDB; import it.reyboz.bustorino.middleware.UserDB; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.net.Uri; import android.os.AsyncTask; import android.support.v4.app.NavUtils; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.content.Intent; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import java.util.List; public class ActivityFavorites extends AppCompatActivity { private ListView favoriteListView; private SQLiteDatabase userDB; private EditText bus_stop_name; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_favorites); // this should be done in onStarted and closed in onStop, but apparently onStarted is never run. this.userDB = new UserDB(getApplicationContext()).getWritableDatabase(); ActionBar ab = getSupportActionBar(); assert ab != null; ab.setIcon(R.drawable.ic_launcher); ab.setDisplayHomeAsUpEnabled(true); // Back button favoriteListView = (ListView) findViewById(R.id.favoriteListView); createFavoriteList(); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); if (v.getId() == R.id.favoriteListView) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_favourites_entry, menu); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { // Respond to the action bar's Up/Home button case android.R.id.home: NavUtils.navigateUpFromSameTask(this); return true; } return super.onOptionsItemSelected(item); } @Override public boolean onContextItemSelected(MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); Stop busStop = (Stop) favoriteListView.getItemAtPosition(info.position); switch (item.getItemId()) { case R.id.action_favourite_entry_delete: UserDB.deleteStop(busStop, this.userDB); createFavoriteList(); return true; case R.id.action_rename_bus_stop_username: showBusStopUsernameInputDialog(busStop); return true; case R.id.action_view_on_map: Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(busStop.getGeoURL())); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); return true; default: return super.onContextItemSelected(item); } } void createFavoriteList() { // TODO: memoize default list, query only user names every time? new AsyncGetFavorites(getApplicationContext(), this.userDB).execute(); } public void showBusStopUsernameInputDialog(final Stop busStop) { AlertDialog.Builder builder = new AlertDialog.Builder(this); LayoutInflater inflater = this.getLayoutInflater(); View renameDialogLayout = inflater.inflate(R.layout.rename_dialog, null); bus_stop_name = (EditText) renameDialogLayout.findViewById(R.id.rename_dialog_bus_stop_name); bus_stop_name.setText(busStop.getStopDisplayName()); bus_stop_name.setHint(busStop.getStopDefaultName()); builder.setTitle(getString(R.string.dialog_rename_bus_stop_username_title)); builder.setView(renameDialogLayout); builder.setPositiveButton(getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String busStopUsername = bus_stop_name.getText().toString(); String oldUserName = busStop.getStopUserName(); // changed to none if (busStopUsername.length() == 0) { // unless it was already empty, set new if (oldUserName != null) { busStop.setStopUserName(null); UserDB.updateStop(busStop, userDB); createFavoriteList(); } } else { // changed to something // something different? if (oldUserName == null || !busStopUsername.equals(oldUserName)) { busStop.setStopUserName(busStopUsername); UserDB.updateStop(busStop, userDB); createFavoriteList(); } } } }); builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); builder.setNeutralButton(R.string.dialog_rename_bus_stop_username_reset_button, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // delete user name from database busStop.setStopUserName(null); UserDB.updateStop(busStop, userDB); createFavoriteList(); } }); builder.show(); } /** * This one runs. onStart instead gets ignored for no reason whatsoever. * * @see <a href="https://i.stack.imgur.com/SAX9I.png">Android Activity Lifecycle</a> */ @Override protected void onStop() { super.onStop(); this.userDB.close(); } private class AsyncGetFavorites extends AsyncTask<Void, Void, List<Stop>> { private Context c; private SQLiteDatabase userDB; AsyncGetFavorites(Context c, SQLiteDatabase userDB) { this.c = c; this.userDB = userDB; } @Override protected List<Stop> doInBackground(Void... voids) { StopsDB stopsDB = new StopsDB(c); stopsDB.openIfNeeded(); List<Stop> busStops = UserDB.getFavorites(this.userDB, stopsDB); stopsDB.closeIfNeeded(); return busStops; } @Override protected void onPostExecute(List<Stop> busStops) { // If no data is found show a friendly message if (busStops.size() == 0) { favoriteListView.setVisibility(View.INVISIBLE); TextView favoriteTipTextView = (TextView) findViewById(R.id.favoriteTipTextView); assert favoriteTipTextView != null; favoriteTipTextView.setVisibility(View.VISIBLE); } /* There's a nice method called notifyDataSetChanged() to avoid building the ListView * all over again. This method exists in a billion answers on Stack Overflow, but * it's nowhere to be seen around here, Android Studio can't find it no matter what. * Anyway, it only works from Android 2.3 onward (which is why it refuses to appear, I * guess) and requires to modify the list with .add() and .clear() and some other * methods, so to update a single stop we need to completely rebuild the list for no * reason. It would probably end up as "slow" as throwing away the old ListView and * redrwaing everything. */ // Show results favoriteListView.setAdapter(new StopAdapter(this.c, busStops)); favoriteListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { /** * Casting because of Javamerda * @url http://stackoverflow.com/questions/30549485/androids-list-view-parameterized-type-in-adapterview-onitemclicklistener */ Stop busStop = (Stop) parent.getItemAtPosition(position); Intent intent = new Intent(ActivityFavorites.this, ActivityMain.class); Bundle b = new Bundle(); // TODO: is passing a serialized object a good idea? Or rather, is it reasonably fast? //b.putSerializable("bus-stop-serialized", busStop); b.putString("bus-stop-ID", busStop.ID); b.putString("bus-stop-display-name", busStop.getStopDisplayName()); intent.putExtras(b); //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); // Intent.FLAG_ACTIVITY_CLEAR_TASK isn't supported in API < 11 and we're targeting API 7... intent.setFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); startActivity(intent); finish(); } }); registerForContextMenu(favoriteListView); } } }