/* * Firetweet - Twitter client for Android * * Copyright (C) 2012-2014 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.getlantern.firetweet.service; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.IBinder; import android.util.Log; import org.getlantern.firetweet.Constants; import org.getlantern.firetweet.app.FiretweetApplication; import org.getlantern.firetweet.model.AccountPreferences; import org.getlantern.firetweet.provider.FiretweetDataStore.DirectMessages; import org.getlantern.firetweet.provider.FiretweetDataStore.Mentions; import org.getlantern.firetweet.provider.FiretweetDataStore.Statuses; import org.getlantern.firetweet.util.AsyncTwitterWrapper; import org.getlantern.firetweet.util.SharedPreferencesWrapper; import java.util.Arrays; import static org.getlantern.firetweet.util.ParseUtils.parseInt; import static org.getlantern.firetweet.util.Utils.getAccountIds; import static org.getlantern.firetweet.util.Utils.getDefaultAccountId; import static org.getlantern.firetweet.util.Utils.getNewestMessageIdsFromDatabase; import static org.getlantern.firetweet.util.Utils.getNewestStatusIdsFromDatabase; import static org.getlantern.firetweet.util.Utils.hasAutoRefreshAccounts; import static org.getlantern.firetweet.util.Utils.isBatteryOkay; import static org.getlantern.firetweet.util.Utils.isDebugBuild; import static org.getlantern.firetweet.util.Utils.isNetworkAvailable; import static org.getlantern.firetweet.util.Utils.shouldStopAutoRefreshOnBatteryLow; public class RefreshService extends Service implements Constants { private SharedPreferencesWrapper mPreferences; private AlarmManager mAlarmManager; private AsyncTwitterWrapper mTwitterWrapper; private PendingIntent mPendingRefreshHomeTimelineIntent, mPendingRefreshMentionsIntent, mPendingRefreshDirectMessagesIntent, mPendingRefreshTrendsIntent; private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); if (isDebugBuild()) { Log.d(LOGTAG, String.format("Refresh service received action %s", action)); } if (BROADCAST_RESCHEDULE_HOME_TIMELINE_REFRESHING.equals(action)) { rescheduleHomeTimelineRefreshing(); } else if (BROADCAST_RESCHEDULE_MENTIONS_REFRESHING.equals(action)) { rescheduleMentionsRefreshing(); } else if (BROADCAST_RESCHEDULE_DIRECT_MESSAGES_REFRESHING.equals(action)) { rescheduleDirectMessagesRefreshing(); } else if (BROADCAST_RESCHEDULE_TRENDS_REFRESHING.equals(action)) { rescheduleTrendsRefreshing(); } else if (isAutoRefreshAllowed()) { final long[] accountIds = getAccountIds(context); final AccountPreferences[] accountPrefs = AccountPreferences.getAccountPreferences(context, accountIds); if (BROADCAST_REFRESH_HOME_TIMELINE.equals(action)) { final long[] refreshIds = getRefreshableIds(accountPrefs, new HomeRefreshableFilter()); final long[] sinceIds = getNewestStatusIdsFromDatabase(context, Statuses.CONTENT_URI, refreshIds); if (isDebugBuild()) { Log.d(LOGTAG, String.format("Auto refreshing home for %s", Arrays.toString(refreshIds))); } if (!isHomeTimelineRefreshing()) { getHomeTimeline(refreshIds, null, sinceIds); } } else if (BROADCAST_REFRESH_MENTIONS.equals(action)) { final long[] refreshIds = getRefreshableIds(accountPrefs, new MentionsRefreshableFilter()); final long[] sinceIds = getNewestStatusIdsFromDatabase(context, Mentions.CONTENT_URI, refreshIds); if (isDebugBuild()) { Log.d(LOGTAG, String.format("Auto refreshing mentions for %s", Arrays.toString(refreshIds))); } if (!isMentionsRefreshing()) { getMentions(refreshIds, null, sinceIds); } } else if (BROADCAST_REFRESH_DIRECT_MESSAGES.equals(action)) { final long[] refreshIds = getRefreshableIds(accountPrefs, new MessagesRefreshableFilter()); final long[] sinceIds = getNewestMessageIdsFromDatabase(context, DirectMessages.Inbox.CONTENT_URI, refreshIds); if (isDebugBuild()) { Log.d(LOGTAG, String.format("Auto refreshing messages for %s", Arrays.toString(refreshIds))); } if (!isReceivedDirectMessagesRefreshing()) { getReceivedDirectMessages(refreshIds, null, sinceIds); } } else if (BROADCAST_REFRESH_TRENDS.equals(action)) { final long[] refreshIds = getRefreshableIds(accountPrefs, new TrendsRefreshableFilter()); if (isDebugBuild()) { Log.d(LOGTAG, String.format("Auto refreshing trends for %s", Arrays.toString(refreshIds))); } if (!isLocalTrendsRefreshing()) { getLocalTrends(refreshIds); } } } } }; @Override public IBinder onBind(final Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); final FiretweetApplication app = FiretweetApplication.getInstance(this); mTwitterWrapper = app.getTwitterWrapper(); mPreferences = SharedPreferencesWrapper.getInstance(app, SHARED_PREFERENCES_NAME, MODE_PRIVATE); 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); mPendingRefreshTrendsIntent = PendingIntent.getBroadcast(this, 0, new Intent(BROADCAST_REFRESH_TRENDS), 0); final IntentFilter filter = new IntentFilter(BROADCAST_NOTIFICATION_DELETED); filter.addAction(BROADCAST_REFRESH_HOME_TIMELINE); filter.addAction(BROADCAST_REFRESH_MENTIONS); filter.addAction(BROADCAST_REFRESH_DIRECT_MESSAGES); filter.addAction(BROADCAST_RESCHEDULE_HOME_TIMELINE_REFRESHING); filter.addAction(BROADCAST_RESCHEDULE_MENTIONS_REFRESHING); filter.addAction(BROADCAST_RESCHEDULE_DIRECT_MESSAGES_REFRESHING); registerReceiver(mStateReceiver, filter); startAutoRefresh(); } @Override public void onDestroy() { unregisterReceiver(mStateReceiver); if (hasAutoRefreshAccounts(this)) { // Auto refresh enabled, so I will try to start service after it was // stopped. startService(new Intent(this, getClass())); } super.onDestroy(); } protected boolean isAutoRefreshAllowed() { return isNetworkAvailable(this) && (isBatteryOkay(this) || !shouldStopAutoRefreshOnBatteryLow(this)); } private int getHomeTimeline(final long[] accountIds, final long[] maxIds, final long[] sinceIds) { return mTwitterWrapper.getHomeTimelineAsync(accountIds, maxIds, sinceIds); } private int getLocalTrends(final long[] accountIds) { final long account_id = getDefaultAccountId(this); final int woeid = mPreferences.getInt(KEY_LOCAL_TRENDS_WOEID, 1); return mTwitterWrapper.getLocalTrendsAsync(account_id, woeid); } private int getMentions(final long[] accountIds, final long[] maxIds, final long[] sinceIds) { return mTwitterWrapper.getMentionsTimelineAsync(accountIds, maxIds, sinceIds); } private int getReceivedDirectMessages(final long[] accountIds, final long[] maxIds, final long[] sinceIds) { return mTwitterWrapper.getReceivedDirectMessagesAsync(accountIds, maxIds, sinceIds); } private long[] getRefreshableIds(final AccountPreferences[] prefs, final RefreshableAccountFilter filter) { if (prefs == null) return null; final long[] temp = new long[prefs.length]; int i = 0; for (final AccountPreferences pref : prefs) { if (pref.isAutoRefreshEnabled() && filter.isRefreshable(pref)) { temp[i++] = pref.getAccountId(); } } final long[] result = new long[i]; System.arraycopy(temp, 0, result, 0, i); return result; } private long getRefreshInterval() { if (mPreferences == null) return 0; final int prefValue = parseInt(mPreferences.getString(KEY_REFRESH_INTERVAL, DEFAULT_REFRESH_INTERVAL)); return Math.max(prefValue, 3) * 60 * 1000; } private boolean isHomeTimelineRefreshing() { return mTwitterWrapper.isHomeTimelineRefreshing(); } private boolean isLocalTrendsRefreshing() { return mTwitterWrapper.isLocalTrendsRefreshing(); } private boolean isMentionsRefreshing() { return mTwitterWrapper.isMentionsTimelineRefreshing(); } private boolean isReceivedDirectMessagesRefreshing() { return mTwitterWrapper.isReceivedDirectMessagesRefreshing(); } private void rescheduleDirectMessagesRefreshing() { mAlarmManager.cancel(mPendingRefreshDirectMessagesIntent); final long refreshInterval = getRefreshInterval(); if (refreshInterval > 0) { mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + refreshInterval, refreshInterval, mPendingRefreshDirectMessagesIntent); } } private void rescheduleHomeTimelineRefreshing() { mAlarmManager.cancel(mPendingRefreshHomeTimelineIntent); final long refreshInterval = getRefreshInterval(); if (refreshInterval > 0) { mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + refreshInterval, refreshInterval, mPendingRefreshHomeTimelineIntent); } } private void rescheduleMentionsRefreshing() { mAlarmManager.cancel(mPendingRefreshMentionsIntent); final long refreshInterval = getRefreshInterval(); if (refreshInterval > 0) { mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + refreshInterval, refreshInterval, mPendingRefreshMentionsIntent); } } private void rescheduleTrendsRefreshing() { mAlarmManager.cancel(mPendingRefreshTrendsIntent); final long refreshInterval = getRefreshInterval(); if (refreshInterval > 0) { mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + refreshInterval, refreshInterval, mPendingRefreshTrendsIntent); } } private boolean startAutoRefresh() { stopAutoRefresh(); final long refreshInterval = getRefreshInterval(); if (refreshInterval <= 0) return false; rescheduleHomeTimelineRefreshing(); rescheduleMentionsRefreshing(); rescheduleDirectMessagesRefreshing(); rescheduleTrendsRefreshing(); return true; } private void stopAutoRefresh() { mAlarmManager.cancel(mPendingRefreshHomeTimelineIntent); mAlarmManager.cancel(mPendingRefreshMentionsIntent); mAlarmManager.cancel(mPendingRefreshDirectMessagesIntent); mAlarmManager.cancel(mPendingRefreshTrendsIntent); } private static class HomeRefreshableFilter implements RefreshableAccountFilter { @Override public boolean isRefreshable(final AccountPreferences pref) { return pref.isAutoRefreshHomeTimelineEnabled(); } } private static class MentionsRefreshableFilter implements RefreshableAccountFilter { @Override public boolean isRefreshable(final AccountPreferences pref) { return pref.isAutoRefreshMentionsEnabled(); } } private static class MessagesRefreshableFilter implements RefreshableAccountFilter { @Override public boolean isRefreshable(final AccountPreferences pref) { return pref.isAutoRefreshDirectMessagesEnabled(); } } private static interface RefreshableAccountFilter { boolean isRefreshable(AccountPreferences pref); } private static class TrendsRefreshableFilter implements RefreshableAccountFilter { @Override public boolean isRefreshable(final AccountPreferences pref) { return pref.isAutoRefreshTrendsEnabled(); } } }