Java tutorial
/* Copyright 2013 Andrew Joiner 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 uk.co.tekkies.readings.activity; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.InputStreamReader; import java.net.ConnectException; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import uk.co.tekkies.readings.R; import uk.co.tekkies.readings.ReadingsApplication; import uk.co.tekkies.readings.fragment.DatePickerFragment; import uk.co.tekkies.readings.day.DayFragment; import uk.co.tekkies.readings.model.Prefs; import uk.co.tekkies.readings.util.Analytics; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.DatePickerDialog.OnDateSetListener; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.view.ViewPager; 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.DatePicker; import android.widget.Toast; public class ReadingsActivity extends BaseActivity implements OnDateSetListener { static final String NEWS_TOAST_URL = "http://tekkies.co.uk/readings/api/news-toast/"; private static final int CENTER_PAGE = 100; public static Calendar selectedDate = null; SimpleDateFormat thisYearDateFormat; SimpleDateFormat anotherYearDateFormat; SimpleDateFormat dayDateFormat; PagerAdapter pagerAdapter; ViewPager viewPager; Boolean today = true; static ReadingsActivity readingsActivity; static Boolean toastAttempted = false; //Static so toast won't show if already exists in RAM. @SuppressLint("SimpleDateFormat") //We don't actually want local formatting. It's too cluttered. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.readings_activity); readingsActivity = this; configureDateFormats(); ReadingsApplication.checkForMP3Plugin(this); checkUpgradeActions(); checkWhatsNew(); setupPager(); setDateToDisplay(savedInstanceState); checkToast(); } private void checkUpgradeActions() { Prefs prefs = new Prefs(this); reEnableSummariesAt114030217(prefs); } private void reEnableSummariesAt114030217(Prefs prefs) { if (prefs.loadLastRunAppVersion() <= 114030216) { prefs.saveShowSummaries(true); } } private void checkWhatsNew() { if (new Prefs(getApplicationContext()).checkForUpgrade()) { showWhatsNewDialog(); } } private void setDateToDisplay(Bundle savedInstanceState) { if (!loadInstanceState(savedInstanceState)) { setDate(Calendar.getInstance()); } } private void checkToast() { if (!toastAttempted) { toastAttempted = true; showNewsToast(); } } private void configureDateFormats() { dayDateFormat = new SimpleDateFormat("E"); thisYearDateFormat = new SimpleDateFormat("E d MMM"); anotherYearDateFormat = new SimpleDateFormat("E d MMM yy"); } private static Handler newsToastHandler = new Handler() { @Override public void handleMessage(Message msg) { Toast.makeText(readingsActivity, msg.obj.toString(), Toast.LENGTH_LONG).show(); } }; private void showNewsToast() { final String versionName = getVersionName(); Thread thread = new Thread(new Runnable() { @Override public void run() { String summary = backgroundDownloadNewsToast(versionName); if (summary != null && summary != "") { Message message = Message.obtain(newsToastHandler, 0, summary); newsToastHandler.sendMessage(message); } } }); thread.setName("Download news toast"); thread.start(); } private String getVersionName() { String versionName = ""; try { versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; } catch (NameNotFoundException e) { Analytics.reportCaughtException(this, e); } return versionName; } private String backgroundDownloadNewsToast(String versionName) { String summary = null; URL url; try { //Append version, so we can easily prompt users to upgrade, if necessary. url = new URL(NEWS_TOAST_URL + "?v=" + versionName); URLConnection connection = url.openConnection(); connection.connect(); BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); String line = reader.readLine(); //Sanity check message: e.g. We wouldn't want to toast html from a hotspot paywall if (line != null) { if (line.equals("uk.co.tekkies.readings.news-toast")) { line = reader.readLine(); summary = ""; while (line != null) { summary += line + "\n"; line = reader.readLine(); } } } reader.close(); } catch (UnknownHostException e) { //swallow it } catch (ConnectException e) { //swallow it } catch (SocketException e) { //swallow it } catch (FileNotFoundException e) { //swallow it } catch (SocketTimeoutException e) { //swallow it } catch (Exception e) { Analytics.reportCaughtException(this, e); } return summary; } private void setDate(Calendar calendar) { Log.v("DATE", "setDate(" + anotherYearDateFormat.format(new Date(calendar.getTimeInMillis()))); selectedDate = calendar; today = isToday(calendar); viewPager.setAdapter(pagerAdapter); // force refresh viewPager.setCurrentItem(CENTER_PAGE); } private Boolean loadInstanceState(Bundle savedInstanceState) { if (savedInstanceState != null) { Calendar calendar = Calendar.getInstance(); if (savedInstanceState.getBoolean("today")) { setDate(calendar); } else { calendar.set(savedInstanceState.getInt("year"), savedInstanceState.getInt("month"), savedInstanceState.getInt("dayOfMonth")); setDate(calendar); } } return savedInstanceState != null; } private void setupPager() { pagerAdapter = new PagerAdapter(getSupportFragmentManager()); viewPager = (ViewPager) findViewById(R.id.pager); viewPager.setAdapter(pagerAdapter); viewPager.setCurrentItem(CENTER_PAGE); } public class PagerAdapter extends FragmentStatePagerAdapter { public PagerAdapter(FragmentManager fragmentManager) { super(fragmentManager); } @Override public android.support.v4.app.Fragment getItem(int i) { DayFragment fragment = new DayFragment(); Bundle args = new Bundle(); Calendar fragmentSelectedDate = getSelectedDate(i); args.putInt(DayFragment.ARG_YEAR, fragmentSelectedDate.get(Calendar.YEAR)); args.putInt(DayFragment.ARG_MONTH, fragmentSelectedDate.get(Calendar.MONTH)); args.putInt(DayFragment.ARG_DAY, fragmentSelectedDate.get(Calendar.DAY_OF_MONTH)); fragment.setArguments(args); return fragment; } public Calendar getSelectedDate(int i) { Calendar fragmentSelectedDate = (Calendar) selectedDate.clone(); fragmentSelectedDate.add(Calendar.DATE, i - CENTER_PAGE); return fragmentSelectedDate; } @Override public int getCount() { return 200; } @Override public CharSequence getPageTitle(int position) { Calendar pageCalendar = getSelectedDate(position); int pageDay = pageCalendar.get(Calendar.YEAR) * 1000 + pageCalendar.get(Calendar.DAY_OF_YEAR); Calendar nowCalendar = Calendar.getInstance(); int nowDay = nowCalendar.get(Calendar.YEAR) * 1000 + nowCalendar.get(Calendar.DAY_OF_YEAR); String title = ""; Date date = new Date(pageCalendar.getTimeInMillis()); switch (pageDay - nowDay) { case -1: title += getResources().getString(R.string.yesterday) + " (" + dayDateFormat.format(date) + ")"; break; case 0: title += getResources().getString(R.string.today) + " (" + dayDateFormat.format(date) + ")"; break; case 1: title += getResources().getString(R.string.tomorrow) + " (" + dayDateFormat.format(date) + ")"; break; default: { if (pageCalendar.get(Calendar.YEAR) == nowCalendar.get(Calendar.YEAR)) { title += thisYearDateFormat.format(date); } else { title += anotherYearDateFormat.format(date); } } } return title; } @Override public void finishUpdate(ViewGroup container) { super.finishUpdate(container); Calendar calendarPage = getSelectedDate(viewPager.getCurrentItem()); today = isToday(calendarPage); } } private void showWhatsNewDialog() { LayoutInflater inflater = LayoutInflater.from(this); View view = inflater.inflate(R.layout.dialog_whatsnew, null); Builder builder = new AlertDialog.Builder(this); builder.setView(view).setTitle(getString(R.string.whats_new)).setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.activity_main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_brightness: case R.id.menu_brightness_overflow: doDayNightToggle(); return true; case R.id.menu_date: Analytics.UIClick(this, Analytics.LABEL_CUSTOM_DATE); doPickDate(); return true; case R.id.menu_settings: doShowSettings(); return true; case R.id.menu_about: Analytics.UIClick(this, Analytics.LABEL_ABOUT); showAboutDialog(); return true; case R.id.menu_whats_new: Analytics.UIClick(this, Analytics.LABEL_WHATS_NEW); showWhatsNewDialog(); return true; default: return super.onOptionsItemSelected(item); } } private void doShowSettings() { Intent intent = new Intent(this, SettingsActivity.class); startActivity(intent); } private void showAboutDialog() { LayoutInflater inflater = LayoutInflater.from(this); View view = inflater.inflate(R.layout.dialog_about, null); Builder builder = new AlertDialog.Builder(this); String version = ""; try { version = " v" + getPackageManager().getPackageInfo(getPackageName(), 0).versionName; } catch (NameNotFoundException e) { Analytics.reportCaughtException(this, e); } builder.setView(view).setTitle(getString(R.string.app_name) + version).setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); } private void doSuggestion() { String url = "http://goo.gl/pSraf"; Intent webIntent = new Intent(Intent.ACTION_VIEW); Uri uri = Uri.parse(url); webIntent.setData(uri); startActivity(webIntent); } private void doRate() { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=uk.co.tekkies.readings"))); } @Override public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { Calendar calendar = Calendar.getInstance(); calendar.set(year, monthOfYear, dayOfMonth); setDate(calendar); } public void onClickFeedback(View v) { showFeedbackOptions(); } public void onClickHelp(View v) { doHelp(); } private void doHelp() { Analytics.UIClick(getReadingsActivity(), "help"); startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://tekkies.co.uk/bible-reading-app/"))); } private void showFeedbackOptions() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Feedback").setItems(R.array.feedback, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { String[] feedbackText = getResources().getStringArray(R.array.feedback); if (which < feedbackText.length) { Analytics.UIClick(getReadingsActivity(), "feedback:" + feedbackText[which]); } switch (which) { case 0: doSuggestion(); break; case 1: doReportBug(); break; case 2: doRate(); break; case 3: doBetaCommunity(); break; } } }); builder.create().show(); } protected void doBetaCommunity() { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://plus.google.com/communities/110884043096085765786"))); } protected void doReportBug() { final Intent intent = new Intent(android.content.Intent.ACTION_SEND); intent.setType("text/html"); intent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] { getString(R.string.bug_email) }); intent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(R.string.bug_subject)); intent.putExtra(android.content.Intent.EXTRA_TEXT, getString(R.string.bug_content)); startActivity(Intent.createChooser(intent, getString(R.string.bug_chooser_title))); } protected ReadingsActivity getReadingsActivity() { return this; } @Override protected void onSaveInstanceState(Bundle outState) { // super.onSaveInstanceState(outState); Calendar calendar = pagerAdapter.getSelectedDate(viewPager.getCurrentItem()); outState.putInt("year", calendar.get(Calendar.YEAR)); outState.putInt("month", calendar.get(Calendar.MONTH)); outState.putInt("dayOfMonth", calendar.get(Calendar.DAY_OF_MONTH)); outState.putBoolean("today", today); } private void doPickDate() { DatePickerFragment datePickerFragment = new DatePickerFragment(); datePickerFragment.setOnDateSetListener(this); datePickerFragment.show(getSupportFragmentManager(), "datePicker"); } @Override protected void onResume() { if (today) { // If was showing today, but current page is not today Calendar calendar = pagerAdapter.getSelectedDate(viewPager.getCurrentItem()); if (!isToday(calendar)) { setDate(Calendar.getInstance()); } } super.onResume(); } Boolean isToday(Calendar calendar) { Calendar calendarNow = Calendar.getInstance(); return (calendar.get(Calendar.YEAR) == calendarNow.get(Calendar.YEAR)) && (calendar.get(Calendar.DAY_OF_YEAR) == calendarNow.get(Calendar.DAY_OF_YEAR)); } public Calendar getSelectedDate() { return selectedDate; } }