au.com.infiniterecursion.hashqanda.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for au.com.infiniterecursion.hashqanda.MainActivity.java

Source

package au.com.infiniterecursion.hashqanda;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import twitter4j.Query;
import twitter4j.QueryResult;
import twitter4j.Tweet;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.conf.ConfigurationBuilder;
import twitter4j.http.AccessToken;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

/*
 * Main HashQanda Activity 
 * 
 * AUTHORS:
 * 
 * Andy Nicholson
 * 
 * 2011
 * Copyright Infinite Recursion Pty Ltd.
 * http://www.infiniterecursion.com.au
 */

public class MainActivity extends ListActivity {

    private static final String TAG = "hashqanda";
    private HQApp app;

    boolean autoRefreshPreference;
    String str_numberTweets;
    int numberTweets;
    SharedPreferences prefs;

    // UI threaded updater infrastructure
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    ScheduledFuture<?> tweet_loader_handler;

    final Runnable tweet_loader = new Runnable() {
        public void run() {

            Log.d(TAG, " Auto loader starting ");

            tryToStartLoader();

        }
    };

    // Menu ids
    private static final int MENU_ITEM_1 = Menu.FIRST;
    private static final int MENU_ITEM_2 = MENU_ITEM_1 + 1;
    private static final int MENU_ITEM_3 = MENU_ITEM_2 + 1;
    private static final int MENU_ITEM_4 = MENU_ITEM_3 + 1;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);
        app = (HQApp) getApplication();

        Log.d(TAG, "onCreate , launching asynch loading if thread not running ? " + app.isThread_running());

        app.setShowing_tweet_dialog(false);
    }

    public void onResume() {
        super.onResume();

        Log.d(TAG, " on Resume... running thread ? " + app.isThread_running());
        prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());

        autoRefreshPreference = prefs.getBoolean("autoloadingPreference", true);
        str_numberTweets = prefs.getString("numberTweetsPreference", "30");
        numberTweets = Integer.valueOf(str_numberTweets).intValue();

        // set up adapter
        TweetAdapter adapter = new TweetAdapter(this, R.layout.tweet_row, app.getTweetList());
        setListAdapter(adapter);
        app.setListAdapter(adapter);

        tryToStartLoader();

        if (autoRefreshPreference) {
            Log.d(TAG, "Starting autorefresh scheduler");
            tweet_loader_handler = scheduler.scheduleAtFixedRate(tweet_loader, 30, 60, TimeUnit.SECONDS);

        } else {
            tweet_loader_handler = null;
        }

    }

    private void tryToStartLoader() {

        //dont do it, if user in middle of tweeting.
        if (app.isShowing_tweet_dialog())
            return;

        // If we are still running, show dialog again, or else launch threaded
        // loader
        if (app.isThread_running()) {

            ThreadedLoader loader = app.getLoader();
            if (loader != null) {

                loader.showDialog();

            } else {
                Log.e(TAG, "Loader is null, though thread is running ?!");
            }

        } else {

            ThreadedLoader loader = new ThreadedLoader();
            loader.start();
            app.setLoader(loader);

        }
    }

    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, " on Destroy");
    }

    public void onPause() {
        super.onPause();
        Log.d(TAG, " on Pause. running thread ? " + app.isThread_running());

        if (app.isThread_running()) {

            ThreadedLoader loader = app.getLoader();
            if (loader != null) {

                loader.dismissDialog();

            } else {
                Log.e(TAG, "Loader is null, though thread is running ?!");
            }
        }

        // cancel the periodic loader.
        if (tweet_loader_handler != null)
            tweet_loader_handler.cancel(true);

    }

    public int getVersionCode() {
        int v = 0;
        try {
            v = getPackageManager().getPackageInfo(getApplicationInfo().packageName, 0).versionCode;
        } catch (NameNotFoundException e) {
            // Huh? Really?
        }
        return v;
    }

    public String getVersionName() {
        String name = null;
        try {
            name = getPackageManager().getPackageInfo(getApplicationInfo().packageName, 0).versionName;
        } catch (NameNotFoundException e) {
            // Huh? Really?
        }
        return name;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);

        Log.i(TAG, "OnPrepareOptionsMenu called");

        menu.clear();

        addConstantMenuItems(menu);

        return true;
    }

    private void addConstantMenuItems(Menu menu) {
        // ALWAYS ON menu items.
        MenuItem menu_about = menu.add(0, MENU_ITEM_1, 0, R.string.about);
        menu_about.setIcon(R.drawable.wizard48);

        MenuItem menu_tweet = menu.add(0, MENU_ITEM_4, 0, R.string.tweet);
        menu_tweet.setIcon(R.drawable.sun48);

        MenuItem menu_prefs = menu.add(0, MENU_ITEM_2, 0, R.string.preferences);
        menu_prefs.setIcon(R.drawable.options);

        MenuItem menu_refresh = menu.add(0, MENU_ITEM_3, 0, R.string.refresh);
        menu_refresh.setIcon(R.drawable.business48);

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem menuitem) {
        int menuNum = menuitem.getItemId();

        Log.d("MENU", "Option " + menuNum + " selected");

        switch (menuitem.getItemId()) {

        case MENU_ITEM_1:

            // ABOUT
            String mesg = getString(R.string.about_this);
            // find&replace VERSION
            mesg = mesg.replace("VERSION", "version " + getVersionName());

            final SpannableString s = new SpannableString(mesg);
            Linkify.addLinks(s, Linkify.ALL);

            // Licenses
            String mesg2 = getString(R.string.third_party_licenses);

            final SpannableString s2 = new SpannableString(mesg2);
            Linkify.addLinks(s2, Linkify.ALL);

            AlertDialog about = new AlertDialog.Builder(this).setMessage(s)
                    .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {

                        }
                    }).setNegativeButton(R.string.licenses, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {

                            AlertDialog licenses = new AlertDialog.Builder(MainActivity.this).setMessage(s2)
                                    .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int whichButton) {

                                        }
                                    }).show();

                            // makes links work
                            ((TextView) licenses.findViewById(android.R.id.message))
                                    .setMovementMethod(LinkMovementMethod.getInstance());

                        }
                    }).show();

            // makes links work
            ((TextView) about.findViewById(android.R.id.message))
                    .setMovementMethod(LinkMovementMethod.getInstance());

            break;

        case MENU_ITEM_2:

            // Preferences
            Intent intent = new Intent().setClass(this, PreferencesActivity.class);
            this.startActivity(intent);

            break;

        case MENU_ITEM_3:

            // refresh
            tryToStartLoader();

            break;

        case MENU_ITEM_4:

            // tweeting

            String twitterToken, twitterTokenSecret;

            String[] toks = twitterTokens();
            twitterToken = toks[0];
            twitterTokenSecret = toks[1];

            if (twitterToken != null && twitterTokenSecret != null) {
                showTweetDialog();
            } else {

                // Need to authorise.

                Toast.makeText(MainActivity.this,
                        R.string.you_need_to_authorise_this_application_with_twitter_first_, Toast.LENGTH_LONG)
                        .show();

                // Launch Authorisation first.
                Intent intent2 = new Intent().setClass(this, TwitterOAuthActivity.class);
                this.startActivity(intent2);
            }

            break;

        default:
            return super.onOptionsItemSelected(menuitem);
        }

        return true;
    }

    public class ThreadedLoader extends Thread {

        ProgressDialog pdialog;

        public void dismissDialog() {
            MainActivity.this.runOnUiThread(new Runnable() {

                public void run() {
                    if (pdialog != null && pdialog.isShowing()) {
                        pdialog.dismiss();
                    }
                    pdialog = null;
                }
            });

        }

        public void showDialog() {
            // Show dialog on MainActivity UI thread
            MainActivity.this.runOnUiThread(new Runnable() {

                public void run() {

                    if (pdialog == null) {

                        pdialog = ProgressDialog.show(MainActivity.this, "HashQanda",
                                "Loading conversation from twitter. Please wait...", true);

                    }
                }

            });
        }

        public void run() {

            // Tell app we are running
            app.setThread_running(true);

            showDialog();

            // do long running network ops
            final boolean loaded_ok = loadTweets();

            // Dismiss dialog on UI thread, and then either update adapter , or
            // show Toast
            dismissDialog();

            MainActivity.this.runOnUiThread(new Runnable() {

                public void run() {
                    Log.d(TAG, " load Tweets success ? " + loaded_ok);

                    if (loaded_ok) {
                        app.getListAdapter().notifyDataSetChanged();
                    } else {
                        Toast.makeText(MainActivity.this, "Failed to connect to twitter. Sorry", Toast.LENGTH_LONG)
                                .show();
                    }
                }

            });

            // Finally tell app we arent running anymore.
            app.setThread_running(false);

        }

    }

    public class CachedBitmapAndTweet {

        Bitmap bm;
        Tweet twt;

    }

    public boolean loadTweets() {

        ConfigurationBuilder cb = new ConfigurationBuilder();
        cb.setDebugEnabled(true).setOAuthConsumerKey("Q2DfeCNOxprbDp66fWlw")
                .setOAuthConsumerSecret("TgyJ26CKXz1SxGiEJx4HG9rytFsqiMZlEPeCO7S9g");

        Twitter twitter = new TwitterFactory(cb.build()).getInstance();
        // clear tweet list.
        MainActivity.this.runOnUiThread(new Runnable() {

            public void run() {
                // add to it , via the runOnUIThread
                app.getTweetList().clear();
            }

        });

        try {
            Log.d(TAG, " starting Tweets loading ");
            Query q = new Query("#qanda");

            q.setRpp(numberTweets);

            QueryResult result = twitter.search(q);
            List<Tweet> tweets = result.getTweets();
            for (Tweet tweet : tweets) {
                // Log.d(TAG, "@" + tweet.getFromUser() + " - " +
                // tweet.getText());
                // Log.d(TAG, " img url " + tweet.getProfileImageUrl());

                final CachedBitmapAndTweet cachedbmtwt = new CachedBitmapAndTweet();

                cachedbmtwt.twt = tweet;

                try {
                    URL url = new URL(tweet.getProfileImageUrl());
                    InputStream is = (InputStream) url.getContent();

                    if (is != null) {
                        Bitmap bitmap = BitmapFactory.decodeStream(is);
                        cachedbmtwt.bm = bitmap;
                    } else {
                        cachedbmtwt.bm = null;
                    }

                } catch (MalformedURLException e) {
                    e.printStackTrace();
                    cachedbmtwt.bm = null;
                } catch (IOException e) {
                    e.printStackTrace();
                    cachedbmtwt.bm = null;
                } catch (NullPointerException npe) {
                    npe.printStackTrace();
                    cachedbmtwt.bm = null;
                }

                MainActivity.this.runOnUiThread(new Runnable() {

                    public void run() {
                        // add to it , via the runOnUIThread
                        app.getTweetList().add(cachedbmtwt);
                    }

                });

            }

            Log.d(TAG, " finished Tweets loading ");

            return true;

        } catch (TwitterException te) {
            te.printStackTrace();
            Log.d(TAG, "Failed to search tweets: " + te.getMessage());
            return false;
        }
    }

    public class TweetAdapter extends ArrayAdapter<CachedBitmapAndTweet> {
        private ArrayList<CachedBitmapAndTweet> items;
        private TweetViewHolder tweetHolder;

        private class TweetViewHolder {
            ImageView img;
            TextView msg;
        }

        public TweetAdapter(Context context, int tvResId, ArrayList<CachedBitmapAndTweet> items) {
            super(context, tvResId, items);
            this.items = items;
        }

        public View getView(int pos, View convertView, ViewGroup parent) {
            View v = convertView;

            if (v == null) {
                LayoutInflater vi = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.tweet_row, null);
                tweetHolder = new TweetViewHolder();
                tweetHolder.img = (ImageView) v.findViewById(R.id.imageView1);
                tweetHolder.msg = (TextView) v.findViewById(R.id.textView1);
                v.setTag(tweetHolder);
            } else {
                tweetHolder = (TweetViewHolder) v.getTag();
            }

            // check items hasnt been reset
            if (items == null || items.size() == 0) {
                return v;
            }

            CachedBitmapAndTweet bmtwt = items.get(pos);

            if (bmtwt != null) {
                String raw = bmtwt.twt.getFromUser() + " : " + bmtwt.twt.getText();

                final SpannableString text = new SpannableString(raw);
                Linkify.addLinks(text, Linkify.ALL);

                tweetHolder.msg.setText(text);
                tweetHolder.msg.setMovementMethod(LinkMovementMethod.getInstance());

                if (bmtwt.bm != null) {
                    tweetHolder.img.setImageBitmap(bmtwt.bm);
                } else {
                    tweetHolder.img.setImageBitmap(null);
                }
            }

            return v;
        }
    }

    private void showTweetDialog() {

        app.setShowing_tweet_dialog(true);

        // Launch Tweet Edit View
        LayoutInflater inflater = (LayoutInflater) getApplicationContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        final View tweet_dialog_view = inflater.inflate(R.layout.tweet_dialog, null);

        final EditText tweet_edittext = (EditText) tweet_dialog_view.findViewById(R.id.EditTextTweet);

        final Dialog d = new Dialog(this);
        Window w = d.getWindow();
        w.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
        d.setTitle(R.string.tweet_dialog_title);
        // the edit layout defined in an xml file (in res/layout)
        d.setContentView(tweet_dialog_view);
        // Cancel
        Button cbutton = (Button) d.findViewById(R.id.button2Cancel);
        cbutton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {

                app.setShowing_tweet_dialog(false);
                d.dismiss();
            }
        });
        // Edit
        Button ebutton = (Button) d.findViewById(R.id.button1Edit);
        ebutton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                // save title and description to DB.
                String tweet = tweet_edittext.getText().toString();

                int end = (tweet.length() > 133) ? 133 : tweet.length();
                String real_tweet = "#qanda " + tweet.substring(0, end);
                Log.d(TAG, "New tweet is " + tweet);
                Log.d(TAG, "real tweet is " + real_tweet);

                String twitterToken, twitterTokenSecret;
                String[] toks = twitterTokens();
                twitterToken = toks[0];
                twitterTokenSecret = toks[1];

                if (twitterToken != null && twitterTokenSecret != null) {

                    // Ok, now we can tweet this URL
                    AccessToken a = new AccessToken(twitterToken, twitterTokenSecret);
                    Twitter twitter = new TwitterFactory().getInstance();
                    twitter.setOAuthConsumer(TwitterOAuthActivity.consumerKey, TwitterOAuthActivity.consumerSecret);
                    twitter.setOAuthAccessToken(a);

                    try {
                        twitter.updateStatus(real_tweet);
                        runOnUiThread(new Runnable() {
                            public void run() {
                                Toast.makeText(MainActivity.this, R.string.tweet_posted, Toast.LENGTH_LONG).show();
                            }
                        });
                    } catch (TwitterException e) {
                        // 
                        e.printStackTrace();
                        Log.e(TAG, " twittering failed " + e.getMessage());
                    }
                } else {

                    runOnUiThread(new Runnable() {
                        public void run() {
                            Toast.makeText(MainActivity.this, R.string.tweet_not_posted, Toast.LENGTH_LONG).show();
                        }
                    });

                }

                app.setShowing_tweet_dialog(false);
                d.dismiss();
            }
        });
        d.show();
    }

    private String[] twitterTokens() {

        // Check there is a valid twitter OAuth tokens.
        String twitterToken = prefs.getString("twitterToken", null);
        String twitterTokenSecret = prefs.getString("twitterTokenSecret", null);

        return new String[] { twitterToken, twitterTokenSecret };

    }

}