Twidere-App-Android-Twitter.../twidere/src/main/java/org/mariotaku/twidere/service/RefreshService.java

365 lines
16 KiB
Java

/*
* Twidere - 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.mariotaku.twidere.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.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.AccountPreferences;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
import org.mariotaku.twidere.provider.TwidereDataStore.Mentions;
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
import org.mariotaku.twidere.receiver.PowerStateReceiver;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.dagger.ApplicationModule;
import org.mariotaku.twidere.util.dagger.DaggerGeneralComponent;
import java.util.Arrays;
import javax.inject.Inject;
import edu.tsinghua.hotmobi.HotMobiLogger;
import edu.tsinghua.hotmobi.model.ScreenEvent;
import static org.mariotaku.twidere.util.ParseUtils.parseInt;
import static org.mariotaku.twidere.util.Utils.getAccountIds;
import static org.mariotaku.twidere.util.Utils.getDefaultAccountId;
import static org.mariotaku.twidere.util.Utils.getNewestMessageIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.getNewestStatusIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.hasAutoRefreshAccounts;
import static org.mariotaku.twidere.util.Utils.isBatteryOkay;
import static org.mariotaku.twidere.util.Utils.isNetworkAvailable;
import static org.mariotaku.twidere.util.Utils.shouldStopAutoRefreshOnBatteryLow;
public class RefreshService extends Service implements Constants {
@Inject
SharedPreferencesWrapper mPreferences;
private AlarmManager mAlarmManager;
@Inject
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 (BuildConfig.DEBUG) {
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 (BuildConfig.DEBUG) {
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 (BuildConfig.DEBUG) {
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 (BuildConfig.DEBUG) {
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 (BuildConfig.DEBUG) {
Log.d(LOGTAG, String.format("Auto refreshing trends for %s", Arrays.toString(refreshIds)));
}
if (!isLocalTrendsRefreshing()) {
getLocalTrends(refreshIds);
}
}
}
}
};
private final BroadcastReceiver mPowerStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case Intent.ACTION_BATTERY_CHANGED: {
HotMobiLogger.logPowerBroadcast(context, intent);
break;
}
default: {
HotMobiLogger.logPowerBroadcast(context);
break;
}
}
}
};
private final BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case Intent.ACTION_SCREEN_ON: {
HotMobiLogger.logScreenEvent(context, ScreenEvent.Action.ON);
break;
}
case Intent.ACTION_SCREEN_OFF: {
HotMobiLogger.logScreenEvent(context, ScreenEvent.Action.OFF);
break;
}
}
}
};
@Override
public IBinder onBind(final Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
DaggerGeneralComponent.builder().applicationModule(ApplicationModule.get(this)).build().inject(this);
mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
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 refreshFilter = new IntentFilter(BROADCAST_NOTIFICATION_DELETED);
refreshFilter.addAction(BROADCAST_REFRESH_HOME_TIMELINE);
refreshFilter.addAction(BROADCAST_REFRESH_MENTIONS);
refreshFilter.addAction(BROADCAST_REFRESH_DIRECT_MESSAGES);
refreshFilter.addAction(BROADCAST_RESCHEDULE_HOME_TIMELINE_REFRESHING);
refreshFilter.addAction(BROADCAST_RESCHEDULE_MENTIONS_REFRESHING);
refreshFilter.addAction(BROADCAST_RESCHEDULE_DIRECT_MESSAGES_REFRESHING);
registerReceiver(mStateReceiver, refreshFilter);
final IntentFilter batteryFilter = new IntentFilter();
batteryFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
batteryFilter.addAction(Intent.ACTION_BATTERY_OKAY);
batteryFilter.addAction(Intent.ACTION_BATTERY_LOW);
batteryFilter.addAction(Intent.ACTION_POWER_CONNECTED);
batteryFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
final IntentFilter screenFilter = new IntentFilter();
screenFilter.addAction(Intent.ACTION_SCREEN_ON);
screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mPowerStateReceiver, batteryFilter);
registerReceiver(mScreenStateReceiver, screenFilter);
PowerStateReceiver.setServiceReceiverStarted(true);
startAutoRefresh();
}
@Override
public void onDestroy() {
PowerStateReceiver.setServiceReceiverStarted(false);
unregisterReceiver(mScreenStateReceiver);
unregisterReceiver(mPowerStateReceiver);
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 boolean 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 boolean 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 interface RefreshableAccountFilter {
boolean isRefreshable(AccountPreferences pref);
}
private static class TrendsRefreshableFilter implements RefreshableAccountFilter {
@Override
public boolean isRefreshable(final AccountPreferences pref) {
return pref.isAutoRefreshTrendsEnabled();
}
}
}