paarmann.physikprofil.HomeworkUpdater.java Source code

Java tutorial

Introduction

Here is the source code for paarmann.physikprofil.HomeworkUpdater.java

Source

/*
 * Copyright (c) 2015  Sebastian Paarmann
 * Licensed under the MIT license, see the LICENSE file
 */

package paarmann.physikprofil;

import android.content.Context;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.preference.PreferenceManager;

import org.apache.commons.io.IOUtils;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HttpsURLConnection;

/**
 * Class used to get the current homework.
 * Capable of using a cached result and of downloading the most current data.
 */
public class HomeworkUpdater {

    public static final String TAG = "HomeworkUpdater";

    // Used for caching results
    public static String HOMEWORK_FILE = "homework.ser";

    /**
     * The data is returned asynchronously to an OnHomeworkLoadedListener.
     */
    public interface OnHomeworkLoadedListener {
        public void setData(List<HAElement> data);
    }

    private Context context;
    private OnHomeworkLoadedListener listener;

    public HomeworkUpdater(Context context) {
        this.context = context;
    }

    public void setOnHomeworkLoadedListener(OnHomeworkLoadedListener listener) {
        this.listener = listener;
    }

    public void getData() {
        getData(false);
    }

    /**
     * Loads the data and returns it to the currently registered listener.
     * @param forceDownload if true, no cached results will be used
     */
    public void getData(boolean forceDownload) {
        Date now = new Date();
        SharedPreferences prefs = context.getSharedPreferences(MainActivity.PREF_NAME, 0);
        Date lastUpdated = new Date(prefs.getLong(MainActivity.PREF_LASTUPDATED, 0));
        long diffMinutes = Utils.getDateDiff(lastUpdated, now, TimeUnit.MINUTES);

        if (diffMinutes >= 90 || forceDownload) {
            //Last updated longer than 90 minutes ago
            downloadHomework();
        } else {
            loadHomeworkFromFile();
        }
    }

    /**
     * Create a new {@code AsyncTask} for downloading the homework and returning it.
     */
    public void downloadHomework() {
        Log.i(TAG, "Downloading homework");
        DownloadTask task = new DownloadTask();
        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
    }

    /**
     * Create a new {@code AsyncTask} for loading the cached homework and returning it.
     */
    private void loadHomeworkFromFile() {
        Log.i(TAG, "Loading homework from file");
        FileTask task = new FileTask();
        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, false);
    }

    /**
     * Saves the specified data to {@code HOMEWORK_FILE} via serialization.
     * @param data the homework data to be saved
     * @return true if saving succeeded, false otherwise
     */
    private boolean saveHomeworkToFile(List<HAElement> data) {
        ArrayList<HAElement> homework = new ArrayList<HAElement>();
        homework.addAll(data);
        try {
            FileOutputStream fos = context.openFileOutput(HOMEWORK_FILE, Context.MODE_PRIVATE);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(homework);
            oos.close();
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "Failed to save homework", e);
            return false;
        }
        return true;
    }

    /**
     * {@code AsyncTask} for loading cached results from {@code HOMEWORK_FILE}
     */
    private class FileTask extends AsyncTask<Boolean, Void, List<HAElement>> {

        // If cached data is used as fallback after a failed download.
        // A warning is added to the results if this is true.
        private boolean triedDownload;

        @Override
        protected List<HAElement> doInBackground(Boolean... params) {
            triedDownload = params[0];
            try {
                FileInputStream fis = context.openFileInput(HOMEWORK_FILE);
                ObjectInputStream ois = new ObjectInputStream(fis);
                Object readObject = ois.readObject();
                ois.close();

                if (readObject != null && readObject instanceof ArrayList) {
                    return (ArrayList<HAElement>) readObject;
                }
            } catch (IOException e) {
                Log.e(TAG, "Failed to load homework from file", e);
            } catch (ClassNotFoundException e) {
                Log.e(TAG, "Failed to load homework from file", e);
            }
            Log.e(TAG, "ERROR reading list from file.");
            return null;
        }

        @Override
        protected void onPostExecute(List<HAElement> result) {
            if (result != null) {
                // Loading worked
                if (triedDownload) {
                    // Add warning about failed download
                    HAElement warning = new HAElement();
                    warning.id = 0;
                    warning.flags = HAElement.FLAG_WARN;
                    warning.date = "";
                    warning.title = "Achtung";
                    warning.subject = "";
                    warning.desc = "Die Hausaufgaben konnten nicht neu heruntergeladen werden, diese Daten knnten veraltet sein.";
                    result.add(0, warning);
                }
                AutomaticReminderManager.setReminders(context, result);
                if (listener != null) {
                    listener.setData(result);
                }
            } else {
                // Loading failed
                if (!triedDownload) {
                    downloadHomework();
                } else {
                    // No results could be loaded via both caching and downloading. Return an error.
                    result = new ArrayList<HAElement>();
                    HAElement error = new HAElement();
                    error.id = 0;
                    error.flags = HAElement.FLAG_ERROR;
                    error.date = "";
                    error.title = "Fehler";
                    error.subject = "";
                    error.desc = "Die Hausaufgaben konnten weder heruntergeladen werden noch konnten gespeicherte Daten verwendet werden.";
                    result.add(error);
                    if (listener != null) {
                        listener.setData(result);
                    }
                }
            }
        }
    }

    /**
     * {@code AsyncTask} for downloading the current homework.
     */
    private class DownloadTask extends AsyncTask<Void, Void, List<HAElement>> {

        private HAElement errorElement = new HAElement();
        boolean error = false;

        @Override
        protected List<HAElement> doInBackground(Void... params) {
            errorElement.title = "";
            errorElement.subject = "";
            errorElement.date = "";

            try {
                return downloadHA();
            } catch (IOException e) {
                /*errorElement.desc = "Es konnte keine Verbindung zum Server hergestellt werden.";
                errorList.add(errorElement);
                return errorList;*/
                error = true;
                return null;
            }
        }

        @Override
        protected void onPostExecute(List<HAElement> result) {
            if (error) {
                Log.i(TAG, "Could not download homework, instead loading from file.");
                // Try loading cached results instead, indicating a download failed
                FileTask task = new FileTask();
                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, true);
                return;
            }
            AutomaticReminderManager.setReminders(context, result);
            // Save results for later reuse
            saveHomeworkToFile(result);
            if (listener != null) {
                listener.setData(result);
            }

            Date now = new Date();
            SharedPreferences prefs = context.getSharedPreferences(MainActivity.PREF_NAME, 0);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putLong(MainActivity.PREF_LASTUPDATED, now.getTime());
            editor.commit();
        }

        /**
         * Download current homework data from server.
         * @return the downloaded data
         * @throws IOException if downloading fails or there is only a mobile network available and the chose to not use it
         */
        private List<HAElement> downloadHA() throws IOException {
            SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
            boolean useMobile = settings.getBoolean(MainActivity.PREF_MOBILEDATA, true);
            boolean mobileActive = false;

            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo netinfo = cm.getActiveNetworkInfo();
            if (netinfo != null && netinfo.getTypeName().equalsIgnoreCase("MOBILE")) {
                mobileActive = true;
            }

            if (!useMobile && mobileActive) {
                throw new IOException("User chose to not use mobile data");
            }

            InputStream is;

            String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            String strUrl = context.getResources().getString(R.string.server_uri) + "/homework.php?date=" + date
                    + "&following=true";
            URL url = new URL(strUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setReadTimeout(10000);
            conn.setConnectTimeout(15000);
            conn.setRequestMethod("GET");
            conn.setDoInput(true);
            conn.connect();

            is = conn.getInputStream();

            String serverResponse = IOUtils.toString(is, "windows-1252");

            return HAElement.createFromSsp(serverResponse);
        }
    }

}