ca.spencerelliott.mercury.ChangesetService.java Source code

Java tutorial

Introduction

Here is the source code for ca.spencerelliott.mercury.ChangesetService.java

Source

package ca.spencerelliott.mercury;

/************************************************************************
 * This file is part of Mercury.
 *
 * Mercury 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.
 *
 * Mercury 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 Mercury.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @author Spencer Elliott
 * @author spencer@spencerelliott.ca
 ************************************************************************/

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.xml.sax.SAXException;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.IBinder;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.util.Xml;

public class ChangesetService extends Service {
    //Constants for the index of the different repositories
    private final static int REPO_HGSERVE = 0;
    private final static int REPO_GOOGLECODE = 1;
    private final static int REPO_BITBUCKET = 2;
    private final static int REPO_CODEPLEX = 3;

    //Constants for the index of the different authentication methods in the spinner
    private final static int NONE = 0;
    private final static int HTTP = 1;
    private final static int HTTPS = 2;
    private final static int SSH = 3;

    private int notification_colour = 0;

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        int broadcast_call = intent.getIntExtra("ca.spencerelliott.mercury.call", -1);

        //If this was on boot we want to set up the alarm to set up repeating notifications
        if (broadcast_call == AlarmReceiver.ON_BOOT) {
            //Get the alarm service
            AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());

            //Generate the interval between notifications, default to fifteen minutes
            long interval = Long.parseLong(prefs.getString("notification_interval", "900000"));

            //Create the intents to launch the service again
            Intent new_intent = new Intent("ca.spencerelliott.mercury.REFRESH_CHANGESETS");
            PendingIntent p_intent = PendingIntent.getBroadcast(this, 0, new_intent, 0);

            final Calendar c = Calendar.getInstance();

            //Create a repeating alarm
            alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, c.getTimeInMillis() + interval,
                    interval, p_intent);

            //Stop the service since we're waiting for the interval
            stopSelf();
        }

        //Create a new feed processor
        FeedProcessor processor = new FeedProcessor();

        //Gather all of the URLs from the databases here

        //Let the processor handle all of the URLs and notify the user of any new changesets
        processor.execute();

    }

    //Do not allow binding to this service since it should not be running constantly
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    //This will handle processing all of the feeds for each repository
    private class FeedProcessor extends AsyncTask<URL, Void, Void> {
        @Override
        protected Void doInBackground(URL... params) {
            boolean new_changeset = false;
            String repo_changes = "";

            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());

            String pref_colour = prefs.getString("led_colour", "-16711681");

            try {
                notification_colour = Integer.parseInt(pref_colour);
            } catch (Exception e) {
                notification_colour = Color.CYAN;
            }

            ArrayList<Beans.RepositoryBean> repo_list = null;
            DatabaseHelper db_helper = DatabaseHelper.getInstance(getBaseContext());

            repo_list = db_helper.getAllRepositories(null);

            for (Beans.RepositoryBean repo_type : repo_list) {
                AtomHandler feed_handler = null;

                //Detect the type of repository and create a parser based on that
                switch (repo_type.getType()) {
                case REPO_HGSERVE:
                    feed_handler = new HGWebAtomHandler();
                    break;
                case REPO_GOOGLECODE:
                    feed_handler = new GoogleCodeAtomHandler();
                    break;
                case REPO_BITBUCKET:
                    feed_handler = new BitbucketAtomHandler();
                    break;
                case REPO_CODEPLEX:
                    break;
                }

                HttpResponse response = null;

                try {
                    //Create a new request for the feed based on the url
                    HttpClient httpClient = new DefaultHttpClient();
                    HttpContext localContext = new BasicHttpContext();
                    HttpGet httpGet = new HttpGet(
                            (repo_type.getUrl().endsWith("/") || repo_type.getUrl().endsWith("\\")
                                    ? feed_handler.formatURL(
                                            repo_type.getUrl().substring(0, repo_type.getUrl().length() - 1))
                                    : feed_handler.formatURL(repo_type.getUrl())));

                    //Check to see if the user enabled HTTP authentication
                    if (repo_type.getAuthentication() == HTTP) {
                        //Get their username and password
                        byte[] decrypted_info = (repo_type.getUsername() + ":" + repo_type.getPassword())
                                .getBytes();

                        //Add the header to the http request
                        httpGet.addHeader("Authorization", "Basic " + Base64.encodeBytes(decrypted_info));
                    }

                    //Attempt to load the page from the internet
                    response = httpClient.execute(httpGet, localContext);
                } catch (ClientProtocolException e2) {
                    e2.printStackTrace();
                } catch (IOException e2) {
                    e2.printStackTrace();
                } catch (NullPointerException e3) {

                } catch (Exception e) {

                }

                BufferedReader reader = null;

                //Create a new reader based on the information retrieved
                if (response != null) {
                    try {
                        reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                    } catch (IllegalStateException e1) {
                        e1.printStackTrace();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                } else {
                    continue;
                }

                //Make sure both the feed handler and info loaded from the web are not null
                if (reader != null && feed_handler != null) {
                    try {
                        Xml.parse(reader, feed_handler);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (SAXException e) {
                        e.printStackTrace();
                    }
                } else {
                    continue;
                }

                //Retreive all the beans from the handler
                ArrayList<Beans.ChangesetBean> beans = feed_handler.getAllChangesets();

                //Test the first bean to the last revision entered in the database
                if (!beans.isEmpty()) {
                    if (!db_helper.getLastRev(repo_type.getId()).equals(beans.get(0).getRevisionID())) {
                        new_changeset = true;

                        //Create the string of repositories for the notification
                        if (repo_changes.length() == 0)
                            repo_changes = repo_type.getTitle();
                        else
                            repo_changes += ", " + repo_type.getTitle();

                        //Update the last revision
                        db_helper.updateLastRev(repo_type.getId(), beans.get(0).getRevisionID());
                    }
                }
            }

            //Show a notification if there were any new changesets
            if (new_changeset) {
                NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

                final Calendar c = Calendar.getInstance();

                Notification notification = new Notification(R.drawable.notification_icon,
                        "New changeset available", c.getTimeInMillis());
                notification.flags = Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS;

                //Use the default options for notifications
                notification.defaults = Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE;
                notification.ledARGB = notification_colour;
                notification.ledOffMS = 2000;
                notification.ledOnMS = 200;

                Context context = getApplicationContext();
                CharSequence contentTitle = "New changesets available";
                CharSequence contentText = repo_changes;
                Intent notificationIntent = new Intent(Intent.ACTION_VIEW,
                        Uri.parse("repo://ca.spencerelliott.mercury/browser"));
                PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);

                notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

                nm.notify(1, notification);
            }

            return null;
        }

        @Override
        protected void onPostExecute(Void results) {
            //Once we're done processing the data and notifying the user, stop the service
            stopSelf();
        }

    }

}