diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/IntentConstants.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/IntentConstants.java
index 3f692fa35..f5fe0e880 100644
--- a/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/IntentConstants.java
+++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/IntentConstants.java
@@ -72,19 +72,10 @@ public interface IntentConstants {
String BROADCAST_NOTIFICATION_DELETED = INTENT_PACKAGE_PREFIX + "NOTIFICATION_DELETED";
- String BROADCAST_USER_LIST_MEMBERS_DELETED = INTENT_PACKAGE_PREFIX + "USER_LIST_MEMBER_DELETED";
- String BROADCAST_REFRESH_HOME_TIMELINE = INTENT_PACKAGE_PREFIX + "REFRESH_HOME_TIMELINE";
- String BROADCAST_REFRESH_NOTIFICATIONS = INTENT_PACKAGE_PREFIX + "REFRESH_NOTIFICATIONS";
- String BROADCAST_REFRESH_DIRECT_MESSAGES = INTENT_PACKAGE_PREFIX + "REFRESH_DIRECT_MESSAGES";
- String BROADCAST_REFRESH_TRENDS = INTENT_PACKAGE_PREFIX + "REFRESH_TRENDS";
- String BROADCAST_RESCHEDULE_HOME_TIMELINE_REFRESHING = INTENT_PACKAGE_PREFIX
- + "RESCHEDULE_HOME_TIMELINE_REFRESHING";
- String BROADCAST_RESCHEDULE_MENTIONS_REFRESHING = INTENT_PACKAGE_PREFIX
- + "RESCHEDULE_MENTIONS_REFRESHING";
- String BROADCAST_RESCHEDULE_DIRECT_MESSAGES_REFRESHING = INTENT_PACKAGE_PREFIX
- + "RESCHEDULE_DIRECT_MESSAGES_REFRESHING";
- String BROADCAST_RESCHEDULE_TRENDS_REFRESHING = INTENT_PACKAGE_PREFIX
- + "RESCHEDULE_TRENDS_REFRESHING";
+ String ACTION_REFRESH_HOME_TIMELINE = INTENT_PACKAGE_PREFIX + "REFRESH_HOME_TIMELINE";
+ String ACTION_REFRESH_NOTIFICATIONS = INTENT_PACKAGE_PREFIX + "REFRESH_NOTIFICATIONS";
+ String ACTION_REFRESH_DIRECT_MESSAGES = INTENT_PACKAGE_PREFIX + "REFRESH_DIRECT_MESSAGES";
+ String ACTION_REFRESH_TRENDS = INTENT_PACKAGE_PREFIX + "REFRESH_TRENDS";
String EXTRA_LATITUDE = "latitude";
String EXTRA_LONGITUDE = "longitude";
diff --git a/twidere/src/main/AndroidManifest.xml b/twidere/src/main/AndroidManifest.xml
index e5f665a2a..22e7236ce 100644
--- a/twidere/src/main/AndroidManifest.xml
+++ b/twidere/src/main/AndroidManifest.xml
@@ -39,6 +39,7 @@
+
-
-
-
-
-
-
-
-
diff --git a/twidere/src/main/java/org/mariotaku/twidere/annotation/AutoRefreshType.java b/twidere/src/main/java/org/mariotaku/twidere/annotation/AutoRefreshType.java
new file mode 100644
index 000000000..bc79672a9
--- /dev/null
+++ b/twidere/src/main/java/org/mariotaku/twidere/annotation/AutoRefreshType.java
@@ -0,0 +1,17 @@
+package org.mariotaku.twidere.annotation;
+
+import android.support.annotation.StringDef;
+
+/**
+ * Created by mariotaku on 2016/12/17.
+ */
+
+@StringDef({AutoRefreshType.HOME_TIMELINE, AutoRefreshType.INTERACTIONS_TIMELINE, AutoRefreshType.DIRECT_MESSAGES})
+public @interface AutoRefreshType {
+
+ String HOME_TIMELINE = "home_timeline";
+ String INTERACTIONS_TIMELINE = "interactions_timeline";
+ String DIRECT_MESSAGES = "direct_messages";
+
+ String[] ALL = {HOME_TIMELINE, INTERACTIONS_TIMELINE, DIRECT_MESSAGES};
+}
diff --git a/twidere/src/main/java/org/mariotaku/twidere/receiver/ConnectivityStateReceiver.java b/twidere/src/main/java/org/mariotaku/twidere/receiver/ConnectivityStateReceiver.java
index 1783c55a3..87e481779 100644
--- a/twidere/src/main/java/org/mariotaku/twidere/receiver/ConnectivityStateReceiver.java
+++ b/twidere/src/main/java/org/mariotaku/twidere/receiver/ConnectivityStateReceiver.java
@@ -48,7 +48,6 @@ public class ConnectivityStateReceiver extends BroadcastReceiver implements Cons
if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) return;
final TwidereApplication application = TwidereApplication.Companion.getInstance(context);
// application.reloadConnectivitySettings();
- Utils.startRefreshServiceIfNeeded(application);
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME,
Context.MODE_PRIVATE);
if (prefs.getBoolean(KEY_USAGE_STATISTICS, false) && prefs.getBoolean(KEY_SETTINGS_WIZARD_COMPLETED, false)) {
diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/DataStoreUtils.java b/twidere/src/main/java/org/mariotaku/twidere/util/DataStoreUtils.java
index 74e0857cf..e4cf731e7 100644
--- a/twidere/src/main/java/org/mariotaku/twidere/util/DataStoreUtils.java
+++ b/twidere/src/main/java/org/mariotaku/twidere/util/DataStoreUtils.java
@@ -1019,8 +1019,11 @@ public class DataStoreUtils implements Constants {
}
public static void prepareDatabase(@NonNull Context context) {
- context.getContentResolver().query(TwidereDataStore.CONTENT_URI_DATABASE_PREPARE, null,
- null, null, null);
+ final ContentResolver cr = context.getContentResolver();
+ final Cursor cursor = cr.query(TwidereDataStore.CONTENT_URI_DATABASE_PREPARE, null, null,
+ null, null);
+ if (cursor == null) return;
+ cursor.close();
}
interface FieldArrayCreator {
diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java b/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java
index aaae7ea83..3d347b38f 100644
--- a/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java
+++ b/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java
@@ -47,7 +47,6 @@ import android.net.NetworkInfo;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
-import android.os.AsyncTask;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
@@ -125,7 +124,6 @@ import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.ConversationEntries;
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
-import org.mariotaku.twidere.service.RefreshService;
import org.mariotaku.twidere.util.TwidereLinkify.HighlightStyle;
import org.mariotaku.twidere.view.CardMediaContainer.PreviewStyle;
import org.mariotaku.twidere.view.ShapedImageView;
@@ -1184,27 +1182,6 @@ public final class Utils implements Constants {
showErrorMessage(context, message, long_message);
}
- public static void startRefreshServiceIfNeeded(@NonNull final Context context) {
- final Context appContext = context.getApplicationContext();
- if (appContext == null) return;
- if (!appContext.getResources().getBoolean(R.bool.use_legacy_refresh_service)) return;
- final Intent refreshServiceIntent = new Intent(appContext, RefreshService.class);
- DataStoreUtils.prepareDatabase(context);
- AsyncTask.execute(new Runnable() {
- @Override
- public void run() {
- if (isNetworkAvailable(appContext) && hasAutoRefreshAccounts(appContext)) {
- if (BuildConfig.DEBUG) {
- Log.d(LOGTAG, "Start background refresh service");
- }
- appContext.startService(refreshServiceIntent);
- } else {
- appContext.stopService(refreshServiceIntent);
- }
- }
- });
- }
-
public static void startStatusShareChooser(final Context context, final ParcelableStatus status) {
final Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
@@ -1230,10 +1207,6 @@ public final class Utils implements Constants {
}
}
- public static String trim(final String str) {
- return str != null ? str.trim() : null;
- }
-
public static String trimLineBreak(final String orig) {
if (orig == null) return null;
return orig.replaceAll("\\n+", "\n");
@@ -1306,11 +1279,6 @@ public final class Utils implements Constants {
}
- public static void setSharedElementTransition(Context context, Window window, int transitionRes) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
- UtilsL.setSharedElementTransition(context, window, transitionRes);
- }
-
public static Object findFieldOfTypes(T obj, Class extends T> cls, Class>... checkTypes) {
labelField:
for (Field field : cls.getDeclaredFields()) {
@@ -1476,4 +1444,5 @@ public final class Utils implements Constants {
}
return true;
}
+
}
diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt
index f5f26eac2..5b91c400e 100644
--- a/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt
+++ b/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt
@@ -62,7 +62,6 @@ import org.mariotaku.twidere.constant.apiLastChangeKey
import org.mariotaku.twidere.constant.bugReportsKey
import org.mariotaku.twidere.constant.defaultFeatureLastUpdated
import org.mariotaku.twidere.model.DefaultFeatures
-import org.mariotaku.twidere.service.RefreshService
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.content.TwidereSQLiteOpenHelper
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
@@ -93,6 +92,8 @@ class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeLis
lateinit internal var externalThemeManager: ExternalThemeManager
@Inject
lateinit internal var kPreferences: KPreferences
+ @Inject
+ lateinit internal var autoRefreshController: AutoRefreshController
private lateinit var profileImageViewViewProcessor: ProfileImageViewViewProcessor
private lateinit var fontFamilyTagProcessor: FontFamilyTagProcessor
@@ -129,13 +130,10 @@ class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeLis
updateEasterEggIcon()
migrateUsageStatisticsPreferences()
- if (resources.getBoolean(R.bool.use_job_refresh_service)) {
- } else {
- Utils.startRefreshServiceIfNeeded(this)
- }
-
GeneralComponentHelper.build(this).inject(this)
+ autoRefreshController.appStarted()
+
registerActivityLifecycleCallbacks(activityTracker)
listenExternalThemeChange()
@@ -288,8 +286,7 @@ class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeLis
override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String) {
when (key) {
KEY_REFRESH_INTERVAL -> {
- stopService(Intent(this, RefreshService::class.java))
- Utils.startRefreshServiceIfNeeded(this)
+ autoRefreshController.rescheduleAll()
}
KEY_ENABLE_PROXY, KEY_PROXY_HOST, KEY_PROXY_PORT, KEY_PROXY_TYPE, KEY_PROXY_USERNAME,
KEY_PROXY_PASSWORD, KEY_CONNECTION_TIMEOUT, KEY_RETRY_ON_NETWORK_ISSUE -> {
diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt
index 957f9789b..378750125 100644
--- a/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt
+++ b/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt
@@ -4,6 +4,7 @@ import android.content.SharedPreferences
import android.os.Build
import android.text.TextUtils
import org.mariotaku.kpreferences.*
+import org.mariotaku.ktextension.toLong
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.Constants.KEY_NO_CLOSE_AFTER_TWEET_SENT
import org.mariotaku.twidere.TwidereConstants.*
@@ -44,6 +45,18 @@ val randomizeAccountNameKey = KBooleanKey(KEY_RANDOMIZE_ACCOUNT_NAME, false)
val defaultAutoRefreshKey = KBooleanKey(KEY_DEFAULT_AUTO_REFRESH, false)
val defaultAutoRefreshKeyAsked = KBooleanKey("default_auto_refresh_asked", true)
+object refreshIntervalKey : KSimpleKey(KEY_REFRESH_INTERVAL, 15) {
+ override fun read(preferences: SharedPreferences): Long {
+ return preferences.getString(key, null).toLong(def)
+ }
+
+ override fun write(editor: SharedPreferences.Editor, value: Long): Boolean {
+ editor.putString(key, value.toString())
+ return true
+ }
+
+}
+
object defaultAPIConfigKey : KPreferenceKey {
override fun contains(preferences: SharedPreferences): Boolean {
if (preferences.getString(KEY_API_URL_FORMAT, null) == null) return false
diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountRefreshSettingsFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountRefreshSettingsFragment.kt
index c6a45b161..e486fc594 100644
--- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountRefreshSettingsFragment.kt
+++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountRefreshSettingsFragment.kt
@@ -19,11 +19,9 @@
package org.mariotaku.twidere.fragment
-import android.content.SharedPreferences
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_AUTO_REFRESH
import org.mariotaku.twidere.constant.defaultAutoRefreshKey
-import org.mariotaku.twidere.util.Utils
class AccountRefreshSettingsFragment : BaseAccountPreferenceFragment() {
@@ -36,9 +34,4 @@ class AccountRefreshSettingsFragment : BaseAccountPreferenceFragment() {
override val switchPreferenceKey: String?
get() = KEY_AUTO_REFRESH
- override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String) {
- if (KEY_AUTO_REFRESH == key) {
- Utils.startRefreshServiceIfNeeded(activity)
- }
- }
}
diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/receiver/PowerStateReceiver.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/receiver/PowerStateReceiver.kt
deleted file mode 100644
index 7d3a4157b..000000000
--- a/twidere/src/main/kotlin/org/mariotaku/twidere/receiver/PowerStateReceiver.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Twidere - Twitter client for Android
- *
- * Copyright (C) 2012-2015 Mariotaku Lee
- *
- * 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 .
- */
-
-package org.mariotaku.twidere.receiver
-
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-
-import edu.tsinghua.hotmobi.model.BatteryRecord
-
-/**
- * Created by mariotaku on 15/9/29.
- */
-class PowerStateReceiver : BroadcastReceiver() {
-
- override fun onReceive(context: Context, intent: Intent) {
- when (intent.action) {
- Intent.ACTION_BATTERY_LOW, Intent.ACTION_BATTERY_OKAY, Intent.ACTION_POWER_CONNECTED,
- Intent.ACTION_POWER_DISCONNECTED -> {
- if (serviceReceiverStarted) return
- BatteryRecord.log(context)
- }
- }
- }
-
- companion object {
- var serviceReceiverStarted: Boolean = false
- }
-}
diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/service/JobRefreshService.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/service/JobRefreshService.kt
index 6e2d50e4e..a0abff9a4 100644
--- a/twidere/src/main/kotlin/org/mariotaku/twidere/service/JobRefreshService.kt
+++ b/twidere/src/main/kotlin/org/mariotaku/twidere/service/JobRefreshService.kt
@@ -24,17 +24,13 @@ import android.annotation.TargetApi
import android.app.job.JobParameters
import android.app.job.JobService
import android.os.Build
-import org.mariotaku.abstask.library.AbstractTask
+import android.util.Log
import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.kpreferences.KPreferences
-import org.mariotaku.twidere.constant.IntentConstants.*
+import org.mariotaku.twidere.BuildConfig
+import org.mariotaku.twidere.TwidereConstants.LOGTAG
+import org.mariotaku.twidere.annotation.AutoRefreshType
import org.mariotaku.twidere.constant.stopAutoRefreshWhenBatteryLowKey
-import org.mariotaku.twidere.model.AccountPreferences
-import org.mariotaku.twidere.provider.TwidereDataStore.*
-import org.mariotaku.twidere.task.GetActivitiesAboutMeTask
-import org.mariotaku.twidere.task.GetHomeTimelineTask
-import org.mariotaku.twidere.task.GetReceivedDirectMessagesTask
-import org.mariotaku.twidere.util.DataStoreUtils
import org.mariotaku.twidere.util.Utils
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
import javax.inject.Inject
@@ -59,10 +55,16 @@ class JobRefreshService : JobService() {
// Low battery, don't refresh
return false
}
+ if (BuildConfig.DEBUG) {
+ Log.d(LOGTAG, "Running job ${params.jobId}")
+ }
- val task = createJobTask(params) ?: return false
+ val task = run {
+ val type = getRefreshType(params.jobId) ?: return@run null
+ return@run RefreshService.createJobTask(this, type)
+ } ?: return false
task.callback = {
- this.jobFinished(params, true)
+ this.jobFinished(params, false)
}
TaskStarter.execute(task)
return true
@@ -72,30 +74,23 @@ class JobRefreshService : JobService() {
return false
}
- internal fun createJobTask(params: JobParameters): AbstractTask<*, *, () -> Unit>? {
- when (params.extras?.getString(EXTRA_ACTION)) {
- BROADCAST_REFRESH_HOME_TIMELINE -> {
- val task = GetHomeTimelineTask(this)
- task.params = RefreshService.AutoRefreshTaskParam(this, AccountPreferences::isAutoRefreshHomeTimelineEnabled) { accountKeys ->
- DataStoreUtils.getNewestStatusIds(this, Statuses.CONTENT_URI, accountKeys)
- }
- return task
- }
- BROADCAST_REFRESH_NOTIFICATIONS -> {
- val task = GetActivitiesAboutMeTask(this)
- task.params = RefreshService.AutoRefreshTaskParam(this, AccountPreferences::isAutoRefreshMentionsEnabled) { accountKeys ->
- DataStoreUtils.getNewestActivityMaxPositions(this, Activities.AboutMe.CONTENT_URI, accountKeys)
- }
- return task
- }
- BROADCAST_REFRESH_DIRECT_MESSAGES -> {
- val task = GetReceivedDirectMessagesTask(this)
- task.params = RefreshService.AutoRefreshTaskParam(this, AccountPreferences::isAutoRefreshDirectMessagesEnabled) { accountKeys ->
- DataStoreUtils.getNewestMessageIds(this, DirectMessages.Inbox.CONTENT_URI, accountKeys)
- }
- return task
- }
+ companion object {
+ const val ID_REFRESH_HOME_TIMELINE = 1
+ const val ID_REFRESH_NOTIFICATIONS = 2
+ const val ID_REFRESH_DIRECT_MESSAGES = 3
+
+ fun getJobId(@AutoRefreshType type: String): Int = when (type) {
+ AutoRefreshType.HOME_TIMELINE -> JobRefreshService.ID_REFRESH_HOME_TIMELINE
+ AutoRefreshType.INTERACTIONS_TIMELINE -> JobRefreshService.ID_REFRESH_NOTIFICATIONS
+ AutoRefreshType.DIRECT_MESSAGES -> JobRefreshService.ID_REFRESH_DIRECT_MESSAGES
+ else -> 0
+ }
+
+ fun getRefreshType(jobId: Int): String? = when (jobId) {
+ JobRefreshService.ID_REFRESH_HOME_TIMELINE -> AutoRefreshType.HOME_TIMELINE
+ JobRefreshService.ID_REFRESH_NOTIFICATIONS -> AutoRefreshType.INTERACTIONS_TIMELINE
+ JobRefreshService.ID_REFRESH_DIRECT_MESSAGES -> AutoRefreshType.DIRECT_MESSAGES
+ else -> null
}
- return null
}
}
diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/service/RefreshService.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/service/RefreshService.kt
index 277e6eaa5..cd5c0cddf 100644
--- a/twidere/src/main/kotlin/org/mariotaku/twidere/service/RefreshService.kt
+++ b/twidere/src/main/kotlin/org/mariotaku/twidere/service/RefreshService.kt
@@ -19,269 +19,53 @@
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.os.SystemClock
import android.util.Log
-import edu.tsinghua.hotmobi.model.BatteryRecord
-import edu.tsinghua.hotmobi.model.ScreenEvent
-import org.apache.commons.lang3.math.NumberUtils
-import org.mariotaku.twidere.BuildConfig
-import org.mariotaku.twidere.Constants
+import org.mariotaku.abstask.library.AbstractTask
+import org.mariotaku.ktextension.convert
import org.mariotaku.twidere.TwidereConstants.LOGTAG
+import org.mariotaku.twidere.annotation.AutoRefreshType
import org.mariotaku.twidere.constant.IntentConstants.*
-import org.mariotaku.twidere.constant.SharedPreferenceConstants.*
import org.mariotaku.twidere.model.AccountPreferences
import org.mariotaku.twidere.model.SimpleRefreshTaskParam
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.provider.TwidereDataStore.*
-import org.mariotaku.twidere.receiver.PowerStateReceiver
-import org.mariotaku.twidere.util.AsyncTwitterWrapper
+import org.mariotaku.twidere.task.GetActivitiesAboutMeTask
+import org.mariotaku.twidere.task.GetHomeTimelineTask
+import org.mariotaku.twidere.task.GetReceivedDirectMessagesTask
import org.mariotaku.twidere.util.DataStoreUtils
import org.mariotaku.twidere.util.SharedPreferencesWrapper
-import org.mariotaku.twidere.util.Utils
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
import javax.inject.Inject
-class RefreshService : Service(), Constants {
+class RefreshService : Service() {
@Inject
internal lateinit var preferences: SharedPreferencesWrapper
- @Inject
- internal lateinit var twitterWrapper: AsyncTwitterWrapper
- private lateinit var alarmManager: AlarmManager
- private var pendingRefreshHomeTimelineIntent: PendingIntent? = null
- private var pendingRefreshMentionsIntent: PendingIntent? = null
- private var pendingRefreshDirectMessagesIntent: PendingIntent? = null
- private var pendingRefreshTrendsIntent: PendingIntent? = null
-
- private val mStateReceiver = object : BroadcastReceiver() {
-
- override fun onReceive(context: Context, intent: Intent) {
- val action = intent.action
- if (BuildConfig.DEBUG) {
- Log.d(LOGTAG, String.format("Refresh service received action %s", action))
- }
- when (action) {
- BROADCAST_RESCHEDULE_HOME_TIMELINE_REFRESHING -> {
- rescheduleHomeTimelineRefreshing()
- }
- BROADCAST_RESCHEDULE_MENTIONS_REFRESHING -> {
- rescheduleMentionsRefreshing()
- }
- BROADCAST_RESCHEDULE_DIRECT_MESSAGES_REFRESHING -> {
- rescheduleDirectMessagesRefreshing()
- }
- BROADCAST_RESCHEDULE_TRENDS_REFRESHING -> {
- rescheduleTrendsRefreshing()
- }
- BROADCAST_REFRESH_HOME_TIMELINE -> {
- if (isAutoRefreshAllowed) {
- twitterWrapper.getHomeTimelineAsync(AutoRefreshTaskParam(context,
- AccountPreferences::isAutoRefreshHomeTimelineEnabled) { accountKeys ->
- DataStoreUtils.getNewestStatusIds(context, Statuses.CONTENT_URI, accountKeys)
- })
- }
- }
- BROADCAST_REFRESH_NOTIFICATIONS -> {
- if (isAutoRefreshAllowed) {
- twitterWrapper.getActivitiesAboutMeAsync(AutoRefreshTaskParam(context,
- AccountPreferences::isAutoRefreshMentionsEnabled) { accountKeys ->
- DataStoreUtils.getNewestActivityMaxPositions(context,
- Activities.AboutMe.CONTENT_URI, accountKeys)
- })
- }
- }
- BROADCAST_REFRESH_DIRECT_MESSAGES -> {
- if (isAutoRefreshAllowed) {
- twitterWrapper.getReceivedDirectMessagesAsync(AutoRefreshTaskParam(context,
- AccountPreferences::isAutoRefreshDirectMessagesEnabled) { accountKeys ->
- DataStoreUtils.getNewestMessageIds(context,
- DirectMessages.Inbox.CONTENT_URI, accountKeys)
- })
- }
- }
- BROADCAST_REFRESH_TRENDS -> {
- if (isAutoRefreshAllowed) {
- val prefs = AccountPreferences.getAccountPreferences(context,
- DataStoreUtils.getAccountKeys(context)).filter(AccountPreferences::isAutoRefreshEnabled)
- getLocalTrends(prefs.filter(AccountPreferences::isAutoRefreshTrendsEnabled)
- .map(AccountPreferences::getAccountKey).toTypedArray())
- }
- }
- }
- }
-
- }
-
- private val mPowerStateReceiver = object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- when (intent.action) {
- Intent.ACTION_BATTERY_CHANGED -> {
- BatteryRecord.log(context, intent)
- }
- else -> {
- BatteryRecord.log(context)
- }
- }
- }
- }
-
- private val mScreenStateReceiver = object : BroadcastReceiver() {
- var mPresentTime: Long = -1
-
- override fun onReceive(context: Context, intent: Intent) {
- when (intent.action) {
- Intent.ACTION_SCREEN_ON -> {
- ScreenEvent.log(context, ScreenEvent.Action.ON, presentDuration)
- }
- Intent.ACTION_SCREEN_OFF -> {
- ScreenEvent.log(context, ScreenEvent.Action.OFF, presentDuration)
- mPresentTime = -1
- }
- Intent.ACTION_USER_PRESENT -> {
- mPresentTime = SystemClock.elapsedRealtime()
- ScreenEvent.log(context, ScreenEvent.Action.PRESENT, -1)
- }
- }
- }
-
- private val presentDuration: Long
- get() {
- if (mPresentTime < 0) return -1
- return SystemClock.elapsedRealtime() - mPresentTime
- }
- }
-
- override fun onBind(intent: Intent): IBinder? {
- return null
- }
+ override fun onBind(intent: Intent): IBinder? = null
override fun onCreate() {
super.onCreate()
GeneralComponentHelper.build(this).inject(this)
- alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
- pendingRefreshHomeTimelineIntent = PendingIntent.getBroadcast(this, 0, Intent(
- BROADCAST_REFRESH_HOME_TIMELINE), 0)
- pendingRefreshMentionsIntent = PendingIntent.getBroadcast(this, 0, Intent(BROADCAST_REFRESH_NOTIFICATIONS), 0)
- pendingRefreshDirectMessagesIntent = PendingIntent.getBroadcast(this, 0, Intent(
- BROADCAST_REFRESH_DIRECT_MESSAGES), 0)
- pendingRefreshTrendsIntent = PendingIntent.getBroadcast(this, 0, Intent(BROADCAST_REFRESH_TRENDS), 0)
- val refreshFilter = IntentFilter(BROADCAST_NOTIFICATION_DELETED)
- refreshFilter.addAction(BROADCAST_REFRESH_HOME_TIMELINE)
- refreshFilter.addAction(BROADCAST_REFRESH_NOTIFICATIONS)
- 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)
- val batteryFilter = 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)
- val screenFilter = IntentFilter()
- screenFilter.addAction(Intent.ACTION_SCREEN_ON)
- screenFilter.addAction(Intent.ACTION_SCREEN_OFF)
- screenFilter.addAction(Intent.ACTION_USER_PRESENT)
- registerReceiver(mPowerStateReceiver, batteryFilter)
- registerReceiver(mScreenStateReceiver, screenFilter)
- PowerStateReceiver.serviceReceiverStarted = true
- if (Utils.hasAutoRefreshAccounts(this)) {
- startAutoRefresh()
- } else {
- stopSelf()
+ }
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ Log.d(LOGTAG, "onStartCommand ${intent?.action}")
+ val task = run {
+ val type = intent?.action?.convert { getRefreshType(it) } ?: return@run null
+ return@run createJobTask(this, type)
+ } ?: run {
+ stopSelfResult(startId)
+ return START_NOT_STICKY
}
- }
-
- override fun onDestroy() {
- PowerStateReceiver.serviceReceiverStarted = false
- unregisterReceiver(mScreenStateReceiver)
- unregisterReceiver(mPowerStateReceiver)
- unregisterReceiver(mStateReceiver)
- if (Utils.hasAutoRefreshAccounts(this)) {
- // Auto refresh enabled, so I will try to start service after it was
- // stopped.
- startService(Intent(this, javaClass))
+ task.callback = {
+ stopSelfResult(startId)
}
- super.onDestroy()
- }
-
- protected val isAutoRefreshAllowed: Boolean
- get() = Utils.isNetworkAvailable(this) && (Utils.isBatteryOkay(this) || !Utils.shouldStopAutoRefreshOnBatteryLow(this))
-
- private fun getLocalTrends(accountIds: Array) {
- val account_id = Utils.getDefaultAccountKey(this)
- val woeid = preferences.getInt(KEY_LOCAL_TRENDS_WOEID, 1)
- twitterWrapper.getLocalTrendsAsync(account_id, woeid)
- }
-
- private val refreshInterval: Long
- get() {
- val prefValue = NumberUtils.toInt(preferences.getString(KEY_REFRESH_INTERVAL, DEFAULT_REFRESH_INTERVAL), -1)
- return (Math.max(prefValue, 3) * 60 * 1000).toLong()
- }
-
- private fun rescheduleDirectMessagesRefreshing() {
- alarmManager.cancel(pendingRefreshDirectMessagesIntent)
- val refreshInterval = refreshInterval
- if (refreshInterval > 0) {
- alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + refreshInterval,
- refreshInterval, pendingRefreshDirectMessagesIntent)
- }
- }
-
- private fun rescheduleHomeTimelineRefreshing() {
- alarmManager.cancel(pendingRefreshHomeTimelineIntent)
- val refreshInterval = refreshInterval
- if (refreshInterval > 0) {
- alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + refreshInterval,
- refreshInterval, pendingRefreshHomeTimelineIntent)
- }
- }
-
- private fun rescheduleMentionsRefreshing() {
- alarmManager.cancel(pendingRefreshMentionsIntent)
- val refreshInterval = refreshInterval
- if (refreshInterval > 0) {
- alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + refreshInterval,
- refreshInterval, pendingRefreshMentionsIntent)
- }
- }
-
- private fun rescheduleTrendsRefreshing() {
- alarmManager.cancel(pendingRefreshTrendsIntent)
- val refreshInterval = refreshInterval
- if (refreshInterval > 0) {
- alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + refreshInterval,
- refreshInterval, pendingRefreshTrendsIntent)
- }
- }
-
- private fun startAutoRefresh(): Boolean {
- stopAutoRefresh()
- val refreshInterval = refreshInterval
- if (refreshInterval <= 0) return false
- rescheduleHomeTimelineRefreshing()
- rescheduleMentionsRefreshing()
- rescheduleDirectMessagesRefreshing()
- rescheduleTrendsRefreshing()
- return true
- }
-
- private fun stopAutoRefresh() {
- alarmManager.cancel(pendingRefreshHomeTimelineIntent)
- alarmManager.cancel(pendingRefreshMentionsIntent)
- alarmManager.cancel(pendingRefreshDirectMessagesIntent)
- alarmManager.cancel(pendingRefreshTrendsIntent)
+ return START_NOT_STICKY
}
class AutoRefreshTaskParam(
@@ -301,4 +85,49 @@ class RefreshService : Service(), Constants {
get() = getSinceIds(accountKeys)
}
+ companion object {
+
+ fun createJobTask(context: Context, @AutoRefreshType refreshType: String): AbstractTask<*, *, () -> Unit>? {
+ when (refreshType) {
+ AutoRefreshType.HOME_TIMELINE -> {
+ val task = GetHomeTimelineTask(context)
+ task.params = RefreshService.AutoRefreshTaskParam(context, AccountPreferences::isAutoRefreshHomeTimelineEnabled) { accountKeys ->
+ DataStoreUtils.getNewestStatusIds(context, Statuses.CONTENT_URI, accountKeys)
+ }
+ return task
+ }
+ AutoRefreshType.INTERACTIONS_TIMELINE -> {
+ val task = GetActivitiesAboutMeTask(context)
+ task.params = RefreshService.AutoRefreshTaskParam(context, AccountPreferences::isAutoRefreshMentionsEnabled) { accountKeys ->
+ DataStoreUtils.getNewestActivityMaxPositions(context, Activities.AboutMe.CONTENT_URI, accountKeys)
+ }
+ return task
+ }
+ AutoRefreshType.DIRECT_MESSAGES -> {
+ val task = GetReceivedDirectMessagesTask(context)
+ task.params = RefreshService.AutoRefreshTaskParam(context, AccountPreferences::isAutoRefreshDirectMessagesEnabled) { accountKeys ->
+ DataStoreUtils.getNewestMessageIds(context, DirectMessages.Inbox.CONTENT_URI, accountKeys)
+ }
+ return task
+ }
+ }
+ return null
+ }
+
+ @AutoRefreshType
+ fun getRefreshType(action: String): String? = when (action) {
+ ACTION_REFRESH_HOME_TIMELINE -> AutoRefreshType.HOME_TIMELINE
+ ACTION_REFRESH_NOTIFICATIONS -> AutoRefreshType.INTERACTIONS_TIMELINE
+ ACTION_REFRESH_DIRECT_MESSAGES -> AutoRefreshType.DIRECT_MESSAGES
+ else -> null
+ }
+
+ fun getRefreshAction(@AutoRefreshType type: String): String? = when (type) {
+ AutoRefreshType.HOME_TIMELINE -> ACTION_REFRESH_HOME_TIMELINE
+ AutoRefreshType.INTERACTIONS_TIMELINE -> ACTION_REFRESH_NOTIFICATIONS
+ AutoRefreshType.DIRECT_MESSAGES -> ACTION_REFRESH_DIRECT_MESSAGES
+ else -> null
+ }
+
+ }
}
diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/AutoRefreshController.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/AutoRefreshController.kt
new file mode 100644
index 000000000..67d2db283
--- /dev/null
+++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/AutoRefreshController.kt
@@ -0,0 +1,31 @@
+package org.mariotaku.twidere.util
+
+import android.content.Context
+import org.mariotaku.kpreferences.KPreferences
+import org.mariotaku.twidere.annotation.AutoRefreshType
+
+/**
+ * Created by mariotaku on 2016/12/17.
+ */
+
+abstract class AutoRefreshController(
+ val context: Context,
+ val kPreferences: KPreferences
+) {
+
+ abstract fun appStarted()
+
+ abstract fun schedule(@AutoRefreshType type: String)
+
+ abstract fun unschedule(@AutoRefreshType type: String)
+
+ fun reschedule(@AutoRefreshType type: String) {
+ unschedule(type)
+ schedule(type)
+ }
+
+ fun rescheduleAll() {
+ AutoRefreshType.ALL.forEach { reschedule(it) }
+ }
+
+}
diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/JobSchedulerAutoRefreshController.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/JobSchedulerAutoRefreshController.kt
new file mode 100644
index 000000000..7f542f1d0
--- /dev/null
+++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/JobSchedulerAutoRefreshController.kt
@@ -0,0 +1,69 @@
+package org.mariotaku.twidere.util
+
+import android.annotation.TargetApi
+import android.app.job.JobInfo
+import android.app.job.JobScheduler
+import android.content.ComponentName
+import android.content.Context
+import android.os.Build
+import org.mariotaku.kpreferences.KPreferences
+import org.mariotaku.twidere.annotation.AutoRefreshType
+import org.mariotaku.twidere.constant.refreshIntervalKey
+import org.mariotaku.twidere.service.JobRefreshService
+import java.util.concurrent.TimeUnit
+import android.Manifest.permission as AndroidPermissions
+
+/**
+ * Created by mariotaku on 2016/12/17.
+ */
+
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+class JobSchedulerAutoRefreshController(
+ context: Context,
+ kPreferences: KPreferences
+) : AutoRefreshController(context, kPreferences) {
+ val scheduler: JobScheduler
+
+ init {
+ scheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
+ }
+
+ override fun appStarted() {
+ val allJobs = scheduler.allPendingJobs
+ AutoRefreshType.ALL.forEach { type ->
+ val jobId = JobRefreshService.getJobId(type)
+ if (allJobs.none { job -> job.id == jobId }) {
+ // Start non existing job
+ schedule(type)
+ }
+ }
+
+ }
+
+ override fun schedule(@AutoRefreshType type: String) {
+ val jobId = JobRefreshService.getJobId(type)
+ scheduler.cancel(jobId)
+ scheduleJob(jobId)
+ }
+
+ override fun unschedule(type: String) {
+ val jobId = JobRefreshService.getJobId(type)
+ scheduler.cancel(jobId)
+ }
+
+ fun scheduleJob(jobId: Int, persisted: Boolean = true) {
+ val builder = JobInfo.Builder(jobId, ComponentName(context, JobRefreshService::class.java))
+ builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ builder.setPeriodic(TimeUnit.MINUTES.toMillis(kPreferences[refreshIntervalKey]))
+ builder.setPersisted(persisted)
+ try {
+ scheduler.schedule(builder.build())
+ } catch (e: IllegalArgumentException) {
+ if (persisted) {
+ scheduleJob(jobId, false)
+ }
+ }
+ }
+
+
+}
diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/LegacyAutoRefreshController.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/LegacyAutoRefreshController.kt
new file mode 100644
index 000000000..503041e7b
--- /dev/null
+++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/LegacyAutoRefreshController.kt
@@ -0,0 +1,54 @@
+package org.mariotaku.twidere.util
+
+import android.app.AlarmManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.support.v4.util.ArrayMap
+import org.mariotaku.kpreferences.KPreferences
+import org.mariotaku.twidere.annotation.AutoRefreshType
+import org.mariotaku.twidere.constant.refreshIntervalKey
+import org.mariotaku.twidere.service.RefreshService
+import java.util.concurrent.TimeUnit
+
+class LegacyAutoRefreshController(
+ context: Context,
+ kPreferences: KPreferences
+) : AutoRefreshController(context, kPreferences) {
+
+ private val alarmManager: AlarmManager
+
+ private val pendingIntents: ArrayMap
+
+ init {
+ alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
+
+ pendingIntents = ArrayMap()
+
+ AutoRefreshType.ALL.forEach { type ->
+ val action = RefreshService.getRefreshAction(type) ?: return@forEach
+ val intent = Intent(context, RefreshService::class.java)
+ intent.action = action
+ pendingIntents[type] = PendingIntent.getService(context, 0, intent, 0)
+ }
+ }
+
+ override fun appStarted() {
+ rescheduleAll()
+ }
+
+ override fun unschedule(type: String) {
+ val pendingIntent = pendingIntents[type] ?: return
+ alarmManager.cancel(pendingIntent)
+ }
+
+ override fun schedule(type: String) {
+ val pendingIntent = pendingIntents[type] ?: return
+ val interval = TimeUnit.MINUTES.toMillis(kPreferences[refreshIntervalKey])
+ if (interval > 0) {
+ val triggerAt = System.currentTimeMillis() + interval
+ alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, triggerAt, interval, pendingIntent)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt
index be4787080..d02b2443d 100644
--- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt
+++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt
@@ -42,6 +42,7 @@ import org.mariotaku.mediaviewer.library.MediaDownloader
import org.mariotaku.restfu.http.RestHttpClient
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.Constants
+import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.SharedPreferenceConstants
import org.mariotaku.twidere.model.DefaultFeatures
import org.mariotaku.twidere.util.*
@@ -228,6 +229,14 @@ class ApplicationModule(private val application: Application) {
return BidiFormatter.getInstance()
}
+ @Provides
+ fun autoRefreshController(kPreferences: KPreferences): AutoRefreshController {
+ if (application.resources.getBoolean(R.bool.use_job_refresh_service)) {
+ return JobSchedulerAutoRefreshController(application, kPreferences)
+ }
+ return LegacyAutoRefreshController(application, kPreferences)
+ }
+
@Provides
@Singleton
fun defaultFeatures(preferences: SharedPreferencesWrapper): DefaultFeatures {
@@ -270,3 +279,4 @@ class ApplicationModule(private val application: Application) {
}
}
}
+
diff --git a/twidere/src/main/res/values-v21/config.xml b/twidere/src/main/res/values-v21/config.xml
index 82c23cba6..bdc19b41d 100644
--- a/twidere/src/main/res/values-v21/config.xml
+++ b/twidere/src/main/res/values-v21/config.xml
@@ -1,5 +1,5 @@
-
-
+ true
+ false
\ No newline at end of file