Java tutorial
/* * Twidere - Twitter client for Android * * 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 org.mariotaku.twidere.service; import static org.mariotaku.twidere.util.Utils.buildQueryUri; import static org.mariotaku.twidere.util.Utils.getActivatedAccountIds; import static org.mariotaku.twidere.util.Utils.getImagePathFromUri; import static org.mariotaku.twidere.util.Utils.getRetweetId; import static org.mariotaku.twidere.util.Utils.getTwitterInstance; import static org.mariotaku.twidere.util.Utils.makeCachedUserContentValues; import static org.mariotaku.twidere.util.Utils.makeDirectMessageContentValues; import static org.mariotaku.twidere.util.Utils.makeStatusContentValues; import static org.mariotaku.twidere.util.Utils.makeTrendsContentValues; import static org.mariotaku.twidere.util.Utils.notifyForUpdatedUri; import static org.mariotaku.twidere.util.Utils.parseInt; import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import org.mariotaku.twidere.Constants; import org.mariotaku.twidere.ITwidereService; import org.mariotaku.twidere.R; import org.mariotaku.twidere.activity.HomeActivity; import org.mariotaku.twidere.app.TwidereApplication; import org.mariotaku.twidere.provider.TweetStore; import org.mariotaku.twidere.provider.TweetStore.CachedTrends; import org.mariotaku.twidere.provider.TweetStore.CachedUsers; import org.mariotaku.twidere.provider.TweetStore.DirectMessages; import org.mariotaku.twidere.provider.TweetStore.Drafts; import org.mariotaku.twidere.provider.TweetStore.Mentions; import org.mariotaku.twidere.provider.TweetStore.Statuses; import org.mariotaku.twidere.util.AsyncTaskManager; import org.mariotaku.twidere.util.ImageUploaderInterface; import org.mariotaku.twidere.util.ListUtils; import org.mariotaku.twidere.util.ManagedAsyncTask; import org.mariotaku.twidere.util.Utils; import twitter4j.DirectMessage; import twitter4j.GeoLocation; import twitter4j.Paging; import twitter4j.ResponseList; import twitter4j.StatusUpdate; import twitter4j.Trends; import twitter4j.Twitter; import twitter4j.TwitterException; import twitter4j.User; import twitter4j.UserList; 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.net.Uri; import android.os.Bundle; import android.os.IBinder; import android.provider.Settings; import android.support.v4.app.NotificationCompat; import android.widget.Toast; public class TwidereService extends Service implements Constants { private final ServiceStub mBinder = new ServiceStub(this); private AsyncTaskManager mAsyncTaskManager; private SharedPreferences mPreferences; private NotificationManager mNotificationManager; 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 mShouldShutdown = false; private BroadcastReceiver mStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (BROADCAST_REFRESHSTATE_CHANGED.equals(action)) { if (!mAsyncTaskManager.hasActivatedTask() && mShouldShutdown) { stopSelf(); } } 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 (BROADCAST_AUTO_REFRESH.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); } } if (mPreferences.getBoolean(PREFERENCE_KEY_REFRESH_ENABLE_MENTIONS, false)) { if (!isMentionsRefreshing()) { getMentions(activated_ids, null, true); } } if (mPreferences.getBoolean(PREFERENCE_KEY_REFRESH_ENABLE_DIRECT_MESSAGES, false)) { if (!isReceivedDirectMessagesRefreshing()) { getReceivedDirectMessages(activated_ids, null, true); } } } } }; private int mNewMessagesCount, mNewMentionsCount, mNewStatusesCount; private AlarmManager mAlarmManager; private PendingIntent mPendingRefreshIntent;; public int addUserListMember(long account_id, int list_id, long user_id, String screen_name) { final AddUserListMemberTask task = new AddUserListMemberTask(account_id, list_id, user_id, screen_name); return mAsyncTaskManager.add(task, true); } public int cancelRetweet(long account_id, long status_id) { final CancelRetweetTask task = new CancelRetweetTask(account_id, status_id); return mAsyncTaskManager.add(task, true); } public void clearNotification(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(long account_id, long user_id) { final CreateBlockTask task = new CreateBlockTask(account_id, user_id); return mAsyncTaskManager.add(task, true); } public int createFavorite(long account_id, long status_id) { final CreateFavoriteTask task = new CreateFavoriteTask(account_id, status_id); return mAsyncTaskManager.add(task, true); } public int createFriendship(long account_id, long user_id) { final CreateFriendshipTask task = new CreateFriendshipTask(account_id, user_id); return mAsyncTaskManager.add(task, true); } public int createUserList(long account_id, String list_name, boolean is_public, String description) { final CreateUserListTask task = new CreateUserListTask(account_id, list_name, is_public, description); return mAsyncTaskManager.add(task, true); } public int createUserListSubscription(long account_id, int list_id) { final CreateUserListSubscriptionTask task = new CreateUserListSubscriptionTask(account_id, list_id); return mAsyncTaskManager.add(task, true); } public int deleteUserListMember(long account_id, int list_id, long user_id) { final DeleteUserListMemberTask task = new DeleteUserListMemberTask(account_id, list_id, user_id); return mAsyncTaskManager.add(task, true); } public int destroyBlock(long account_id, long user_id) { final DestroyBlockTask task = new DestroyBlockTask(account_id, user_id); return mAsyncTaskManager.add(task, true); } public int destroyDirectMessage(long account_id, long message_id) { final DestroyDirectMessageTask task = new DestroyDirectMessageTask(account_id, message_id); return mAsyncTaskManager.add(task, true); } public int destroyFavorite(long account_id, long status_id) { final DestroyFavoriteTask task = new DestroyFavoriteTask(account_id, status_id); return mAsyncTaskManager.add(task, true); } public int destroyFriendship(long account_id, long user_id) { final DestroyFriendshipTask task = new DestroyFriendshipTask(account_id, user_id); return mAsyncTaskManager.add(task, true); } public int destroyStatus(long account_id, long status_id) { final DestroyStatusTask task = new DestroyStatusTask(account_id, status_id); return mAsyncTaskManager.add(task, true); } public int destroyUserList(long account_id, int list_id) { final DestroyUserListTask task = new DestroyUserListTask(account_id, list_id); return mAsyncTaskManager.add(task, true); } public int destroyUserListSubscription(long account_id, int list_id) { final DestroyUserListSubscriptionTask task = new DestroyUserListSubscriptionTask(account_id, list_id); return mAsyncTaskManager.add(task, true); } public int getDailyTrends(long account_id) { mAsyncTaskManager.cancel(mGetDailyTrendsTaskId); final GetDailyTrendsTask task = new GetDailyTrendsTask(account_id); return mGetDailyTrendsTaskId = mAsyncTaskManager.add(task, true); } public int getHomeTimeline(long[] account_ids, long[] max_ids) { final boolean notification = mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_HOME_TIMELINE, false); return getHomeTimeline(account_ids, max_ids, notification); } public int getLocalTrends(long account_id, int woeid) { mAsyncTaskManager.cancel(mGetLocalTrendsTaskId); final GetLocalTrendsTask task = new GetLocalTrendsTask(account_id, woeid); return mGetLocalTrendsTaskId = mAsyncTaskManager.add(task, true); } public int getMentions(long[] account_ids, long[] max_ids) { final boolean notification = mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_MENTIONS, false); return getMentions(account_ids, max_ids, notification); } public int getReceivedDirectMessages(long[] account_ids, long[] max_ids) { final boolean notification = mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_DIRECT_MESSAGES, false); return getReceivedDirectMessages(account_ids, max_ids, notification); } public int getSentDirectMessages(long[] account_ids, long[] max_ids) { mAsyncTaskManager.cancel(mGetSentDirectMessagesTaskId); final GetSentDirectMessagesTask task = new GetSentDirectMessagesTask(account_ids, max_ids); return mGetSentDirectMessagesTaskId = mAsyncTaskManager.add(task, true); } public int getWeeklyTrends(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(Intent intent) { return mBinder; } @Override public void onCreate() { super.onCreate(); mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); mAsyncTaskManager = ((TwidereApplication) getApplication()).getAsyncTaskManager(); mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE); final Intent refresh_intent = new Intent(BROADCAST_AUTO_REFRESH); mPendingRefreshIntent = PendingIntent.getBroadcast(this, 0, refresh_intent, 0); final IntentFilter filter = new IntentFilter(BROADCAST_REFRESHSTATE_CHANGED); filter.addAction(BROADCAST_NOTIFICATION_CLEARED); filter.addAction(BROADCAST_AUTO_REFRESH); 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 int reportSpam(long account_id, long user_id) { final ReportSpamTask task = new ReportSpamTask(account_id, user_id); return mAsyncTaskManager.add(task, true); } public int retweetStatus(long account_id, long status_id) { final RetweetStatusTask task = new RetweetStatusTask(account_id, status_id); return mAsyncTaskManager.add(task, true); } public int sendDirectMessage(long account_id, String screen_name, long user_id, 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() { mAlarmManager.cancel(mPendingRefreshIntent); 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, mPendingRefreshIntent); return true; } return false; } public void stopAutoRefresh() { mAlarmManager.cancel(mPendingRefreshIntent); } public boolean test() { try { return startService(new Intent(INTENT_ACTION_SERVICE)) != null; } catch (final Exception e) { return false; } } public int updateProfile(long account_id, String name, String url, String location, String description) { final UpdateProfileTask task = new UpdateProfileTask(account_id, name, url, location, description); return mAsyncTaskManager.add(task, true); } public int updateProfileImage(long account_id, Uri image_uri, boolean delete_image) { final UpdateProfileImageTask task = new UpdateProfileImageTask(account_id, image_uri, delete_image); return mAsyncTaskManager.add(task, true); } public int updateStatus(long[] account_ids, String content, Location location, Uri image_uri, long in_reply_to, boolean delete_image) { final UpdateStatusTask task = new UpdateStatusTask(account_ids, content, location, image_uri, in_reply_to, delete_image); return mAsyncTaskManager.add(task, true); } public int updateUserListDetails(long account_id, int list_id, boolean is_public, String name, String description) { final UpdateUserListProfileTask task = new UpdateUserListProfileTask(account_id, list_id, is_public, name, description); return mAsyncTaskManager.add(task, true); } private Notification buildNotification(String message, int icon, Intent content_intent, Intent delete_intent) { final NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setTicker(message); builder.setContentTitle(getString(R.string.new_notifications)); builder.setContentText(message); builder.setAutoCancel(true); builder.setWhen(System.currentTimeMillis()); builder.setSmallIcon(icon); builder.setDeleteIntent( PendingIntent.getBroadcast(this, 0, delete_intent, PendingIntent.FLAG_UPDATE_CURRENT)); builder.setContentIntent( PendingIntent.getActivity(this, 0, content_intent, PendingIntent.FLAG_UPDATE_CURRENT)); int defaults = 0; if (mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_HAVE_SOUND, false)) { builder.setSound(Uri.parse(mPreferences.getString(PREFERENCE_KEY_NOTIFICATION_RINGTONE, Settings.System.DEFAULT_RINGTONE_URI.getPath())), Notification.STREAM_DEFAULT); } if (mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_HAVE_VIBRATION, false)) { defaults |= Notification.DEFAULT_VIBRATE; } if (mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_HAVE_LIGHTS, false)) { final int color_def = getResources().getColor(R.color.holo_blue_light); 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(long[] account_ids, long[] max_ids, boolean is_auto_refresh) { mAsyncTaskManager.cancel(mGetHomeTimelineTaskId); final GetHomeTimelineTask task = new GetHomeTimelineTask(account_ids, max_ids, is_auto_refresh); return mGetHomeTimelineTaskId = mAsyncTaskManager.add(task, true); } private int getMentions(long[] account_ids, long[] max_ids, boolean is_auto_refresh) { mAsyncTaskManager.cancel(mGetMentionsTaskId); final GetMentionsTask task = new GetMentionsTask(account_ids, max_ids, is_auto_refresh); return mGetMentionsTaskId = mAsyncTaskManager.add(task, true); } private int getReceivedDirectMessages(long[] account_ids, long[] max_ids, boolean is_auto_refresh) { mAsyncTaskManager.cancel(mGetReceivedDirectMessagesTaskId); final GetReceivedDirectMessagesTask task = new GetReceivedDirectMessagesTask(account_ids, max_ids, is_auto_refresh); return mGetReceivedDirectMessagesTaskId = mAsyncTaskManager.add(task, true); } private void showErrorToast(Exception e, boolean long_message) { Utils.showErrorToast(this, e, long_message); } private 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(long account_id, int list_id, long user_id, String screen_name) { super(TwidereService.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(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<UserList> result) { final boolean succeed = result != null && result.data != null && result.data.getId() > 0; if (succeed) { Toast.makeText(TwidereService.this, R.string.add_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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); } } private class CacheUsersTask extends ManagedAsyncTask<Void, Void, Void> { private final List<ListResponse<twitter4j.Status>> responses; public CacheUsersTask(List<ListResponse<twitter4j.Status>> result) { super(TwidereService.this, mAsyncTaskManager); responses = result; } @Override protected Void doInBackground(Void... args) { final ContentResolver resolver = getContentResolver(); 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)); } } resolver.delete(CachedUsers.CONTENT_URI, CachedUsers.USER_ID + " IN (" + ListUtils.buildString(user_ids, ',', true) + " )", null); resolver.bulkInsert(CachedUsers.CONTENT_URI, cached_users_list.toArray(new ContentValues[cached_users_list.size()])); } return null; } } private class CancelRetweetTask extends ManagedAsyncTask<Void, Void, SingleResponse<twitter4j.Status>> { private long account_id; private long status_id, retweeted_id; public CancelRetweetTask(long account_id, long status_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.status_id = status_id; } @Override protected SingleResponse<twitter4j.Status> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.this, account_id, false); if (twitter != null) { try { final twitter4j.Status status = twitter.destroyStatus(retweeted_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(SingleResponse<twitter4j.Status> result) { if (result != null && result.data != null) { final ContentResolver resolver = getContentResolver(); final User user = result.data.getUser(); final twitter4j.Status retweeted_status = result.data.getRetweetedStatus(); if (user != null && retweeted_status != null) { final ContentValues values = new ContentValues(); values.put(Statuses.RETWEET_COUNT, result.data.getRetweetCount()); values.put(Statuses.RETWEET_ID, -1); values.put(Statuses.RETWEETED_BY_ID, -1); values.put(Statuses.RETWEETED_BY_NAME, ""); values.put(Statuses.RETWEETED_BY_SCREEN_NAME, ""); values.put(Statuses.IS_RETWEET, 0); final String status_where = Statuses.STATUS_ID + " = " + result.data.getId(); final String retweet_where = Statuses.STATUS_ID + " = " + retweeted_status.getId(); for (final Uri uri : TweetStore.STATUSES_URIS) { resolver.delete(uri, status_where, null); resolver.update(uri, values, retweet_where, null); } } Toast.makeText(TwidereService.this, R.string.cancel_retweet_success, Toast.LENGTH_SHORT).show(); final Intent intent = new Intent(BROADCAST_RETWEET_CHANGED); intent.putExtra(INTENT_KEY_STATUS_ID, status_id); intent.putExtra(INTENT_KEY_RETWEETED, false); sendBroadcast(intent); } else { showErrorToast(result.exception, true); } super.onPostExecute(result); } @Override protected void onPreExecute() { super.onPreExecute(); retweeted_id = getRetweetId(TwidereService.this, status_id); } } private class CreateBlockTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> { private long account_id; private long user_id; public CreateBlockTask(long account_id, long user_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.user_id = user_id; } @Override protected SingleResponse<User> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<User> result) { if (result != null && result.data != null) { Toast.makeText(TwidereService.this, R.string.user_blocked, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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); } } private class CreateFavoriteTask extends ManagedAsyncTask<Void, Void, SingleResponse<twitter4j.Status>> { private long account_id; private long status_id; public CreateFavoriteTask(long account_id, long status_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.status_id = status_id; } @Override protected SingleResponse<twitter4j.Status> doInBackground(Void... params) { if (account_id < 0) return new SingleResponse<twitter4j.Status>(account_id, null, null); final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<twitter4j.Status> result) { final ContentResolver resolver = getContentResolver(); 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) { resolver.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(TwidereService.this, R.string.favorite_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(result.exception, true); } super.onPostExecute(result); } } private class CreateFriendshipTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> { private long account_id; private long user_id; public CreateFriendshipTask(long account_id, long user_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.user_id = user_id; } @Override protected SingleResponse<User> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<User> result) { if (result != null && result.data != null) { Toast.makeText(TwidereService.this, R.string.follow_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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); } } private class CreateUserListSubscriptionTask extends ManagedAsyncTask<Void, Void, SingleResponse<UserList>> { private final long account_id; private final int list_id; public CreateUserListSubscriptionTask(long account_id, int list_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.list_id = list_id; } @Override protected SingleResponse<UserList> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<UserList> result) { final boolean succeed = result != null && result.data != null && result.data.getId() > 0; if (succeed) { Toast.makeText(TwidereService.this, R.string.follow_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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); } } private 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(long account_id, String list_name, boolean is_public, String description) { super(TwidereService.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(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<UserList> result) { final boolean succeed = result != null && result.data != null && result.data.getId() > 0; if (succeed) { Toast.makeText(TwidereService.this, R.string.create_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(result.exception, true); } final Intent intent = new Intent(BROADCAST_USER_LIST_CREATED); intent.putExtra(INTENT_KEY_SUCCEED, succeed); sendBroadcast(intent); super.onPostExecute(result); } } private class DeleteUserListMemberTask extends ManagedAsyncTask<Void, Void, SingleResponse<UserList>> { private final long account_id, user_id; private final int list_id; public DeleteUserListMemberTask(long account_id, int list_id, long user_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.list_id = list_id; this.user_id = user_id; } @Override protected SingleResponse<UserList> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<UserList> result) { final boolean succeed = result != null && result.data != null && result.data.getId() > 0; if (succeed) { Toast.makeText(TwidereService.this, R.string.delete_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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); } } private class DestroyBlockTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> { private long account_id; private long user_id; public DestroyBlockTask(long account_id, long user_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.user_id = user_id; } @Override protected SingleResponse<User> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<User> result) { if (result != null && result.data != null) { Toast.makeText(TwidereService.this, R.string.user_unblocked, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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); } } private class DestroyDirectMessageTask extends ManagedAsyncTask<Void, Void, SingleResponse<DirectMessage>> { private final Twitter twitter; private final long message_id; private final long account_id; public DestroyDirectMessageTask(long account_id, long message_id) { super(TwidereService.this, mAsyncTaskManager); twitter = getTwitterInstance(TwidereService.this, account_id, false); this.account_id = account_id; this.message_id = message_id; } @Override protected SingleResponse<DirectMessage> doInBackground(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(SingleResponse<DirectMessage> result) { super.onPostExecute(result); if (result == null) return; if (result.data != null && result.data.getId() > 0) { Toast.makeText(TwidereService.this, R.string.delete_success, Toast.LENGTH_SHORT).show(); final String where = DirectMessages.MESSAGE_ID + " = " + result.data.getId(); final ContentResolver resolver = getContentResolver(); resolver.delete(DirectMessages.Inbox.CONTENT_URI, where, null); resolver.delete(DirectMessages.Outbox.CONTENT_URI, where, null); } else { showErrorToast(result.exception, true); } } } private class DestroyFavoriteTask extends ManagedAsyncTask<Void, Void, SingleResponse<twitter4j.Status>> { private long account_id; private long status_id; public DestroyFavoriteTask(long account_id, long status_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.status_id = status_id; } @Override protected SingleResponse<twitter4j.Status> doInBackground(Void... params) { if (account_id < 0) { new SingleResponse<twitter4j.Status>(account_id, null, null); } final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<twitter4j.Status> result) { final ContentResolver resolver = getContentResolver(); 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) { resolver.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(TwidereService.this, R.string.unfavorite_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(result.exception, true); } super.onPostExecute(result); } } private class DestroyFriendshipTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> { private long account_id; private long user_id; public DestroyFriendshipTask(long account_id, long user_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.user_id = user_id; } @Override protected SingleResponse<User> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<User> result) { if (result != null && result.data != null) { Toast.makeText(TwidereService.this, R.string.unfollow_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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); } } private class DestroyStatusTask extends ManagedAsyncTask<Void, Void, SingleResponse<twitter4j.Status>> { private long account_id; private long status_id; public DestroyStatusTask(long account_id, long status_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.status_id = status_id; } @Override protected SingleResponse<twitter4j.Status> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(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 ContentResolver resolver = getContentResolver(); 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) { resolver.delete(uri, where.toString(), null); } intent.putExtra(INTENT_KEY_STATUS_ID, status_id); intent.putExtra(INTENT_KEY_SUCCEED, true); Toast.makeText(TwidereService.this, R.string.delete_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(result.exception, true); } sendBroadcast(intent); super.onPostExecute(result); } } private class DestroyUserListSubscriptionTask extends ManagedAsyncTask<Void, Void, SingleResponse<UserList>> { private final long account_id; private final int list_id; public DestroyUserListSubscriptionTask(long account_id, int list_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.list_id = list_id; } @Override protected SingleResponse<UserList> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<UserList> result) { final boolean succeed = result != null && result.data != null && result.data.getId() > 0; if (succeed) { Toast.makeText(TwidereService.this, R.string.unfollow_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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); } } private class DestroyUserListTask extends ManagedAsyncTask<Void, Void, SingleResponse<UserList>> { private final long account_id; private final int list_id; public DestroyUserListTask(long account_id, int list_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.list_id = list_id; } @Override protected SingleResponse<UserList> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<UserList> result) { final boolean succeed = result != null && result.data != null && result.data.getId() > 0; if (succeed) { Toast.makeText(TwidereService.this, R.string.delete_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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); } } private class GetDailyTrendsTask extends GetTrendsTask { public GetDailyTrendsTask(long account_id) { super(account_id); } @Override public ResponseList<Trends> getTrends(Twitter twitter) throws TwitterException { if (twitter == null) return null; return twitter.getDailyTrends(); } @Override protected void onPostExecute(ListResponse<Trends> result) { mStoreDailyTrendsTaskId = mAsyncTaskManager.add(new StoreDailyTrendsTask(result), true); super.onPostExecute(result); } } private abstract class GetDirectMessagesTask extends ManagedAsyncTask<Void, Void, List<ListResponse<DirectMessage>>> { private final long[] account_ids, max_ids; public GetDirectMessagesTask(Uri uri, long[] account_ids, long[] max_ids) { super(TwidereService.this, mAsyncTaskManager); this.account_ids = account_ids; this.max_ids = max_ids; } public abstract ResponseList<DirectMessage> getDirectMessages(Twitter twitter, Paging paging) throws TwitterException; @Override protected List<ListResponse<DirectMessage>> doInBackground(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; 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(TwidereService.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); } final ResponseList<DirectMessage> statuses = getDirectMessages(twitter, paging); if (statuses != null) { result.add(new ListResponse<DirectMessage>(account_id, max_id, statuses)); } } catch (final TwitterException e) { e.printStackTrace(); } } idx++; } return result; } } private class GetHomeTimelineTask extends GetStatusesTask { private final boolean is_auto_refresh; public GetHomeTimelineTask(long[] account_ids, long[] max_ids, boolean is_auto_refresh) { super(Statuses.CONTENT_URI, account_ids, max_ids); this.is_auto_refresh = is_auto_refresh; } @Override public ResponseList<twitter4j.Status> getStatuses(Twitter twitter, Paging paging) throws TwitterException { return twitter.getHomeTimeline(paging); } @Override public Twitter getTwitter(long account_id) { return getTwitterInstance(TwidereService.this, account_id, true, true); } @Override protected void onPostExecute(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() { super.onPreExecute(); } } private class GetLocalTrendsTask extends GetTrendsTask { private final int woeid; public GetLocalTrendsTask(long account_id, int woeid) { super(account_id); this.woeid = woeid; } @Override public List<Trends> getTrends(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(ListResponse<Trends> result) { mStoreLocalTrendsTaskId = mAsyncTaskManager.add(new StoreLocalTrendsTask(result), true); super.onPostExecute(result); } } private class GetMentionsTask extends GetStatusesTask { private final boolean is_auto_refresh; public GetMentionsTask(long[] account_ids, long[] max_ids, boolean is_auto_refresh) { super(Mentions.CONTENT_URI, account_ids, max_ids); this.is_auto_refresh = is_auto_refresh; } @Override public ResponseList<twitter4j.Status> getStatuses(Twitter twitter, Paging paging) throws TwitterException { return twitter.getMentions(paging); } @Override public Twitter getTwitter(long account_id) { return getTwitterInstance(TwidereService.this, account_id, true, false); } @Override protected void onPostExecute(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() { super.onPreExecute(); } } private class GetReceivedDirectMessagesTask extends GetDirectMessagesTask { private final boolean is_auto_refresh; public GetReceivedDirectMessagesTask(long[] account_ids, long[] max_ids, boolean is_auto_refresh) { super(DirectMessages.Inbox.CONTENT_URI, account_ids, max_ids); this.is_auto_refresh = is_auto_refresh; } @Override public ResponseList<DirectMessage> getDirectMessages(Twitter twitter, Paging paging) throws TwitterException { return twitter.getDirectMessages(paging); } @Override protected void onPostExecute(List<ListResponse<DirectMessage>> responses) { super.onPostExecute(responses); mStoreReceivedDirectMessagesTaskId = mAsyncTaskManager .add(new StoreReceivedDirectMessagesTask(responses, is_auto_refresh), true); mGetReceivedDirectMessagesTaskId = -1; } } private class GetSentDirectMessagesTask extends GetDirectMessagesTask { public GetSentDirectMessagesTask(long[] account_ids, long[] max_ids) { super(DirectMessages.Outbox.CONTENT_URI, account_ids, max_ids); } @Override public ResponseList<DirectMessage> getDirectMessages(Twitter twitter, Paging paging) throws TwitterException { return twitter.getSentDirectMessages(paging); } @Override protected void onPostExecute(List<ListResponse<DirectMessage>> responses) { super.onPostExecute(responses); mStoreSentDirectMessagesTaskId = mAsyncTaskManager.add(new StoreSentDirectMessagesTask(responses), true); mGetSentDirectMessagesTaskId = -1; } } private abstract class GetStatusesTask extends ManagedAsyncTask<Void, Void, List<ListResponse<twitter4j.Status>>> { private final long[] account_ids, max_ids; private boolean should_set_min_id; public GetStatusesTask(Uri uri, long[] account_ids, long[] max_ids) { super(TwidereService.this, mAsyncTaskManager); this.account_ids = account_ids; this.max_ids = max_ids; } public abstract ResponseList<twitter4j.Status> getStatuses(Twitter twitter, Paging paging) throws TwitterException; public abstract Twitter getTwitter(long account_id); public boolean shouldSetMinId() { return should_set_min_id; } @Override protected List<ListResponse<twitter4j.Status>> doInBackground(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; 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); } final ResponseList<twitter4j.Status> statuses = getStatuses(twitter, paging); if (statuses != null) { result.add(new ListResponse<twitter4j.Status>(account_id, max_id, statuses)); } } catch (final TwitterException e) { e.printStackTrace(); } } idx++; } return result; } } private abstract class GetTrendsTask extends ManagedAsyncTask<Void, Void, ListResponse<Trends>> { private final long account_id; public GetTrendsTask(long account_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; } public abstract List<Trends> getTrends(Twitter twitter) throws TwitterException; @Override protected ListResponse<Trends> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.this, account_id, false); if (twitter != null) { try { return new ListResponse<Trends>(account_id, -1, getTrends(twitter)); } catch (final TwitterException e) { e.printStackTrace(); } } return new ListResponse<Trends>(account_id, -1, null); } } private class GetWeeklyTrendsTask extends GetTrendsTask { public GetWeeklyTrendsTask(long account_id) { super(account_id); } @Override public ResponseList<Trends> getTrends(Twitter twitter) throws TwitterException { if (twitter == null) return null; return twitter.getWeeklyTrends(); } @Override protected void onPostExecute(ListResponse<Trends> result) { mStoreWeeklyTrendsTaskId = mAsyncTaskManager.add(new StoreWeeklyTrendsTask(result), true); super.onPostExecute(result); } } private static final class ListResponse<Data> { public final long account_id, max_id; public final List<Data> list; public ListResponse(long account_id, long max_id, List<Data> responselist) { this.account_id = account_id; this.max_id = max_id; this.list = responselist; } } private class ReportSpamTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> { private long account_id; private long user_id; public ReportSpamTask(long account_id, long user_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.user_id = user_id; } @Override protected SingleResponse<User> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<User> result) { if (result != null && result.data != null) { Toast.makeText(TwidereService.this, R.string.reported_user_for_spam, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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); } } private class RetweetStatusTask extends ManagedAsyncTask<Void, Void, SingleResponse<twitter4j.Status>> { private long account_id; private long status_id; public RetweetStatusTask(long account_id, long status_id) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.status_id = status_id; } @Override protected SingleResponse<twitter4j.Status> doInBackground(Void... params) { if (account_id < 0) return new SingleResponse<twitter4j.Status>(account_id, null, null); final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<twitter4j.Status> result) { final ContentResolver resolver = getContentResolver(); if (result.data != null && result.data.getId() > 0) { final User user = result.data.getUser(); if (user != null) { final ContentValues values = new ContentValues(); values.put(Statuses.RETWEET_ID, result.data.getId()); values.put(Statuses.RETWEETED_BY_ID, user.getId()); values.put(Statuses.RETWEETED_BY_NAME, user.getName()); values.put(Statuses.RETWEETED_BY_SCREEN_NAME, user.getScreenName()); values.put(Statuses.RETWEET_COUNT, result.data.getRetweetCount()); values.put(Statuses.IS_RETWEET, 1); 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) { resolver.update(uri, values, where.toString(), null); } } Toast.makeText(TwidereService.this, R.string.retweet_success, Toast.LENGTH_SHORT).show(); 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(result.exception, true); } super.onPostExecute(result); } } private 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; public SendDirectMessageTask(long account_id, String screen_name, long user_id, String message) { super(TwidereService.this, mAsyncTaskManager); twitter = getTwitterInstance(TwidereService.this, account_id, false); this.account_id = account_id; this.user_id = user_id; this.screen_name = screen_name; this.message = message; } @Override protected SingleResponse<DirectMessage> doInBackground(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(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); Toast.makeText(TwidereService.this, R.string.send_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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. */ private static final class ServiceStub extends ITwidereService.Stub { final WeakReference<TwidereService> mService; public ServiceStub(TwidereService service) { mService = new WeakReference<TwidereService>(service); } @Override public int addUserListMember(long account_id, int list_id, long user_id, String screen_name) { return mService.get().addUserListMember(account_id, list_id, user_id, screen_name); } @Override public int cancelRetweet(long account_id, long status_id) { return mService.get().cancelRetweet(account_id, status_id); } @Override public void clearNotification(int id) { mService.get().clearNotification(id); } @Override public int createBlock(long account_id, long user_id) { return mService.get().createBlock(account_id, user_id); } @Override public int createFavorite(long account_id, long status_id) { return mService.get().createFavorite(account_id, status_id); } @Override public int createFriendship(long account_id, long user_id) { return mService.get().createFriendship(account_id, user_id); } @Override public int createUserList(long account_id, String list_name, boolean is_public, String description) { return mService.get().createUserList(account_id, list_name, is_public, description); } @Override public int createUserListSubscription(long account_id, int list_id) { return mService.get().createUserListSubscription(account_id, list_id); } @Override public int deleteUserListMember(long account_id, int list_id, long user_id) { return mService.get().deleteUserListMember(account_id, list_id, user_id); } @Override public int destroyBlock(long account_id, long user_id) { return mService.get().destroyBlock(account_id, user_id); } @Override public int destroyDirectMessage(long account_id, long message_id) { return mService.get().destroyDirectMessage(account_id, message_id); } @Override public int destroyFavorite(long account_id, long status_id) { return mService.get().destroyFavorite(account_id, status_id); } @Override public int destroyFriendship(long account_id, long user_id) { return mService.get().destroyFriendship(account_id, user_id); } @Override public int destroyStatus(long account_id, long status_id) { return mService.get().destroyStatus(account_id, status_id); } @Override public int destroyUserList(long account_id, int list_id) { return mService.get().destroyUserList(account_id, list_id); } @Override public int destroyUserListSubscription(long account_id, int list_id) { return mService.get().destroyUserListSubscription(account_id, list_id); } @Override public int getDailyTrends(long account_id) { return mService.get().getDailyTrends(account_id); } @Override public int getHomeTimeline(long[] account_ids, long[] max_ids) { return mService.get().getHomeTimeline(account_ids, max_ids); } @Override public int getLocalTrends(long account_id, int woeid) { return mService.get().getLocalTrends(account_id, woeid); } @Override public int getMentions(long[] account_ids, long[] max_ids) { return mService.get().getMentions(account_ids, max_ids); } @Override public int getReceivedDirectMessages(long[] account_ids, long[] max_ids) { return mService.get().getReceivedDirectMessages(account_ids, max_ids); } @Override public int getSentDirectMessages(long[] account_ids, long[] max_ids) { return mService.get().getSentDirectMessages(account_ids, max_ids); } @Override public int getWeeklyTrends(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 reportSpam(long account_id, long user_id) { return mService.get().reportSpam(account_id, user_id); } @Override public int retweetStatus(long account_id, long status_id) { return mService.get().retweetStatus(account_id, status_id); } @Override public int sendDirectMessage(long account_id, String screen_name, long user_id, 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(long account_id, String name, String url, String location, String description) { return mService.get().updateProfile(account_id, name, url, location, description); } @Override public int updateProfileImage(long account_id, Uri image_uri, boolean delete_image) { return mService.get().updateProfileImage(account_id, image_uri, delete_image); } @Override public int updateStatus(long[] account_ids, String content, Location location, Uri image_uri, long in_reply_to, boolean delete_image) { return mService.get().updateStatus(account_ids, content, location, image_uri, in_reply_to, delete_image); } @Override public int updateUserListDetails(long account_id, int list_id, boolean is_public, String name, String description) { return mService.get().updateUserListDetails(account_id, list_id, is_public, name, description); } } private static final class SingleResponse<Data> { public final Exception exception; public final Data data; public final long account_id; public SingleResponse(long account_id, Data data, Exception exception) { this.exception = exception; this.data = data; this.account_id = account_id; } } private class StoreDailyTrendsTask extends StoreTrendsTask { public StoreDailyTrendsTask(ListResponse<Trends> result) { super(result, CachedTrends.Daily.CONTENT_URI); } } private class StoreDirectMessagesTask extends ManagedAsyncTask<Void, Void, SingleResponse<Bundle>> { private final List<ListResponse<DirectMessage>> responses; private final Uri uri; public StoreDirectMessagesTask(List<ListResponse<DirectMessage>> result, Uri uri) { super(TwidereService.this, mAsyncTaskManager); responses = result; this.uri = uri; } @Override protected SingleResponse<Bundle> doInBackground(Void... args) { final ContentResolver resolver = getContentResolver(); 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 = resolver.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.buildString(message_ids, ',', true) + " ) "); rows_deleted = resolver.delete(query_uri, where.toString(), null); } // Insert previously fetched items. resolver.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); resolver.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(SingleResponse<Bundle> response) { if (response != null && response.data != null && response.data.getBoolean(INTENT_KEY_SUCCEED)) { notifyForUpdatedUri(TwidereService.this, uri); } super.onPostExecute(response); } } private class StoreHomeTimelineTask extends StoreStatusesTask { private final boolean is_auto_refresh; public StoreHomeTimelineTask(List<ListResponse<twitter4j.Status>> result, boolean is_auto_refresh, 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(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)); if (succeed && is_auto_refresh && mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_HOME_TIMELINE, false)) { mNewStatusesCount += response.data.getInt(INTENT_KEY_ITEMS_INSERTED); if (mNewStatusesCount > 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(TwidereService.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); mNotificationManager.notify(NOTIFICATION_ID_HOME_TIMELINE, buildNotification(message, R.drawable.ic_stat_tweet, content_intent, delete_intent)); } } super.onPostExecute(response); } } private class StoreLocalTrendsTask extends StoreTrendsTask { public StoreLocalTrendsTask(ListResponse<Trends> result) { super(result, CachedTrends.Local.CONTENT_URI); } } private class StoreMentionsTask extends StoreStatusesTask { private final boolean is_auto_refresh; public StoreMentionsTask(List<ListResponse<twitter4j.Status>> result, 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(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)); if (succeed && is_auto_refresh && mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_MENTIONS, false)) { mNewMentionsCount += response.data.getInt(INTENT_KEY_ITEMS_INSERTED); if (mNewMentionsCount > 0) { final String message = getResources().getQuantityString(R.plurals.Nmentions, mNewMentionsCount, mNewMentionsCount); 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(TwidereService.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); mNotificationManager.notify(NOTIFICATION_ID_MENTIONS, buildNotification(message, R.drawable.ic_stat_mention, content_intent, delete_intent)); } } super.onPostExecute(response); } } private class StoreReceivedDirectMessagesTask extends StoreDirectMessagesTask { private final boolean is_auto_refresh; public StoreReceivedDirectMessagesTask(List<ListResponse<DirectMessage>> result, boolean is_auto_refresh) { super(result, DirectMessages.Inbox.CONTENT_URI); this.is_auto_refresh = is_auto_refresh; } @Override protected void onPostExecute(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)) { mNewMessagesCount += response.data.getInt(INTENT_KEY_ITEMS_INSERTED); if (mNewMessagesCount > 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(TwidereService.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); mNotificationManager.notify(NOTIFICATION_ID_DIRECT_MESSAGES, buildNotification(message, R.drawable.ic_stat_direct_message, content_intent, delete_intent)); } } super.onPostExecute(response); } } private class StoreSentDirectMessagesTask extends StoreDirectMessagesTask { public StoreSentDirectMessagesTask(List<ListResponse<DirectMessage>> result) { super(result, DirectMessages.Outbox.CONTENT_URI); } @Override protected void onPostExecute(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); } } private 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(List<ListResponse<twitter4j.Status>> result, Uri uri, boolean should_set_min_id) { super(TwidereService.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(Void... args) { final ContentResolver resolver = getContentResolver(); boolean succeed = false; final Uri query_uri = buildQueryUri(uri, false); final ArrayList<Long> newly_inserted_ids = new ArrayList<Long>(); 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(TwidereService.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.buildString(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 = resolver.delete(query_uri, where.toString(), null); } // Insert previously fetched items. resolver.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; } // No row deleted, so I will insert a gap. 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); resolver.update(query_uri, values, where.toString(), null); // Ignore gaps newly_inserted_ids.remove(min_id); } succeed = true; } final Bundle bundle = new Bundle(); bundle.putBoolean(INTENT_KEY_SUCCEED, succeed); bundle.putInt(INTENT_KEY_ITEMS_INSERTED, total_items_inserted); 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(SingleResponse<Bundle> response) { if (response.data.getBoolean(INTENT_KEY_SUCCEED)) { notifyForUpdatedUri(TwidereService.this, uri); } super.onPostExecute(response); mAsyncTaskManager.add(new CacheUsersTask(responses), true); } } private class StoreTrendsTask extends ManagedAsyncTask<Void, Void, SingleResponse<Bundle>> { private final ListResponse<Trends> response; private final Uri uri; public StoreTrendsTask(ListResponse<Trends> result, Uri uri) { super(TwidereService.this, mAsyncTaskManager); response = result; this.uri = uri; } @Override protected SingleResponse<Bundle> doInBackground(Void... args) { final Bundle bundle = new Bundle(); if (response != null) { final ContentResolver resolver = getContentResolver(); 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); resolver.delete(query_uri, null, null); resolver.bulkInsert(query_uri, values_array); bundle.putBoolean(INTENT_KEY_SUCCEED, true); } } return new SingleResponse<Bundle>(-1, bundle, null); } @Override protected void onPostExecute(SingleResponse<Bundle> response) { final Intent intent = new Intent(BROADCAST_TRENDS_UPDATED); if (response != null && response.data != null && response.data.getBoolean(INTENT_KEY_SUCCEED)) { notifyForUpdatedUri(TwidereService.this, uri); intent.putExtra(INTENT_KEY_SUCCEED, true); } super.onPostExecute(response); sendBroadcast(intent); } } private class StoreWeeklyTrendsTask extends StoreTrendsTask { public StoreWeeklyTrendsTask(ListResponse<Trends> result) { super(result, CachedTrends.Weekly.CONTENT_URI); } } private 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(long account_id, Uri image_uri, boolean delete_image) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.image_uri = image_uri; this.delete_image = delete_image; } @Override protected SingleResponse<User> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<User> result) { if (result != null && result.data != null) { Toast.makeText(TwidereService.this, R.string.profile_image_update_success, Toast.LENGTH_SHORT) .show(); if (delete_image) { new File(image_uri.getPath()).delete(); } } else { showErrorToast(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); } } private class UpdateProfileTask extends ManagedAsyncTask<Void, Void, SingleResponse<User>> { private final long account_id; private final String name, url, location, description; public UpdateProfileTask(long account_id, String name, String url, String location, String description) { super(TwidereService.this, mAsyncTaskManager); this.account_id = account_id; this.name = name; this.url = url; this.location = location; this.description = description; } @Override protected SingleResponse<User> doInBackground(Void... params) { final Twitter twitter = getTwitterInstance(TwidereService.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(SingleResponse<User> result) { if (result != null && result.data != null) { Toast.makeText(TwidereService.this, R.string.profile_update_success, Toast.LENGTH_SHORT).show(); } else { showErrorToast(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); } } private class UpdateStatusTask extends ManagedAsyncTask<Void, Void, List<SingleResponse<twitter4j.Status>>> { private long[] account_ids; private String content; private Location location; private Uri image_uri; private long in_reply_to; private boolean delete_image; public UpdateStatusTask(long[] account_ids, String content, Location location, Uri image_uri, long in_reply_to, boolean delete_image) { super(TwidereService.this, mAsyncTaskManager); this.account_ids = account_ids; this.content = content; this.location = location; this.image_uri = image_uri; this.in_reply_to = in_reply_to; this.delete_image = delete_image; } @Override protected List<SingleResponse<twitter4j.Status>> doInBackground(Void... params) { if (account_ids == null) return null; final List<SingleResponse<twitter4j.Status>> result = new ArrayList<SingleResponse<twitter4j.Status>>(); for (final long account_id : account_ids) { final Twitter twitter = getTwitterInstance(TwidereService.this, account_id, false); if (twitter != null) { try { final String component = mPreferences.getString(PREFERENCE_KEY_IMAGE_UPLOADER, null); final ImageUploaderInterface uploader = ImageUploaderInterface.getInstance(getApplication(), component); final String image_path = getImagePathFromUri(TwidereService.this, image_uri); final Uri result_uri = image_path != null && uploader != null ? uploader.upload(Uri.parse(image_path), content) : null; final StatusUpdate status = new StatusUpdate( result_uri != null ? content + " " + result_uri : content); status.setInReplyToStatusId(in_reply_to); if (location != null) { status.setLocation(new GeoLocation(location.getLatitude(), location.getLongitude())); } if (image_path != null && result_uri == null) { final File image_file = new File(image_path); if (image_file.exists()) { status.setMedia(image_file); } } 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)); } } } return result; } @Override protected void onPostExecute(List<SingleResponse<twitter4j.Status>> result) { boolean succeed = false; Exception exception = null; final List<Long> failed_account_ids = new ArrayList<Long>(); for (final SingleResponse<twitter4j.Status> response : result) { if (response.data != null) { succeed = true; break; } else { failed_account_ids.add(response.account_id); exception = response.exception; } } if (succeed) { Toast.makeText(TwidereService.this, R.string.send_success, Toast.LENGTH_SHORT).show(); if (image_uri != null && delete_image) { final String path = getImagePathFromUri(TwidereService.this, image_uri); if (path != null) { new File(path).delete(); } } } else { showErrorToast(exception, true); final StringBuilder ids_builder = new StringBuilder(); final int size = failed_account_ids.size(); for (int i = 0; i < size; i++) { final String id_string = String.valueOf(failed_account_ids.get(i)); if (id_string != null) { if (i > 0) { ids_builder.append(';'); } ids_builder.append(id_string); } } final ContentValues values = new ContentValues(); values.put(Drafts.ACCOUNT_IDS, ids_builder.toString()); values.put(Drafts.IN_REPLY_TO_STATUS_ID, in_reply_to); values.put(Drafts.TEXT, content); if (image_uri != null) { values.put(Drafts.MEDIA_URI, image_uri.toString()); } final ContentResolver resolver = getContentResolver(); resolver.insert(Drafts.CONTENT_URI, values); } super.onPostExecute(result); if (mPreferences.getBoolean(PREFERENCE_KEY_REFRESH_AFTER_TWEET, false)) { final long[] activated_ids = getActivatedAccountIds(TwidereService.this); getHomeTimeline(activated_ids, null); getMentions(activated_ids, null); } } } private 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(TwidereService.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(TwidereService.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(TwidereService.this, R.string.profile_update_success, Toast.LENGTH_SHORT).show(); intent.putExtra(INTENT_KEY_SUCCEED, true); } else { showErrorToast(result.exception, true); } sendBroadcast(intent); super.onPostExecute(result); } } }