-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor code that depends on a logged in user
Makes use of dagger subcomponents to have seperate state for each logged in user. This is useful for when we want to allow to have more than one account in the app. But already now it resolves a lot of bugs in case an account is removed at any time. And it improves the readability of the code as dependencies are much more explicit. Moreover, it makes the story of "what is available when?" much easier to understand.
- Loading branch information
Showing
67 changed files
with
1,580 additions
and
941 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91 changes: 91 additions & 0 deletions
91
app/src/main/java/fi/bitrite/android/ws/AutoMessageReloadJobService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package fi.bitrite.android.ws; | ||
|
||
import android.app.job.JobInfo; | ||
import android.app.job.JobParameters; | ||
import android.app.job.JobScheduler; | ||
import android.app.job.JobService; | ||
import android.content.ComponentName; | ||
import android.content.Context; | ||
import android.os.Build; | ||
import android.support.annotation.RequiresApi; | ||
import android.util.Log; | ||
|
||
import javax.inject.Inject; | ||
|
||
import io.reactivex.disposables.Disposable; | ||
|
||
/** | ||
* Runs the reloading of messages in a scheduled job service. That uses less battery power than | ||
* using a traditional service which is running all the time in the background. | ||
*/ | ||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) | ||
public class AutoMessageReloadJobService extends JobService { | ||
private final static String TAG = AutoMessageReloadJobService.class.getCanonicalName(); | ||
private final static int JOB_ID_RELOAD_MESSAGES = 1; | ||
|
||
@Inject AutoMessageReloadScheduler mAutoMessageReloadScheduler; | ||
|
||
private Disposable mDisposable; | ||
|
||
public static void reschedule(Context context, long messageReloadIntervalMs) { | ||
JobScheduler jobScheduler = | ||
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); | ||
if (jobScheduler == null) { | ||
return; | ||
} | ||
|
||
if (messageReloadIntervalMs > 0) { | ||
ComponentName componentName = | ||
new ComponentName(context, AutoMessageReloadJobService.class); | ||
JobInfo jobInfo = new JobInfo.Builder(JOB_ID_RELOAD_MESSAGES, componentName) | ||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) | ||
.setMinimumLatency(messageReloadIntervalMs) | ||
.build(); | ||
|
||
int resultCode = jobScheduler.schedule(jobInfo); | ||
if (resultCode != JobScheduler.RESULT_SUCCESS) { | ||
Log.e(TAG, "Message reload job failed to be scheduled."); | ||
} | ||
} else { | ||
jobScheduler.cancel(JOB_ID_RELOAD_MESSAGES); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean onStartJob(JobParameters jobParameters) { | ||
WSAndroidApplication.getAppComponent().inject(this); | ||
|
||
Log.d(TAG, "Auto-reloading messages"); | ||
|
||
mDisposable = mAutoMessageReloadScheduler.reloadMessagesInAllAccounts() | ||
.onErrorComplete() | ||
.subscribe(() -> { | ||
mDisposable = null; | ||
|
||
Log.d(TAG, "Auto-reloading messages completed"); | ||
|
||
// Mark the job as finished and do NOT request a reschedule. A reschedule should | ||
// take place in case of an error and has nothing to do with repeated job | ||
// execution. It would apply back-off policy for the job. | ||
jobFinished(jobParameters, false); | ||
|
||
// Reschedule the job. | ||
reschedule(getApplicationContext(), | ||
mAutoMessageReloadScheduler.getMessageReloadIntervalMs()); | ||
}); | ||
|
||
return true; | ||
} | ||
|
||
@Override | ||
public boolean onStopJob(JobParameters jobParameters) { | ||
Log.d(TAG, "Auto-reload messages job stopped."); | ||
if (mDisposable != null) { | ||
mDisposable.dispose(); | ||
mDisposable = null; | ||
} | ||
|
||
// Try to reschedule. This is never done in case of the reload time being zero. | ||
return true; | ||
} | ||
} |
91 changes: 91 additions & 0 deletions
91
app/src/main/java/fi/bitrite/android/ws/AutoMessageReloadScheduler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package fi.bitrite.android.ws; | ||
|
||
import android.accounts.Account; | ||
import android.content.Context; | ||
import android.content.SharedPreferences; | ||
import android.os.Build; | ||
|
||
import java.util.LinkedList; | ||
import java.util.List; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
import javax.inject.Inject; | ||
|
||
import fi.bitrite.android.ws.auth.AccountManager; | ||
import fi.bitrite.android.ws.di.AppScope; | ||
import fi.bitrite.android.ws.di.account.AccountComponentManager; | ||
import fi.bitrite.android.ws.repository.MessageRepository; | ||
import fi.bitrite.android.ws.repository.SettingsRepository; | ||
import io.reactivex.Completable; | ||
|
||
@AppScope | ||
public class AutoMessageReloadScheduler | ||
implements SharedPreferences.OnSharedPreferenceChangeListener { | ||
private final AccountComponentManager mAccountComponentManager; | ||
private final AccountManager mAccountManager; | ||
private final Context mContext; | ||
private final SettingsRepository mSettingsRepository; | ||
|
||
private boolean mHasAccounts = true; | ||
private long mMessageReloadIntervalMs; | ||
|
||
@Inject | ||
AutoMessageReloadScheduler(AccountManager accountManager, | ||
AccountComponentManager accountComponentManager, Context context, | ||
SettingsRepository settingsRepository) { | ||
mAccountComponentManager = accountComponentManager; | ||
mAccountManager = accountManager; | ||
mContext = context; | ||
mSettingsRepository = settingsRepository; | ||
|
||
mAccountManager.getAccounts().subscribe(accounts -> { | ||
boolean hasAccounts = accounts.length > 0; | ||
if (hasAccounts == mHasAccounts) { | ||
return; | ||
} | ||
mHasAccounts = hasAccounts; | ||
|
||
reschedule(); | ||
}); | ||
|
||
// Register for settings updates. That triggers an initial run of the change listener. | ||
mSettingsRepository.registerOnChangeListener(this); | ||
} | ||
|
||
public long getMessageReloadIntervalMs() { | ||
return mHasAccounts ? mMessageReloadIntervalMs : 0; | ||
} | ||
|
||
public static class AccountHelper { | ||
@Inject MessageRepository messageRepository; | ||
} | ||
|
||
public Completable reloadMessagesInAllAccounts() { | ||
AccountHelper accountHelper = new AccountHelper(); | ||
List<Completable> completables = new LinkedList<>(); | ||
for (Account account : mAccountManager.getAccounts().getValue()) { | ||
mAccountComponentManager.get(account).inject(accountHelper); | ||
completables.add(accountHelper.messageRepository.reloadThreads()); | ||
} | ||
return Completable.mergeDelayError(completables); | ||
} | ||
|
||
@Override | ||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { | ||
if (key == null || key.equals(mSettingsRepository.getMessageRefreshIntervalKey())) { | ||
mMessageReloadIntervalMs = TimeUnit.MINUTES.toMillis( | ||
mSettingsRepository.getMessageRefreshIntervalMin()); | ||
reschedule(); | ||
} | ||
} | ||
|
||
private void reschedule() { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { | ||
AutoMessageReloadJobService.reschedule(mContext, getMessageReloadIntervalMs()); | ||
} else { | ||
AutoMessageReloadService.reschedule(mContext, getMessageReloadIntervalMs()); | ||
} | ||
|
||
} | ||
} | ||
|
118 changes: 118 additions & 0 deletions
118
app/src/main/java/fi/bitrite/android/ws/AutoMessageReloadService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package fi.bitrite.android.ws; | ||
|
||
import android.app.Service; | ||
import android.content.Context; | ||
import android.content.Intent; | ||
import android.os.IBinder; | ||
import android.util.Log; | ||
|
||
import java.util.Timer; | ||
import java.util.TimerTask; | ||
|
||
import javax.annotation.Nullable; | ||
import javax.inject.Inject; | ||
|
||
import io.reactivex.disposables.Disposable; | ||
|
||
public class AutoMessageReloadService extends Service { | ||
private final static String TAG = AutoMessageReloadService.class.getCanonicalName(); | ||
|
||
@Inject AutoMessageReloadScheduler mAutoMessageReloadScheduler; | ||
|
||
private Timer mTimer; | ||
private ReloadMessagesTask mReloadTask; | ||
|
||
/** | ||
* Starts the service to periodically reload the message threads. | ||
*/ | ||
public static void reschedule(Context context, long messageReloadInterval) { | ||
Intent serviceIntent = new Intent(context, AutoMessageReloadService.class); | ||
if (messageReloadInterval > 0) { | ||
context.startService(serviceIntent); | ||
} else { | ||
context.stopService(serviceIntent); | ||
} | ||
} | ||
|
||
@Override | ||
public void onCreate() { | ||
Log.d(TAG, "Auto-message reload service: created."); | ||
super.onCreate(); | ||
|
||
WSAndroidApplication.getAppComponent().inject(this); | ||
|
||
// Reload the messages now. | ||
mTimer = new Timer(); | ||
} | ||
|
||
@Override | ||
public int onStartCommand(Intent intent, int flags, int startId) { | ||
// This method is fired every time we do a startService call in reschedule(). | ||
Log.d(TAG, "Auto-message reload service: onStartCommand trigger."); | ||
scheduleReloadTask(); | ||
|
||
return Service.START_STICKY; | ||
} | ||
|
||
@Override | ||
public void onDestroy() { | ||
Log.d(TAG, "Auto-message reload service: destroyed."); | ||
mTimer.cancel(); | ||
super.onDestroy(); | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public IBinder onBind(Intent intent) { | ||
return null; | ||
} | ||
|
||
void scheduleReloadTask() { | ||
// Cancel any scheduled task. | ||
if (mReloadTask != null) { | ||
Log.d(TAG, "Cancelling currently scheduled task"); | ||
mReloadTask.cancel(); | ||
mReloadTask = null; | ||
} | ||
|
||
final long messageReloadIntervalMs = | ||
mAutoMessageReloadScheduler.getMessageReloadIntervalMs(); | ||
|
||
// Zero means no scheduled executions. | ||
if (messageReloadIntervalMs == 0) { | ||
Log.d(TAG, "Disabling message auto-reloading"); | ||
return; | ||
} | ||
|
||
// Schedule the tasks. | ||
mReloadTask = new ReloadMessagesTask(); | ||
Log.d(TAG, String.format("Scheduled to run at intervals of %dms", messageReloadIntervalMs)); | ||
mTimer.schedule(mReloadTask, 0, messageReloadIntervalMs); | ||
} | ||
|
||
class ReloadMessagesTask extends TimerTask { | ||
private Disposable mDisposable; | ||
|
||
@Override | ||
public void run() { | ||
dispose(); | ||
Log.d(TAG, "Auto-reloading messages"); | ||
mDisposable = mAutoMessageReloadScheduler.reloadMessagesInAllAccounts() | ||
.onErrorComplete() | ||
.subscribe(() -> Log.d(TAG, "Auto-reloading messages completed.")); | ||
} | ||
|
||
@Override | ||
public boolean cancel() { | ||
dispose(); | ||
return super.cancel(); | ||
} | ||
|
||
private void dispose() { | ||
if (mDisposable != null) { | ||
mDisposable.dispose(); | ||
mDisposable = null; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.