com.dwdesign.tweetings.service.TweetingsService.java Source code

Java tutorial

Introduction

Here is the source code for com.dwdesign.tweetings.service.TweetingsService.java

Source

/*
 *            Tweetings - Twitter client for Android
 * 
 * Copyright (C) 2012-2013 RBD Solutions Limited <apps@tweetings.net>
 * Copyright (C) 2012 Mariotaku Lee <mariotaku.lee@gmail.com>
 *
 * 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 com.dwdesign.tweetings.service;

import static com.dwdesign.tweetings.util.Utils.buildQueryUri;
import static com.dwdesign.tweetings.util.Utils.getAccountUsername;
import static com.dwdesign.tweetings.util.Utils.getActivatedAccountIds;
import static com.dwdesign.tweetings.util.Utils.getAllStatusesIds;
import static com.dwdesign.tweetings.util.Utils.getImagePathFromUri;
import static com.dwdesign.tweetings.util.Utils.getImageUploadStatus;
import static com.dwdesign.tweetings.util.Utils.getTwitterInstance;
import static com.dwdesign.tweetings.util.Utils.hasActiveConnection;
import static com.dwdesign.tweetings.util.Utils.isNullOrEmpty;
import static com.dwdesign.tweetings.util.Utils.getNewestMessageIdsFromDatabase;
import static com.dwdesign.tweetings.util.Utils.getNewestStatusIdsFromDatabase;
import static com.dwdesign.tweetings.util.Utils.makeCachedUserContentValues;
import static com.dwdesign.tweetings.util.Utils.makeDirectMessageContentValues;
import static com.dwdesign.tweetings.util.Utils.makeStatusContentValues;
import static com.dwdesign.tweetings.util.Utils.makeTrendsContentValues;
import static com.dwdesign.tweetings.util.Utils.notifyForUpdatedUri;
import static com.dwdesign.tweetings.util.Utils.parseInt;
import static com.dwdesign.tweetings.util.Utils.parseString;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.dwdesign.tweetings.Constants;
import com.dwdesign.tweetings.HttpClientFactory;
import com.dwdesign.tweetings.ITweetingsService;
import com.dwdesign.tweetings.R;
import com.dwdesign.tweetings.activity.HomeActivity;
import com.dwdesign.tweetings.app.TweetingsApplication;
import com.dwdesign.tweetings.provider.TweetStore;
import com.dwdesign.tweetings.provider.TweetStore.CachedTrends;
import com.dwdesign.tweetings.provider.TweetStore.CachedUsers;
import com.dwdesign.tweetings.provider.TweetStore.DirectMessages;
import com.dwdesign.tweetings.provider.TweetStore.Drafts;
import com.dwdesign.tweetings.provider.TweetStore.Mentions;
import com.dwdesign.tweetings.provider.TweetStore.Statuses;
import com.dwdesign.tweetings.util.AsyncTaskManager;
import com.dwdesign.tweetings.util.ImageUploaderInterface;
import com.dwdesign.tweetings.util.ListUtils;
import com.dwdesign.tweetings.util.ManagedAsyncTask;
import com.dwdesign.tweetings.util.TweetShortenerInterface;
import com.dwdesign.tweetings.util.Utils;

import twitter4j.DirectMessage;
import twitter4j.GeoLocation;
import twitter4j.Paging;
import twitter4j.RateLimitStatus;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.StatusUpdate;
import twitter4j.Trends;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.User;
import twitter4j.UserList;
import twitter4j.auth.AccessToken;
import twitter4j.auth.Authorization;
import twitter4j.auth.OAuthAuthorization;
import twitter4j.internal.http.HttpClientWrapper;
import twitter4j.internal.http.HttpParameter;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.location.Location;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.SoundPool;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

import com.twitter.Validator;

public class TweetingsService extends Service implements Constants {

    private final ServiceStub mBinder = new ServiceStub(this);

    private AsyncTaskManager mAsyncTaskManager;
    private SharedPreferences mPreferences;
    private NotificationManager mNotificationManager;
    private AlarmManager mAlarmManager;
    private ContentResolver mResolver;
    private MediaPlayer mPlayer;

    private int activityCount = 1;

    private int mGetHomeTimelineTaskId, mGetMentionsTaskId;
    private int mStoreStatusesTaskId, mStoreMentionsTaskId;
    private int mGetReceivedDirectMessagesTaskId, mGetSentDirectMessagesTaskId;
    private int mStoreReceivedDirectMessagesTaskId, mStoreSentDirectMessagesTaskId;
    private int mGetLocalTrendsTaskId, mGetWeeklyTrendsTaskId, mGetDailyTrendsTaskId;
    private int mStoreLocalTrendsTaskId, mStoreWeeklyTrendsTaskId, mStoreDailyTrendsTaskId;

    private boolean mBatteryLow = false;
    private boolean mShouldShutdown = false;

    private int mNewMessagesCount, mNewMentionsCount, mNewStatusesCount;

    private PendingIntent mPendingRefreshHomeTimelineIntent, mPendingRefreshMentionsIntent,
            mPendingRefreshDirectMessagesIntent;

    private BroadcastReceiver mStateReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(final Context context, final Intent intent) {
            final String action = intent.getAction();
            if (BROADCAST_REFRESHSTATE_CHANGED.equals(action)) {
                if (!mAsyncTaskManager.hasActivatedTask() && mShouldShutdown) {
                    stopSelf();
                }
            } else if (Intent.ACTION_BATTERY_LOW.equals(action)) {
                mBatteryLow = true;
            } else if (Intent.ACTION_BATTERY_OKAY.equals(action)) {
                mBatteryLow = false;
            } else if (BROADCAST_NOTIFICATION_CLEARED.equals(action)) {
                final Bundle extras = intent.getExtras();
                if (extras != null && extras.containsKey(INTENT_KEY_NOTIFICATION_ID)) {
                    clearNotification(extras.getInt(INTENT_KEY_NOTIFICATION_ID));
                }
            } else if (hasActiveConnection(context) && !(mBatteryLow
                    && mPreferences.getBoolean(PREFERENCE_KEY_STOP_AUTO_REFRESH_WHEN_BATTERY_LOW, true))) {
                if (BROADCAST_REFRESH_HOME_TIMELINE.equals(action)) {
                    final long[] activated_ids = getActivatedAccountIds(context);
                    if (mPreferences.getBoolean(PREFERENCE_KEY_REFRESH_ENABLE_HOME_TIMELINE, false)) {
                        if (!isHomeTimelineRefreshing()) {
                            getHomeTimeline(activated_ids, null, true);
                        }
                    }
                } else if (BROADCAST_REFRESH_MENTIONS.equals(action)) {
                    final long[] activated_ids = getActivatedAccountIds(context);
                    if (mPreferences.getBoolean(PREFERENCE_KEY_REFRESH_ENABLE_MENTIONS, false)) {
                        if (!isMentionsRefreshing()) {
                            getMentions(activated_ids, null, true);
                        }
                    }
                } else if (BROADCAST_REFRESH_DIRECT_MESSAGES.equals(action)) {
                    final long[] activated_ids = getActivatedAccountIds(context);
                    if (mPreferences.getBoolean(PREFERENCE_KEY_REFRESH_ENABLE_DIRECT_MESSAGES, false)) {
                        if (!isReceivedDirectMessagesRefreshing()) {
                            getReceivedDirectMessages(activated_ids, null, true);
                        }
                    }
                }
            }
        }

    };

    public void cancelShutdown() {
        mShouldShutdown = false;
    }

    public int addUserListMember(final long account_id, final int list_id, final long user_id,
            final String screen_name) {
        final AddUserListMemberTask task = new AddUserListMemberTask(account_id, list_id, user_id, screen_name);
        return mAsyncTaskManager.add(task, true);
    }

    public void clearNotification(final int id) {
        switch (id) {
        case NOTIFICATION_ID_HOME_TIMELINE: {
            mNewStatusesCount = 0;
            break;
        }
        case NOTIFICATION_ID_MENTIONS: {
            mNewMentionsCount = 0;
            break;
        }
        case NOTIFICATION_ID_DIRECT_MESSAGES: {
            mNewMessagesCount = 0;
            break;
        }
        }
        mNotificationManager.cancel(id);
    }

    public int createBlock(final long account_id, final long user_id) {
        final CreateBlockTask task = new CreateBlockTask(account_id, user_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int createFavorite(final long account_id, final long status_id) {
        final CreateFavoriteTask task = new CreateFavoriteTask(account_id, status_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int createFriendship(final long account_id, final long user_id) {
        final CreateFriendshipTask task = new CreateFriendshipTask(account_id, user_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int createMultiBlock(final long account_id, final long[] user_ids) {
        final CreateMultiBlockTask task = new CreateMultiBlockTask(account_id, user_ids);
        return mAsyncTaskManager.add(task, true);
    }

    public int createUserList(final long account_id, final String list_name, final boolean is_public,
            final String description) {
        final CreateUserListTask task = new CreateUserListTask(account_id, list_name, is_public, description);
        return mAsyncTaskManager.add(task, true);
    }

    public int createUserListSubscription(final long account_id, final int list_id) {
        final CreateUserListSubscriptionTask task = new CreateUserListSubscriptionTask(account_id, list_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int deleteUserListMember(final long account_id, final int list_id, final long user_id) {
        final DeleteUserListMemberTask task = new DeleteUserListMemberTask(account_id, list_id, user_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int destroyBlock(final long account_id, final long user_id) {
        final DestroyBlockTask task = new DestroyBlockTask(account_id, user_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int destroyDirectMessage(final long account_id, final long message_id) {
        final DestroyDirectMessageTask task = new DestroyDirectMessageTask(account_id, message_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int destroyFavorite(final long account_id, final long status_id) {
        final DestroyFavoriteTask task = new DestroyFavoriteTask(account_id, status_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int destroyFriendship(long account_id, final long user_id) {
        final DestroyFriendshipTask task = new DestroyFriendshipTask(account_id, user_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int destroyStatus(final long account_id, final long status_id) {
        final DestroyStatusTask task = new DestroyStatusTask(account_id, status_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int destroySavedSearch(final long account_id, final int search_id) {
        final DestroySavedSearchTask task = new DestroySavedSearchTask(account_id, search_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int createSavedSearch(final long account_id, final String query) {
        final CreateSavedSearchTask task = new CreateSavedSearchTask(account_id, query);
        return mAsyncTaskManager.add(task, true);
    }

    public int destroyUserList(final long account_id, final int list_id) {
        final DestroyUserListTask task = new DestroyUserListTask(account_id, list_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int destroyUserListSubscription(final long account_id, final int list_id) {
        final DestroyUserListSubscriptionTask task = new DestroyUserListSubscriptionTask(account_id, list_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int getDailyTrends(final long account_id) {
        mAsyncTaskManager.cancel(mGetDailyTrendsTaskId);
        final GetDailyTrendsTask task = new GetDailyTrendsTask(account_id);
        return mGetDailyTrendsTaskId = mAsyncTaskManager.add(task, true);
    }

    public int insertStreamToHomeTimeline(final long account_id, final Intent intent) {
        final String action = intent.getAction();
        if (BROADCAST_STREAM_STATUS_RECEIVED.equals(action)) {
            twitter4j.Status status = (twitter4j.Status) intent.getExtras().get("status");

            List<twitter4j.Status> statuses = new ArrayList<twitter4j.Status>();
            statuses.add(status);
            ListResponse<twitter4j.Status> result = new ListResponse<twitter4j.Status>(account_id, 0, 0, statuses,
                    null);
            List<ListResponse<twitter4j.Status>> result2 = new ArrayList<ListResponse<twitter4j.Status>>();
            result2.add(result);

            try {
                return mAsyncTaskManager.add(new StoreHomeTimelineTask(result2, false, false), true);
            } catch (Exception e) {
                return -1;
            }
        }
        return -1;
    }

    public int insertStreamToMentions(final long account_id, final Intent intent) {
        final String action = intent.getAction();
        if (BROADCAST_STREAM_STATUS_RECEIVED.equals(action)) {
            twitter4j.Status status = (twitter4j.Status) intent.getExtras().get("status");

            List<twitter4j.Status> statuses = new ArrayList<twitter4j.Status>();
            statuses.add(status);
            ListResponse<twitter4j.Status> result = new ListResponse<twitter4j.Status>(account_id, 0, 0, statuses,
                    null);
            List<ListResponse<twitter4j.Status>> result2 = new ArrayList<ListResponse<twitter4j.Status>>();
            result2.add(result);

            try {
                return mAsyncTaskManager.add(new StoreMentionsTask(result2, false, false), true);
            } catch (Exception e) {
                return -1;
            }
        }
        return -1;
    }

    public int insertStreamToInbox(final long account_id, final Intent intent) {
        final String action = intent.getAction();
        if (BROADCAST_STREAM_STATUS_RECEIVED.equals(action)) {
            twitter4j.DirectMessage dm = (twitter4j.DirectMessage) intent.getExtras().get("status");

            List<twitter4j.DirectMessage> statuses = new ArrayList<twitter4j.DirectMessage>();
            statuses.add(dm);
            ListResponse<twitter4j.DirectMessage> result = new ListResponse<twitter4j.DirectMessage>(account_id, 0,
                    0, statuses, null);
            List<ListResponse<twitter4j.DirectMessage>> result2 = new ArrayList<ListResponse<twitter4j.DirectMessage>>();
            result2.add(result);

            try {
                return mAsyncTaskManager.add(new StoreReceivedDirectMessagesTask(result2, false), true);
            } catch (Exception e) {
                return -1;
            }
        }
        return -1;
    }

    public int getHomeTimeline(final long[] account_ids, final long[] max_ids) {
        final boolean notification = mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_HOME_TIMELINE,
                false);
        return getHomeTimeline(account_ids, max_ids, notification);
    }

    public int getHomeTimelineWithSinceId(final long[] account_ids, final long[] max_ids, final long[] since_ids) {
        final boolean notification = mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_HOME_TIMELINE,
                false);
        return getHomeTimelineWithSinceId(account_ids, max_ids, since_ids, notification);
    }

    public int getLocalTrends(final long account_id, final int woeid) {
        mAsyncTaskManager.cancel(mGetLocalTrendsTaskId);
        final GetLocalTrendsTask task = new GetLocalTrendsTask(account_id, woeid);
        return mGetLocalTrendsTaskId = mAsyncTaskManager.add(task, true);
    }

    public String generateOAuthEchoHeader(final long account_id) {
        final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
        if (twitter != null) {
            Authorization authorization = twitter.getAuthorization();
            if (!(authorization instanceof OAuthAuthorization)) {
                throw new IllegalArgumentException("OAuth authorization is required.");
            }
            OAuthAuthorization oauth = (OAuthAuthorization) authorization;

            List<HttpParameter> oauthSignatureParams = oauth.generateOAuthSignatureHttpParams("GET",
                    TWITTER_VERIFY_CREDENTIALS_JSON);
            return "OAuth realm=\"http://api.twitter.com/\","
                    + OAuthAuthorization.encodeParameters(oauthSignatureParams, ",", true);

        }
        return null;
    }

    public int getMentions(final long[] account_ids, final long[] max_ids) {
        final boolean notification = mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_MENTIONS, false)
                && max_ids == null;
        return getMentions(account_ids, max_ids, notification);
    }

    public int getMentionsWithSinceId(final long[] account_ids, final long[] max_ids, final long[] since_ids) {
        final boolean notification = mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_MENTIONS, false)
                && max_ids == null;
        return getMentionsWithSinceId(account_ids, max_ids, since_ids, notification);
    }

    public int getReceivedDirectMessages(final long[] account_ids, final long[] max_ids) {
        final boolean notification = mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_DIRECT_MESSAGES,
                false) && max_ids == null;
        return getReceivedDirectMessages(account_ids, max_ids, notification);
    }

    public int getReceivedDirectMessagesWithSinceId(final long[] account_ids, final long[] max_ids,
            final long[] since_ids) {
        final boolean notification = mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_DIRECT_MESSAGES,
                false) && max_ids == null;
        return getReceivedDirectMessagesWithSinceId(account_ids, max_ids, since_ids, notification);
    }

    public int getSentDirectMessages(final long[] account_ids, final long[] max_ids) {
        mAsyncTaskManager.cancel(mGetSentDirectMessagesTaskId);
        final GetSentDirectMessagesTask task = new GetSentDirectMessagesTask(account_ids, max_ids, null);
        return mGetSentDirectMessagesTaskId = mAsyncTaskManager.add(task, true);
    }

    public int getSentDirectMessagesWithSinceId(final long[] account_ids, final long[] max_ids,
            final long[] since_ids) {
        mAsyncTaskManager.cancel(mGetSentDirectMessagesTaskId);
        final GetSentDirectMessagesTask task = new GetSentDirectMessagesTask(account_ids, max_ids, since_ids);
        return mGetSentDirectMessagesTaskId = mAsyncTaskManager.add(task, true);
    }

    public int getWeeklyTrends(final long account_id) {
        mAsyncTaskManager.cancel(mGetWeeklyTrendsTaskId);
        final GetWeeklyTrendsTask task = new GetWeeklyTrendsTask(account_id);
        return mGetWeeklyTrendsTaskId = mAsyncTaskManager.add(task, true);
    }

    public boolean hasActivatedTask() {
        return mAsyncTaskManager.hasActivatedTask();
    }

    public boolean isDailyTrendsRefreshing() {
        return mAsyncTaskManager.isExcuting(mGetDailyTrendsTaskId)
                || mAsyncTaskManager.isExcuting(mStoreDailyTrendsTaskId);
    }

    public boolean isHomeTimelineRefreshing() {
        return mAsyncTaskManager.isExcuting(mGetHomeTimelineTaskId)
                || mAsyncTaskManager.isExcuting(mStoreStatusesTaskId);
    }

    public boolean isLocalTrendsRefreshing() {
        return mAsyncTaskManager.isExcuting(mGetLocalTrendsTaskId)
                || mAsyncTaskManager.isExcuting(mStoreLocalTrendsTaskId);
    }

    public boolean isMentionsRefreshing() {
        return mAsyncTaskManager.isExcuting(mGetMentionsTaskId)
                || mAsyncTaskManager.isExcuting(mStoreMentionsTaskId);
    }

    public boolean isReceivedDirectMessagesRefreshing() {
        return mAsyncTaskManager.isExcuting(mGetReceivedDirectMessagesTaskId)
                || mAsyncTaskManager.isExcuting(mStoreReceivedDirectMessagesTaskId);
    }

    public boolean isSentDirectMessagesRefreshing() {
        return mAsyncTaskManager.isExcuting(mGetSentDirectMessagesTaskId)
                || mAsyncTaskManager.isExcuting(mStoreSentDirectMessagesTaskId);
    }

    public boolean isWeeklyTrendsRefreshing() {
        return mAsyncTaskManager.isExcuting(mGetWeeklyTrendsTaskId)
                || mAsyncTaskManager.isExcuting(mStoreWeeklyTrendsTaskId);
    }

    @Override
    public IBinder onBind(final Intent intent) {
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        mAsyncTaskManager = ((TweetingsApplication) getApplication()).getAsyncTaskManager();
        mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
        mResolver = getContentResolver();
        mPendingRefreshHomeTimelineIntent = PendingIntent.getBroadcast(this, 0,
                new Intent(BROADCAST_REFRESH_HOME_TIMELINE), 0);
        mPendingRefreshMentionsIntent = PendingIntent.getBroadcast(this, 0, new Intent(BROADCAST_REFRESH_MENTIONS),
                0);
        mPendingRefreshDirectMessagesIntent = PendingIntent.getBroadcast(this, 0,
                new Intent(BROADCAST_REFRESH_DIRECT_MESSAGES), 0);
        final IntentFilter filter = new IntentFilter(BROADCAST_REFRESHSTATE_CHANGED);
        filter.addAction(BROADCAST_NOTIFICATION_CLEARED);
        filter.addAction(BROADCAST_REFRESH_HOME_TIMELINE);
        filter.addAction(BROADCAST_REFRESH_MENTIONS);
        filter.addAction(BROADCAST_REFRESH_DIRECT_MESSAGES);
        filter.addAction(Intent.ACTION_BATTERY_LOW);
        filter.addAction(Intent.ACTION_BATTERY_OKAY);
        registerReceiver(mStateReceiver, filter);
        startAutoRefresh();
    }

    @Override
    public void onDestroy() {
        unregisterReceiver(mStateReceiver);
        mNotificationManager.cancelAll();
        if (mPreferences.getBoolean(PREFERENCE_KEY_AUTO_REFRESH, false)) {
            // Auto refresh enabled, so I will try to start service after it was
            // stopped.
            startService(new Intent(INTENT_ACTION_SERVICE));
        }
        super.onDestroy();
    }

    public void incrementActivityCount() {
        if (this.activityCount == 0) {
            final Intent intent = new Intent(BROADCAST_BACKGROUND_CHANGED);
            intent.putExtra(INTENT_KEY_BACKGROUND, false);
            sendBroadcast(intent);
        }
        this.activityCount++;
    }

    public void decrementActivityCount() {
        this.activityCount--;
        if (this.activityCount == 0) {
            final Intent intent = new Intent(BROADCAST_BACKGROUND_CHANGED);
            intent.putExtra(INTENT_KEY_BACKGROUND, true);
            sendBroadcast(intent);
        }
    }

    public int refreshAll() {
        final long[] account_ids = getActivatedAccountIds(this);
        final long[] since_ids = getNewestStatusIdsFromDatabase(this, Mentions.CONTENT_URI);
        getMentionsWithSinceId(account_ids, null, since_ids);
        final long[] since_idsDm = getNewestMessageIdsFromDatabase(this, DirectMessages.Inbox.CONTENT_URI);
        getReceivedDirectMessagesWithSinceId(account_ids, null, since_idsDm);
        getSentDirectMessagesWithSinceId(account_ids, null, since_idsDm);
        final long[] since_idsHome = getNewestStatusIdsFromDatabase(this, Statuses.CONTENT_URI);
        return getHomeTimelineWithSinceId(account_ids, null, since_idsHome);

        /*final long[] account_ids = getActivatedAccountIds(this);
        getMentions(account_ids, null);
        getReceivedDirectMessages(account_ids, null);
        getSentDirectMessages(account_ids, null);
        return getHomeTimeline(account_ids, null);*/
    }

    public int reportMultiSpam(final long account_id, final long[] user_ids) {
        final ReportMultiSpamTask task = new ReportMultiSpamTask(account_id, user_ids);
        return mAsyncTaskManager.add(task, true);
    }

    public int reportSpam(final long account_id, final long user_id) {
        final ReportSpamTask task = new ReportSpamTask(account_id, user_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int retweetStatus(final long account_id, final long status_id) {
        final RetweetStatusTask task = new RetweetStatusTask(account_id, status_id);
        return mAsyncTaskManager.add(task, true);
    }

    public int sendDirectMessage(final long account_id, final String screen_name, final long user_id,
            final String message) {
        final SendDirectMessageTask task = new SendDirectMessageTask(account_id, screen_name, user_id, message);
        return mAsyncTaskManager.add(task, true);
    }

    public void shutdownService() {
        // Auto refresh is enabled, so this service cannot be shut down.
        if (mPreferences.getBoolean(PREFERENCE_KEY_AUTO_REFRESH, false))
            return;
        if (!mAsyncTaskManager.hasActivatedTask()) {
            stopSelf();
        } else {
            mShouldShutdown = true;
        }
    }

    public boolean startAutoRefresh() {
        stopAutoRefresh();
        if (mPreferences.getBoolean(PREFERENCE_KEY_AUTO_REFRESH, false)) {
            final long update_interval = parseInt(mPreferences.getString(PREFERENCE_KEY_REFRESH_INTERVAL, "30"))
                    * 60 * 1000;
            if (update_interval <= 0)
                return false;
            mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + update_interval,
                    update_interval, mPendingRefreshHomeTimelineIntent);
            mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + update_interval,
                    update_interval, mPendingRefreshMentionsIntent);
            mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + update_interval,
                    update_interval, mPendingRefreshDirectMessagesIntent);
            return true;
        }
        return false;
    }

    public void stopAutoRefresh() {
        mAlarmManager.cancel(mPendingRefreshHomeTimelineIntent);
        mAlarmManager.cancel(mPendingRefreshMentionsIntent);
        mAlarmManager.cancel(mPendingRefreshDirectMessagesIntent);
    }

    public boolean test() {
        try {
            return startService(new Intent(INTENT_ACTION_SERVICE)) != null;
        } catch (final Exception e) {
            return false;
        }
    }

    public int updateProfile(final long account_id, final String name, final String url, final String location,
            final String description) {
        final UpdateProfileTask task = new UpdateProfileTask(account_id, name, url, location, description);
        return mAsyncTaskManager.add(task, true);
    }

    public int updateProfileImage(final long account_id, final Uri image_uri, final boolean delete_image) {
        final UpdateProfileImageTask task = new UpdateProfileImageTask(account_id, image_uri, delete_image);
        return mAsyncTaskManager.add(task, true);
    }

    public int updateBannerImage(final long account_id, final Uri image_uri, final boolean delete_image) {
        final UpdateBannerImageTask task = new UpdateBannerImageTask(account_id, image_uri, delete_image);
        return mAsyncTaskManager.add(task, true);
    }

    public int updateStatus(final long[] account_ids, final String content, final Location location,
            final Uri image_uri, final long in_reply_to, final boolean is_possibly_sensitive,
            final boolean delete_image) {
        final UpdateStatusTask task = new UpdateStatusTask(account_ids, content, location, image_uri, in_reply_to,
                is_possibly_sensitive, delete_image);
        return mAsyncTaskManager.add(task, true);
    }

    public int scheduleStatus(final String schedule_date, final long[] account_ids, final String content,
            final Location location, final Uri image_uri, final long in_reply_to, final boolean delete_image) {
        final ScheduleStatusTask task = new ScheduleStatusTask(schedule_date, account_ids, content, location,
                image_uri, in_reply_to, delete_image);
        return mAsyncTaskManager.add(task, true);
    }

    public int bufferStatus(final long[] account_ids, final String content) {
        final BufferStatusTask task = new BufferStatusTask(account_ids, content);
        return mAsyncTaskManager.add(task, true);
    }

    public int updateUserListDetails(final long account_id, final int list_id, final boolean is_public,
            final String name, final String description) {
        final UpdateUserListProfileTask task = new UpdateUserListProfileTask(account_id, list_id, is_public, name,
                description);
        return mAsyncTaskManager.add(task, true);
    }

    private Notification buildNotification(final String title, final String message, final int icon,
            final Intent content_intent, final Intent delete_intent) {
        final NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setTicker(message);
        builder.setContentTitle(title);
        builder.setContentText(message);
        builder.setAutoCancel(true);
        builder.setWhen(System.currentTimeMillis());
        builder.setSmallIcon(icon);
        if (delete_intent != null) {
            builder.setDeleteIntent(
                    PendingIntent.getBroadcast(this, 0, delete_intent, PendingIntent.FLAG_UPDATE_CURRENT));
        }
        if (content_intent != null) {
            builder.setContentIntent(
                    PendingIntent.getActivity(this, 0, content_intent, PendingIntent.FLAG_UPDATE_CURRENT));
        }
        int defaults = 0;
        final Calendar now = Calendar.getInstance();
        if (mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_HAVE_SOUND, true)
                && !mPreferences.getBoolean("silent_notifications_at_" + now.get(Calendar.HOUR_OF_DAY), false)) {
            Uri soundUri = Uri.parse(mPreferences.getString(PREFERENCE_KEY_NOTIFICATION_RINGTONE,
                    "android.resource://" + getPackageName() + "/" + R.raw.notify));
            builder.setSound(soundUri, Notification.STREAM_DEFAULT);
        }
        if (mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_HAVE_VIBRATION, true)
                && !mPreferences.getBoolean("silent_notifications_at_" + now.get(Calendar.HOUR_OF_DAY), false)) {
            defaults |= Notification.DEFAULT_VIBRATE;
        }
        if (mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_HAVE_LIGHTS, true)
                && !mPreferences.getBoolean("silent_notifications_at_" + now.get(Calendar.HOUR_OF_DAY), false)) {
            final int color_def = getResources().getColor(R.color.holo_blue_dark);
            final int color = mPreferences.getInt(PREFERENCE_KEY_NOTIFICATION_LIGHT_COLOR, color_def);
            builder.setLights(color, 1000, 2000);
        }
        builder.setDefaults(defaults);
        return builder.getNotification();
    }

    private int getHomeTimeline(final long[] account_ids, final long[] max_ids, final boolean is_auto_refresh) {
        mAsyncTaskManager.cancel(mGetHomeTimelineTaskId);
        final GetHomeTimelineTask task = new GetHomeTimelineTask(account_ids, max_ids, null, is_auto_refresh);
        return mGetHomeTimelineTaskId = mAsyncTaskManager.add(task, true);
    }

    private int getHomeTimelineWithSinceId(final long[] account_ids, final long[] max_ids, final long[] since_ids,
            final boolean is_auto_refresh) {
        mAsyncTaskManager.cancel(mGetHomeTimelineTaskId);
        final GetHomeTimelineTask task = new GetHomeTimelineTask(account_ids, max_ids, since_ids, is_auto_refresh);
        return mGetHomeTimelineTaskId = mAsyncTaskManager.add(task, true);
    }

    private int getMentions(final long[] account_ids, final long[] max_ids, final boolean is_auto_refresh) {
        mAsyncTaskManager.cancel(mGetMentionsTaskId);
        final GetMentionsTask task = new GetMentionsTask(account_ids, max_ids, null, is_auto_refresh);
        return mGetMentionsTaskId = mAsyncTaskManager.add(task, true);
    }

    private int getMentionsWithSinceId(final long[] account_ids, final long[] max_ids, final long[] since_ids,
            final boolean is_auto_refresh) {
        mAsyncTaskManager.cancel(mGetMentionsTaskId);
        final GetMentionsTask task = new GetMentionsTask(account_ids, max_ids, since_ids, is_auto_refresh);
        return mGetMentionsTaskId = mAsyncTaskManager.add(task, true);
    }

    private int getReceivedDirectMessages(final long[] account_ids, final long[] max_ids,
            final boolean is_auto_refresh) {
        mAsyncTaskManager.cancel(mGetReceivedDirectMessagesTaskId);
        final GetReceivedDirectMessagesTask task = new GetReceivedDirectMessagesTask(account_ids, max_ids, null,
                is_auto_refresh);
        return mGetReceivedDirectMessagesTaskId = mAsyncTaskManager.add(task, true);
    }

    private int getReceivedDirectMessagesWithSinceId(final long[] account_ids, final long[] max_ids,
            final long[] since_ids, final boolean is_auto_refresh) {
        mAsyncTaskManager.cancel(mGetReceivedDirectMessagesTaskId);
        final GetReceivedDirectMessagesTask task = new GetReceivedDirectMessagesTask(account_ids, max_ids,
                since_ids, is_auto_refresh);
        return mGetReceivedDirectMessagesTaskId = mAsyncTaskManager.add(task, true);
    }

    private void showErrorToast(final int action_res, final Exception e, final boolean long_message) {
        Utils.showErrorToast(this, getString(action_res), e, long_message);
    }

    class AddUserListMemberTask extends ManagedAsyncTask<Void, Void, SingleResponse<UserList>> {

        private final long account_id, user_id;
        private final int list_id;
        private final String screen_name;

        public AddUserListMemberTask(final long account_id, final int list_id, final long user_id,
                final String screen_name) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.list_id = list_id;
            this.user_id = user_id;
            this.screen_name = screen_name;
        }

        @Override
        protected SingleResponse<UserList> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    if (user_id > 0) {
                        final UserList list = twitter.addUserListMember(list_id, user_id);
                        return new SingleResponse<UserList>(account_id, list, null);
                    } else if (screen_name != null) {
                        final User user = twitter.showUser(screen_name);
                        if (user != null && user.getId() > 0) {
                            final UserList list = twitter.addUserListMember(list_id, user.getId());
                            return new SingleResponse<UserList>(account_id, list, null);
                        }
                    }
                } catch (final TwitterException e) {
                    return new SingleResponse<UserList>(account_id, null, e);
                }
            }
            return new SingleResponse<UserList>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<UserList> result) {
            final boolean succeed = result != null && result.data != null && result.data.getId() > 0;
            if (succeed) {
                Toast.makeText(TweetingsService.this, R.string.add_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.add_member, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_USER_LIST_MEMBER_DELETED);
            intent.putExtra(INTENT_KEY_USER_ID, user_id);
            intent.putExtra(INTENT_KEY_LIST_ID, list_id);
            intent.putExtra(INTENT_KEY_SUCCEED, succeed);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class CacheUsersTask extends ManagedAsyncTask<Void, Void, Void> {

        private final List<ListResponse<twitter4j.Status>> responses;

        public CacheUsersTask(final List<ListResponse<twitter4j.Status>> result) {
            super(TweetingsService.this, mAsyncTaskManager);
            responses = result;
        }

        @Override
        protected Void doInBackground(final Void... args) {

            for (final ListResponse<twitter4j.Status> response : responses) {
                final List<twitter4j.Status> statuses = response.list;
                if (statuses == null || statuses.size() <= 0) {
                    continue;
                }
                final List<ContentValues> cached_users_list = new ArrayList<ContentValues>();
                final List<Long> user_ids = new ArrayList<Long>();

                for (final twitter4j.Status status : statuses) {
                    if (status == null) {
                        continue;
                    }
                    final User user = status.getUser();
                    final long user_id = user.getId();

                    if (!user_ids.contains(user_id)) {
                        user_ids.add(user_id);
                        cached_users_list.add(makeCachedUserContentValues(user));
                    }

                }

                mResolver.delete(CachedUsers.CONTENT_URI,
                        CachedUsers.USER_ID + " IN (" + ListUtils.toString(user_ids, ',', true) + " )", null);
                mResolver.bulkInsert(CachedUsers.CONTENT_URI,
                        cached_users_list.toArray(new ContentValues[cached_users_list.size()]));

            }
            return null;
        }

    }

    class CreateBlockTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> {

        private long account_id;
        private long user_id;

        public CreateBlockTask(final long account_id, final long user_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.user_id = user_id;
        }

        @Override
        protected SingleResponse<User> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final User user = twitter.createBlock(user_id);
                    return new SingleResponse<User>(account_id, user, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<User>(account_id, null, e);
                }
            }
            return new SingleResponse<User>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<User> result) {
            if (result != null && result.data != null && result.data.getId() > 0) {
                for (final Uri uri : Utils.STATUSES_URIS) {
                    final String where = Statuses.ACCOUNT_ID + " = " + account_id + " AND " + Statuses.USER_ID
                            + " = " + user_id;
                    mResolver.delete(uri, where, null);

                }
                //I bet you don't want to see this user in your auto complete list.
                final String where = CachedUsers.USER_ID + " = " + user_id;
                mResolver.delete(CachedUsers.CONTENT_URI, where, null);
                Toast.makeText(TweetingsService.this, R.string.user_blocked, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.block, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_BLOCKSTATE_CHANGED);
            intent.putExtra(INTENT_KEY_USER_ID, user_id);
            intent.putExtra(INTENT_KEY_SUCCEED, result != null && result.data != null);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class CreateFavoriteTask extends ManagedAsyncTask<Void, Void, SingleResponse<twitter4j.Status>> {

        private long account_id;

        private long status_id;

        public CreateFavoriteTask(final long account_id, final long status_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.status_id = status_id;
        }

        @Override
        protected SingleResponse<twitter4j.Status> doInBackground(final Void... params) {

            if (account_id < 0)
                return new SingleResponse<twitter4j.Status>(account_id, null, null);

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final twitter4j.Status status = twitter.createFavorite(status_id);
                    return new SingleResponse<twitter4j.Status>(account_id, status, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<twitter4j.Status>(account_id, null, e);
                }
            }
            return new SingleResponse<twitter4j.Status>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<twitter4j.Status> result) {

            if (result.data != null) {
                final long status_id = result.data.getId();
                final ContentValues values = new ContentValues();
                values.put(Statuses.IS_FAVORITE, 1);
                final StringBuilder where = new StringBuilder();
                where.append(Statuses.ACCOUNT_ID + " = " + result.account_id);
                where.append(" AND ");
                where.append("(");
                where.append(Statuses.STATUS_ID + "=" + status_id);
                where.append(" OR ");
                where.append(Statuses.RETWEET_ID + "=" + status_id);
                where.append(")");
                for (final Uri uri : TweetStore.STATUSES_URIS) {
                    mResolver.update(uri, values, where.toString(), null);
                }
                final Intent intent = new Intent(BROADCAST_FAVORITE_CHANGED);
                intent.putExtra(INTENT_KEY_STATUS_ID, status_id);
                intent.putExtra(INTENT_KEY_FAVORITED, true);
                sendBroadcast(intent);
                Toast.makeText(TweetingsService.this, R.string.favorite_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.fav, result.exception, true);
            }
            super.onPostExecute(result);
        }

    }

    class CreateFriendshipTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> {

        private long account_id;
        private long user_id;

        public CreateFriendshipTask(final long account_id, final long user_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.user_id = user_id;
        }

        @Override
        protected SingleResponse<User> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final User user = twitter.createFriendship(user_id);
                    return new SingleResponse<User>(account_id, user, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<User>(account_id, null, e);
                }
            }
            return new SingleResponse<User>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<User> result) {
            if (result != null && result.data != null) {
                Toast.makeText(TweetingsService.this, R.string.follow_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.follow, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_FRIENDSHIP_CHANGED);
            intent.putExtra(INTENT_KEY_USER_ID, user_id);
            intent.putExtra(INTENT_KEY_SUCCEED, result != null && result.data != null);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class CreateMultiBlockTask extends ManagedAsyncTask<Void, Void, ListResponse<Long>> {

        private long account_id;
        private long[] user_ids;

        public CreateMultiBlockTask(final long account_id, final long[] user_ids) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.user_ids = user_ids;
        }

        @Override
        protected ListResponse<Long> doInBackground(final Void... params) {

            final List<Long> blocked_users = new ArrayList<Long>();
            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                for (final long user_id : user_ids) {
                    try {
                        final User user = twitter.createBlock(user_id);
                        if (user == null || user.getId() <= 0) {
                            continue;
                        }
                        blocked_users.add(user.getId());
                    } catch (final TwitterException e) {
                        e.printStackTrace();
                    }
                }
            }
            return new ListResponse<Long>(account_id, -1, -1, blocked_users, null);
        }

        @Override
        protected void onPostExecute(final ListResponse<Long> result) {
            if (result != null) {
                final String user_ids = ListUtils.toString(result.list, ',', false);
                for (final Uri uri : Utils.STATUSES_URIS) {
                    final String where = Statuses.ACCOUNT_ID + " = " + account_id + " AND " + Statuses.USER_ID
                            + " IN (" + user_ids + ")";
                    mResolver.delete(uri, where, null);
                }
                //I bet you don't want to see these users in your auto complete list.
                final String where = CachedUsers.USER_ID + " IN (" + user_ids + ")";
                mResolver.delete(CachedUsers.CONTENT_URI, where, null);
                Toast.makeText(TweetingsService.this, R.string.users_blocked, Toast.LENGTH_SHORT).show();
            }
            final Intent intent = new Intent(BROADCAST_MULTI_BLOCKSTATE_CHANGED);
            intent.putExtra(INTENT_KEY_USER_ID, user_ids);
            intent.putExtra(INTENT_KEY_SUCCEED, result != null);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class CreateUserListSubscriptionTask extends ManagedAsyncTask<Void, Void, SingleResponse<UserList>> {

        private final long account_id;
        private final int list_id;

        public CreateUserListSubscriptionTask(final long account_id, final int list_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.list_id = list_id;
        }

        @Override
        protected SingleResponse<UserList> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final UserList list = twitter.createUserListSubscription(list_id);
                    return new SingleResponse<UserList>(account_id, list, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<UserList>(account_id, null, e);
                }
            }
            return new SingleResponse<UserList>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<UserList> result) {
            final boolean succeed = result != null && result.data != null && result.data.getId() > 0;
            if (succeed) {
                Toast.makeText(TweetingsService.this, R.string.follow_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.block, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_USER_LIST_SUBSCRIPTION_CHANGED);
            intent.putExtra(INTENT_KEY_LIST_ID, list_id);
            intent.putExtra(INTENT_KEY_SUCCEED, succeed);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class CreateUserListTask extends ManagedAsyncTask<Void, Void, SingleResponse<UserList>> {

        private final long account_id;
        private final String list_name, description;
        private final boolean is_public;

        public CreateUserListTask(final long account_id, final String list_name, final boolean is_public,
                final String description) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.list_name = list_name;
            this.description = description;
            this.is_public = is_public;
        }

        @Override
        protected SingleResponse<UserList> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    if (list_name != null) {
                        final UserList list = twitter.createUserList(list_name, is_public, description);
                        return new SingleResponse<UserList>(account_id, list, null);
                    }
                } catch (final TwitterException e) {
                    return new SingleResponse<UserList>(account_id, null, e);
                }
            }
            return new SingleResponse<UserList>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<UserList> result) {
            final boolean succeed = result != null && result.data != null && result.data.getId() > 0;
            if (succeed) {
                Toast.makeText(TweetingsService.this, R.string.create_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.create, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_USER_LIST_CREATED);
            intent.putExtra(INTENT_KEY_SUCCEED, succeed);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class DeleteUserListMemberTask extends ManagedAsyncTask<Void, Void, SingleResponse<UserList>> {

        private final long account_id, user_id;
        private final int list_id;

        public DeleteUserListMemberTask(final long account_id, final int list_id, final long user_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.list_id = list_id;
            this.user_id = user_id;
        }

        @Override
        protected SingleResponse<UserList> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final UserList list = twitter.deleteUserListMember(list_id, user_id);
                    return new SingleResponse<UserList>(account_id, list, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<UserList>(account_id, null, e);
                }
            }
            return new SingleResponse<UserList>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<UserList> result) {
            final boolean succeed = result != null && result.data != null && result.data.getId() > 0;
            if (succeed) {
                Toast.makeText(TweetingsService.this, R.string.delete_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.create, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_USER_LIST_MEMBER_DELETED);
            intent.putExtra(INTENT_KEY_USER_ID, user_id);
            intent.putExtra(INTENT_KEY_LIST_ID, list_id);
            intent.putExtra(INTENT_KEY_SUCCEED, succeed);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class DestroyBlockTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> {

        private long account_id;
        private long user_id;

        public DestroyBlockTask(final long account_id, final long user_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.user_id = user_id;
        }

        @Override
        protected SingleResponse<User> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final User user = twitter.destroyBlock(user_id);
                    return new SingleResponse<User>(account_id, user, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<User>(account_id, null, e);
                }
            }
            return new SingleResponse<User>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<User> result) {
            if (result != null && result.data != null) {
                Toast.makeText(TweetingsService.this, R.string.user_unblocked, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.unblock, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_BLOCKSTATE_CHANGED);
            intent.putExtra(INTENT_KEY_USER_ID, user_id);
            intent.putExtra(INTENT_KEY_SUCCEED, result != null && result.data != null);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class DestroyDirectMessageTask extends ManagedAsyncTask<Void, Void, SingleResponse<DirectMessage>> {

        private final Twitter twitter;
        private final long message_id;
        private final long account_id;

        public DestroyDirectMessageTask(final long account_id, final long message_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            this.account_id = account_id;
            this.message_id = message_id;
        }

        @Override
        protected SingleResponse<DirectMessage> doInBackground(final Void... args) {
            if (twitter == null)
                return new SingleResponse<DirectMessage>(account_id, null, null);
            try {
                return new SingleResponse<DirectMessage>(account_id, twitter.destroyDirectMessage(message_id),
                        null);
            } catch (final TwitterException e) {
                return new SingleResponse<DirectMessage>(account_id, null, e);
            }
        }

        @Override
        protected void onPostExecute(final SingleResponse<DirectMessage> result) {
            super.onPostExecute(result);
            if (result == null)
                return;
            if (result.data != null && result.data.getId() > 0) {
                Toast.makeText(TweetingsService.this, R.string.delete_success, Toast.LENGTH_SHORT).show();
                final String where = DirectMessages.MESSAGE_ID + " = " + message_id;

                mResolver.delete(DirectMessages.Inbox.CONTENT_URI, where, null);
                mResolver.delete(DirectMessages.Outbox.CONTENT_URI, where, null);
            } else {
                showErrorToast(R.string.delete, result.exception, true);
            }
        }

    }

    class DestroyFavoriteTask extends ManagedAsyncTask<Void, Void, SingleResponse<twitter4j.Status>> {

        private long account_id;

        private long status_id;

        public DestroyFavoriteTask(final long account_id, final long status_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.status_id = status_id;
        }

        @Override
        protected SingleResponse<twitter4j.Status> doInBackground(final Void... params) {

            if (account_id < 0) {
                new SingleResponse<twitter4j.Status>(account_id, null, null);
            }

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final twitter4j.Status status = twitter.destroyFavorite(status_id);
                    return new SingleResponse<twitter4j.Status>(account_id, status, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<twitter4j.Status>(account_id, null, e);
                }
            }
            return new SingleResponse<twitter4j.Status>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<twitter4j.Status> result) {

            if (result.data != null) {
                final long status_id = result.data.getId();
                final ContentValues values = new ContentValues();
                values.put(Statuses.IS_FAVORITE, 0);
                final StringBuilder where = new StringBuilder();
                where.append(Statuses.ACCOUNT_ID + " = " + result.account_id);
                where.append(" AND ");
                where.append("(");
                where.append(Statuses.STATUS_ID + "=" + status_id);
                where.append(" OR ");
                where.append(Statuses.RETWEET_ID + "=" + status_id);
                where.append(")");
                for (final Uri uri : TweetStore.STATUSES_URIS) {
                    mResolver.update(uri, values, where.toString(), null);
                }
                final Intent intent = new Intent(BROADCAST_FAVORITE_CHANGED);
                intent.putExtra(INTENT_KEY_USER_ID, account_id);
                intent.putExtra(INTENT_KEY_STATUS_ID, status_id);
                intent.putExtra(INTENT_KEY_FAVORITED, false);
                sendBroadcast(intent);
                Toast.makeText(TweetingsService.this, R.string.unfavorite_success, Toast.LENGTH_SHORT).show();

            } else {
                showErrorToast(R.string.unfav, result.exception, true);
            }
            super.onPostExecute(result);
        }

    }

    class DestroyFriendshipTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> {

        private long account_id;
        private long user_id;

        public DestroyFriendshipTask(final long account_id, final long user_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.user_id = user_id;
        }

        @Override
        protected SingleResponse<User> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final User user = twitter.destroyFriendship(user_id);
                    return new SingleResponse<User>(account_id, user, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<User>(account_id, null, e);
                }
            }
            return new SingleResponse<User>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<User> result) {
            if (result != null && result.data != null) {
                Toast.makeText(TweetingsService.this, R.string.unfollow_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.unfollow, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_FRIENDSHIP_CHANGED);
            intent.putExtra(INTENT_KEY_USER_ID, user_id);
            intent.putExtra(INTENT_KEY_SUCCEED, result != null && result.data != null);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class DestroyStatusTask extends ManagedAsyncTask<Void, Void, SingleResponse<twitter4j.Status>> {

        private long account_id;

        private long status_id;

        public DestroyStatusTask(final long account_id, final long status_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.status_id = status_id;
        }

        @Override
        protected SingleResponse<twitter4j.Status> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final twitter4j.Status status = twitter.destroyStatus(status_id);
                    return new SingleResponse<twitter4j.Status>(account_id, status, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<twitter4j.Status>(account_id, null, e);
                }
            }
            return new SingleResponse<twitter4j.Status>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<twitter4j.Status> result) {
            final Intent intent = new Intent(BROADCAST_STATUS_DESTROYED);
            if (result != null && result.data != null && result.data.getId() > 0) {
                final long status_id = result.data.getId();

                final StringBuilder where = new StringBuilder();
                where.append(Statuses.STATUS_ID + " = " + status_id);
                where.append(" OR " + Statuses.RETWEET_ID + " = " + status_id);
                for (final Uri uri : TweetStore.STATUSES_URIS) {
                    mResolver.delete(uri, where.toString(), null);
                }
                intent.putExtra(INTENT_KEY_STATUS_ID, status_id);
                intent.putExtra(INTENT_KEY_SUCCEED, true);
                Toast.makeText(TweetingsService.this, R.string.delete_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.delete, result.exception, true);
            }
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class DestroySavedSearchTask extends ManagedAsyncTask<Void, Void, SingleResponse<twitter4j.SavedSearch>> {

        private long account_id;

        private int search_id;

        public DestroySavedSearchTask(final long account_id, final int search_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.search_id = search_id;
        }

        @Override
        protected SingleResponse<twitter4j.SavedSearch> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final twitter4j.SavedSearch status = twitter.destroySavedSearch(search_id);
                    return new SingleResponse<twitter4j.SavedSearch>(account_id, status, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<twitter4j.SavedSearch>(account_id, null, e);
                }
            }
            return new SingleResponse<twitter4j.SavedSearch>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<twitter4j.SavedSearch> result) {
            final Intent intent = new Intent(BROADCAST_SEARCH_CHANGED);
            if (result != null && result.data != null && result.data.getId() > 0) {
                Toast.makeText(TweetingsService.this, R.string.delete_search_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.delete, result.exception, true);
            }
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class CreateSavedSearchTask extends ManagedAsyncTask<Void, Void, SingleResponse<twitter4j.SavedSearch>> {

        private long account_id;

        private String query;

        public CreateSavedSearchTask(final long account_id, final String query) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.query = query;
        }

        @Override
        protected SingleResponse<twitter4j.SavedSearch> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final twitter4j.SavedSearch status = twitter.createSavedSearch(query);
                    return new SingleResponse<twitter4j.SavedSearch>(account_id, status, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<twitter4j.SavedSearch>(account_id, null, e);
                }
            }
            return new SingleResponse<twitter4j.SavedSearch>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<twitter4j.SavedSearch> result) {
            final Intent intent = new Intent(BROADCAST_SEARCH_CHANGED);
            if (result != null && result.data != null && result.data.getId() > 0) {
                Toast.makeText(TweetingsService.this, R.string.create_search_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.save, result.exception, true);
            }
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class DestroyUserListSubscriptionTask extends ManagedAsyncTask<Void, Void, SingleResponse<UserList>> {

        private final long account_id;
        private final int list_id;

        public DestroyUserListSubscriptionTask(final long account_id, final int list_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.list_id = list_id;
        }

        @Override
        protected SingleResponse<UserList> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final UserList list = twitter.destroyUserListSubscription(list_id);
                    return new SingleResponse<UserList>(account_id, list, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<UserList>(account_id, null, e);
                }
            }
            return new SingleResponse<UserList>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<UserList> result) {
            final boolean succeed = result != null && result.data != null && result.data.getId() > 0;
            if (succeed) {
                Toast.makeText(TweetingsService.this, R.string.unfollow_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.delete, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_USER_LIST_SUBSCRIPTION_CHANGED);
            intent.putExtra(INTENT_KEY_LIST_ID, list_id);
            intent.putExtra(INTENT_KEY_SUCCEED, succeed);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class DestroyUserListTask extends ManagedAsyncTask<Void, Void, SingleResponse<UserList>> {

        private final long account_id;
        private final int list_id;

        public DestroyUserListTask(final long account_id, final int list_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.list_id = list_id;
        }

        @Override
        protected SingleResponse<UserList> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    if (list_id > 0) {
                        final UserList list = twitter.destroyUserList(list_id);
                        return new SingleResponse<UserList>(account_id, list, null);
                    }
                } catch (final TwitterException e) {
                    return new SingleResponse<UserList>(account_id, null, e);
                }
            }
            return new SingleResponse<UserList>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<UserList> result) {
            final boolean succeed = result != null && result.data != null && result.data.getId() > 0;
            if (succeed) {
                Toast.makeText(TweetingsService.this, R.string.delete_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.delete, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_USER_LIST_DELETED);
            intent.putExtra(INTENT_KEY_SUCCEED, succeed);
            intent.putExtra(INTENT_KEY_LIST_ID, list_id);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class GetDailyTrendsTask extends GetTrendsTask {

        public GetDailyTrendsTask(final long account_id) {
            super(account_id);
        }

        @Override
        public ResponseList<Trends> getTrends(final Twitter twitter) throws TwitterException {
            if (twitter == null)
                return null;
            return twitter.getDailyTrends();
        }

        @Override
        protected void onPostExecute(final ListResponse<Trends> result) {
            mStoreDailyTrendsTaskId = mAsyncTaskManager.add(new StoreDailyTrendsTask(result), true);
            super.onPostExecute(result);

        }

    }

    abstract class GetDirectMessagesTask extends ManagedAsyncTask<Void, Void, List<ListResponse<DirectMessage>>> {

        private final long[] account_ids, max_ids, since_ids;

        public GetDirectMessagesTask(final long[] account_ids, final long[] max_ids, final long[] since_ids) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_ids = account_ids;
            this.max_ids = max_ids;
            this.since_ids = since_ids;
        }

        public abstract ResponseList<DirectMessage> getDirectMessages(final Twitter twitter, final Paging paging)
                throws TwitterException;

        @Override
        protected List<ListResponse<DirectMessage>> doInBackground(final Void... params) {

            final List<ListResponse<DirectMessage>> result = new ArrayList<ListResponse<DirectMessage>>();

            if (account_ids == null)
                return result;

            final boolean max_ids_valid = max_ids != null && max_ids.length == account_ids.length;
            final boolean since_ids_valid = since_ids != null && since_ids.length == account_ids.length;

            int idx = 0;
            final int load_item_limit = mPreferences.getInt(PREFERENCE_KEY_LOAD_ITEM_LIMIT,
                    PREFERENCE_DEFAULT_LOAD_ITEM_LIMIT);
            for (final long account_id : account_ids) {
                final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, true);
                if (twitter != null) {
                    try {
                        final Paging paging = new Paging();
                        paging.setCount(load_item_limit);
                        long max_id = -1;
                        if (max_ids_valid && max_ids[idx] > 0) {
                            max_id = max_ids[idx];
                            paging.setMaxId(max_id);
                        }
                        long since_id = -1;
                        if (since_ids_valid && since_ids[idx] > 0) {
                            since_id = since_ids[idx];
                            paging.setSinceId(since_id);
                        }
                        final ResponseList<DirectMessage> statuses = getDirectMessages(twitter, paging);

                        if (statuses != null) {
                            result.add(
                                    new ListResponse<DirectMessage>(account_id, max_id, since_id, statuses, null));
                        }
                    } catch (final TwitterException e) {
                        e.printStackTrace();
                    }
                }
                idx++;
            }
            return result;

        }

    }

    class GetHomeTimelineTask extends GetStatusesTask {

        private final boolean is_auto_refresh;

        public GetHomeTimelineTask(final long[] account_ids, final long[] max_ids, final long[] since_ids,
                final boolean is_auto_refresh) {
            super(Statuses.CONTENT_URI, account_ids, max_ids, since_ids);
            this.is_auto_refresh = is_auto_refresh;
        }

        @Override
        public ResponseList<twitter4j.Status> getStatuses(final Twitter twitter, final Paging paging)
                throws TwitterException {
            if (mPreferences.getBoolean(PREFERENCE_KEY_API_V1, true) == true) {
                return twitter.getHomeTimelinev1(paging);
            }
            return twitter.getHomeTimeline(paging);
        }

        @Override
        public Twitter getTwitter(final long account_id) {
            return getTwitterInstance(TweetingsService.this, account_id, true, true, true);
        }

        @Override
        protected void onPostExecute(final List<ListResponse<twitter4j.Status>> responses) {
            super.onPostExecute(responses);
            mStoreStatusesTaskId = mAsyncTaskManager
                    .add(new StoreHomeTimelineTask(responses, is_auto_refresh, shouldSetMinId()), true);
            mGetHomeTimelineTaskId = -1;
        }

        @Override
        protected void onPreExecute() {
            mAlarmManager.cancel(mPendingRefreshHomeTimelineIntent);
            if (mPreferences.getBoolean(PREFERENCE_KEY_AUTO_REFRESH, false)) {
                final long update_interval = parseInt(mPreferences.getString(PREFERENCE_KEY_REFRESH_INTERVAL, "30"))
                        * 60 * 1000;
                if (update_interval > 0) {
                    mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                            System.currentTimeMillis() + update_interval, update_interval,
                            mPendingRefreshHomeTimelineIntent);
                }
            }
            super.onPreExecute();
        }

    }

    class GetLocalTrendsTask extends GetTrendsTask {

        private final int woeid;

        public GetLocalTrendsTask(final long account_id, final int woeid) {
            super(account_id);
            this.woeid = woeid;
        }

        @Override
        public List<Trends> getTrends(final Twitter twitter) throws TwitterException {
            final ArrayList<Trends> trends_list = new ArrayList<Trends>();
            if (twitter != null) {
                trends_list.add(twitter.getLocationTrends(woeid));
            }
            return trends_list;
        }

        @Override
        protected void onPostExecute(final ListResponse<Trends> result) {
            mStoreLocalTrendsTaskId = mAsyncTaskManager.add(new StoreLocalTrendsTask(result), true);
            super.onPostExecute(result);

        }

    }

    class GetMentionsTask extends GetStatusesTask {

        private final boolean is_auto_refresh;

        public GetMentionsTask(final long[] account_ids, final long[] max_ids, final long[] since_ids,
                final boolean is_auto_refresh) {
            super(Mentions.CONTENT_URI, account_ids, max_ids, since_ids);
            this.is_auto_refresh = is_auto_refresh;
        }

        @Override
        public ResponseList<twitter4j.Status> getStatuses(final Twitter twitter, final Paging paging)
                throws TwitterException {
            if (mPreferences.getBoolean(PREFERENCE_KEY_API_V1, true) == true) {
                return twitter.getMentionsv1(paging);
            }
            return twitter.getMentions(paging);
        }

        @Override
        public Twitter getTwitter(final long account_id) {
            return getTwitterInstance(TweetingsService.this, account_id, true, false, true);
        }

        @Override
        protected void onPostExecute(final List<ListResponse<twitter4j.Status>> responses) {
            super.onPostExecute(responses);
            mStoreMentionsTaskId = mAsyncTaskManager
                    .add(new StoreMentionsTask(responses, is_auto_refresh, shouldSetMinId()), true);
            mGetMentionsTaskId = -1;
        }

        @Override
        protected void onPreExecute() {
            mAlarmManager.cancel(mPendingRefreshMentionsIntent);
            if (mPreferences.getBoolean(PREFERENCE_KEY_AUTO_REFRESH, false)) {
                final long update_interval = parseInt(mPreferences.getString(PREFERENCE_KEY_REFRESH_INTERVAL, "30"))
                        * 60 * 1000;
                if (update_interval > 0) {
                    mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                            System.currentTimeMillis() + update_interval, update_interval,
                            mPendingRefreshMentionsIntent);
                }
            }
            super.onPreExecute();
        }

    }

    class GetReceivedDirectMessagesTask extends GetDirectMessagesTask {

        private final boolean is_auto_refresh;

        public GetReceivedDirectMessagesTask(final long[] account_ids, final long[] max_ids, final long[] since_ids,
                final boolean is_auto_refresh) {
            super(account_ids, max_ids, since_ids);
            this.is_auto_refresh = is_auto_refresh;
        }

        @Override
        public ResponseList<DirectMessage> getDirectMessages(final Twitter twitter, final Paging paging)
                throws TwitterException {
            if (mPreferences.getBoolean(PREFERENCE_KEY_API_V1, true) == true) {
                return twitter.getDirectMessagesv1(paging);
            }
            return twitter.getDirectMessages(paging);
        }

        @Override
        protected void onPreExecute() {
            mAlarmManager.cancel(mPendingRefreshDirectMessagesIntent);
            if (mPreferences.getBoolean(PREFERENCE_KEY_AUTO_REFRESH, false)) {
                final long update_interval = parseInt(mPreferences.getString(PREFERENCE_KEY_REFRESH_INTERVAL, "30"))
                        * 60 * 1000;
                if (update_interval > 0) {
                    mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                            System.currentTimeMillis() + update_interval, update_interval,
                            mPendingRefreshDirectMessagesIntent);
                }
            }
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(final List<ListResponse<DirectMessage>> responses) {
            super.onPostExecute(responses);
            mStoreReceivedDirectMessagesTaskId = mAsyncTaskManager
                    .add(new StoreReceivedDirectMessagesTask(responses, is_auto_refresh), true);
            mGetReceivedDirectMessagesTaskId = -1;
        }

    }

    class GetSentDirectMessagesTask extends GetDirectMessagesTask {

        public GetSentDirectMessagesTask(final long[] account_ids, final long[] max_ids, final long[] since_ids) {
            super(account_ids, max_ids, since_ids);
        }

        @Override
        public ResponseList<DirectMessage> getDirectMessages(final Twitter twitter, final Paging paging)
                throws TwitterException {
            if (mPreferences.getBoolean(PREFERENCE_KEY_API_V1, true) == true) {
                return twitter.getSentDirectMessagesv1(paging);
            }
            return twitter.getSentDirectMessages(paging);
        }

        @Override
        protected void onPostExecute(final List<ListResponse<DirectMessage>> responses) {
            super.onPostExecute(responses);
            mStoreSentDirectMessagesTaskId = mAsyncTaskManager.add(new StoreSentDirectMessagesTask(responses),
                    true);
            mGetSentDirectMessagesTaskId = -1;
        }

    }

    abstract class GetStatusesTask extends ManagedAsyncTask<Void, Void, List<ListResponse<twitter4j.Status>>> {

        private final long[] account_ids, max_ids, since_ids;

        private boolean should_set_min_id, should_set_since_id;

        public GetStatusesTask(final Uri uri, final long[] account_ids, final long[] max_ids,
                final long[] since_ids) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_ids = account_ids;
            this.max_ids = max_ids;
            this.since_ids = since_ids;
        }

        public abstract ResponseList<twitter4j.Status> getStatuses(final Twitter twitter, final Paging paging)
                throws TwitterException;

        public abstract Twitter getTwitter(final long account_id);

        public boolean shouldSetMinId() {
            return should_set_min_id;
        }

        public boolean shouldSetSinceId() {
            return should_set_since_id;
        }

        @Override
        protected void onPostExecute(final List<ListResponse<twitter4j.Status>> result) {
            super.onPostExecute(result);
            for (final ListResponse<twitter4j.Status> response : result) {
                if (response.list == null) {
                    showErrorToast(R.string.refresh, response.exception, true);
                }
            }
        }

        @Override
        protected List<ListResponse<twitter4j.Status>> doInBackground(final Void... params) {

            final List<ListResponse<twitter4j.Status>> result = new ArrayList<ListResponse<twitter4j.Status>>();

            if (account_ids == null)
                return result;

            final boolean max_ids_valid = max_ids != null && max_ids.length == account_ids.length;
            should_set_min_id = !max_ids_valid;
            final boolean since_ids_valid = since_ids != null && since_ids.length == account_ids.length;
            should_set_since_id = !since_ids_valid;

            int idx = 0;
            final int load_item_limit = mPreferences.getInt(PREFERENCE_KEY_LOAD_ITEM_LIMIT,
                    PREFERENCE_DEFAULT_LOAD_ITEM_LIMIT);
            for (final long account_id : account_ids) {
                final Twitter twitter = getTwitter(account_id);
                if (twitter != null) {
                    try {
                        final Paging paging = new Paging();
                        paging.setCount(load_item_limit);
                        long max_id = -1;
                        if (max_ids_valid && max_ids[idx] > 0) {
                            max_id = max_ids[idx];
                            paging.setMaxId(max_id);
                        }
                        long since_id = -1;
                        if (since_ids_valid && since_ids[idx] > 0) {
                            since_id = since_ids[idx];
                            paging.setSinceId(since_id);
                        }
                        final ResponseList<twitter4j.Status> statuses = getStatuses(twitter, paging);

                        if (statuses != null) {
                            result.add(new ListResponse<twitter4j.Status>(account_id, max_id, since_id, statuses,
                                    null));
                        }
                    } catch (final TwitterException e) {
                        e.printStackTrace();
                        result.add(new ListResponse<twitter4j.Status>(account_id, -1, -1, null, e));
                    }
                }
                idx++;
            }
            return result;
        }

    }

    abstract class GetTrendsTask extends ManagedAsyncTask<Void, Void, ListResponse<Trends>> {

        private final long account_id;

        public GetTrendsTask(final long account_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
        }

        public abstract List<Trends> getTrends(final Twitter twitter) throws TwitterException;

        @Override
        protected ListResponse<Trends> doInBackground(final Void... params) {
            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    return new ListResponse<Trends>(account_id, -1, -1, getTrends(twitter), null);
                } catch (final TwitterException e) {
                    e.printStackTrace();
                }
            }
            return new ListResponse<Trends>(account_id, -1, -1, null, null);
        }

    }

    class GetWeeklyTrendsTask extends GetTrendsTask {

        public GetWeeklyTrendsTask(final long account_id) {
            super(account_id);
        }

        @Override
        public ResponseList<Trends> getTrends(final Twitter twitter) throws TwitterException {
            if (twitter == null)
                return null;
            return twitter.getWeeklyTrends();
        }

        @Override
        protected void onPostExecute(final ListResponse<Trends> result) {
            mStoreWeeklyTrendsTaskId = mAsyncTaskManager.add(new StoreWeeklyTrendsTask(result), true);
            super.onPostExecute(result);

        }

    }

    public static final class ListResponse<Data> {

        public final long account_id, max_id, since_id;
        public final List<Data> list;
        public final TwitterException exception;

        public ListResponse(final long account_id, final long max_id, final long since_id,
                final List<Data> responselist, TwitterException exception) {
            this.account_id = account_id;
            this.max_id = max_id;
            this.since_id = since_id;
            this.list = responselist;
            this.exception = exception;
        }
    }

    class ReportMultiSpamTask extends ManagedAsyncTask<Void, Void, ListResponse<Long>> {

        private long account_id;
        private long[] user_ids;

        public ReportMultiSpamTask(final long account_id, final long[] user_ids) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.user_ids = user_ids;
        }

        @Override
        protected ListResponse<Long> doInBackground(final Void... params) {

            final List<Long> reported_users = new ArrayList<Long>();
            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                for (final long user_id : user_ids) {
                    try {
                        final User user = twitter.reportSpam(user_id);
                        if (user == null || user.getId() <= 0) {
                            continue;
                        }
                        reported_users.add(user.getId());
                    } catch (final TwitterException e) {
                        e.printStackTrace();
                    }
                }
            }
            return new ListResponse<Long>(account_id, -1, -1, reported_users, null);
        }

        @Override
        protected void onPostExecute(final ListResponse<Long> result) {
            if (result != null) {
                final String user_id_where = ListUtils.toString(result.list, ',', false);
                for (final Uri uri : Utils.STATUSES_URIS) {
                    final String where = Statuses.ACCOUNT_ID + " = " + account_id + " AND " + Statuses.USER_ID
                            + " IN (" + user_id_where + ")";
                    mResolver.delete(uri, where, null);
                }
                Toast.makeText(TweetingsService.this, R.string.reported_users_for_spam, Toast.LENGTH_SHORT).show();
            }
            final Intent intent = new Intent(BROADCAST_MULTI_BLOCKSTATE_CHANGED);
            intent.putExtra(INTENT_KEY_USER_ID, user_ids);
            intent.putExtra(INTENT_KEY_SUCCEED, result != null);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class ReportSpamTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> {

        private long account_id;
        private long user_id;

        public ReportSpamTask(final long account_id, final long user_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.user_id = user_id;
        }

        @Override
        protected SingleResponse<User> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final User user = twitter.reportSpam(user_id);
                    return new SingleResponse<User>(account_id, user, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<User>(account_id, null, e);
                }
            }
            return new SingleResponse<User>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<User> result) {
            if (result != null && result.data != null && result.data.getId() > 0) {
                for (final Uri uri : Utils.STATUSES_URIS) {
                    final String where = Statuses.ACCOUNT_ID + " = " + account_id + " AND " + Statuses.USER_ID
                            + " = " + user_id;
                    mResolver.delete(uri, where, null);
                }
                Toast.makeText(TweetingsService.this, R.string.reported_user_for_spam, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.refresh, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_BLOCKSTATE_CHANGED);
            intent.putExtra(INTENT_KEY_USER_ID, user_id);
            intent.putExtra(INTENT_KEY_SUCCEED, result != null && result.data != null);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class RetweetStatusTask extends ManagedAsyncTask<Void, Void, SingleResponse<twitter4j.Status>> {

        private long account_id;

        private long status_id;

        private final AudioManager audioManager = (AudioManager) getSystemService(Activity.AUDIO_SERVICE);

        public RetweetStatusTask(final long account_id, final long status_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.status_id = status_id;
        }

        @Override
        protected SingleResponse<twitter4j.Status> doInBackground(final Void... params) {

            if (account_id < 0)
                return new SingleResponse<twitter4j.Status>(account_id, null, null);

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final twitter4j.Status status = twitter.retweetStatus(status_id);
                    return new SingleResponse<twitter4j.Status>(account_id, status, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<twitter4j.Status>(account_id, null, e);
                }
            }
            return new SingleResponse<twitter4j.Status>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<twitter4j.Status> result) {

            if (result.data != null && result.data.getId() > 0) {
                Toast.makeText(TweetingsService.this, R.string.retweet_success, Toast.LENGTH_SHORT).show();
                boolean isMuted = false;
                switch (audioManager.getRingerMode()) {
                case AudioManager.RINGER_MODE_NORMAL:
                    isMuted = false;
                    break;
                case AudioManager.RINGER_MODE_SILENT:
                    isMuted = true;
                    break;
                case AudioManager.RINGER_MODE_VIBRATE:
                    isMuted = true;
                    break;
                }
                if (mPreferences.getBoolean(PREFERENCE_KEY_SOUND_SEND, true)) {
                    if (mPlayer != null) {
                        if (mPlayer.isPlaying()) {
                            mPlayer.stop();
                        }
                        mPlayer.release();
                    }
                    mPlayer = MediaPlayer.create(TweetingsService.this, R.raw.whoosh);
                    if (isMuted == true) {
                        mPlayer.setVolume(0, 0);
                    }
                    mPlayer.start();
                }
                final Intent intent = new Intent(BROADCAST_RETWEET_CHANGED);
                intent.putExtra(INTENT_KEY_STATUS_ID, status_id);
                intent.putExtra(INTENT_KEY_RETWEETED, true);
                sendBroadcast(intent);
            } else {
                showErrorToast(R.string.retweet, result.exception, true);
            }

            super.onPostExecute(result);
        }

    }

    class SendDirectMessageTask extends ManagedAsyncTask<Void, Void, SingleResponse<DirectMessage>> {

        private final Twitter twitter;
        private final long user_id;
        private final String screen_name;
        private final String message;
        private final long account_id;

        private final AudioManager audioManager = (AudioManager) getSystemService(Activity.AUDIO_SERVICE);

        public SendDirectMessageTask(final long account_id, final String screen_name, final long user_id,
                final String message) {
            super(TweetingsService.this, mAsyncTaskManager);
            twitter = getTwitterInstance(TweetingsService.this, account_id, true);
            this.account_id = account_id;
            this.user_id = user_id;
            this.screen_name = screen_name;
            this.message = message;
        }

        @Override
        protected SingleResponse<DirectMessage> doInBackground(final Void... args) {
            if (twitter == null)
                return new SingleResponse<DirectMessage>(account_id, null, null);
            try {
                if (user_id > 0)
                    return new SingleResponse<DirectMessage>(account_id,
                            twitter.sendDirectMessage(user_id, message), null);
                else if (screen_name != null)
                    return new SingleResponse<DirectMessage>(account_id,
                            twitter.sendDirectMessage(screen_name, message), null);
            } catch (final TwitterException e) {
                return new SingleResponse<DirectMessage>(account_id, null, e);
            }
            return new SingleResponse<DirectMessage>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<DirectMessage> result) {
            super.onPostExecute(result);
            if (result == null)
                return;
            if (result.data != null && result.data.getId() > 0) {
                final Uri.Builder builder = DirectMessages.Outbox.CONTENT_URI.buildUpon();
                builder.appendQueryParameter(QUERY_PARAM_NOTIFY, String.valueOf(true));
                final ContentValues values = makeDirectMessageContentValues(result.data, account_id);
                getContentResolver().insert(builder.build(), values);
                boolean isMuted = false;
                switch (audioManager.getRingerMode()) {
                case AudioManager.RINGER_MODE_NORMAL:
                    isMuted = false;
                    break;
                case AudioManager.RINGER_MODE_SILENT:
                    isMuted = true;
                    break;
                case AudioManager.RINGER_MODE_VIBRATE:
                    isMuted = true;
                    break;
                }
                if (mPreferences.getBoolean(PREFERENCE_KEY_SOUND_SEND, true)) {
                    if (mPlayer != null) {
                        if (mPlayer.isPlaying()) {
                            mPlayer.stop();
                        }
                        mPlayer.release();
                    }
                    mPlayer = MediaPlayer.create(TweetingsService.this, R.raw.whoosh);
                    if (isMuted == true) {
                        mPlayer.setVolume(0, 0);
                    }
                    mPlayer.start();
                }
                Toast.makeText(TweetingsService.this, R.string.send_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.update, result.exception, true);
            }
        }

    }

    /*
     * By making this a static class with a WeakReference to the Service, we
     * ensure that the Service can be GCd even when the system process still has
     * a remote reference to the stub.
     */
    static final class ServiceStub extends ITweetingsService.Stub {

        public void cancelShutdown() {
            mService.get().cancelShutdown();
        }

        final WeakReference<TweetingsService> mService;

        public ServiceStub(TweetingsService service) {

            mService = new WeakReference<TweetingsService>(service);
        }

        @Override
        public int addUserListMember(final long account_id, final int list_id, final long user_id,
                final String screen_name) {
            return mService.get().addUserListMember(account_id, list_id, user_id, screen_name);
        }

        @Override
        public void clearNotification(final int id) {
            mService.get().clearNotification(id);
        }

        @Override
        public int createBlock(final long account_id, final long user_id) {
            return mService.get().createBlock(account_id, user_id);
        }

        @Override
        public int insertStreamToHomeTimeline(final long account_id, final Intent intent) {
            return mService.get().insertStreamToHomeTimeline(account_id, intent);
        }

        @Override
        public int insertStreamToMentions(final long account_id, final Intent intent) {
            return mService.get().insertStreamToMentions(account_id, intent);
        }

        @Override
        public int insertStreamToInbox(final long account_id, final Intent intent) {
            return mService.get().insertStreamToInbox(account_id, intent);
        }

        @Override
        public int createFavorite(final long account_id, final long status_id) {
            return mService.get().createFavorite(account_id, status_id);
        }

        @Override
        public int createFriendship(final long account_id, final long user_id) {
            return mService.get().createFriendship(account_id, user_id);
        }

        @Override
        public String generateOAuthEchoHeader(final long account_id) {
            return mService.get().generateOAuthEchoHeader(account_id);
        }

        @Override
        public int createMultiBlock(final long account_id, final long[] user_ids) {
            return mService.get().createMultiBlock(account_id, user_ids);
        }

        @Override
        public int createUserList(final long account_id, final String list_name, final boolean is_public,
                final String description) {
            return mService.get().createUserList(account_id, list_name, is_public, description);
        }

        @Override
        public int createUserListSubscription(final long account_id, final int list_id) {
            return mService.get().createUserListSubscription(account_id, list_id);
        }

        @Override
        public int deleteUserListMember(final long account_id, final int list_id, final long user_id) {
            return mService.get().deleteUserListMember(account_id, list_id, user_id);
        }

        @Override
        public int destroyBlock(final long account_id, final long user_id) {
            return mService.get().destroyBlock(account_id, user_id);
        }

        @Override
        public int destroyDirectMessage(final long account_id, final long message_id) {
            return mService.get().destroyDirectMessage(account_id, message_id);
        }

        @Override
        public int destroyFavorite(final long account_id, final long status_id) {
            return mService.get().destroyFavorite(account_id, status_id);
        }

        @Override
        public int destroyFriendship(final long account_id, final long user_id) {
            return mService.get().destroyFriendship(account_id, user_id);
        }

        @Override
        public int destroyStatus(final long account_id, final long status_id) {
            return mService.get().destroyStatus(account_id, status_id);
        }

        @Override
        public int destroySavedSearch(final long account_id, final int search_id) {
            return mService.get().destroySavedSearch(account_id, search_id);
        }

        @Override
        public int createSavedSearch(final long account_id, final String query) {
            return mService.get().createSavedSearch(account_id, query);
        }

        @Override
        public int destroyUserList(final long account_id, final int list_id) {
            return mService.get().destroyUserList(account_id, list_id);
        }

        @Override
        public int destroyUserListSubscription(final long account_id, final int list_id) {
            return mService.get().destroyUserListSubscription(account_id, list_id);
        }

        @Override
        public int getDailyTrends(final long account_id) {
            return mService.get().getDailyTrends(account_id);
        }

        @Override
        public int getHomeTimeline(final long[] account_ids, final long[] max_ids) {
            return mService.get().getHomeTimeline(account_ids, max_ids);
        }

        @Override
        public int getHomeTimelineWithSinceId(final long[] account_ids, final long[] max_ids,
                final long[] since_ids) {
            return mService.get().getHomeTimelineWithSinceId(account_ids, max_ids, since_ids);
        }

        @Override
        public int getLocalTrends(final long account_id, final int woeid) {
            return mService.get().getLocalTrends(account_id, woeid);
        }

        @Override
        public int getMentions(final long[] account_ids, final long[] max_ids) {
            return mService.get().getMentions(account_ids, max_ids);
        }

        @Override
        public int getMentionsWithSinceId(final long[] account_ids, final long[] max_ids, final long[] since_ids) {
            return mService.get().getMentionsWithSinceId(account_ids, max_ids, since_ids);
        }

        @Override
        public int getReceivedDirectMessages(final long[] account_ids, final long[] max_ids) {
            return mService.get().getReceivedDirectMessages(account_ids, max_ids);
        }

        @Override
        public int getReceivedDirectMessagesWithSinceId(final long[] account_ids, final long[] max_ids,
                final long[] since_ids) {
            return mService.get().getReceivedDirectMessagesWithSinceId(account_ids, max_ids, since_ids);
        }

        @Override
        public int getSentDirectMessages(final long[] account_ids, final long[] max_ids) {
            return mService.get().getSentDirectMessages(account_ids, max_ids);
        }

        @Override
        public int getSentDirectMessagesWithSinceId(final long[] account_ids, final long[] max_ids,
                final long[] since_ids) {
            return mService.get().getSentDirectMessagesWithSinceId(account_ids, max_ids, since_ids);
        }

        @Override
        public int getWeeklyTrends(final long account_id) {
            return mService.get().getWeeklyTrends(account_id);
        }

        @Override
        public boolean hasActivatedTask() {
            return mService.get().hasActivatedTask();
        }

        @Override
        public boolean isDailyTrendsRefreshing() {
            return mService.get().isDailyTrendsRefreshing();
        }

        @Override
        public boolean isHomeTimelineRefreshing() {
            return mService.get().isHomeTimelineRefreshing();
        }

        @Override
        public boolean isLocalTrendsRefreshing() {
            return mService.get().isLocalTrendsRefreshing();
        }

        @Override
        public boolean isMentionsRefreshing() {
            return mService.get().isMentionsRefreshing();
        }

        @Override
        public boolean isReceivedDirectMessagesRefreshing() {
            return mService.get().isReceivedDirectMessagesRefreshing();
        }

        @Override
        public boolean isSentDirectMessagesRefreshing() {
            return mService.get().isSentDirectMessagesRefreshing();
        }

        @Override
        public boolean isWeeklyTrendsRefreshing() {
            return mService.get().isWeeklyTrendsRefreshing();
        }

        @Override
        public int refreshAll() {
            return mService.get().refreshAll();
        }

        @Override
        public void incrementActivityCount() {
            mService.get().incrementActivityCount();
        }

        @Override
        public void decrementActivityCount() {
            mService.get().decrementActivityCount();
        }

        @Override
        public int reportMultiSpam(final long account_id, final long[] user_ids) {
            return mService.get().reportMultiSpam(account_id, user_ids);
        }

        @Override
        public int reportSpam(final long account_id, final long user_id) {
            return mService.get().reportSpam(account_id, user_id);
        }

        @Override
        public int retweetStatus(final long account_id, final long status_id) {
            return mService.get().retweetStatus(account_id, status_id);
        }

        @Override
        public int sendDirectMessage(final long account_id, final String screen_name, final long user_id,
                final String message) {
            return mService.get().sendDirectMessage(account_id, screen_name, user_id, message);
        }

        @Override
        public void shutdownService() {
            mService.get().shutdownService();
        }

        @Override
        public boolean startAutoRefresh() {
            return mService.get().startAutoRefresh();
        }

        @Override
        public void stopAutoRefresh() {
            mService.get().stopAutoRefresh();
        }

        @Override
        public boolean test() {
            return mService.get().test();
        }

        @Override
        public int updateProfile(final long account_id, final String name, final String url, final String location,
                final String description) {
            return mService.get().updateProfile(account_id, name, url, location, description);
        }

        @Override
        public int updateProfileImage(final long account_id, final Uri image_uri, final boolean delete_image) {
            return mService.get().updateProfileImage(account_id, image_uri, delete_image);
        }

        @Override
        public int updateBannerImage(final long account_id, final Uri image_uri, final boolean delete_image) {
            return mService.get().updateBannerImage(account_id, image_uri, delete_image);
        }

        @Override
        public int updateStatus(final long[] account_ids, final String content, final Location location,
                final Uri image_uri, final long in_reply_to, final boolean is_possibly_sensitive,
                final boolean delete_image) {
            return mService.get().updateStatus(account_ids, content, location, image_uri, in_reply_to,
                    is_possibly_sensitive, delete_image);
        }

        @Override
        public int scheduleStatus(final String schedule_date, final long[] account_ids, final String content,
                final Location location, final Uri image_uri, final long in_reply_to, final boolean delete_image) {
            return mService.get().scheduleStatus(schedule_date, account_ids, content, location, image_uri,
                    in_reply_to, delete_image);
        }

        @Override
        public int bufferStatus(final long[] account_ids, final String content) {
            return mService.get().bufferStatus(account_ids, content);
        }

        @Override
        public int updateUserListDetails(final long account_id, final int list_id, final boolean is_public,
                final String name, final String description) {
            return mService.get().updateUserListDetails(account_id, list_id, is_public, name, description);
        }
    }

    static final class SingleResponse<Data> {
        public final Exception exception;
        public final Data data;
        public final long account_id;

        public SingleResponse(final long account_id, final Data data, final Exception exception) {
            this.exception = exception;
            this.data = data;
            this.account_id = account_id;
        }
    }

    class StoreDailyTrendsTask extends StoreTrendsTask {

        public StoreDailyTrendsTask(final ListResponse<Trends> result) {
            super(result, CachedTrends.Daily.CONTENT_URI);
        }

    }

    class StoreDirectMessagesTask extends ManagedAsyncTask<Void, Void, SingleResponse<Bundle>> {

        private final List<ListResponse<DirectMessage>> responses;
        private final Uri uri;

        public StoreDirectMessagesTask(final List<ListResponse<DirectMessage>> result, final Uri uri) {
            super(TweetingsService.this, mAsyncTaskManager);
            responses = result;
            this.uri = uri;
        }

        @Override
        protected SingleResponse<Bundle> doInBackground(final Void... args) {

            boolean succeed = false;
            final Uri query_uri = buildQueryUri(uri, false);
            int total_items_inserted = 0;
            for (final ListResponse<DirectMessage> response : responses) {
                final long account_id = response.account_id;
                final List<DirectMessage> messages = response.list;
                final Cursor cur = mResolver.query(uri, new String[0],
                        DirectMessages.ACCOUNT_ID + " = " + account_id, null, null);
                boolean no_items_before = false;
                if (cur != null) {
                    no_items_before = cur.getCount() <= 0;
                    cur.close();
                }
                if (messages != null) {
                    final List<ContentValues> values_list = new ArrayList<ContentValues>();
                    final List<Long> message_ids = new ArrayList<Long>();

                    final long min_id = -1;

                    for (final DirectMessage message : messages) {
                        if (message == null || message.getId() <= 0) {
                            continue;
                        }
                        message_ids.add(message.getId());

                        values_list.add(makeDirectMessageContentValues(message, account_id));

                    }

                    int rows_deleted = -1;

                    // Delete all rows conflicting before new data inserted.
                    {
                        final StringBuilder where = new StringBuilder();
                        where.append(DirectMessages.ACCOUNT_ID + " = " + account_id);
                        where.append(" AND ");
                        where.append(DirectMessages.MESSAGE_ID + " IN ( "
                                + ListUtils.toString(message_ids, ',', true) + " ) ");
                        rows_deleted = mResolver.delete(query_uri, where.toString(), null);
                    }

                    // Insert previously fetched items.
                    mResolver.bulkInsert(query_uri, values_list.toArray(new ContentValues[values_list.size()]));

                    // No row deleted, so I will insert a gap.
                    final boolean insert_gap = rows_deleted == 1 && message_ids.contains(response.max_id)
                            || rows_deleted == 0 && response.max_id == -1 && !no_items_before;
                    if (insert_gap) {
                        final ContentValues values = new ContentValues();
                        values.put(DirectMessages.IS_GAP, 1);
                        final StringBuilder where = new StringBuilder();
                        where.append(DirectMessages.ACCOUNT_ID + "=" + account_id);
                        where.append(" AND " + DirectMessages.MESSAGE_ID + "=" + min_id);
                        mResolver.update(query_uri, values, where.toString(), null);
                    }
                    final int actual_items_inserted = values_list.size() - rows_deleted;
                    if (actual_items_inserted > 0) {
                        total_items_inserted += actual_items_inserted;
                    }
                }
                succeed = true;
            }
            final Bundle bundle = new Bundle();
            bundle.putBoolean(INTENT_KEY_SUCCEED, succeed);
            bundle.putInt(INTENT_KEY_ITEMS_INSERTED, total_items_inserted);
            return new SingleResponse<Bundle>(-1, bundle, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<Bundle> response) {
            if (response != null && response.data != null && response.data.getBoolean(INTENT_KEY_SUCCEED)) {
                notifyForUpdatedUri(TweetingsService.this, uri);
            }
            super.onPostExecute(response);
        }

    }

    public class StoreHomeTimelineTask extends StoreStatusesTask {

        private final boolean is_auto_refresh;

        public StoreHomeTimelineTask(final List<ListResponse<twitter4j.Status>> result,
                final boolean is_auto_refresh, final boolean should_set_min_id) {
            super(result, Statuses.CONTENT_URI, should_set_min_id);
            this.is_auto_refresh = is_auto_refresh;
        }

        @Override
        protected void onPostExecute(final SingleResponse<Bundle> response) {
            mStoreStatusesTaskId = -1;
            final boolean succeed = response != null && response.data != null
                    && response.data.getBoolean(INTENT_KEY_SUCCEED);
            final Bundle extras = new Bundle();
            extras.putBoolean(INTENT_KEY_SUCCEED, succeed);
            if (shouldSetMinId() && getTotalItemsInserted() > 0) {
                extras.putLong(INTENT_KEY_MIN_ID,
                        response != null && response.data != null ? response.data.getLong(INTENT_KEY_MIN_ID, -1)
                                : -1);
            }
            sendBroadcast(new Intent(BROADCAST_HOME_TIMELINE_REFRESHED).putExtras(extras));
            final int items_inserted = response.data.getInt(INTENT_KEY_ITEMS_INSERTED);
            mNewStatusesCount += items_inserted;
            if (items_inserted > 0) {
                Intent intent = new Intent(BROADCAST_TABS_NEW_TWEETS);
                intent.putExtra(INTENT_KEY_UPDATE_TAB, TAB_HOME);
                sendBroadcast(intent);
            }
            if (succeed && is_auto_refresh
                    && mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_HOME_TIMELINE, false)) {
                if (items_inserted > 0) {
                    final String message = getResources().getQuantityString(R.plurals.Ntweets, mNewStatusesCount,
                            mNewStatusesCount);
                    final Intent delete_intent = new Intent(BROADCAST_NOTIFICATION_CLEARED);
                    final Bundle delete_extras = new Bundle();
                    delete_extras.putInt(INTENT_KEY_NOTIFICATION_ID, NOTIFICATION_ID_HOME_TIMELINE);
                    delete_intent.putExtras(delete_extras);
                    final Intent content_intent = new Intent(TweetingsService.this, HomeActivity.class);
                    content_intent.setAction(Intent.ACTION_MAIN);
                    content_intent.addCategory(Intent.CATEGORY_LAUNCHER);
                    final Bundle content_extras = new Bundle();
                    content_extras.putInt(INTENT_KEY_INITIAL_TAB, HomeActivity.TAB_POSITION_HOME);
                    content_intent.putExtras(content_extras);
                    if (mPreferences.getBoolean(PREFERENCE_KEY_LOCAL_NOTIFICATIONS, true)) {
                        mNotificationManager.notify(NOTIFICATION_ID_HOME_TIMELINE,
                                buildNotification(getString(R.string.new_notifications), message,
                                        R.drawable.ic_stat_tweet, content_intent, delete_intent));
                    }
                }
            }
            super.onPostExecute(response);
        }

    }

    class StoreLocalTrendsTask extends StoreTrendsTask {

        public StoreLocalTrendsTask(final ListResponse<Trends> result) {
            super(result, CachedTrends.Local.CONTENT_URI);
        }

    }

    class StoreMentionsTask extends StoreStatusesTask {

        private final boolean is_auto_refresh;

        public StoreMentionsTask(final List<ListResponse<twitter4j.Status>> result, final boolean is_auto_refresh,
                boolean should_set_min_id) {
            super(result, Mentions.CONTENT_URI, should_set_min_id);
            this.is_auto_refresh = is_auto_refresh;
        }

        @Override
        protected void onPostExecute(final SingleResponse<Bundle> response) {
            mStoreMentionsTaskId = -1;
            final boolean succeed = response != null && response.data != null
                    && response.data.getBoolean(INTENT_KEY_SUCCEED);
            final Bundle extras = new Bundle();
            extras.putBoolean(INTENT_KEY_SUCCEED, succeed);
            if (shouldSetMinId() && getTotalItemsInserted() > 0) {
                extras.putLong(INTENT_KEY_MIN_ID,
                        response != null && response.data != null ? response.data.getLong(INTENT_KEY_MIN_ID, -1)
                                : -1);
            }
            sendBroadcast(new Intent(BROADCAST_MENTIONS_REFRESHED).putExtras(extras));
            final int items_inserted = response.data.getInt(INTENT_KEY_ITEMS_INSERTED);

            if (items_inserted > 0) {
                Intent intent = new Intent(BROADCAST_TABS_NEW_TWEETS);
                intent.putExtra(INTENT_KEY_UPDATE_TAB, TAB_MENTIONS);
                sendBroadcast(intent);
            }
            if (succeed && is_auto_refresh
                    && mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_MENTIONS, false)) {
                mNewMentionsCount += items_inserted;
                if (items_inserted > 0) {
                    final Intent delete_intent = new Intent(BROADCAST_NOTIFICATION_CLEARED);
                    final Bundle delete_extras = new Bundle();
                    delete_extras.putInt(INTENT_KEY_NOTIFICATION_ID, NOTIFICATION_ID_MENTIONS);
                    delete_intent.putExtras(delete_extras);
                    final Intent content_intent = new Intent(TweetingsService.this, HomeActivity.class);
                    content_intent.setAction(Intent.ACTION_MAIN);
                    content_intent.addCategory(Intent.CATEGORY_LAUNCHER);
                    final Bundle content_extras = new Bundle();
                    content_extras.putInt(INTENT_KEY_INITIAL_TAB, HomeActivity.TAB_POSITION_MENTIONS);
                    content_intent.putExtras(content_extras);
                    final String title = getString(R.string.mentions);
                    final String message = getResources().getQuantityString(R.plurals.Nmentions, mNewMentionsCount,
                            mNewMentionsCount);
                    final Notification notification = buildNotification(title, message, R.drawable.ic_stat_mention,
                            content_intent, delete_intent);
                    if (mPreferences.getBoolean(PREFERENCE_KEY_LOCAL_NOTIFICATIONS, true)) {
                        mNotificationManager.notify(NOTIFICATION_ID_MENTIONS, notification);
                    }
                }
            }
            super.onPostExecute(response);
        }

    }

    class StoreReceivedDirectMessagesTask extends StoreDirectMessagesTask {

        private final boolean is_auto_refresh;

        public StoreReceivedDirectMessagesTask(final List<ListResponse<DirectMessage>> result,
                final boolean is_auto_refresh) {
            super(result, DirectMessages.Inbox.CONTENT_URI);
            this.is_auto_refresh = is_auto_refresh;
        }

        @Override
        protected void onPostExecute(final SingleResponse<Bundle> response) {
            mStoreReceivedDirectMessagesTaskId = -1;
            final boolean succeed = response != null && response.data != null
                    && response.data.getBoolean(INTENT_KEY_SUCCEED);
            sendBroadcast(
                    new Intent(BROADCAST_RECEIVED_DIRECT_MESSAGES_REFRESHED).putExtra(INTENT_KEY_SUCCEED, succeed));
            if (succeed && is_auto_refresh
                    && mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_DIRECT_MESSAGES, false)) {
                final int items_inserted = response.data.getInt(INTENT_KEY_ITEMS_INSERTED);
                mNewMessagesCount += items_inserted;
                if (items_inserted > 0) {
                    final String message = getResources().getQuantityString(R.plurals.Ndirect_messages,
                            mNewMessagesCount, mNewMessagesCount);
                    final Intent delete_intent = new Intent(BROADCAST_NOTIFICATION_CLEARED);
                    final Bundle delete_extras = new Bundle();
                    delete_extras.putInt(INTENT_KEY_NOTIFICATION_ID, NOTIFICATION_ID_DIRECT_MESSAGES);
                    delete_intent.putExtras(delete_extras);
                    final Intent content_intent = new Intent(TweetingsService.this, HomeActivity.class);
                    content_intent.setAction(Intent.ACTION_MAIN);
                    content_intent.addCategory(Intent.CATEGORY_LAUNCHER);
                    final Bundle content_extras = new Bundle();
                    content_extras.putInt(INTENT_KEY_INITIAL_TAB, HomeActivity.TAB_POSITION_MESSAGES);
                    content_intent.putExtras(content_extras);
                    if (mPreferences.getBoolean(PREFERENCE_KEY_LOCAL_NOTIFICATIONS, true)) {
                        mNotificationManager.notify(NOTIFICATION_ID_DIRECT_MESSAGES,
                                buildNotification(getString(R.string.new_notifications), message,
                                        R.drawable.ic_stat_direct_message, content_intent, delete_intent));
                    }
                }
            }
            super.onPostExecute(response);
        }

    }

    class StoreSentDirectMessagesTask extends StoreDirectMessagesTask {

        public StoreSentDirectMessagesTask(final List<ListResponse<DirectMessage>> result) {
            super(result, DirectMessages.Outbox.CONTENT_URI);
        }

        @Override
        protected void onPostExecute(final SingleResponse<Bundle> response) {
            mStoreSentDirectMessagesTaskId = -1;
            final boolean succeed = response != null && response.data != null
                    && response.data.getBoolean(INTENT_KEY_SUCCEED);
            sendBroadcast(
                    new Intent(BROADCAST_SENT_DIRECT_MESSAGES_REFRESHED).putExtra(INTENT_KEY_SUCCEED, succeed));
            super.onPostExecute(response);
        }

    }

    abstract class StoreStatusesTask extends ManagedAsyncTask<Void, Void, SingleResponse<Bundle>> {

        private final List<ListResponse<twitter4j.Status>> responses;
        private final Uri uri;
        private final boolean should_set_min_id;

        int total_items_inserted = 0;

        public StoreStatusesTask(final List<ListResponse<twitter4j.Status>> result, final Uri uri,
                final boolean should_set_min_id) {
            super(TweetingsService.this, mAsyncTaskManager);
            responses = result;
            this.should_set_min_id = should_set_min_id;
            this.uri = uri;
        }

        public int getTotalItemsInserted() {
            return total_items_inserted;
        }

        public boolean shouldSetMinId() {
            return should_set_min_id;
        }

        @Override
        protected SingleResponse<Bundle> doInBackground(final Void... args) {

            boolean succeed = false;
            final Uri query_uri = buildQueryUri(uri, false);
            final ArrayList<Long> newly_inserted_ids = new ArrayList<Long>();
            final long[] old_ids = getAllStatusesIds(TweetingsService.this, uri,
                    mPreferences.getBoolean(PREFERENCE_KEY_ENABLE_FILTER, false));
            for (final ListResponse<twitter4j.Status> response : responses) {
                final long account_id = response.account_id;
                final List<twitter4j.Status> statuses = response.list;
                if (statuses == null || statuses.size() <= 0) {
                    continue;
                }
                final ArrayList<Long> ids_in_db = Utils.getStatusIdsInDatabase(TweetingsService.this, query_uri,
                        account_id);
                final boolean no_items_before = ids_in_db.size() <= 0;
                final List<ContentValues> values_list = new ArrayList<ContentValues>();
                final List<Long> status_ids = new ArrayList<Long>(), retweet_ids = new ArrayList<Long>();

                long min_id = -1;

                for (final twitter4j.Status status : statuses) {
                    if (status == null) {
                        continue;
                    }
                    final long status_id = status.getId();
                    final long retweet_id = status.getRetweetedStatus() != null
                            ? status.getRetweetedStatus().getId()
                            : -1;

                    status_ids.add(status_id);

                    if ((retweet_id <= 0 || !retweet_ids.contains(retweet_id))
                            && !retweet_ids.contains(status_id)) {
                        if (status_id < min_id || min_id == -1) {
                            min_id = status_id;
                        }
                        if (retweet_id > 0) {
                            retweet_ids.add(retweet_id);
                        }
                        values_list.add(makeStatusContentValues(status, account_id));
                    }

                }

                int rows_deleted = -1;

                // Delete all rows conflicting before new data inserted.
                {

                    final ArrayList<Long> account_newly_inserted = new ArrayList<Long>();
                    account_newly_inserted.addAll(status_ids);
                    account_newly_inserted.removeAll(ids_in_db);
                    newly_inserted_ids.addAll(account_newly_inserted);
                    final StringBuilder where = new StringBuilder();
                    final String ids_string = ListUtils.toString(status_ids, ',', true);
                    where.append(Statuses.ACCOUNT_ID + " = " + account_id);
                    where.append(" AND ");
                    where.append("(");
                    where.append(Statuses.STATUS_ID + " IN ( " + ids_string + " ) ");
                    where.append(" OR ");
                    where.append(Statuses.RETWEET_ID + " IN ( " + ids_string + " ) ");
                    where.append(")");
                    rows_deleted = mResolver.delete(query_uri, where.toString(), null);
                }

                // Insert previously fetched items.
                mResolver.bulkInsert(query_uri, values_list.toArray(new ContentValues[values_list.size()]));

                final int actual_items_inserted = values_list.size() - rows_deleted;

                if (actual_items_inserted > 0) {
                    total_items_inserted += actual_items_inserted;
                }

                int variance = 0;
                final int load_item_limit = mPreferences.getInt(PREFERENCE_KEY_LOAD_ITEM_LIMIT,
                        PREFERENCE_DEFAULT_LOAD_ITEM_LIMIT);
                if (load_item_limit > 50) {
                    variance = 5;
                } else if (load_item_limit > 100) {
                    variance = 10;
                }

                boolean insert_gap = false;
                int tryCount = load_item_limit - variance;
                if (no_items_before) {
                    insert_gap = false;
                }
                if (response.list.size() == 0) {
                    insert_gap = false;
                } else if (load_item_limit == response.list.size()) {
                    insert_gap = true;
                } else if (response.list.size() > tryCount) {
                    insert_gap = true;
                }
                //final boolean insert_gap = rows_deleted == 1 && status_ids.contains(response.max_id)
                //   || rows_deleted == 0 && response.max_id == -1 && !no_items_before;
                if (insert_gap) {
                    final ContentValues values = new ContentValues();
                    values.put(Statuses.IS_GAP, 1);
                    final StringBuilder where = new StringBuilder();
                    where.append(Statuses.ACCOUNT_ID + "=" + account_id);
                    where.append(" AND " + Statuses.STATUS_ID + "=" + min_id);
                    mResolver.update(query_uri, values, where.toString(), null);
                    // Ignore gaps
                    newly_inserted_ids.remove(min_id);
                }
                succeed = true;
            }
            final long[] new_ids = getAllStatusesIds(TweetingsService.this, uri,
                    mPreferences.getBoolean(PREFERENCE_KEY_ENABLE_FILTER, false));
            final Bundle bundle = new Bundle();
            bundle.putBoolean(INTENT_KEY_SUCCEED, succeed);
            getAllStatusesIds(TweetingsService.this, uri,
                    mPreferences.getBoolean(PREFERENCE_KEY_ENABLE_FILTER, false));
            bundle.putInt(INTENT_KEY_ITEMS_INSERTED, new_ids.length - old_ids.length);
            if (should_set_min_id && total_items_inserted > 0) {
                bundle.putLong(INTENT_KEY_MIN_ID, ListUtils.min(newly_inserted_ids));
            }
            return new SingleResponse<Bundle>(-1, bundle, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<Bundle> response) {
            if (response.data.getBoolean(INTENT_KEY_SUCCEED)) {
                notifyForUpdatedUri(TweetingsService.this, uri);
            }
            super.onPostExecute(response);
            mAsyncTaskManager.add(new CacheUsersTask(responses), true);
        }

    }

    class StoreTrendsTask extends ManagedAsyncTask<Void, Void, SingleResponse<Bundle>> {

        private final ListResponse<Trends> response;
        private final Uri uri;

        public StoreTrendsTask(final ListResponse<Trends> result, Uri uri) {
            super(TweetingsService.this, mAsyncTaskManager);
            response = result;
            this.uri = uri;
        }

        @Override
        protected SingleResponse<Bundle> doInBackground(final Void... args) {
            final Bundle bundle = new Bundle();
            if (response != null) {

                final Uri query_uri = buildQueryUri(uri, false);
                final List<Trends> messages = response.list;
                if (messages != null && messages.size() > 0) {
                    final ContentValues[] values_array = makeTrendsContentValues(messages);
                    mResolver.delete(query_uri, null, null);
                    mResolver.bulkInsert(query_uri, values_array);

                    bundle.putBoolean(INTENT_KEY_SUCCEED, true);
                }
            }
            return new SingleResponse<Bundle>(-1, bundle, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<Bundle> response) {
            final Intent intent = new Intent(BROADCAST_TRENDS_UPDATED);
            if (response != null && response.data != null && response.data.getBoolean(INTENT_KEY_SUCCEED)) {
                notifyForUpdatedUri(TweetingsService.this, uri);
                intent.putExtra(INTENT_KEY_SUCCEED, true);
            }
            super.onPostExecute(response);
            sendBroadcast(intent);
        }

    }

    class StoreWeeklyTrendsTask extends StoreTrendsTask {

        public StoreWeeklyTrendsTask(final ListResponse<Trends> result) {
            super(result, CachedTrends.Weekly.CONTENT_URI);
        }

    }

    class UpdateProfileImageTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> {

        private final long account_id;
        private final Uri image_uri;
        private final boolean delete_image;

        public UpdateProfileImageTask(final long account_id, final Uri image_uri, final boolean delete_image) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.image_uri = image_uri;
            this.delete_image = delete_image;
        }

        @Override
        protected SingleResponse<User> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null && image_uri != null && "file".equals(image_uri.getScheme())) {
                try {
                    final User user = twitter.updateProfileImage(new File(image_uri.getPath()));
                    return new SingleResponse<User>(account_id, user, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<User>(account_id, null, e);
                }
            }
            return new SingleResponse<User>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<User> result) {
            if (result != null && result.data != null) {
                Toast.makeText(TweetingsService.this, R.string.profile_image_update_success, Toast.LENGTH_SHORT)
                        .show();
                if (delete_image) {
                    new File(image_uri.getPath()).delete();
                }
            } else {
                showErrorToast(R.string.update, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_PROFILE_UPDATED);
            intent.putExtra(INTENT_KEY_USER_ID, account_id);
            intent.putExtra(INTENT_KEY_SUCCEED, result != null && result.data != null);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class UpdateBannerImageTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> {

        private final long account_id;
        private final Uri image_uri;
        private final boolean delete_image;

        public UpdateBannerImageTask(final long account_id, final Uri image_uri, final boolean delete_image) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.image_uri = image_uri;
            this.delete_image = delete_image;
        }

        @Override
        protected SingleResponse<User> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null && image_uri != null && "file".equals(image_uri.getScheme())) {
                try {
                    final User user = twitter.updateBannerImage(new File(image_uri.getPath()));
                    return new SingleResponse<User>(account_id, user, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<User>(account_id, null, e);
                }
            }
            return new SingleResponse<User>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<User> result) {
            //if (result != null && result.data != null) {
            Toast.makeText(TweetingsService.this, R.string.profile_banner_update_success, Toast.LENGTH_SHORT)
                    .show();
            if (delete_image) {
                new File(image_uri.getPath()).delete();
            }
            //} else {
            //showErrorToast(R.string.update, result.exception, true);
            //}
            final Intent intent = new Intent(BROADCAST_PROFILE_UPDATED);
            intent.putExtra(INTENT_KEY_USER_ID, account_id);
            intent.putExtra(INTENT_KEY_SUCCEED, result != null && result.data != null);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class UpdateProfileTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> {

        private final long account_id;
        private final String name, url, location, description;

        public UpdateProfileTask(final long account_id, final String name, final String url, final String location,
                final String description) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.name = name;
            this.url = url;
            this.location = location;
            this.description = description;
        }

        @Override
        protected SingleResponse<User> doInBackground(final Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final User user = twitter.updateProfile(name, url, location, description);
                    return new SingleResponse<User>(account_id, user, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<User>(account_id, null, e);
                }
            }
            return new SingleResponse<User>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(final SingleResponse<User> result) {
            if (result != null && result.data != null) {
                Toast.makeText(TweetingsService.this, R.string.profile_update_success, Toast.LENGTH_SHORT).show();
            } else {
                showErrorToast(R.string.update, result.exception, true);
            }
            final Intent intent = new Intent(BROADCAST_PROFILE_UPDATED);
            intent.putExtra(INTENT_KEY_USER_ID, account_id);
            intent.putExtra(INTENT_KEY_SUCCEED, result != null && result.data != null);
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

    class ScheduleStatusTask extends ManagedAsyncTask<Void, Void, String> {

        private final Validator validator = new Validator();

        private String schedule_date;
        private long[] account_ids;
        private String content;
        private Location location;
        private Uri image_uri;
        private long in_reply_to;

        private final AudioManager audioManager = (AudioManager) getSystemService(Activity.AUDIO_SERVICE);

        public ScheduleStatusTask(final String schedule_date, final long[] account_ids, final String content,
                final Location location, final Uri image_uri, final long in_reply_to, final boolean delete_image) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_ids = account_ids != null ? account_ids : new long[0];
            this.content = content;
            this.location = location;
            this.image_uri = image_uri;
            this.in_reply_to = in_reply_to;
            this.schedule_date = schedule_date;
        }

        @Override
        protected String doInBackground(final Void... params) {

            if (account_ids.length == 0)
                return null;

            final String unshortened_content = content;
            final String send_on_date = schedule_date;
            final StatusUpdate status = new StatusUpdate(unshortened_content);
            final String deviceId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
            if (location != null) {
                status.setLocation(new GeoLocation(location.getLatitude(), location.getLongitude()));
            }
            if (in_reply_to > 0) {
                status.setInReplyToStatusId(in_reply_to);
            }

            for (final long account_id : account_ids) {

                final String screen_name = getAccountUsername(TweetingsService.this, account_id);

                final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
                AccessToken accessToken = null;
                try {
                    accessToken = twitter.getOAuthAccessToken();
                } catch (TwitterException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }

                HttpClient client = HttpClientFactory.getThreadSafeClient();
                HttpPost post = new HttpPost(TWEETINGS_SCHEDULER_POST_URL);

                if (accessToken != null) {
                    try {
                        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
                        // Get the deviceID
                        nameValuePairs.add(new BasicNameValuePair("status", unshortened_content));
                        if (in_reply_to > 0) {
                            nameValuePairs.add(new BasicNameValuePair("replyto", String.valueOf(in_reply_to)));
                        }
                        if (location != null) {
                            nameValuePairs.add(new BasicNameValuePair("display_coordinates", "true"));
                            nameValuePairs
                                    .add(new BasicNameValuePair("lat", String.valueOf(location.getLatitude())));
                            nameValuePairs
                                    .add(new BasicNameValuePair("long", String.valueOf(location.getLongitude())));
                        }
                        nameValuePairs.add(new BasicNameValuePair("app", "android"));

                        TimeZone tz = TimeZone.getDefault();
                        Date now = new Date();
                        int offsetFromUtc = tz.getOffset(now.getTime());

                        nameValuePairs.add(new BasicNameValuePair("time", send_on_date));
                        nameValuePairs.add(new BasicNameValuePair("tz", String.valueOf(offsetFromUtc)));

                        nameValuePairs.add(new BasicNameValuePair("u", screen_name));
                        nameValuePairs.add(new BasicNameValuePair("did", deviceId));

                        nameValuePairs.add(new BasicNameValuePair("se", accessToken.getTokenSecret()));
                        nameValuePairs.add(new BasicNameValuePair("tk", accessToken.getToken()));

                        post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                        HttpResponse response = client.execute(post);
                        BufferedReader rd = new BufferedReader(
                                new InputStreamReader(response.getEntity().getContent()));
                        String line = "";

                        while ((line = rd.readLine()) != null) {
                            return null;
                            //Log.e("HttpResponse", line);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }

            return "";
        }

        @Override
        protected void onPostExecute(final String result) {

            boolean isMuted = false;
            switch (audioManager.getRingerMode()) {
            case AudioManager.RINGER_MODE_NORMAL:
                isMuted = false;
                break;
            case AudioManager.RINGER_MODE_SILENT:
                isMuted = true;
                break;
            case AudioManager.RINGER_MODE_VIBRATE:
                isMuted = true;
                break;
            }
            if (mPreferences.getBoolean(PREFERENCE_KEY_SOUND_SEND, true)) {
                if (mPlayer != null) {
                    if (mPlayer.isPlaying()) {
                        mPlayer.stop();
                    }
                    mPlayer.release();
                }
                mPlayer = MediaPlayer.create(TweetingsService.this, R.raw.whoosh);
                if (isMuted == true) {
                    mPlayer.setVolume(0, 0);
                }
                mPlayer.start();
            }
            //if (result != null) {
            Toast.makeText(TweetingsService.this, R.string.schedule_success, Toast.LENGTH_SHORT).show();
            //}
            //else {
            //Toast.makeText(TweetingsService.this, R.string.schedule_error, Toast.LENGTH_SHORT).show();
            //}

            super.onPostExecute(result);
        }
    }

    class BufferStatusTask extends ManagedAsyncTask<Void, Void, String> {

        private final Validator validator = new Validator();

        private long[] account_ids;
        private String content;
        private String buffer_access_token;

        private final AudioManager audioManager = (AudioManager) getSystemService(Activity.AUDIO_SERVICE);

        public BufferStatusTask(final long[] account_ids, final String content) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_ids = account_ids != null ? account_ids : new long[0];
            this.content = content;
            this.buffer_access_token = mPreferences.getString(PREFERENCE_KEY_BUFFERAPP_ACCESS_TOKEN, null);
        }

        @Override
        protected String doInBackground(final Void... params) {
            boolean oneOrMoreFailed = true;
            if (account_ids.length == 0)
                return null;
            if (buffer_access_token == null)
                return null;
            final String unshortened_content = content;
            final StatusUpdate status = new StatusUpdate(unshortened_content);

            String accountJson = null;

            HttpClient client = HttpClientFactory.getThreadSafeClient();
            try {
                HttpResponse response = client.execute(new HttpGet(
                        "https://api.bufferapp.com/1/profiles.json?access_token=" + buffer_access_token));

                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(response.getEntity().getContent(), "UTF-8"));

                String sResponse;
                StringBuilder s = new StringBuilder();

                while ((sResponse = reader.readLine()) != null) {
                    s = s.append(sResponse);
                }
                accountJson = s.toString();
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalStateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if (accountJson != null) {
                try {
                    JSONArray jArray = new JSONArray(accountJson);
                    for (int i = 0; i < jArray.length(); i++) {
                        JSONObject jObject = jArray.getJSONObject(i);
                        final String service = jObject.getString("service");
                        final String service_user = jObject.getString("service_username").toLowerCase();
                        final String profile_id = jObject.getString("id");
                        if (service != null && service.equals("twitter")) {
                            for (final long account_id : account_ids) {
                                final String screen_name = getAccountUsername(TweetingsService.this, account_id)
                                        .toLowerCase();
                                if (screen_name.equals(service_user)) {
                                    // We have a matching user!
                                    try {
                                        HttpPost post = new HttpPost(
                                                "https://api.bufferapp.com/1/updates/create.json");
                                        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
                                        nameValuePairs.add(new BasicNameValuePair("text", unshortened_content));
                                        nameValuePairs
                                                .add(new BasicNameValuePair("access_token", buffer_access_token));
                                        nameValuePairs.add(new BasicNameValuePair("profile_ids[]", profile_id));
                                        post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                                        HttpResponse response = client.execute(post);
                                        BufferedReader rd = new BufferedReader(
                                                new InputStreamReader(response.getEntity().getContent()));
                                        String line = "";
                                        String outputContent = "";

                                        while ((line = rd.readLine()) != null) {
                                            outputContent += line;
                                            //Log.e("HttpResponse", line);
                                        }

                                        if (!outputContent.equals("")) {
                                            JSONObject bufferResponse = new JSONObject(outputContent);
                                            boolean didSucceed = bufferResponse.getBoolean("success");
                                            if (didSucceed == true) {
                                                oneOrMoreFailed = false;
                                            } else {
                                                oneOrMoreFailed = true;
                                            }
                                        }
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }

                                }
                            }
                        }
                    }
                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            } else {
                return null;
            }
            if (oneOrMoreFailed == false) {
                boolean isMuted = false;
                switch (audioManager.getRingerMode()) {
                case AudioManager.RINGER_MODE_NORMAL:
                    isMuted = false;
                    break;
                case AudioManager.RINGER_MODE_SILENT:
                    isMuted = true;
                    break;
                case AudioManager.RINGER_MODE_VIBRATE:
                    isMuted = true;
                    break;
                }
                if (mPreferences.getBoolean(PREFERENCE_KEY_SOUND_SEND, true)) {
                    if (mPlayer != null) {
                        if (mPlayer.isPlaying()) {
                            mPlayer.stop();
                        }
                        mPlayer.release();
                    }
                    mPlayer = MediaPlayer.create(TweetingsService.this, R.raw.whoosh);
                    if (isMuted == true) {
                        mPlayer.setVolume(0, 0);
                    }
                    mPlayer.start();
                }
                return "";
            }

            return null;
        }

        @Override
        protected void onPostExecute(final String result) {

            if (result == null) {
                Toast.makeText(TweetingsService.this, R.string.buffer_failed, Toast.LENGTH_SHORT).show();
            } else {
                boolean isMuted = false;
                switch (audioManager.getRingerMode()) {
                case AudioManager.RINGER_MODE_NORMAL:
                    isMuted = false;
                    break;
                case AudioManager.RINGER_MODE_SILENT:
                    isMuted = true;
                    break;
                case AudioManager.RINGER_MODE_VIBRATE:
                    isMuted = true;
                    break;
                }
                if (mPlayer != null) {
                    if (mPlayer.isPlaying()) {
                        mPlayer.stop();
                    }
                    mPlayer.release();
                }
                mPlayer = MediaPlayer.create(TweetingsService.this, R.raw.whoosh);
                if (isMuted == true) {
                    mPlayer.setVolume(0, 0);
                }
                mPlayer.start();
                Toast.makeText(TweetingsService.this, R.string.tweet_buffered, Toast.LENGTH_SHORT).show();
            }
            super.onPostExecute(result);
        }
    }

    class UpdateStatusTask extends ManagedAsyncTask<Void, Void, List<SingleResponse<twitter4j.Status>>> {

        private final ImageUploaderInterface uploader;
        private final TweetShortenerInterface shortener;
        private final Validator validator = new Validator();

        private long[] account_ids;
        private String content;
        private Location location;
        private Uri image_uri;
        private Timer uploadTimer;
        private long in_reply_to;
        private boolean use_uploader, use_shortener, delete_image, is_possibly_sensitive;
        private Notification notification;
        private NotificationManager notificationManager;

        private final AudioManager audioManager = (AudioManager) getSystemService(Activity.AUDIO_SERVICE);

        public UpdateStatusTask(final long[] account_ids, final String content, final Location location,
                final Uri image_uri, final long in_reply_to, final boolean is_possibly_sensitive,
                final boolean delete_image) {
            super(TweetingsService.this, mAsyncTaskManager);
            final String uploader_component = mPreferences.getString(PREFERENCE_KEY_IMAGE_UPLOADER, null);
            final String shortener_component = mPreferences.getString(PREFERENCE_KEY_TWEET_SHORTENER, null);
            use_uploader = !isNullOrEmpty(uploader_component);
            uploader = use_uploader ? ImageUploaderInterface.getInstance(getApplication(), uploader_component)
                    : null;
            use_shortener = !isNullOrEmpty(shortener_component);
            shortener = use_shortener ? TweetShortenerInterface.getInstance(getApplication(), shortener_component)
                    : null;
            this.account_ids = account_ids != null ? account_ids : new long[0];
            this.content = content;
            this.location = location;
            this.image_uri = image_uri;
            this.in_reply_to = in_reply_to;
            this.delete_image = delete_image;
            this.is_possibly_sensitive = is_possibly_sensitive;
        }

        @Override
        protected List<SingleResponse<twitter4j.Status>> doInBackground(final Void... params) {

            final List<SingleResponse<twitter4j.Status>> result = new ArrayList<SingleResponse<twitter4j.Status>>();

            if (account_ids.length == 0)
                return result;

            try {
                if (use_shortener && shortener == null)
                    throw new TweetShortenerNotFoundException();

                final String image_path = getImagePathFromUri(TweetingsService.this, image_uri);
                final File image_file = image_path != null ? new File(image_path) : null;
                if (uploader != null) {
                    uploader.waitForService();
                }

                final String unshortened_content = content;
                final StatusUpdate status = new StatusUpdate(unshortened_content);

                if (location != null) {
                    status.setLocation(new GeoLocation(location.getLatitude(), location.getLongitude()));
                }
                if (in_reply_to > 0) {
                    status.setInReplyToStatusId(in_reply_to);
                }
                if (!use_uploader && image_file != null && image_file.exists()) {
                    status.setMedia(image_file);
                }
                status.setPossiblySensitive(is_possibly_sensitive);

                for (final long account_id : account_ids) {
                    final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);

                    if (!use_uploader && image_file != null && image_file.exists()) {
                        /*CreateNotification();
                        uploadTimer = new Timer();
                         uploadTimer.schedule(new TimerTask() {         
                            @Override
                            public void run() {
                               UploadProgressMethod(twitter);
                            }
                                
                         }, 0, 50);*/
                    }

                    if (twitter != null) {
                        try {
                            result.add(new SingleResponse<twitter4j.Status>(account_id,
                                    twitter.updateStatus(status), null));
                        } catch (final TwitterException e) {
                            e.printStackTrace();
                            result.add(new SingleResponse<twitter4j.Status>(account_id, null, e));
                        }
                    }
                }
            } catch (final UpdateStatusException e) {
                for (final long account_id : account_ids) {
                    result.add(new SingleResponse<twitter4j.Status>(account_id, null, e));
                }
            }
            return result;
        }

        protected void CreateNotification() {
            // configure the notification
            Intent intent = new Intent(TweetingsService.this, HomeActivity.class);
            final PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);

            notification = new Notification(R.drawable.logo, getString(R.string.uploading_media),
                    System.currentTimeMillis());
            notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;
            notification.contentView = new RemoteViews(getApplicationContext().getPackageName(),
                    R.layout.upload_progress);
            notification.contentIntent = pendingIntent;
            notification.contentView.setImageViewResource(R.id.status_icon, R.drawable.logo);
            notification.contentView.setTextViewText(R.id.status_text, getString(R.string.uploading_media));
            notification.contentView.setProgressBar(R.id.status_progress, 100, 0, false);
            notificationManager = (NotificationManager) getApplicationContext()
                    .getSystemService(Context.NOTIFICATION_SERVICE);

            notificationManager.notify(NOTIFICATION_ID_UPLOAD_PROGRESS, notification);
        }

        protected void UploadProgressMethod(final Twitter twitter) {
            if (twitter.getHttpClientWrapper() != null) {
                HttpClientWrapper http = twitter.getHttpClientWrapper();
                float progress = (float) http.getRequestStatus() / (float) http.getRequestLength();
                float longPc = progress * 100;
                int percentage = Math.round(longPc);
                if (notification != null && notificationManager != null) {
                    notification.contentView.setProgressBar(R.id.status_progress, 100, percentage, false);

                    // inform the progress bar of updates in progress
                    notificationManager.notify(NOTIFICATION_ID_UPLOAD_PROGRESS, notification);
                }
            }
            ;
        }

        @Override
        protected void onPostExecute(final List<SingleResponse<twitter4j.Status>> result) {

            /*if (uploadTimer != null) {
               uploadTimer.cancel();
            }
            NotificationManager notificationManager = (NotificationManager) getApplicationContext()
                  .getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.cancelAll();*/

            boolean succeed = true;
            Exception exception = null;
            final List<Long> failed_account_ids = new ArrayList<Long>();

            for (final SingleResponse<twitter4j.Status> response : result) {
                if (response.data == null) {
                    succeed = false;
                    failed_account_ids.add(response.account_id);
                    if (exception == null) {
                        exception = response.exception;
                    }
                }
            }
            if (succeed) {
                boolean isMuted = false;
                switch (audioManager.getRingerMode()) {
                case AudioManager.RINGER_MODE_NORMAL:
                    isMuted = false;
                    break;
                case AudioManager.RINGER_MODE_SILENT:
                    isMuted = true;
                    break;
                case AudioManager.RINGER_MODE_VIBRATE:
                    isMuted = true;
                    break;
                }
                if (mPreferences.getBoolean(PREFERENCE_KEY_SOUND_SEND, true)) {
                    if (mPlayer != null) {
                        if (mPlayer.isPlaying()) {
                            mPlayer.stop();
                        }
                        mPlayer.release();
                    }
                    mPlayer = MediaPlayer.create(TweetingsService.this, R.raw.whoosh);
                    if (isMuted == true) {
                        mPlayer.setVolume(0, 0);
                    }
                    mPlayer.start();
                }
                Toast.makeText(TweetingsService.this, R.string.send_success, Toast.LENGTH_SHORT).show();
                if (image_uri != null && delete_image) {
                    final String path = getImagePathFromUri(TweetingsService.this, image_uri);
                    if (path != null) {
                        new File(path).delete();
                    }
                }
            } else {
                showErrorToast(R.string.send, exception, true);

                final ContentValues values = new ContentValues();
                values.put(Drafts.ACCOUNT_IDS, ListUtils.toString(failed_account_ids, ';', false));
                values.put(Drafts.IN_REPLY_TO_STATUS_ID, in_reply_to);
                values.put(Drafts.TEXT, content);
                if (mPreferences.getBoolean(PREFERENCE_KEY_AUTOMATIC_RETRY, false)) {
                    values.put(Drafts.IS_QUEUED, true);
                } else {
                    values.put(Drafts.IS_QUEUED, false);
                }
                if (image_uri != null) {
                    values.put(Drafts.IS_IMAGE_ATTACHED, !delete_image);
                    values.put(Drafts.IS_PHOTO_ATTACHED, delete_image);
                    values.put(Drafts.IMAGE_URI, parseString(image_uri));
                }

                mResolver.insert(Drafts.CONTENT_URI, values);
                final String title = getString(R.string.tweet_not_sent);
                final String message = getString(R.string.tweet_not_sent_summary);
                final Intent intent = new Intent(INTENT_ACTION_DRAFTS);
                final Notification notification = buildNotification(title, message, R.drawable.ic_stat_tweet,
                        intent, null);
                mNotificationManager.notify(NOTIFICATION_ID_DRAFTS, notification);

            }
            super.onPostExecute(result);

            // Add sound in here

            if (mPreferences.getBoolean(PREFERENCE_KEY_REFRESH_AFTER_TWEET, true)) {
                final long[] activated_ids = getActivatedAccountIds(TweetingsService.this);
                getHomeTimeline(activated_ids, null);
                if (mPreferences.getBoolean(PREFERENCE_KEY_HOME_REFRESH_MENTIONS, false)) {
                    getMentions(account_ids, null);
                }
                if (mPreferences.getBoolean(PREFERENCE_KEY_HOME_REFRESH_DIRECT_MESSAGES, false)) {
                    getReceivedDirectMessages(account_ids, null);
                    //getSentDirectMessages(account_ids, null);
                }
            }
        }

        class ImageUploaderNotFoundException extends UpdateStatusException {
            private static final long serialVersionUID = 1041685850011544106L;

            public ImageUploaderNotFoundException() {
                super(R.string.error_message_image_uploader_not_found);
            }
        }

        class ImageUploadException extends UpdateStatusException {
            private static final long serialVersionUID = 8596614696393917525L;

            public ImageUploadException() {
                super(R.string.error_message_image_upload_failed);
            }
        }

        class StatusTooLongException extends UpdateStatusException {
            private static final long serialVersionUID = -6469920130856384219L;

            public StatusTooLongException() {
                super(R.string.error_message_status_too_long);
            }
        }

        class TweetShortenerNotFoundException extends UpdateStatusException {
            private static final long serialVersionUID = -7262474256595304566L;

            public TweetShortenerNotFoundException() {
                super(R.string.error_message_tweet_shortener_not_found);
            }
        }

        class TweetShortenException extends UpdateStatusException {
            private static final long serialVersionUID = 3075877185536740034L;

            public TweetShortenException() {
                super(R.string.error_message_tweet_shorten_failed);
            }
        }

        class UpdateStatusException extends Exception {
            private static final long serialVersionUID = -1267218921727097910L;

            public UpdateStatusException(int message) {
                super(getString(message));
            }
        }
    }

    class UpdateUserListProfileTask extends ManagedAsyncTask<Void, Void, SingleResponse<UserList>> {

        private final long account_id;
        private final int list_id;
        private final boolean is_public;
        private final String name, description;

        public UpdateUserListProfileTask(long account_id, int list_id, boolean is_public, String name,
                String description) {
            super(TweetingsService.this, mAsyncTaskManager);
            this.account_id = account_id;
            this.name = name;
            this.list_id = list_id;
            this.is_public = is_public;
            this.description = description;
        }

        @Override
        protected SingleResponse<UserList> doInBackground(Void... params) {

            final Twitter twitter = getTwitterInstance(TweetingsService.this, account_id, false);
            if (twitter != null) {
                try {
                    final UserList user = twitter.updateUserList(list_id, name, is_public, description);
                    return new SingleResponse<UserList>(account_id, user, null);
                } catch (final TwitterException e) {
                    return new SingleResponse<UserList>(account_id, null, e);
                }
            }
            return new SingleResponse<UserList>(account_id, null, null);
        }

        @Override
        protected void onPostExecute(SingleResponse<UserList> result) {
            final Intent intent = new Intent(BROADCAST_USER_LIST_DETAILS_UPDATED);
            intent.putExtra(INTENT_KEY_LIST_ID, list_id);
            if (result != null && result.data != null && result.data.getId() > 0) {
                Toast.makeText(TweetingsService.this, R.string.profile_update_success, Toast.LENGTH_SHORT).show();
                intent.putExtra(INTENT_KEY_SUCCEED, true);
            } else {
                showErrorToast(R.string.update, result.exception, true);
            }
            sendBroadcast(intent);
            super.onPostExecute(result);
        }

    }

}