com.chalmers.feedlr.service.DataService.java Source code

Java tutorial

Introduction

Here is the source code for com.chalmers.feedlr.service.DataService.java

Source

/*
 * Copyright 2012 Feedlr
 *
 * 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 com.chalmers.feedlr.service;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;

import com.chalmers.feedlr.activity.FeedActivity;
import com.chalmers.feedlr.client.FacebookHelper;
import com.chalmers.feedlr.client.TwitterHelper;
import com.chalmers.feedlr.database.DatabaseHelper;
import com.chalmers.feedlr.model.FacebookItem;

import com.chalmers.feedlr.model.Feed;
import com.chalmers.feedlr.model.TwitterItem;
import com.chalmers.feedlr.model.User;
import com.chalmers.feedlr.parser.FacebookJSONParser;
import com.chalmers.feedlr.parser.TwitterJSONParser;
import com.facebook.android.FacebookError;

import android.app.Service;
import android.content.Intent;
import android.database.Cursor;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

/**
 * The DataService class handles requests, response parsing and database storage
 * of client data. On call from an Activity the service makes the necessary
 * requests to client APIs, parses the received JSON response and stores all
 * relevant data to the application database. When a complete request has been
 * made and all data has successfully been saved to the database a broadcast is
 * made to inform listeners that new data is avalable for display.
 * 
 * @author Olle Werme
 */

public class DataService extends Service {
    private final IBinder binder = new FeedServiceBinder();

    private LocalBroadcastManager lbm;

    private TwitterHelper twitter;
    private FacebookHelper facebook;

    private DatabaseHelper db;

    public class FeedServiceBinder extends Binder {
        DataService getService() {
            return DataService.this;
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        lbm = LocalBroadcastManager.getInstance(DataService.this);

        twitter = new TwitterHelper(this);
        facebook = new FacebookHelper();

        db = new DatabaseHelper(this);

        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return binder;
    }

    /**
     * Simple method for running tasks asynchronous.
     * 
     * @param runnable
     *            the runnable to be run
     */
    private void runAsync(final Runnable runnable) {
        new Thread() {
            @Override
            public void run() {
                runnable.run();
            }
        }.start();
    }

    /**
     * Populates the application database ITEM table with the most recent tweets
     * from the registered users twitter timeline. This method is currently not
     * in use.
     */
    public void updateTwitterTimeline() {
        runAsync(new Runnable() {
            @Override
            public void run() {
                long time = System.currentTimeMillis();

                List<TwitterItem> twitterTimeline = twitter.getTimeline();

                if (twitterTimeline != null) {
                    // Save to database
                    db.addListOfItems(twitterTimeline);
                }

                // Broadcast update to activity
                Intent intent = new Intent();
                intent.setAction(FeedActivity.FEED_UPDATED);
                lbm.sendBroadcast(intent);

                Log.i(TwitterJSONParser.class.getName(), "Time in millis for complete Twitter timeline request: "
                        + (System.currentTimeMillis() - time));
            }
        });
    }

    /**
     * Updates application database USER table with the registered users
     * "following users" from his or her Twitter account, also known as
     * "friends".
     */
    public void updateTwitterUsers() {
        runAsync(new Runnable() {
            @Override
            public void run() {
                long time = System.currentTimeMillis();
                Intent intent = new Intent();

                List<User> users = twitter.getFollowing();

                if (users != null) {
                    // Save to database
                    db.addUsers(users);
                    intent.setAction(FeedActivity.TWITTER_USERS_UPDATED);
                } else {
                    intent.setAction(FeedActivity.TWITTER_USERS_PROBLEM_UPDATING);
                }

                // Broadcast update to activity
                lbm.sendBroadcast(intent);

                Log.i(TwitterJSONParser.class.getName(), "Time in millis for complete Twitter following request: "
                        + (System.currentTimeMillis() - time));
            }
        });
    }

    /**
     * Populates application database ITEM table with the most recent tweets
     * from the user with the given userID within a specific feed.
     * 
     * This method is currently not in use.
     * 
     * @param userID
     *            the id for the user
     * @param feed
     *            the feed that sent the request
     */
    private void updateTweetsByUser(final String userID, final Feed feed) {
        runAsync(new Runnable() {
            @Override
            public void run() {
                long time = System.currentTimeMillis();
                Intent intent = new Intent();

                List<TwitterItem> userTweets = twitter.getUserTweets(userID);
                if (userTweets != null) {
                    db.addListOfItems(userTweets);
                    intent.setAction(FeedActivity.FEED_UPDATED);
                } else {
                    intent.setAction(FeedActivity.FEED_PROBLEM_UPDATING);
                }

                // Broadcast update to activity
                Bundle b = new Bundle();
                b.putString("feedTitle", feed.getTitle());
                intent.putExtras(b);
                lbm.sendBroadcast(intent);

                Log.i(TwitterJSONParser.class.getName(), "Time in millis for complete Twitter user tweets request: "
                        + (System.currentTimeMillis() - time));
            }
        });
    }

    /**
     * Populates application database ITEM table with the most recent tweets
     * from all the users in the specified feed through {@link
     * #updateTweetsByUser(final String userID, final Feed feed)
     * updateTweetsByUser}.
     * 
     * @param feed
     *            the feed to be updated
     */
    public void updateFeedTwitterItems(final Feed feed) {
        runAsync(new Runnable() {
            @Override
            public void run() {
                final List<User> twitterUsersInFeed = new ArrayList<User>();

                Cursor c = db.getUsers(feed, "twitter");
                c.moveToFirst();
                while (!c.isAfterLast()) {
                    User u = new User(c.getString(c.getColumnIndex(DatabaseHelper.USER_COLUMN_USERID)),
                            c.getString(c.getColumnIndex(DatabaseHelper.USER_COLUMN_USERNAME)));
                    twitterUsersInFeed.add(u);
                    c.moveToNext();
                }

                for (User u : twitterUsersInFeed) {
                    updateTweetsByUser(u.getId(), feed);
                }
            }
        });
    }

    /**
     * Updates application database USER table with all the friends the
     * registered user has on its facebook account.
     */

    public void updateFacebookUsers() {
        final long time = System.currentTimeMillis();

        facebook.getFriends(new com.facebook.android.AsyncFacebookRunner.RequestListener() {

            @Override
            public void onComplete(String response, Object state) {
                if (response != null) {
                    List<User> users = new FacebookJSONParser().parseUsers(response);

                    for (User u : users) {
                        u.setSource("facebook");
                        u.setProfileImageURL(facebook.getProfileImageURL(u.getId()));
                    }
                    db.addUsers(users);

                    // Broadcast update to activity
                    Intent intent = new Intent();
                    intent.setAction(FeedActivity.FACEBOOK_USERS_UPDATED);
                    lbm.sendBroadcast(intent);

                    Log.i(FacebookJSONParser.class.getName(),
                            "Time in millis for complete Facebook friends request: "
                                    + (System.currentTimeMillis() - time));
                }
            }

            @Override
            public void onFacebookError(FacebookError e, final Object state) {
                Log.e("Parse", "Facebook Error:" + e.getMessage());
            }

            @Override
            public void onFileNotFoundException(FileNotFoundException e, final Object state) {
                Log.e("Parse", "Resource not found:" + e.getMessage());
            }

            @Override
            public void onIOException(IOException e, final Object state) {
                Log.e("Parse", "Network Error:" + e.getMessage());
            }

            @Override
            public void onMalformedURLException(MalformedURLException e, final Object state) {
                Log.e("Parse", "Invalid URL:" + e.getMessage());
            }
        });
    }

    /**
     * Populates the application database ITEM table with the most recent feed
     * from the registered users facebook timeline.
     * 
     * This method is currently not in use.
     */
    public void updateFacebookTimeline() {
        final long time = System.currentTimeMillis();

        facebook.getTimeline(new com.facebook.android.AsyncFacebookRunner.RequestListener() {

            @Override
            public void onComplete(String response, Object state) {
                if (response != null) {
                    List<FacebookItem> facebookTimeline = new FacebookJSONParser().parseFeed(response);

                    // save to database

                    // Broadcast update to activity
                    Intent intent = new Intent();
                    intent.setAction(FeedActivity.FACEBOOK_USERS_UPDATED);
                    lbm.sendBroadcast(intent);

                    Log.i(FacebookJSONParser.class.getName(),
                            "Time in millis for complete Facebook friends request: "
                                    + (System.currentTimeMillis() - time));
                }
            }

            @Override
            public void onFacebookError(FacebookError e, final Object state) {
                Log.e("Parse", "Facebook Error:" + e.getMessage());
            }

            @Override
            public void onFileNotFoundException(FileNotFoundException e, final Object state) {
                Log.e("Parse", "Resource not found:" + e.getMessage());
            }

            @Override
            public void onIOException(IOException e, final Object state) {
                Log.e("Parse", "Network Error:" + e.getMessage());
            }

            @Override
            public void onMalformedURLException(MalformedURLException e, final Object state) {
                Log.e("Parse", "Invalid URL:" + e.getMessage());
            }
        });

        // Broadcast update to activity
        Intent intent = new Intent();
        intent.setAction(FeedActivity.FACEBOOK_TIMELINE_UPDATED);
        lbm.sendBroadcast(intent);

        Log.i(FacebookJSONParser.class.getName(),
                "Time in millis for complete Facebook timeline request: " + (System.currentTimeMillis() - time));

    }

    /*
     * Populates application database ITEM table with the most recent facebook
     * feed updates from the users in the feed.
     */
    public void updateFeedFacebookItems(final Feed feed) {
        final long time = System.currentTimeMillis();

        final List<User> facebookUsersInFeed = new ArrayList<User>();
        final List<FacebookItem> facebookItemsForUsers = new ArrayList<FacebookItem>();

        Cursor c = db.getUsers(feed, "facebook");

        c.moveToFirst();
        while (!c.isAfterLast()) {
            facebookUsersInFeed.add(new User(c.getString(c.getColumnIndex(DatabaseHelper.USER_COLUMN_USERID)),
                    c.getString(c.getColumnIndex(DatabaseHelper.USER_COLUMN_USERNAME))));
            c.moveToNext();
        }

        facebook.getFeedsForUsers(facebookUsersInFeed,
                new com.facebook.android.AsyncFacebookRunner.RequestListener() {
                    private int responses = 0;

                    @Override
                    public void onComplete(String response, Object state) {

                        try {
                            if (response != null) {
                                facebookItemsForUsers.addAll(new FacebookJSONParser().parseFeed(response));
                            }
                        } catch (Exception e) {
                            Log.e(getClass().getName(), e.getMessage());
                        }
                        responses++;

                        if (responses == facebookUsersInFeed.size()) {
                            onAllComplete();
                        }
                    }

                    private void onAllComplete() {

                        db.addListOfItems(facebookItemsForUsers);

                        // Broadcast update to activity
                        Intent intent = new Intent();
                        intent.setAction(FeedActivity.FEED_UPDATED);
                        Bundle b = new Bundle();
                        b.putString("feedTitle", feed.getTitle());
                        intent.putExtras(b);
                        lbm.sendBroadcast(intent);

                        Log.i(TwitterJSONParser.class.getName(),
                                "Time in millis for complete update of feed \"" + feed.getTitle()
                                        + "\" facebook items request: " + (System.currentTimeMillis() - time));
                    }

                    @Override
                    public void onFacebookError(FacebookError e, final Object state) {
                        Log.e("Parse", "Facebook Error:" + e.getMessage());
                    }

                    @Override
                    public void onFileNotFoundException(FileNotFoundException e, final Object state) {
                        Log.e("Parse", "Resource not found:" + e.getMessage());
                    }

                    @Override
                    public void onIOException(IOException e, final Object state) {
                        Log.e("Parse", "Network Error:" + e.getMessage());
                    }

                    @Override
                    public void onMalformedURLException(MalformedURLException e, final Object state) {
                        Log.e("Parse", "Invalid URL:" + e.getMessage());
                    }
                });
    }
}