Back to project page SELP2013.
The source code is released under:
License ======= This work is licensed under the BSD 2-clause license as follows. # BSD 2-clause license Copyright (c) 2013, Sky Welch All rights reserved. Redistribution and use in source and ...
If you think the Android project SELP2013 listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package uk.co.skywelch.selp2013; /*ww w . j av a 2s. c om*/ import java.io.File; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.os.Bundle; import android.os.Environment; import android.preference.PreferenceManager; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.Window; import android.widget.AdapterView; import android.widget.ListView; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; public class TimetableActivity extends ActionBarActivity implements TimetableFragment.OnTimetableItemSelected { public static final String TAG = "TimetableActivity"; public final static String SDRoot = "uk.co.skywelch.selp2013"; public static ArrayList<Lecture> lectures = new ArrayList<Lecture>(); public static TimetableListAdapter checked_semesterone_adapter; public static TimetableListAdapter checked_semestertwo_adapter; public static TimetableListAdapter all_semesterone_adapter; public static TimetableListAdapter all_semestertwo_adapter; public static CourseListAdapter courses_adapter; public static DrawerListAdapter draweradapter; public final static List<StringListItem> drawerItems = Arrays.asList(new StringListItem( "My timetables", true), new StringListItem("My semester 1", false), new StringListItem( "My semester 2", false), new StringListItem("All timetables", true), new StringListItem("All semester 1", false), new StringListItem("All semester 2", false), new StringListItem("Courses", true), new StringListItem("Course list", false)); public static Set<String> course_checks = new HashSet<String>(); public static HashMap<String, Course> course_map = new HashMap<String, Course>(); public static ArrayList<Course> courses = new ArrayList<Course>(); public static final List<String> days = Arrays.asList("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "Unknown"); public static HashMap<String, Venue> venue_map = new HashMap<String, Venue>(); private CharSequence mDrawerTitle; private CharSequence mTitle; private DrawerLayout mDrawerLayout; private View mDrawerView; private ListView mDrawerList; private ActionBarDrawerToggle mDrawerToggle; private MenuItem filesDownloadButton; private static boolean coursesDownloading = false; private static boolean timetableDownloading = false; private static boolean venuesDownloading = false; private static boolean coursesParsing = false; private static boolean timetableParsing = false; private static boolean venuesParsing = false; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Request ability to show progress spinner in the action bar supportRequestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); // Set the appropriate content view setContentView(R.layout.activity_home); // Set the drawer title to that of the application mTitle = mDrawerTitle = getTitle(); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerList = (ListView) findViewById(R.id.left_drawer); mDrawerView = findViewById(R.id.drawer_view); draweradapter = new DrawerListAdapter(this, drawerItems); // Custom shadow for the navigation drawer mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); mDrawerList.setAdapter(draweradapter); mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); // Set up action bar to act as a navigation drawer getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) { public void onDrawerClosed(View view) { getSupportActionBar().setTitle(mTitle); } public void onDrawerOpened(View drawerView) { getSupportActionBar().setTitle(mDrawerTitle); } }; mDrawerLayout.setDrawerListener(mDrawerToggle); // Load course check settings SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); String json_checks = preferences.getString("course_checks", ""); if (!json_checks.equalsIgnoreCase("")) { Log.d(TAG, "Course checks: " + json_checks); Type checkType = new TypeToken<Set<String>>() { }.getType(); course_checks = new Gson().fromJson(json_checks, checkType); } else { Log.d(TAG, "Course checks was empty in SharedPreferences, not adding any checked courses"); } // Decide which navigation drawer view is selected int position = preferences.getInt("selected_menu", -1); if (position == -1) { // Should select the default semester // July - December = semester 1 (position 1) // January - June = semester 2 (position 2) Calendar c = Calendar.getInstance(); int month = c.get(Calendar.MONTH); if (month >= 1 && month <= 6) { position = 2; } else { position = 1; } } selectItem(position); // Set up all the list adapters if (courses_adapter == null) courses_adapter = new CourseListAdapter(this, R.layout.courses_row, TimetableActivity.courses); if (checked_semesterone_adapter == null) checked_semesterone_adapter = new TimetableListAdapter(this, lectures, 1, true, ""); if (checked_semestertwo_adapter == null) checked_semestertwo_adapter = new TimetableListAdapter(this, lectures, 2, true, ""); if (all_semesterone_adapter == null) all_semesterone_adapter = new TimetableListAdapter(this, lectures, 1, false, ""); if (all_semestertwo_adapter == null) all_semestertwo_adapter = new TimetableListAdapter(this, lectures, 2, false, ""); // Download and parse files if necessary String path = Environment.getExternalStorageDirectory().getPath() + "/" + TimetableActivity.SDRoot + "/data/"; Log.d(TAG, path); File SDCardRoot = new File(path); File venues_xml = new File(SDCardRoot, "venues.xml"); File courses_xml = new File(SDCardRoot, "courses.xml"); File timetable_xml = new File(SDCardRoot, "timetable.xml"); if (venues_xml.exists() && TimetableActivity.venue_map.isEmpty()) onVenuesReady(venues_xml); else if (!venues_xml.exists()) { Log.d(TAG, "Venues XML file doesn't appear to exist. Trying to download it..."); downloadVenues(); } if (courses_xml.exists() && TimetableActivity.courses.isEmpty()) onCoursesReady(courses_xml); else if (!courses_xml.exists()) { Log.d(TAG, "Courses XML file doesn't appear to exist. Trying to download it..."); downloadCourses(); } if (timetable_xml.exists() && TimetableActivity.lectures.isEmpty()) onTimetableReady(timetable_xml); else if (!timetable_xml.exists()) { Log.d(TAG, "Timetable XML file doesn't appear to exist. Trying to download it..."); downloadTimetable(); } } // Navigation drawer item click handler private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selectItem(position); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); // Make the manual file download button visible filesDownloadButton = menu.findItem(R.id.action_files_download); filesDownloadButton.setVisible(true); return super.onCreateOptionsMenu(menu); } @Override public boolean onPrepareOptionsMenu(Menu menu) { return super.onPrepareOptionsMenu(menu); } public void downloadCourses() { // Make sure we don't spawn two of the same download jobs if (!coursesDownloading) { FileDownloader coursesDownloader = new FileDownloader() { @Override protected void onPostExecute(Boolean result) { if (result) { Log.d(CoursesParseTask.TAG, "Courses download successful, calling onCoursesReady"); onCoursesReady(file); } else Log.e(CoursesParseTask.TAG, "Download reported as failed, not doing onCoursesReady"); coursesDownloading = false; parseDownloadProgress(); } @Override protected void onProgressUpdate(Integer... progress) { Log.d(CoursesParseTask.TAG, "Progress: " + progress[0]); } }; coursesDownloading = true; parseDownloadProgress(); coursesDownloader.execute( "http://www.inf.ed.ac.uk/teaching/courses/selp/xml/courses.xml", "courses.xml"); } } public void downloadTimetable() { // Make sure we don't spawn two of the same download jobs if (!timetableDownloading) { FileDownloader timetableDownloader = new FileDownloader() { @Override protected void onPostExecute(Boolean result) { if (result) { Log.d(TimetableParseTask.TAG, "Timetable download successful, calling onTimetableReady"); onTimetableReady(file); } else Log.e(TimetableParseTask.TAG, "Download reported as failed, not calling onTimetableReady"); timetableDownloading = false; parseDownloadProgress(); } @Override protected void onProgressUpdate(Integer... progress) { Log.d(TimetableParseTask.TAG, "Progress: " + progress[0]); } }; timetableDownloading = true; parseDownloadProgress(); timetableDownloader.execute( "http://www.inf.ed.ac.uk/teaching/courses/selp/xml/timetable.xml", "timetable.xml"); } } public void downloadVenues() { // Make sure we don't spawn two of the same download jobs if (!venuesDownloading) { FileDownloader venuesDownloader = new FileDownloader() { @Override protected void onPostExecute(Boolean result) { if (result) { Log.d(VenuesParseTask.TAG, "Venues download successful, calling onVenuesReady"); onVenuesReady(file); } else Log.e(VenuesParseTask.TAG, "Download reported as failed, not notifying onVenuesReady"); venuesDownloading = false; parseDownloadProgress(); } @Override protected void onProgressUpdate(Integer... progress) { Log.d(VenuesParseTask.TAG, "Progress: " + progress[0]); } }; venuesDownloading = true; parseDownloadProgress(); venuesDownloader.execute( "http://www.inf.ed.ac.uk/teaching/courses/selp/xml/venues.xml", "venues.xml"); } } @Override public boolean onOptionsItemSelected(MenuItem item) { // Don't do anything if the navigation drawer handled the menu item // click if (mDrawerToggle.onOptionsItemSelected(item)) { return true; } // Handle item selection switch (item.getItemId()) { case R.id.action_about: { Intent i = new Intent(this, AboutActivity.class); startActivity(i); return true; } case R.id.action_files_download: { downloadVenues(); downloadCourses(); downloadTimetable(); return true; } default: return super.onOptionsItemSelected(item); } } // Navigation drawer item selector private void selectItem(int position) { StringListItem item = drawerItems.get(position); // Don't allow selection of section items if (item.isSection()) return; // Items 1-5 are timetable specific views if (position >= 1 && position <= 5) { // Prepare filter options and put them in a bundle to pass to // the TimetableFragment Fragment fragment = new TimetableFragment(); Bundle bundle = new Bundle(); setTitle(item.getText()); switch (position) { case 1: bundle.putInt("semester", 1); bundle.putBoolean("filter_checked", true); break; case 2: bundle.putInt("semester", 2); bundle.putBoolean("filter_checked", true); break; case 4: bundle.putInt("semester", 1); bundle.putBoolean("filter_checked", false); break; case 5: bundle.putInt("semester", 2); bundle.putBoolean("filter_checked", false); break; } fragment.setArguments(bundle); FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit(); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences.Editor editor = preferences.edit(); editor.putInt("selected_menu", position); editor.commit(); Log.d(TAG, "Saving selected view as " + Integer.toString(position)); } else if (position == 7) { // Item 7 is the course list item Intent i = new Intent(this, CourseListActivity.class); startActivity(i); } mDrawerList.setItemChecked(position, true); mDrawerLayout.closeDrawer(mDrawerView); } @Override public void setTitle(CharSequence title) { mTitle = title; getSupportActionBar().setTitle(mTitle); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); // Sync the toggle state after onRestoreInstanceState has occurred mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Pass any configuration change to the drawer toggle mDrawerToggle.onConfigurationChanged(newConfig); } public void onCoursesReady(File file) { CoursesParseTask coursesParser = new CoursesParseTask() { @Override protected void onPostExecute(Boolean result) { if (result) { // Clear whatever courses we already have TimetableActivity.courses.clear(); // Ready for the new ones TimetableActivity.courses.addAll(this.courses); // Repopulate the course map TimetableActivity.course_map.clear(); for (int i = 0; i < TimetableActivity.courses.size(); i++) { Course course = TimetableActivity.courses.get(i); TimetableActivity.course_map.put(course.acronym, course); } Log.d(TAG, "Populated course hashmap with " + Integer.toString(TimetableActivity.course_map.size()) + " items"); TimetableActivity.courses_adapter.notifyDataSetChanged(); } else Log.e(TAG, "Parse reported as failed, not doing course adapter notifications"); coursesParsing = false; parseDownloadProgress(); } @Override protected void onProgressUpdate(Integer... progress) { Log.d(TAG, "Progress: " + progress[0]); } }; coursesParsing = true; coursesParser.execute(file); } // Handles the enabling/disabling of the main progress indicator // and the download button public void parseDownloadProgress() { if (timetableDownloading || coursesDownloading || venuesDownloading || timetableParsing || coursesParsing || venuesParsing) { setSupportProgressBarIndeterminateVisibility(true); if (filesDownloadButton != null) filesDownloadButton.setEnabled(false); } else { setSupportProgressBarIndeterminateVisibility(false); if (filesDownloadButton != null) filesDownloadButton.setEnabled(true); } } public void onTimetableReady(File file) { TimetableParseTask timetableParser = new TimetableParseTask() { @Override protected void onPostExecute(Boolean result) { if (result) { // Clear whatever lectures we already have TimetableActivity.lectures.clear(); // Ready for the new ones TimetableActivity.lectures.addAll(this.lectures); // Check for courses without an expansion and add a dummy // item if necessary int added_courses = 0; for (Lecture l : TimetableActivity.lectures) { if (!l.course.isEmpty() && !TimetableActivity.course_map.containsKey(l.course)) { Course course = new Course("", "", "", "", l.course, false, false, false, false, -1, -1, -1, "", ""); TimetableActivity.courses.add(course); TimetableActivity.course_map.put(l.course, course); added_courses++; Log.d(TimetableParseTask.TAG, "Course code " + l.course + " was missing. Added dummy item for it."); } } if (added_courses > 0) { Log.d(TimetableParseTask.TAG, "Found " + Integer.toString(added_courses) + " timetable items without associated courses. Added dummy items for them."); Collections.sort(TimetableActivity.courses); TimetableActivity.courses_adapter.notifyDataSetChanged(); } resetTimetableAdapters(); } else Log.e(TimetableParseTask.TAG, "Parse reported as failed, not doing timetable adapter notifications"); timetableParsing = false; parseDownloadProgress(); } @Override protected void onProgressUpdate(Integer... progress) { Log.d(TimetableParseTask.TAG, "Progress: " + progress[0]); } }; timetableParsing = true; timetableParser.execute(file); } public void onVenuesReady(File file) { VenuesParseTask venuesParser = new VenuesParseTask() { @Override protected void onPostExecute(Boolean result) { if (result) { // Clear whatever venues we already have TimetableActivity.venue_map.clear(); // Repopulate with the new ones for (Venue venue : this.venues) { if (!venue.name.isEmpty()) { TimetableActivity.venue_map.put(venue.name, venue); } } Log.d(VenuesParseTask.TAG, "Added " + TimetableActivity.venue_map.size() + " items to venue map"); } else Log.e(VenuesParseTask.TAG, "Venues parse reported as failed"); venuesParsing = false; parseDownloadProgress(); } @Override protected void onProgressUpdate(Integer... progress) { Log.d(VenuesParseTask.TAG, "Progress: " + progress[0]); } }; venuesParsing = true; venuesParser.execute(file); } public static void resetTimetableAdapters() { Log.d(TAG, "Resetting timetable adapters"); checked_semesterone_adapter.resetItems(); checked_semestertwo_adapter.resetItems(); all_semesterone_adapter.resetItems(); all_semestertwo_adapter.resetItems(); } // Timetable item long press handler @Override public void onItemLongClicked(final Lecture lecture) { // Build and show the information dialog // Includes the course and venue option String[] info_options = new String[] { "Course (" + lecture.course + ")", "Venue (" + lecture.building + ")" }; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.dialog_info_title); builder.setItems(info_options, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: { if (lecture.course.isEmpty()) { Log.e(TAG, "Didn't get a course code from the long click, button won't do anything."); } else { Intent i = new Intent(TimetableActivity.this, CourseInformationActivity.class); i.putExtra(CourseInformationActivity.COURSE_CODE, lecture.course); startActivity(i); } break; } case 1: { if (lecture.building.isEmpty()) { Log.e(TAG, "Didn't get a venue code from the long click, button won't do anything."); } else { Intent i = new Intent(TimetableActivity.this, VenueInformationActivity.class); i.putExtra(VenueInformationActivity.VENUE_CODE, lecture.building); startActivity(i); } break; } default: Log.e(TAG, "Unknown information option selected, not doing anything."); break; } } }); builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { Log.d(TAG, "Cancel button clicked, ignoring information options"); } }); builder.show(); } }