/*
 * Derived from com.android.mms.ui.ConversationList
 * (tag android-4.4.4_r2.0.1)
 */

package ca.bmaupin.merge.sms.ui;

import ca.bmaupin.merge.sms.R;
import ca.bmaupin.merge.sms.data.Contact;
import ca.bmaupin.merge.sms.data.Conversation;
import android.app.ListActivity;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SqliteWrapper;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;
import android.widget.TextView;

public class ConversationList extends ListActivity {
    private static final String TAG = "ConversationList";
    private static final int THREAD_LIST_QUERY_TOKEN       = 1701;
	
    private ThreadListQueryHandler mQueryHandler;
    private ConversationListAdapter mListAdapter;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.conversation_list_screen);
        
        mQueryHandler = new ThreadListQueryHandler(getContentResolver());
        
        ListView listView = getListView();
        
        // Tell the list view which view to display when the list is empty
        listView.setEmptyView(findViewById(R.id.empty));

        initListAdapter();
    }
    
    @Override
    public void onPause() {
        super.onPause();

        // Don't listen for changes while we're paused.
        mListAdapter.setOnContentChangedListener(null);
    }
    
    @Override
    protected void onResume() {
        super.onResume();

        mListAdapter.setOnContentChangedListener(mContentChangedListener);
    }
    
    private final ConversationListAdapter.OnContentChangedListener mContentChangedListener =
            new ConversationListAdapter.OnContentChangedListener() {
            @Override
            public void onContentChanged(ConversationListAdapter adapter) {
                startAsyncQuery();
            }
        };

    private void initListAdapter() {
        mListAdapter = new ConversationListAdapter(this, null);
        mListAdapter.setOnContentChangedListener(mContentChangedListener);
        setListAdapter(mListAdapter);
        getListView().setRecyclerListener(mListAdapter);
    }
    
    @Override
    protected void onStart() {
        super.onStart();

        startAsyncQuery();

        // we invalidate the contact cache here because we want to get updated presence
        // and any contact changes. We don't invalidate the cache by observing presence and contact
        // changes (since that's too untargeted), so as a tradeoff we do it here.
        // If we're in the middle of the app initialization where we're loading the conversation
        // threads, don't invalidate the cache because we're in the process of building it.
        // TODO: think of a better way to invalidate cache more surgically or based on actual
        // TODO: changes we care about
        if (!Conversation.loadingThreads()) {
            Contact.invalidateCache();
        }
    }
    
    @Override
    protected void onStop() {
        super.onStop();

        // Close the cursor in the ListAdapter if the activity stopped.
        Cursor cursor = mListAdapter.getCursor();
        
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }

        mListAdapter.changeCursor(null);
    }
    
    private void startAsyncQuery() {
        try {
            ((TextView)(getListView().getEmptyView())).setText(R.string.loading_conversations);

            Conversation.startQueryForAll(mQueryHandler, THREAD_LIST_QUERY_TOKEN);
        } catch (SQLiteException e) {
            SqliteWrapper.checkSQLiteException(this, e);
        }
    }
    
    private final class ThreadListQueryHandler extends AsyncQueryHandler {
        public ThreadListQueryHandler(ContentResolver contentResolver) {
            super(contentResolver);
        }
        
        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
            switch (token) {
            case THREAD_LIST_QUERY_TOKEN:
                mListAdapter.changeCursor(cursor);

                if (mListAdapter.getCount() == 0) {
                    ((TextView)(getListView().getEmptyView())).setText(R.string.no_conversations);
                }

                break;

            default:
                Log.e(TAG, "onQueryComplete called with unknown token " + token);
            }
        }
    }
}

@@ -117,16 +117,52 @@
 ms.ui;%0A%0A
+import ca.bmaupin.merge.sms.LogTag;%0A
 import c
@@ -565,16 +565,42 @@
 il.Log;%0A
+import android.view.View;%0A
 import a
@@ -3860,32 +3860,1191 @@
    %7D%0A    %7D%0A    %0A
+    @Override%0A    protected void onListItemClick(ListView l, View v, int position, long id) %7B%0A        // Note: don't read the thread id data from the ConversationListItem view passed in.%0A        // It's unreliable to read the cached data stored in the view because the ListItem%0A        // can be recycled, and the same view could be assigned to a different position%0A        // if you click the list item fast enough. Instead, get the cursor at the position%0A        // clicked and load the data from the cursor.%0A        // (ConversationListAdapter extends CursorAdapter, so getItemAtPosition() should%0A        // return the cursor object, which is moved to the position passed in)%0A        Cursor cursor  = (Cursor) getListView().getItemAtPosition(position);%0A        Conversation conv = Conversation.from(this, cursor);%0A        long tid = conv.getThreadId();%0A%0A        if (LogTag.VERBOSE) %7B%0A            Log.d(TAG, %22onListItemClick: pos=%22 + position + %22, view=%22 + v + %22, tid=%22 + tid);%0A        %7D%0A%0A        openThread(tid);%0A    %7D%0A    %0A    private void openThread(long threadId) %7B%0A        startActivity(ComposeMessageActivity.createIntent(this, threadId));%0A    %7D%0A    %0A
     private fina

Add ability to select a conversation thread