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 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