de.ub0r.android.smsdroid.ConversationListActivity.java Source code

Java tutorial

Introduction

Here is the source code for de.ub0r.android.smsdroid.ConversationListActivity.java

Source

/*
 * Copyright (C) 2010-2012 Felix Bechstein
 * 
 * This file is part of SMSdroid.
 * 
 * This program 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.
 * 
 * This program 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
 * this program; If not, see <http://www.gnu.org/licenses/>.
 */
package de.ub0r.android.smsdroid;

import java.util.Calendar;
import java.util.HashSet;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog.Builder;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.Window;

import de.ub0r.android.lib.ChangelogHelper;
import de.ub0r.android.lib.DonationHelper;
import de.ub0r.android.lib.Log;
import de.ub0r.android.lib.Market;
import de.ub0r.android.lib.Utils;
import de.ub0r.android.lib.apis.Contact;
import de.ub0r.android.lib.apis.ContactsWrapper;
import de.ub0r.android.smsdroid.grid.R;

/**
 * Main {@link FragmentActivity} showing conversations.
 * 
 * @author flx
 */
public final class ConversationListActivity extends SherlockFragmentActivity
        implements OnItemClickListener, OnItemLongClickListener {
    /** Tag for output. */
    public static final String TAG = "main";

    /** Ad's unit id. */
    private static final String AD_UNITID = "a14b9f701ee348f";

    /** Ad's keywords. */
    public static final HashSet<String> AD_KEYWORDS = new HashSet<String>();
    static {
        AD_KEYWORDS.add("android");
        AD_KEYWORDS.add("mobile");
        AD_KEYWORDS.add("handy");
        AD_KEYWORDS.add("cellphone");
        AD_KEYWORDS.add("google");
        AD_KEYWORDS.add("htc");
        AD_KEYWORDS.add("samsung");
        AD_KEYWORDS.add("motorola");
        AD_KEYWORDS.add("market");
        AD_KEYWORDS.add("app");
        AD_KEYWORDS.add("message");
        AD_KEYWORDS.add("txt");
        AD_KEYWORDS.add("sms");
        AD_KEYWORDS.add("mms");
        AD_KEYWORDS.add("game");
        AD_KEYWORDS.add("websms");
        AD_KEYWORDS.add("amazon");
    }

    /** ORIG_URI to resolve. */
    static final Uri URI = Uri.parse("content://mms-sms/conversations/");

    /** Number of items. */
    private static final int WHICH_N = 6;
    /** Index in dialog: answer. */
    private static final int WHICH_ANSWER = 0;
    /** Index in dialog: answer. */
    private static final int WHICH_CALL = 1;
    /** Index in dialog: view/add contact. */
    private static final int WHICH_VIEW_CONTACT = 2;
    /** Index in dialog: view. */
    private static final int WHICH_VIEW = 3;
    /** Index in dialog: delete. */
    private static final int WHICH_DELETE = 4;
    /** Index in dialog: mark as spam. */
    private static final int WHICH_MARK_SPAM = 5;

    /** Preferences: hide ads. */
    private static boolean prefsNoAds = false;

    /** Minimum date. */
    public static final long MIN_DATE = 10000000000L;
    /** Miliseconds per seconds. */
    public static final long MILLIS = 1000L;

    /** Show contact's photo. */
    public static boolean showContactPhoto = false;
    /** Show emoticons in {@link MessageListActivity}. */
    public static boolean showEmoticons = false;

    /** Dialog items shown if an item was long clicked. */
    private String[] longItemClickDialog = null;

    /** Conversations. */
    private ConversationAdapter adapter = null;

    /** {@link Calendar} holding today 00:00. */
    private static final Calendar CAL_DAYAGO = Calendar.getInstance();
    static {
        // Get time for now - 24 hours
        CAL_DAYAGO.add(Calendar.DAY_OF_MONTH, -1);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onStart() {
        super.onStart();
        AsyncHelper.setAdapter(this.adapter);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onStop() {
        super.onStop();
        AsyncHelper.setAdapter(null);
    }

    /**
     * Get {@link ListView}.
     * 
     * @return {@link ListView}
     */
    private ListView getListView() {
        return (ListView) this.findViewById(android.R.id.list);
    }

    /**
     * Set {@link ListAdapter} to {@link ListView}.
     * 
     * @param la
     *            ListAdapter
     */
    private void setListAdapter(final ListAdapter la) {
        this.getListView().setAdapter(la);
    }

    /**
     * Show all rows of a particular {@link Uri}.
     * 
     * @param context
     *            {@link Context}
     * @param u
     *            {@link Uri}
     */
    static void showRows(final Context context, final Uri u) {
        Log.d(TAG, "-----GET HEADERS-----");
        Log.d(TAG, "-- " + u.toString() + " --");
        Cursor c = context.getContentResolver().query(u, null, null, null, null);
        if (c != null) {
            int l = c.getColumnCount();
            StringBuilder buf = new StringBuilder();
            for (int i = 0; i < l; i++) {
                buf.append(i + ":");
                buf.append(c.getColumnName(i));
                buf.append(" | ");
            }
            Log.d(TAG, buf.toString());
        }

    }

    /**
     * Show rows for debugging purposes.
     * 
     * @param context
     *            {@link Context}
     */
    static void showRows(final Context context) {
        // this.showRows(ContactsWrapper.getInstance().getUriFilter());
        // showRows(context, URI);
        // showRows(context, Uri.parse("content://sms/"));
        // showRows(context, Uri.parse("content://mms/"));
        // showRows(context, Uri.parse("content://mms/part/"));
        // showRows(context, ConversationProvider.CONTENT_URI);
        // showRows(context, Uri.parse("content://mms-sms/threads"));
        // this.showRows(Uri.parse(MessageList.URI));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onNewIntent(final Intent intent) {
        final Intent i = intent;
        if (i != null) {
            Log.d(TAG, "got intent: " + i.getAction());
            Log.d(TAG, "got uri: " + i.getData());
            final Bundle b = i.getExtras();
            if (b != null) {
                Log.d(TAG, "user_query: " + b.get("user_query"));
                Log.d(TAG, "got extra: " + b);
            }
            final String query = i.getStringExtra("user_query");
            Log.d(TAG, "user query: " + query);
            // TODO: do something with search query
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        final Intent i = this.getIntent();
        Log.d(TAG, "got intent: " + i.getAction());
        Log.d(TAG, "got uri: " + i.getData());
        Log.d(TAG, "got extra: " + i.getExtras());

        this.setTheme(PreferencesActivity.getTheme(this));
        Utils.setLocale(this);
        this.setContentView(R.layout.conversationlist);

        ChangelogHelper.showChangelog(this, true);
        final List<ResolveInfo> ri = this.getPackageManager()
                .queryBroadcastReceivers(new Intent("de.ub0r.android.websms.connector.INFO"), 0);
        if (ri.size() == 0) {
            final Intent intent = Market.getInstallAppIntent(this, "de.ub0r.android.websms", Market.ALT_WEBSMS);
            ChangelogHelper.showNotes(this, true, "get WebSMS", null, intent);
        } else {
            ChangelogHelper.showNotes(this, true, null, null, null);
        }

        showRows(this);

        final ListView list = this.getListView();
        this.adapter = new ConversationAdapter(this);
        this.setListAdapter(this.adapter);
        list.setOnItemClickListener(this);
        list.setOnItemLongClickListener(this);
        this.longItemClickDialog = new String[WHICH_N];
        this.longItemClickDialog[WHICH_ANSWER] = this.getString(R.string.reply);
        this.longItemClickDialog[WHICH_CALL] = this.getString(R.string.call);
        this.longItemClickDialog[WHICH_VIEW_CONTACT] = this.getString(R.string.view_contact_);
        this.longItemClickDialog[WHICH_VIEW] = this.getString(R.string.view_thread_);
        this.longItemClickDialog[WHICH_DELETE] = this.getString(R.string.delete_thread_);
        this.longItemClickDialog[WHICH_MARK_SPAM] = this.getString(R.string.filter_spam_);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void onResume() {
        super.onResume();
        prefsNoAds = DonationHelper.hideAds(this);
        if (!prefsNoAds) {
            Ads.loadAd(this, R.id.ad, AD_UNITID, AD_KEYWORDS);
        }
        CAL_DAYAGO.setTimeInMillis(System.currentTimeMillis());
        CAL_DAYAGO.add(Calendar.DAY_OF_MONTH, -1);

        final SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(this);
        showContactPhoto = p.getBoolean(PreferencesActivity.PREFS_CONTACT_PHOTO, true);
        showEmoticons = p.getBoolean(PreferencesActivity.PREFS_EMOTICONS, false);
        this.adapter.startMsgListQuery();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onCreateOptionsMenu(final Menu menu) {
        this.getSupportMenuInflater().inflate(R.menu.conversationlist, menu);
        if (prefsNoAds) {
            menu.removeItem(R.id.item_donate);
        }
        return true;
    }

    /**
     * Mark all messages with a given {@link Uri} as read.
     * 
     * @param context
     *            {@link Context}
     * @param uri
     *            {@link Uri}
     * @param read
     *            read status
     */
    static void markRead(final Context context, final Uri uri, final int read) {
        Log.d(TAG, "markRead(" + uri + "," + read + ")");
        if (uri == null) {
            return;
        }
        String[] sel = Message.SELECTION_UNREAD;
        if (read == 0) {
            sel = Message.SELECTION_READ;
        }
        final ContentResolver cr = context.getContentResolver();
        final ContentValues cv = new ContentValues();
        cv.put(Message.PROJECTION[Message.INDEX_READ], read);
        try {
            cr.update(uri, cv, Message.SELECTION_READ_UNREAD, sel);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "failed update", e);
            Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
        }
        SmsReceiver.updateNewMessageNotification(context, null);
    }

    /**
     * Delete messages with a given {@link Uri}.
     * 
     * @param context
     *            {@link Context}
     * @param uri
     *            {@link Uri}
     * @param title
     *            title of Dialog
     * @param message
     *            message of the Dialog
     * @param activity
     *            {@link Activity} to finish when deleting.
     */
    static void deleteMessages(final Context context, final Uri uri, final int title, final int message,
            final Activity activity) {
        Log.i(TAG, "deleteMessages(..," + uri + " ,..)");
        final Builder builder = new Builder(context);
        builder.setTitle(title);
        builder.setMessage(message);
        builder.setNegativeButton(android.R.string.no, null);
        builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(final DialogInterface dialog, final int which) {
                final int ret = context.getContentResolver().delete(uri, null, null);
                Log.d(TAG, "deleted: " + ret);
                if (activity != null && !activity.isFinishing()) {
                    activity.finish();
                }
                if (ret > 0) {
                    Conversation.flushCache();
                    Message.flushCache();
                    SmsReceiver.updateNewMessageNotification(context, null);
                }
            }
        });
        builder.show();
    }

    /**
     * Add or remove an entry to/from blacklist.
     * 
     * @param context
     *            {@link Context}
     * @param addr
     *            address
     */
    private static void addToOrRemoveFromSpamlist(final Context context, final String addr) {
        final SpamDB db = new SpamDB(context);
        db.open();
        if (!db.isInDB(addr)) {
            db.insertNr(addr);
            Log.d(TAG, "Added " + addr + " to spam list");
        } else {
            db.removeNr(addr);
            Log.d(TAG, "Removed " + addr + " from spam list");
        }
        db.close();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
        case R.id.item_compose:
            final Intent i = getComposeIntent(this, null);
            try {
                this.startActivity(i);
            } catch (ActivityNotFoundException e) {
                Log.e(TAG, "error launching intent: " + i.getAction() + ", " + i.getData());
                Toast.makeText(this, "error launching messaging app!\n" + "Please contact the developer.",
                        Toast.LENGTH_LONG).show();
            }
            return true;
        case R.id.item_settings: // start settings activity
            if (Utils.isApi(Build.VERSION_CODES.HONEYCOMB)) {
                this.startActivity(new Intent(this, Preferences11Activity.class));
            } else {
                this.startActivity(new Intent(this, PreferencesActivity.class));
            }
            return true;
        case R.id.item_donate:
            DonationHelper.startDonationActivity(this, true);
            return true;
        case R.id.item_delete_all_threads:
            deleteMessages(this, Uri.parse("content://sms/"), R.string.delete_threads_,
                    R.string.delete_threads_question, null);
            return true;
        case R.id.item_mark_all_read:
            markRead(this, Uri.parse("content://sms/"), 1);
            markRead(this, Uri.parse("content://mms/"), 1);
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    /**
     * Get a {@link Intent} for sending a new message.
     * 
     * @param context
     *            {@link Context}
     * @param address
     *            address
     * @return {@link Intent}
     */
    static Intent getComposeIntent(final Context context, final String address) {
        final Intent i = new Intent(Intent.ACTION_SENDTO);
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (address == null) {
            i.setData(Uri.parse("sms:"));
        } else {
            i.setData(Uri.parse("smsto:" + PreferencesActivity.fixNumber(context, address)));
        }
        return i;
    }

    /**
     * {@inheritDoc}
     */
    public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
        final Conversation c = Conversation.getConversation(this, (Cursor) parent.getItemAtPosition(position),
                false);
        final Uri target = c.getUri();
        final Intent i = new Intent(this, MessageListActivity.class);
        i.setData(target);
        try {
            this.startActivity(i);
        } catch (ActivityNotFoundException e) {
            Log.e(TAG, "error launching intent: " + i.getAction() + ", " + i.getData());
            Toast.makeText(this, "error launching messaging app!\n" + "Please contact the developer.",
                    Toast.LENGTH_LONG).show();
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean onItemLongClick(final AdapterView<?> parent, final View view, final int position,
            final long id) {
        final Conversation c = Conversation.getConversation(this, (Cursor) parent.getItemAtPosition(position),
                true);
        final Uri target = c.getUri();
        Builder builder = new Builder(this);
        String[] items = this.longItemClickDialog;
        final Contact contact = c.getContact();
        final String a = contact.getNumber();
        Log.d(TAG, "p: " + a);
        final String n = contact.getName();
        if (TextUtils.isEmpty(n)) {
            builder.setTitle(a);
            items = items.clone();
            items[WHICH_VIEW_CONTACT] = this.getString(R.string.add_contact_);
        } else {
            builder.setTitle(n);
        }
        final SpamDB db = new SpamDB(this.getApplicationContext());
        db.open();
        if (db.isInDB(a)) {
            items = items.clone();
            items[WHICH_MARK_SPAM] = this.getString(R.string.dont_filter_spam_);
        }
        db.close();
        builder.setItems(items, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(final DialogInterface dialog, final int which) {
                Intent i = null;
                switch (which) {
                case WHICH_ANSWER:
                    ConversationListActivity.this.startActivity(getComposeIntent(ConversationListActivity.this, a));
                    break;
                case WHICH_CALL:
                    i = new Intent(Intent.ACTION_VIEW, Uri.parse("tel:" + a));
                    ConversationListActivity.this.startActivity(i);
                    break;
                case WHICH_VIEW_CONTACT:
                    if (n == null) {
                        i = ContactsWrapper.getInstance().getInsertPickIntent(a);
                        Conversation.flushCache();
                    } else {
                        final Uri uri = c.getContact().getUri();
                        i = new Intent(Intent.ACTION_VIEW, uri);
                    }
                    ConversationListActivity.this.startActivity(i);
                    break;
                case WHICH_VIEW:
                    i = new Intent(ConversationListActivity.this, MessageListActivity.class);
                    i.setData(target);
                    ConversationListActivity.this.startActivity(i);
                    break;
                case WHICH_DELETE:
                    ConversationListActivity.deleteMessages(ConversationListActivity.this, target,
                            R.string.delete_thread_, R.string.delete_thread_question, null);
                    break;
                case WHICH_MARK_SPAM:
                    ConversationListActivity.addToOrRemoveFromSpamlist(ConversationListActivity.this,
                            c.getContact().getNumber());
                    break;
                default:
                    break;
                }
            }
        });
        builder.create().show();
        return true;
    }

    /**
     * Convert time into formated date.
     * 
     * @param context
     *            {@link Context}
     * @param time
     *            time
     * @return formated date.
     */
    static String getDate(final Context context, final long time) {
        long t = time;
        if (t < MIN_DATE) {
            t *= MILLIS;
        }
        if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PreferencesActivity.PREFS_FULL_DATE,
                false)) {
            return DateFormat.getTimeFormat(context).format(t) + " " + DateFormat.getDateFormat(context).format(t);
        } else if (t < CAL_DAYAGO.getTimeInMillis()) {
            return DateFormat.getDateFormat(context).format(t);
        } else {
            return DateFormat.getTimeFormat(context).format(t);
        }
    }
}