/*
* Copyright (C) 2008 Torgny Bjers
*
* 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.xorcode.andtweet;
import org.json.JSONObject;
import android.app.SearchManager;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.SearchRecentSuggestions;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;
import com.xorcode.andtweet.AndTweetService.CommandData;
import com.xorcode.andtweet.AndTweetService.CommandEnum;
import com.xorcode.andtweet.TwitterUser.CredentialsVerified;
import com.xorcode.andtweet.data.AndTweetDatabase;
import com.xorcode.andtweet.data.AndTweetPreferences;
import com.xorcode.andtweet.data.PagedCursorAdapter;
import com.xorcode.andtweet.data.TimelineSearchSuggestionProvider;
import com.xorcode.andtweet.data.TweetBinder;
import com.xorcode.andtweet.data.AndTweetDatabase.Tweets;
import com.xorcode.andtweet.util.SelectionAndArgs;
/**
* @author torgny.bjers
*/
public class TweetListActivity extends TimelineActivity {
private static final String TAG = TweetListActivity.class.getSimpleName();
// Context menu items
public static final int CONTEXT_MENU_ITEM_REPLY = Menu.FIRST + 2;
public static final int CONTEXT_MENU_ITEM_FAVORITE = Menu.FIRST + 3;
public static final int CONTEXT_MENU_ITEM_DIRECT_MESSAGE = Menu.FIRST + 4;
public static final int CONTEXT_MENU_ITEM_UNFOLLOW = Menu.FIRST + 5;
public static final int CONTEXT_MENU_ITEM_BLOCK = Menu.FIRST + 6;
public static final int CONTEXT_MENU_ITEM_RETWEET = Menu.FIRST + 7;
public static final int CONTEXT_MENU_ITEM_PROFILE = Menu.FIRST + 8;
public static final int CONTEXT_MENU_ITEM_DESTROY_FAVORITE = Menu.FIRST + 9;
public static final int CONTEXT_MENU_ITEM_DESTROY_STATUS = Menu.FIRST + 10;
// Views and widgets
private Button mSendButton;
private EditText mEditText;
private TextView mCharsLeftText;
// Text limits
private int mCurrentChars = 0;
private int mLimitChars = 140;
private boolean mInitializing = false;
/**
* Id of the Tweet to which we are replying
*/
protected long mReplyId = 0;
/**
* Id of the Tweet that was selected (clicked, or whose context menu item
* was selected) TODO: clicked, restore position...
*/
protected long mCurrentId = 0;
// Table columns to use for the tweets data
private static final String[] PROJECTION = new String[] {
Tweets._ID, Tweets.AUTHOR_ID, Tweets.MESSAGE, Tweets.IN_REPLY_TO_AUTHOR_ID,
Tweets.FAVORITED, Tweets.SENT_DATE
};
/**
* Called when the activity is first created.
*
* @see android.app.Activity#onCreate(android.os.Bundle)
* @param savedInstanceState
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Log.isLoggable(AndTweetService.APPTAG, Log.VERBOSE)) {
Log.v(TAG, "onCreate");
}
if (savedInstanceState != null) {
if (savedInstanceState.containsKey(AndTweetService.EXTRA_INREPLYTOID)) {
mReplyId = savedInstanceState.getLong(AndTweetService.EXTRA_INREPLYTOID);
}
if (savedInstanceState.containsKey(BUNDLE_KEY_IS_LOADING)) {
mIsLoading = savedInstanceState.getBoolean(BUNDLE_KEY_IS_LOADING);
}
if (savedInstanceState.containsKey(AndTweetService.EXTRA_TWEETID)) {
mCurrentId = savedInstanceState.getLong(AndTweetService.EXTRA_TWEETID);
}
}
// Set up views
mSendButton = (Button) findViewById(R.id.messageEditSendButton);
mEditText = (EditText) findViewById(R.id.edtTweetInput);
mCharsLeftText = (TextView) findViewById(R.id.messageEditCharsLeftTextView);
// Create list footer for loading messages
mListFooter = new LinearLayout(getApplicationContext());
mListFooter.setClickable(false);
getListView().addFooterView(mListFooter);
LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
View tv = inflater.inflate(R.layout.item_loading, null);
mListFooter.addView(tv, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
mListFooter.setVisibility(View.INVISIBLE);
getListView().setOnScrollListener(this);
initUI();
}
@Override
public boolean onSearchRequested() {
Bundle appDataBundle = new Bundle();
appDataBundle.putParcelable("content_uri", AndTweetDatabase.Tweets.SEARCH_URI);
startSearch(null, false, appDataBundle, false);
return true;
}
@Override
public void onNewIntent(Intent newIntent) {
super.onNewIntent(newIntent);
// All actions are actually search actions...
// So get and process search query here
queryListData(newIntent, false, false);
}
/**
* Prepare query to the ContentProvider (to the database) and load List of Tweets with data
* @param queryIntent
* @param otherThread This method is being accessed from other thread
* @param loadOneMorePage load one more page of tweets
*/
protected void queryListData(Intent queryIntent, boolean otherThread, boolean loadOneMorePage) {
// The search query is provided as an "extra" string in the query intent
// TODO maybe use mQueryString here...
String queryString = queryIntent.getStringExtra(SearchManager.QUERY);
Intent intent = getIntent();
if (Log.isLoggable(AndTweetService.APPTAG, Log.VERBOSE)) {
Log.v(TAG, "doSearchQuery; queryString=\"" + queryString + "\"; TimelineType="
+ mTimelineType);
}
Uri contentUri = Tweets.CONTENT_URI;
SelectionAndArgs sa = new SelectionAndArgs();
String sortOrder = Tweets.DEFAULT_SORT_ORDER;
// Id of the last (oldest) tweet to retrieve
long lastItemId = -1;
if (queryString != null && queryString.length() > 0) {
// Record the query string in the recent queries suggestions
// provider
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
TimelineSearchSuggestionProvider.AUTHORITY,
TimelineSearchSuggestionProvider.MODE);
suggestions.saveRecentQuery(queryString, null);
contentUri = Tweets.SEARCH_URI;
contentUri = Uri.withAppendedPath(contentUri, Uri.encode(queryString));
}
intent.putExtra(SearchManager.QUERY, queryString);
if (!contentUri.equals(intent.getData())) {
intent.setData(contentUri);
}
if (sa.nArgs == 0) {
// In fact this is needed every time you want to load next page of
// tweets.
// So we have to duplicate here everything we set in
// com.xorcode.andtweet.TimelineActivity.onOptionsItemSelected()
sa.clear();
sa.addSelection(
Tweets.TWEET_TYPE + " IN (?, ?)",
new String[] {
String.valueOf(Tweets.TIMELINE_TYPE_FRIENDS),
String.valueOf(Tweets.TIMELINE_TYPE_MENTIONS)
});
if (mTimelineType == Tweets.TIMELINE_TYPE_FAVORITES) {
sa.addSelection(AndTweetDatabase.Tweets.FAVORITED + " = ?", new String[] {
"1"
});
}
if (mTimelineType == Tweets.TIMELINE_TYPE_MENTIONS) {
sa.addSelection(Tweets.MESSAGE + " LIKE ?", new String[] {
"%@" + TwitterUser.getTwitterUser().getUsername() + "%"
});
}
}
if (!positionRestored) {
// We have to ensure that saved position will be
// loaded from database into the list
lastItemId = getSavedPosition(true);
}
int nTweets = 0;
if (mCursor != null && !mCursor.isClosed()) {
if (positionRestored) {
// If position is NOT loaded - this cursor is from other
// timeline/search
// and we shouldn't care how much rows are there.
nTweets = mCursor.getCount();
}
if (!otherThread) {
mCursor.close();
}
}
if (lastItemId > 0) {
if (sa.nArgs == 0) {
sa.addSelection(
"AndTweetDatabase.Tweets.TWEET_TYPE" + " IN (?, ?)" + ")",
new String[] {
String.valueOf(Tweets.TIMELINE_TYPE_FRIENDS),
String.valueOf(Tweets.TIMELINE_TYPE_MENTIONS)
});
}
sa.addSelection(Tweets._ID + " >= ?", new String[] {
String.valueOf(lastItemId)
});
} else {
if (loadOneMorePage) {
nTweets += PAGE_SIZE;
} else if (nTweets < PAGE_SIZE) {
nTweets = PAGE_SIZE;
}
sortOrder += " LIMIT 0," + nTweets;
}
// This is for testing pruneOldRecords
// try {
// FriendTimeline fl = new FriendTimeline(TweetListActivity.this,
// AndTweetDatabase.Tweets.TIMELINE_TYPE_FRIENDS);
// fl.pruneOldRecords();
//
// } catch (Exception e) {
// e.printStackTrace();
// }
mCursor = getContentResolver().query(contentUri, PROJECTION, sa.selection,
sa.selectionArgs, sortOrder);
if (!otherThread) {
createAdapters();
}
}
@Override
protected void onStart() {
super.onStart();
if (Log.isLoggable(AndTweetService.APPTAG, Log.VERBOSE)) {
Log.v(TAG, "onStart");
}
Intent intent = getIntent();
queryListData(intent, false, false);
if (hasHardwareKeyboard()) {
// TODO: Only if the EditText is visible!
mEditText.requestFocus();
}
}
@Override
protected void onResume() {
super.onResume();
if (Log.isLoggable(AndTweetService.APPTAG, Log.VERBOSE)) {
Log.v(TAG, "onResume");
}
if (TwitterUser.getTwitterUser().getCredentialsVerified() == CredentialsVerified.SUCCEEDED) {
if (!TwitterUser.getTwitterUser().getSharedPreferences().getBoolean("loadedOnce", false)) {
TwitterUser.getTwitterUser().getSharedPreferences().edit().putBoolean("loadedOnce", true).commit();
// One-time "manually" load tweets from the Internet for the new TwitterUser
manualReload();
}
}
mCharsLeftText.setText(String.valueOf(mLimitChars - mEditText.length()));
}
@Override
protected void onStop() {
super.onStop();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
//disconnectService();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putLong(AndTweetService.EXTRA_INREPLYTOID, mReplyId);
outState.putBoolean(BUNDLE_KEY_IS_LOADING, mIsLoading);
outState.putLong(AndTweetService.EXTRA_TWEETID, mCurrentId);
super.onSaveInstanceState(outState);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
// Get the adapter context menu information
AdapterView.AdapterContextMenuInfo info;
try {
info = (AdapterView.AdapterContextMenuInfo) menuInfo;
} catch (ClassCastException e) {
Log.e(TAG, "bad menuInfo", e);
return;
}
int m = 0;
// Add menu items
menu.add(0, CONTEXT_MENU_ITEM_REPLY, m++, R.string.menu_item_reply);
menu.add(0, CONTEXT_MENU_ITEM_RETWEET, m++, R.string.menu_item_retweet);
// menu.add(0, CONTEXT_MENU_ITEM_DIRECT_MESSAGE, m++,
// R.string.menu_item_direct_message);
// menu.add(0, CONTEXT_MENU_ITEM_UNFOLLOW, m++,
// R.string.menu_item_unfollow);
// menu.add(0, CONTEXT_MENU_ITEM_BLOCK, m++, R.string.menu_item_block);
// menu.add(0, CONTEXT_MENU_ITEM_PROFILE, m++,
// R.string.menu_item_view_profile);
// Get the record for the currently selected item
Uri uri = ContentUris.withAppendedId(Tweets.CONTENT_URI, info.id);
Cursor c = getContentResolver().query(uri, new String[] {
Tweets._ID, Tweets.MESSAGE, Tweets.AUTHOR_ID, Tweets.FAVORITED
}, null, null, null);
try {
c.moveToFirst();
menu.setHeaderTitle(c.getString(c.getColumnIndex(Tweets.MESSAGE)));
if (c.getInt(c.getColumnIndex(Tweets.FAVORITED)) == 1) {
menu.add(0, CONTEXT_MENU_ITEM_DESTROY_FAVORITE, m++,
R.string.menu_item_destroy_favorite);
} else {
menu.add(0, CONTEXT_MENU_ITEM_FAVORITE, m++, R.string.menu_item_favorite);
}
if (AndTweetPreferences.getDefaultSharedPreferences().getString(PreferencesActivity.KEY_TWITTER_USERNAME, null).equals(
c.getString(c.getColumnIndex(Tweets.AUTHOR_ID)))) {
menu.add(0, CONTEXT_MENU_ITEM_DESTROY_STATUS, m++,
R.string.menu_item_destroy_status);
}
} catch (Exception e) {
Log.e(TAG, "onCreateContextMenu: " + e.toString());
} finally {
if (c != null && !c.isClosed())
c.close();
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
super.onContextItemSelected(item);
AdapterView.AdapterContextMenuInfo info;
try {
info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
} catch (ClassCastException e) {
Log.e(TAG, "bad menuInfo", e);
return false;
}
mCurrentId = info.id;
Uri uri;
Cursor c;
switch (item.getItemId()) {
case CONTEXT_MENU_ITEM_REPLY:
uri = ContentUris.withAppendedId(Tweets.CONTENT_URI, info.id);
c = getContentResolver().query(uri, new String[] {
Tweets._ID, Tweets.AUTHOR_ID
}, null, null, null);
try {
c.moveToFirst();
if (hasHardwareKeyboard()) {
mEditText.requestFocus();
}
String reply = "@" + c.getString(c.getColumnIndex(Tweets.AUTHOR_ID)) + " ";
mEditText.setText("");
mEditText.append(reply, 0, reply.length());
mReplyId = c.getLong(c.getColumnIndex(Tweets._ID));
} catch (Exception e) {
Log.e(TAG, "onContextItemSelected: " + e.toString());
return false;
} finally {
if (c != null && !c.isClosed())
c.close();
}
return true;
case CONTEXT_MENU_ITEM_RETWEET:
uri = ContentUris.withAppendedId(Tweets.CONTENT_URI, info.id);
c = getContentResolver().query(uri, new String[] {
Tweets._ID, Tweets.AUTHOR_ID, Tweets.MESSAGE
}, null, null, null);
try {
c.moveToFirst();
if (hasHardwareKeyboard()) {
mEditText.requestFocus();
}
StringBuilder message = new StringBuilder();
String reply = "RT @" + c.getString(c.getColumnIndex(Tweets.AUTHOR_ID)) + " ";
message.append(reply);
CharSequence text = c.getString(c.getColumnIndex(Tweets.MESSAGE));
int len = 140 - reply.length() - 3;
if (text.length() < len) {
len = text.length();
}
message.append(text, 0, len);
if (message.length() == 137) {
message.append("...");
}
mEditText.setText("");
mEditText.append(message, 0, message.length());
} catch (Exception e) {
Log.e(TAG, "onContextItemSelected: " + e.toString());
return false;
} finally {
if (c != null && !c.isClosed())
c.close();
}
return true;
case CONTEXT_MENU_ITEM_DESTROY_STATUS:
sendCommand( new CommandData(CommandEnum.DESTROY_STATUS, mCurrentId));
return true;
case CONTEXT_MENU_ITEM_FAVORITE:
sendCommand( new CommandData(CommandEnum.CREATE_FAVORITE, mCurrentId));
return true;
case CONTEXT_MENU_ITEM_DESTROY_FAVORITE:
sendCommand( new CommandData(CommandEnum.DESTROY_FAVORITE, mCurrentId));
return true;
case CONTEXT_MENU_ITEM_UNFOLLOW:
case CONTEXT_MENU_ITEM_BLOCK:
case CONTEXT_MENU_ITEM_DIRECT_MESSAGE:
case CONTEXT_MENU_ITEM_PROFILE:
Toast.makeText(this, R.string.unimplemented, Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
/**
* Handles threaded sending of the message, typed in the mEditText text box.
* Queued message sending is supported (if initial sending
* failed for some reason).
*/
void updateStatus() {
String status = mEditText.getText().toString();
if (TextUtils.isEmpty(status.trim())) {
Toast.makeText(TweetListActivity.this, R.string.cannot_send_empty_message,
Toast.LENGTH_SHORT).show();
} else {
CommandData commandData = new CommandData(CommandEnum.UPDATE_STATUS);
commandData.bundle.putString(AndTweetService.EXTRA_STATUS, status);
commandData.bundle.putLong(AndTweetService.EXTRA_INREPLYTOID, mReplyId);
sendCommand(commandData);
closeSoftKeyboard();
// Let's assume that everything will be Ok
// so we may clear the text box with the sent tweet
// text...
mReplyId = 0;
mEditText.setText("");
if (hasHardwareKeyboard()) {
mEditText.requestFocus();
}
}
}
/**
* Close the on-screen keyboard.
*/
private void closeSoftKeyboard() {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
}
/**
* Initialize UI
*/
@Override
protected void initUI() {
super.initUI();
mSendButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
updateStatus();
}
});
mEditText.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
mCurrentChars = s.length();
mCharsLeftText.setText(String.valueOf(mLimitChars - mCurrentChars));
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
});
mEditText.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
mCurrentChars = mEditText.length();
if (mCurrentChars == 0) {
mReplyId = 0;
}
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
updateStatus();
return true;
case KeyEvent.KEYCODE_ENTER:
if (event.isAltPressed()) {
mEditText.append("\n");
return true;
}
default:
if (keyCode != KeyEvent.KEYCODE_DEL && mCurrentChars > mLimitChars) {
return true;
}
mCharsLeftText.setText(String.valueOf(mLimitChars - mCurrentChars));
break;
}
}
return false;
}
});
mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (event != null) {
if (event.isAltPressed()) {
return false;
}
}
updateStatus();
return true;
}
});
}
/**
* Create adapters
*/
private void createAdapters() {
int listItemId = R.layout.tweetlist_item;
if (AndTweetPreferences.getDefaultSharedPreferences().getBoolean("appearance_use_avatars", false)) {
listItemId = R.layout.tweetlist_item_avatar;
}
PagedCursorAdapter tweetsAdapter = new PagedCursorAdapter(TweetListActivity.this,
listItemId, mCursor, new String[] {
Tweets.AUTHOR_ID, Tweets.MESSAGE, Tweets.SENT_DATE, Tweets.FAVORITED
}, new int[] {
R.id.tweet_screen_name, R.id.tweet_message, R.id.tweet_sent,
R.id.tweet_favorite
}, getIntent().getData(), PROJECTION, Tweets.DEFAULT_SORT_ORDER);
tweetsAdapter.setViewBinder(new TweetBinder());
setListAdapter(tweetsAdapter);
}
/**
* Listener that checks for clicks on the main list view.
*
* @param adapterView
* @param view
* @param position
* @param id
*/
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
if (Log.isLoggable(AndTweetService.APPTAG, Log.VERBOSE)) {
Log.v(TAG, "onItemClick, id=" + id);
}
if (id <= 0) {
return;
}
Uri uri = ContentUris.withAppendedId(Tweets.CONTENT_URI, id);
String action = getIntent().getAction();
if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) {
if (Log.isLoggable(AndTweetService.APPTAG, Log.DEBUG)) {
Log.d(TAG, "onItemClick, setData=" + uri);
}
setResult(RESULT_OK, new Intent().setData(uri));
} else {
if (Log.isLoggable(AndTweetService.APPTAG, Log.DEBUG)) {
Log.d(TAG, "onItemClick, startActivity=" + uri);
}
startActivity(new Intent(Intent.ACTION_VIEW, uri));
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
mTotalItemCount = totalItemCount;
if (positionRestored && !mIsLoading) {
// Idea from
// http://stackoverflow.com/questions/1080811/android-endless-list
boolean loadMore = (visibleItemCount > 0) && (firstVisibleItem > 0)
&& (firstVisibleItem + visibleItemCount >= totalItemCount);
if (loadMore) {
mIsLoading = true;
Log.d(TAG, "Start Loading more items, total=" + totalItemCount);
// setProgressBarIndeterminateVisibility(true);
mListFooter.setVisibility(View.VISIBLE);
Thread thread = new Thread(mLoadListItems);
thread.start();
}
}
}
/**
* Updates the activity title.
*/
@Override
public void updateTitle() {
// First set less detailed title
super.updateTitle();
// Then start asynchronous task that will set detailed info
sendCommand(new CommandData(CommandEnum.RATE_LIMIT_STATUS));
}
{
/**
* Message handler for messages from threads.
*/
mHandler = new Handler() {
/**
* Message handler
*
* @param msg
*/
@Override
public void handleMessage(Message msg) {
JSONObject result = null;
switch (msg.what) {
case MSG_TWEETS_CHANGED:
int numTweets = msg.arg1;
if (numTweets > 0) {
mNM.cancelAll();
}
break;
case MSG_DATA_LOADING:
mIsLoading = (msg.arg1 == 1) ? true : false;
if (!mIsLoading) {
Toast.makeText(TweetListActivity.this, R.string.timeline_reloaded,
Toast.LENGTH_SHORT).show();
}
break;
case MSG_UPDATE_STATUS:
result = (JSONObject) msg.obj;
if (result == null) {
Toast.makeText(TweetListActivity.this, R.string.error_connection_error,
Toast.LENGTH_LONG).show();
} else if (result.optString("error").length() > 0) {
Toast.makeText(TweetListActivity.this,
(CharSequence) result.optString("error"), Toast.LENGTH_LONG).show();
} else {
// The tweet was sent successfully
Toast.makeText(TweetListActivity.this, R.string.message_sent,
Toast.LENGTH_SHORT).show();
}
break;
case MSG_AUTHENTICATION_ERROR:
mListFooter.setVisibility(View.INVISIBLE);
showDialog(DIALOG_AUTHENTICATION_FAILED);
break;
case MSG_SERVICE_UNAVAILABLE_ERROR:
mListFooter.setVisibility(View.INVISIBLE);
showDialog(DIALOG_SERVICE_UNAVAILABLE);
break;
case MSG_MANUAL_RELOAD:
mIsLoading = false;
Toast.makeText(TweetListActivity.this, R.string.timeline_reloaded,
Toast.LENGTH_SHORT).show();
mListFooter.setVisibility(View.INVISIBLE);
updateTitle();
if (mInitializing) {
mInitializing = false;
bindToService();
}
break;
case MSG_LOAD_ITEMS:
mListFooter.setVisibility(View.INVISIBLE);
switch (msg.arg1) {
case STATUS_LOAD_ITEMS_SUCCESS:
updateTitle();
mListFooter.setVisibility(View.INVISIBLE);
if (positionRestored) {
// This will prevent continuous loading...
if (mCursor.getCount() > getListAdapter().getCount()) {
((SimpleCursorAdapter) getListAdapter()).changeCursor(mCursor);
}
}
mIsLoading = false;
// setProgressBarIndeterminateVisibility(false);
break;
case STATUS_LOAD_ITEMS_FAILURE:
break;
}
break;
case MSG_UPDATED_TITLE:
if (msg.arg1 > 0) {
TweetListActivity.super.updateTitle(msg.arg1 + "/" + msg.arg2);
}
break;
case MSG_CONNECTION_TIMEOUT_EXCEPTION:
mListFooter.setVisibility(View.INVISIBLE);
showDialog(DIALOG_CONNECTION_TIMEOUT);
break;
case MSG_STATUS_DESTROY:
result = (JSONObject) msg.obj;
if (result == null) {
Toast.makeText(TweetListActivity.this, R.string.error_connection_error,
Toast.LENGTH_LONG).show();
} else if (result.optString("error").length() > 0) {
Toast.makeText(TweetListActivity.this,
(CharSequence) result.optString("error"), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(TweetListActivity.this, R.string.status_destroyed,
Toast.LENGTH_SHORT).show();
mCurrentId = 0;
}
break;
case MSG_FAVORITE_CREATE:
result = (JSONObject) msg.obj;
if (result == null) {
Toast.makeText(TweetListActivity.this, R.string.error_connection_error,
Toast.LENGTH_LONG).show();
} else if (result.optString("error").length() > 0) {
Toast.makeText(TweetListActivity.this,
(CharSequence) result.optString("error"), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(TweetListActivity.this, R.string.favorite_created,
Toast.LENGTH_SHORT).show();
mCurrentId = 0;
}
break;
case MSG_FAVORITE_DESTROY:
result = (JSONObject) msg.obj;
if (result == null) {
Toast.makeText(TweetListActivity.this, R.string.error_connection_error,
Toast.LENGTH_LONG).show();
} else if (result.optString("error").length() > 0) {
Toast.makeText(TweetListActivity.this,
(CharSequence) result.optString("error"), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(TweetListActivity.this, R.string.favorite_destroyed,
Toast.LENGTH_SHORT).show();
mCurrentId = 0;
}
break;
case MSG_CONNECTION_EXCEPTION:
switch (msg.arg1) {
case MSG_FAVORITE_CREATE:
case MSG_FAVORITE_DESTROY:
case MSG_STATUS_DESTROY:
try {
dismissDialog(DIALOG_EXECUTING_COMMAND);
} catch (IllegalArgumentException e) {
AndTweetService.d(TAG, "", e);
}
break;
}
Toast.makeText(TweetListActivity.this, R.string.error_connection_error,
Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
};
}
/**
* Load more items from the database into the list. This procedure doesn't
* download any new tweets from the Internet
*/
protected Runnable mLoadListItems = new Runnable() {
public void run() {
if (Log.isLoggable(AndTweetService.APPTAG, Log.VERBOSE)) {
Log.v(TAG, "mLoadListItems run");
}
queryListData(TweetListActivity.this.getIntent(), true, true);
mHandler.sendMessageDelayed(
mHandler.obtainMessage(MSG_LOAD_ITEMS, STATUS_LOAD_ITEMS_SUCCESS, 0), 400);
}
};
}