diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 1e4723557c..146151eee4 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -541,8 +541,6 @@ - - UPGRADE_VERSIONS = new TreeSet() {{ add(NO_MORE_KEY_EXCHANGE_PREFIX_VERSION); @@ -108,6 +114,7 @@ public class DatabaseUpgradeActivity extends BaseActivity { add(FULL_TEXT_SEARCH); add(BAD_IMPORT_CLEANUP); add(IMAGE_CACHE_CLEANUP); + add(WORKMANAGER_MIGRATION); }}; private MasterSecret masterSecret; @@ -318,6 +325,18 @@ public class DatabaseUpgradeActivity extends BaseActivity { } } + if (params[0] < WORKMANAGER_MIGRATION) { + Log.i(TAG, "Beginning migration of existing jobs to WorkManager"); + + JobManager jobManager = ApplicationContext.getInstance(getApplicationContext()).getJobManager(); + PersistentStorage storage = new PersistentStorage(getApplicationContext(), "TextSecureJobs", new JavaJobSerializer()); + + for (Job job : storage.getAllUnencrypted()) { + jobManager.add(job); + Log.i(TAG, "Migrated job with class '" + job.getClass().getSimpleName() + "' to run on new JobManager."); + } + } + return null; } diff --git a/src/org/thoughtcrime/securesms/components/camera/QuickAttachmentDrawer.java b/src/org/thoughtcrime/securesms/components/camera/QuickAttachmentDrawer.java index cbdb428dc2..eadc5cf896 100644 --- a/src/org/thoughtcrime/securesms/components/camera/QuickAttachmentDrawer.java +++ b/src/org/thoughtcrime/securesms/components/camera/QuickAttachmentDrawer.java @@ -254,7 +254,7 @@ public class QuickAttachmentDrawer extends ViewGroup implements InputView, Camer @Override protected boolean drawChild(@NonNull Canvas canvas, @NonNull View child, long drawingTime) { boolean result; - final int save = canvas.save(Canvas.CLIP_SAVE_FLAG); + final int save = canvas.save(); canvas.getClipBounds(drawChildrenRect); if (child == coverView) { diff --git a/src/org/thoughtcrime/securesms/jobmanager/Job.java b/src/org/thoughtcrime/securesms/jobmanager/Job.java index 8735dd44da..b658b087b3 100644 --- a/src/org/thoughtcrime/securesms/jobmanager/Job.java +++ b/src/org/thoughtcrime/securesms/jobmanager/Job.java @@ -1,138 +1,139 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * 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.thoughtcrime.securesms.jobmanager; -import android.os.PowerManager; +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; -import org.thoughtcrime.securesms.jobmanager.requirements.Requirement; +import org.thoughtcrime.securesms.ApplicationContext; +import org.thoughtcrime.securesms.jobmanager.dependencies.ContextDependent; +import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.jobs.requirements.SqlCipherMigrationRequirement; +import org.thoughtcrime.securesms.logging.Log; import java.io.Serializable; -import java.util.List; +import java.util.UUID; -/** - * An abstract class representing a unit of work that can be scheduled with - * the JobManager. This should be extended to implement tasks. - */ -public abstract class Job implements Serializable { +import androidx.work.Data; +import androidx.work.Worker; +import androidx.work.WorkerParameters; - private final JobParameters parameters; +public abstract class Job extends Worker implements Serializable { - private transient long persistentId; - private transient int runIteration; - private transient long lastRunTime; - private transient PowerManager.WakeLock wakeLock; + private static final long serialVersionUID = -4658540468214421276L; - public Job(JobParameters parameters) { - this.parameters = parameters; - } + private static final String TAG = Job.class.getSimpleName(); - public List getRequirements() { - return parameters.getRequirements(); - } + static final String KEY_RETRY_COUNT = "Job_retry_count"; + static final String KEY_RETRY_UNTIL = "Job_retry_until"; + static final String KEY_SUBMIT_TIME = "Job_submit_time"; + static final String KEY_REQUIRES_MASTER_SECRET = "Job_requires_master_secret"; + static final String KEY_REQUIRES_SQLCIPHER = "Job_requires_sqlcipher"; - public boolean isRequirementsMet() { - for (Requirement requirement : parameters.getRequirements()) { - if (!requirement.isPresent(this)) return false; - } + private JobParameters parameters; - return true; - } - - public String getGroupId() { - return parameters.getGroupId(); - } - - public boolean isPersistent() { - return parameters.isPersistent(); - } - - public EncryptionKeys getEncryptionKeys() { - return parameters.getEncryptionKeys(); - } - - public void setEncryptionKeys(EncryptionKeys keys) { - parameters.setEncryptionKeys(keys); - } - - public int getRetryCount() { - return parameters.getRetryCount(); - } - - public long getRetryUntil() { - return parameters.getRetryUntil(); - } - - public long getLastRunTime() { - return lastRunTime; - } - - public void resetRunStats() { - runIteration = 0; - lastRunTime = 0; - } - - public void setPersistentId(long persistentId) { - this.persistentId = persistentId; - } - - public long getPersistentId() { - return persistentId; - } - - public int getRunIteration() { - return runIteration; - } - - public boolean needsWakeLock() { - return parameters.needsWakeLock(); - } - - public long getWakeLockTimeout() { - return parameters.getWakeLockTimeout(); - } - - public void setWakeLock(PowerManager.WakeLock wakeLock) { - this.wakeLock = wakeLock; - } - - public PowerManager.WakeLock getWakeLock() { - return this.wakeLock; - } - - public void onRetry() { - runIteration++; - lastRunTime = System.currentTimeMillis(); - - for (Requirement requirement : parameters.getRequirements()) { - requirement.onRetry(this); - } + public Job(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); } /** - * Called after a job has been added to the JobManager queue. If it's a persistent job, - * the state has been persisted to disk before this method is called. + * Invoked when a job is first created in our own codebase. */ - public abstract void onAdded(); + protected Job(@Nullable JobParameters parameters) { + this.parameters = parameters; + } + + @NonNull + @Override + public Result doWork() { + Data data = getInputData(); + + log("doWork()" + logSuffix()); + + ApplicationContext.getInstance(getApplicationContext()).ensureInitialized(); + ApplicationContext.getInstance(getApplicationContext()).injectDependencies(this); + + if (this instanceof ContextDependent) { + ((ContextDependent)this).setContext(getApplicationContext()); + } + + initialize(new SafeData(data)); + + try { + if (withinRetryLimits(data)) { + if (requirementsMet(data)) { + onRun(); + log("Successfully completed." + logSuffix()); + return Result.SUCCESS; + } else { + log("Retrying due to unmet requirements." + logSuffix()); + return retry(); + } + } else { + warn("Failing after hitting the retry limit." + logSuffix()); + return cancel(); + } + } catch (Exception e) { + if (onShouldRetry(e)) { + log("Retrying after a retryable exception." + logSuffix()); + return retry(); + } + warn("Failing due to an exception." + logSuffix(), e); + return cancel(); + } + } + + @Override + public void onStopped(boolean cancelled) { + if (cancelled) { + warn("onStopped() with cancellation signal." + logSuffix()); + onCanceled(); + } + } + + final void onSubmit(UUID id) { + log(id, "onSubmit()"); + onAdded(); + } + + /** + * Called after a run has finished and we've determined a retry is required, but before the next + * attempt is run. + */ + protected void onRetry() { } + + /** + * Called after a job has been added to the JobManager queue. Invoked off the main thread, so its + * safe to do longer-running work. However, work should finish relatively quickly, as it will + * block the submission of future tasks. + */ + protected void onAdded() { } + + /** + * All instance state needs to be persisted in the provided {@link Data.Builder} so that it can + * be restored in {@link #initialize(SafeData)}. + * @param dataBuilder The builder where you put your state. + * @return The result of {@code dataBuilder.build()}. + */ + protected abstract @NonNull Data serialize(@NonNull Data.Builder dataBuilder); + + /** + * Restore all of your instance state from the provided {@link Data}. It should contain all of + * the data put in during {@link #serialize(Data.Builder)}. + * @param data Where your data is stored. + */ + protected abstract void initialize(@NonNull SafeData data); /** * Called to actually execute the job. * @throws Exception */ - protected abstract void onRun() throws Exception; + public abstract void onRun() throws Exception; + + /** + * Called if a job fails to run (onShouldRetry returned false, or the number of retries exceeded + * the job's configured retry count. + */ + protected abstract void onCanceled(); /** * If onRun() throws an exception, this method will be called to determine whether the @@ -141,14 +142,69 @@ public abstract class Job implements Serializable { * @param exception The exception onRun() threw. * @return true if onRun() should be called again, false otherwise. */ - public abstract boolean onShouldRetry(Exception exception); + protected abstract boolean onShouldRetry(Exception exception); - /** - * Called if a job fails to run (onShouldRetry returned false, or the number of retries exceeded - * the job's configured retry count. - */ - public abstract void onCanceled(); + @Nullable JobParameters getJobParameters() { + return parameters; + } + private Result retry() { + onRetry(); + return Result.RETRY; + } + private Result cancel() { + onCanceled(); + return Result.SUCCESS; + } + private boolean requirementsMet(Data data) { + boolean met = true; + + if (data.getBoolean(KEY_REQUIRES_MASTER_SECRET, false)) { + met &= new MasterSecretRequirement(getApplicationContext()).isPresent(); + } + + if (data.getBoolean(KEY_REQUIRES_SQLCIPHER, false)) { + met &= new SqlCipherMigrationRequirement(getApplicationContext()).isPresent(); + } + + return met; + } + + private boolean withinRetryLimits(Data data) { + int retryCount = data.getInt(KEY_RETRY_COUNT, 0); + long retryUntil = data.getLong(KEY_RETRY_UNTIL, 0); + + if (retryCount > 0) { + return getRunAttemptCount() <= retryCount; + } + + return System.currentTimeMillis() < retryUntil; + } + + private void log(@NonNull String message) { + log(getId(), message); + } + + private void log(@NonNull UUID id, @NonNull String message) { + Log.i(TAG, buildLog(id, message)); + } + + private void warn(@NonNull String message) { + warn(message, null); + } + + private void warn(@NonNull String message, @Nullable Throwable t) { + Log.w(TAG, buildLog(getId(), message), t); + } + + private String buildLog(@NonNull UUID id, @NonNull String message) { + return "[" + id + "] " + getClass().getSimpleName() + " :: " + message; + } + + private String logSuffix() { + long timeSinceSubmission = System.currentTimeMillis() - getInputData().getLong(KEY_SUBMIT_TIME, 0); + return " (Time since submission: " + timeSinceSubmission + " ms, Run attempt: " + getRunAttemptCount() + ")"; + } } diff --git a/src/org/thoughtcrime/securesms/jobmanager/JobConsumer.java b/src/org/thoughtcrime/securesms/jobmanager/JobConsumer.java deleted file mode 100644 index cbdb43be9e..0000000000 --- a/src/org/thoughtcrime/securesms/jobmanager/JobConsumer.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * 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.thoughtcrime.securesms.jobmanager; - -import android.support.annotation.NonNull; -import org.thoughtcrime.securesms.logging.Log; - -import org.thoughtcrime.securesms.jobmanager.persistence.PersistentStorage; - -class JobConsumer extends Thread { - - private static final String TAG = JobConsumer.class.getSimpleName(); - - enum JobResult { - SUCCESS, - FAILURE, - DEFERRED - } - - private final JobQueue jobQueue; - private final PersistentStorage persistentStorage; - - public JobConsumer(String name, JobQueue jobQueue, PersistentStorage persistentStorage) { - super(name); - this.jobQueue = jobQueue; - this.persistentStorage = persistentStorage; - } - - @Override - public void run() { - while (true) { - Job job = jobQueue.getNext(); - JobResult result = runJob(job); - - if (result == JobResult.DEFERRED) { - jobQueue.push(job); - } else { - if (result == JobResult.FAILURE) { - job.onCanceled(); - } - - if (job.isPersistent()) { - persistentStorage.remove(job.getPersistentId()); - } - - if (job.getWakeLock() != null && job.getWakeLockTimeout() == 0) { - job.getWakeLock().release(); - } - - if (job.getGroupId() != null) { - jobQueue.setGroupIdAvailable(job.getGroupId()); - } - } - } - } - - private JobResult runJob(Job job) { - while (canRetry(job)) { - try { - job.onRun(); - return JobResult.SUCCESS; - } catch (Exception exception) { - Log.w(TAG, exception); - if (exception instanceof RuntimeException) { - throw (RuntimeException)exception; - } else if (!job.onShouldRetry(exception)) { - return JobResult.FAILURE; - } - - job.onRetry(); - if (!job.isRequirementsMet()) { - return JobResult.DEFERRED; - } - } - } - - return JobResult.FAILURE; - } - - private boolean canRetry(@NonNull Job job) { - if (job.getRetryCount() > 0) { - return job.getRunIteration() < job.getRetryCount(); - } - return System.currentTimeMillis() < job.getRetryUntil(); - } -} diff --git a/src/org/thoughtcrime/securesms/jobmanager/JobManager.java b/src/org/thoughtcrime/securesms/jobmanager/JobManager.java index c41956581f..c408d742ed 100644 --- a/src/org/thoughtcrime/securesms/jobmanager/JobManager.java +++ b/src/org/thoughtcrime/securesms/jobmanager/JobManager.java @@ -1,252 +1,69 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * 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.thoughtcrime.securesms.jobmanager; -import android.content.Context; -import android.os.PowerManager; +import android.support.annotation.NonNull; -import org.thoughtcrime.securesms.jobmanager.dependencies.AggregateDependencyInjector; -import org.thoughtcrime.securesms.jobmanager.dependencies.DependencyInjector; -import org.thoughtcrime.securesms.jobmanager.persistence.JobSerializer; -import org.thoughtcrime.securesms.jobmanager.persistence.PersistentStorage; -import org.thoughtcrime.securesms.jobmanager.requirements.RequirementListener; -import org.thoughtcrime.securesms.jobmanager.requirements.RequirementProvider; -import org.thoughtcrime.securesms.logging.Log; - -import java.io.IOException; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.TimeUnit; -/** - * A JobManager allows you to enqueue {@link org.thoughtcrime.securesms.jobmanager.Job} tasks - * that are executed once a Job's {@link org.thoughtcrime.securesms.jobmanager.requirements.Requirement}s - * are met. - */ -public class JobManager implements RequirementListener { +import androidx.work.BackoffPolicy; +import androidx.work.Constraints; +import androidx.work.Data; +import androidx.work.ExistingWorkPolicy; +import androidx.work.NetworkType; +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkManager; - private final JobQueue jobQueue = new JobQueue(); - private final Executor eventExecutor = Executors.newSingleThreadExecutor(); - private final AtomicBoolean hasLoadedEncrypted = new AtomicBoolean(false); +public class JobManager { - private final Context context; - private final PersistentStorage persistentStorage; - private final List requirementProviders; - private final AggregateDependencyInjector dependencyInjector; + private static final Constraints NETWORK_CONSTRAINT = new Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build(); - private JobManager(Context context, String name, - List requirementProviders, - DependencyInjector dependencyInjector, - JobSerializer jobSerializer, int consumers) - { - this.context = context; - this.dependencyInjector = new AggregateDependencyInjector(dependencyInjector); - this.persistentStorage = new PersistentStorage(context, name, jobSerializer, this.dependencyInjector); - this.requirementProviders = requirementProviders; + private final Executor executor = Executors.newSingleThreadExecutor(); - eventExecutor.execute(new LoadTask(null)); + private final WorkManager workManager; - if (requirementProviders != null && !requirementProviders.isEmpty()) { - for (RequirementProvider provider : requirementProviders) { - provider.setListener(this); + public JobManager(@NonNull WorkManager workManager) { + this.workManager = workManager; + } + + public void add(Job job) { + executor.execute(() -> { + workManager.synchronous().pruneWorkSync(); + + JobParameters jobParameters = job.getJobParameters(); + + if (jobParameters == null) { + throw new IllegalStateException("Jobs must have JobParameters at this stage."); } - } - for (int i=0;i pendingJobs; - - if (keys == null) pendingJobs = persistentStorage.getAllUnencrypted(); - else pendingJobs = persistentStorage.getAllEncrypted(keys); - - jobQueue.addAll(pendingJobs); - } - } - - public static class Builder { - private final Context context; - private String name; - private List requirementProviders; - private DependencyInjector dependencyInjector; - private JobSerializer jobSerializer; - private int consumerThreads; - - Builder(Context context) { - this.context = context; - this.consumerThreads = 5; - } - - /** - * A name for the {@link org.thoughtcrime.securesms.jobmanager.JobManager}. This is a required parameter, - * and is linked to the durable queue used by persistent jobs. - * - * @param name The name for the JobManager to build. - * @return The builder. - */ - public Builder withName(String name) { - this.name = name; - return this; - } - - /** - * The {@link org.thoughtcrime.securesms.jobmanager.requirements.RequirementProvider}s to register with this - * JobManager. Optional. Each {@link org.thoughtcrime.securesms.jobmanager.requirements.Requirement} an - * enqueued Job depends on should have a matching RequirementProvider registered here. - * - * @param requirementProviders The RequirementProviders - * @return The builder. - */ - public Builder withRequirementProviders(RequirementProvider... requirementProviders) { - this.requirementProviders = Arrays.asList(requirementProviders); - return this; - } - - /** - * The {@link org.thoughtcrime.securesms.jobmanager.dependencies.DependencyInjector} to use for injecting - * dependencies into {@link Job}s. Optional. Injection occurs just before a Job's onAdded() callback, or - * after deserializing a persistent job. - * - * @param dependencyInjector The injector to use. - * @return The builder. - */ - public Builder withDependencyInjector(DependencyInjector dependencyInjector) { - this.dependencyInjector = dependencyInjector; - return this; - } - - /** - * The {@link org.thoughtcrime.securesms.jobmanager.persistence.JobSerializer} to use for persistent Jobs. - * Required if persistent Jobs are used. - * - * @param jobSerializer The serializer to use. - * @return The builder. - */ - public Builder withJobSerializer(JobSerializer jobSerializer) { - this.jobSerializer = jobSerializer; - return this; - } - - /** - * Set the number of threads dedicated to consuming Jobs from the queue and executing them. - * - * @param consumerThreads The number of threads. - * @return The builder. - */ - public Builder withConsumerThreads(int consumerThreads) { - this.consumerThreads = consumerThreads; - return this; - } - - /** - * @return A constructed JobManager. - */ - public JobManager build() { - if (name == null) { - throw new IllegalArgumentException("You must specify a name!"); - } - - if (requirementProviders == null) { - requirementProviders = new LinkedList<>(); - } - - return new JobManager(context, name, requirementProviders, - dependencyInjector, jobSerializer, - consumerThreads); - } - } - } diff --git a/src/org/thoughtcrime/securesms/jobmanager/JobParameters.java b/src/org/thoughtcrime/securesms/jobmanager/JobParameters.java index 506747e4bd..910aea5839 100644 --- a/src/org/thoughtcrime/securesms/jobmanager/JobParameters.java +++ b/src/org/thoughtcrime/securesms/jobmanager/JobParameters.java @@ -16,12 +16,16 @@ */ package org.thoughtcrime.securesms.jobmanager; +import org.thoughtcrime.securesms.jobmanager.requirements.NetworkBackoffRequirement; +import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; import org.thoughtcrime.securesms.jobmanager.requirements.Requirement; +import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.jobs.requirements.NetworkOrServiceRequirement; +import org.thoughtcrime.securesms.jobs.requirements.SqlCipherMigrationRequirement; import java.io.Serializable; -import java.util.LinkedList; +import java.util.Collections; import java.util.List; -import java.util.concurrent.TimeUnit; /** * The set of parameters that describe a {@link org.thoughtcrime.securesms.jobmanager.Job}. @@ -30,46 +34,86 @@ public class JobParameters implements Serializable { private static final long serialVersionUID = 4880456378402584584L; - private transient EncryptionKeys encryptionKeys; - private final List requirements; - private final boolean isPersistent; + private final boolean requiresNetwork; + private final boolean requiresMasterSecret; + private final boolean requiresSqlCipher; private final int retryCount; private final long retryUntil; private final String groupId; - private final boolean wakeLock; - private final long wakeLockTimeout; + private final boolean ignoreDuplicates; - private JobParameters(List requirements, - boolean isPersistent, String groupId, - EncryptionKeys encryptionKeys, - int retryCount, long retryUntil, boolean wakeLock, - long wakeLockTimeout) + private JobParameters(String groupId, + boolean ignoreDuplicates, + boolean requiresNetwork, + boolean requiresMasterSecret, + boolean requiresSqlCipher, + int retryCount, + long retryUntil) { - this.requirements = requirements; - this.isPersistent = isPersistent; - this.groupId = groupId; - this.encryptionKeys = encryptionKeys; - this.retryCount = retryCount; - this.retryUntil = retryUntil; - this.wakeLock = wakeLock; - this.wakeLockTimeout = wakeLockTimeout; + this.groupId = groupId; + this.ignoreDuplicates = ignoreDuplicates; + this.requirements = Collections.emptyList(); + this.requiresNetwork = requiresNetwork; + this.requiresMasterSecret = requiresMasterSecret; + this.requiresSqlCipher = requiresSqlCipher; + this.retryCount = retryCount; + this.retryUntil = retryUntil; } - public List getRequirements() { - return requirements; + public boolean shouldIgnoreDuplicates() { + return ignoreDuplicates; } - public boolean isPersistent() { - return isPersistent; + public boolean requiresNetwork() { + return requiresNetwork || hasNetworkRequirement(requirements); } - public EncryptionKeys getEncryptionKeys() { - return encryptionKeys; + public boolean requiresMasterSecret() { + return requiresMasterSecret || hasMasterSecretRequirement(requirements); } - public void setEncryptionKeys(EncryptionKeys encryptionKeys) { - this.encryptionKeys = encryptionKeys; + public boolean requiresSqlCipher() { + return requiresSqlCipher || hasSqlCipherRequirement(requirements); + } + + private boolean hasNetworkRequirement(List requirements) { + if (requirements == null || requirements.size() == 0) return false; + + for (Requirement requirement : requirements) { + if (requirement instanceof NetworkRequirement || + requirement instanceof NetworkOrServiceRequirement || + requirement instanceof NetworkBackoffRequirement) + { + return true; + } + } + + return false; + } + + private boolean hasMasterSecretRequirement(List requirements) { + if (requirements == null || requirements.size() == 0) return false; + + for (Requirement requirement : requirements) { + if (requirement instanceof MasterSecretRequirement) { + return true; + } + } + + return false; + } + + private boolean hasSqlCipherRequirement(List requirements) { + if (requirements == null || requirements.size() == 0) return false; + + for (Requirement requirement : requirements) { + if (requirement instanceof SqlCipherMigrationRequirement) { + return true; + } + } + + return false; } public int getRetryCount() { @@ -91,52 +135,29 @@ public class JobParameters implements Serializable { return groupId; } - public boolean needsWakeLock() { - return wakeLock; - } - - public long getWakeLockTimeout() { - return wakeLockTimeout; - } - public static class Builder { - private List requirements = new LinkedList<>(); - private boolean isPersistent = false; - private EncryptionKeys encryptionKeys = null; - private int retryCount = 100; - private long retryDuration = 0; - private String groupId = null; - private boolean wakeLock = false; - private long wakeLockTimeout = 0; + private int retryCount = 100; + private long retryDuration = 0; + private String groupId = null; + private boolean ignoreDuplicates = false; + private boolean requiresNetwork = false; + private boolean requiresSqlCipher = false; + private boolean requiresMasterSecret = false; - /** - * Specify a {@link org.thoughtcrime.securesms.jobmanager.requirements.Requirement }that must be met - * before the Job is executed. May be called multiple times to register multiple requirements. - * @param requirement The Requirement that must be met. - * @return the builder. - */ - public Builder withRequirement(Requirement requirement) { - this.requirements.add(requirement); + public Builder withNetworkRequirement() { + requiresNetwork = true; return this; } - /** - * Specify that the Job should be durably persisted to disk, so that it remains in the queue - * across application restarts. - * @return The builder. - */ - public Builder withPersistence() { - this.isPersistent = true; + @Deprecated + public Builder withMasterSecretRequirement() { + requiresMasterSecret = true; return this; } - /** - * Specify that the job should use encryption when durably persisted to disk. - * @param encryptionKeys The keys to encrypt the serialized job with before persisting. - * @return the builder. - */ - public Builder withEncryption(EncryptionKeys encryptionKeys) { - this.encryptionKeys = encryptionKeys; + @Deprecated + public Builder withSqlCipherRequirement() { + requiresSqlCipher = true; return this; } @@ -153,6 +174,11 @@ public class JobParameters implements Serializable { return this; } + /** + * Specify for how long we should keep retrying this job. Ignored if retryCount is set. + * @param duration The duration (in ms) for how long we should keep retrying this job for. + * @return the builder + */ public Builder withRetryDuration(long duration) { this.retryDuration = duration; this.retryCount = 0; @@ -172,35 +198,25 @@ public class JobParameters implements Serializable { } /** - * Specify whether this job should hold a wake lock. + * If true, only one job with this groupId can be active at a time. If a job with the same + * groupId is already running, then subsequent jobs will be ignored silently. Only has an effect + * if a groupId has been specified via {@link #withGroupId(String)}. + *

+ * Defaults to false. * - * @param needsWakeLock If set, this job will acquire a wakelock on add(), and hold it until - * run() completes, or cancel(). - * @param timeout Specify a timeout for the wakelock. A timeout of - * 0 will result in no timeout. - * - * @return the builder. + * @param ignoreDuplicates Whether to ignore duplicates. + * @return the builder */ - public Builder withWakeLock(boolean needsWakeLock, long timeout, TimeUnit unit) { - this.wakeLock = needsWakeLock; - this.wakeLockTimeout = unit.toMillis(timeout); + public Builder withDuplicatesIgnored(boolean ignoreDuplicates) { + this.ignoreDuplicates = ignoreDuplicates; return this; } - /** - * Specify whether this job should hold a wake lock. - * - * @return the builder. - */ - public Builder withWakeLock(boolean needsWakeLock) { - return withWakeLock(needsWakeLock, 0, TimeUnit.MILLISECONDS); - } - /** * @return the JobParameters instance that describes a Job. */ public JobParameters create() { - return new JobParameters(requirements, isPersistent, groupId, encryptionKeys, retryCount, System.currentTimeMillis() + retryDuration, wakeLock, wakeLockTimeout); + return new JobParameters(groupId, ignoreDuplicates, requiresNetwork, requiresMasterSecret, requiresSqlCipher, retryCount, System.currentTimeMillis() + retryDuration); } } } diff --git a/src/org/thoughtcrime/securesms/jobmanager/JobQueue.java b/src/org/thoughtcrime/securesms/jobmanager/JobQueue.java deleted file mode 100644 index 07d986e69d..0000000000 --- a/src/org/thoughtcrime/securesms/jobmanager/JobQueue.java +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * 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.thoughtcrime.securesms.jobmanager; - -import android.support.annotation.NonNull; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; - -class JobQueue { - - private final Map activeGroupIds = new HashMap<>(); - private final LinkedList jobQueue = new LinkedList<>(); - - synchronized void onRequirementStatusChanged() { - notifyAll(); - } - - synchronized void add(Job job) { - jobQueue.add(job); - processJobAddition(job); - notifyAll(); - } - - synchronized void addAll(List jobs) { - jobQueue.addAll(jobs); - - for (Job job : jobs) { - processJobAddition(job); - } - - notifyAll(); - } - - private void processJobAddition(@NonNull Job job) { - if (isJobActive(job) && isGroupIdAvailable(job)) { - setGroupIdUnavailable(job); - } else if (!isGroupIdAvailable(job)) { - Job blockingJob = activeGroupIds.get(job.getGroupId()); - blockingJob.resetRunStats(); - } - } - - synchronized void push(Job job) { - jobQueue.addFirst(job); - } - - synchronized Job getNext() { - try { - Job nextAvailableJob; - - while ((nextAvailableJob = getNextAvailableJob()) == null) { - wait(); - } - - return nextAvailableJob; - } catch (InterruptedException e) { - throw new AssertionError(e); - } - } - - synchronized void setGroupIdAvailable(String groupId) { - if (groupId != null) { - activeGroupIds.remove(groupId); - notifyAll(); - } - } - - private Job getNextAvailableJob() { - if (jobQueue.isEmpty()) return null; - - ListIterator iterator = jobQueue.listIterator(); - while (iterator.hasNext()) { - Job job = iterator.next(); - - if (job.isRequirementsMet() && isGroupIdAvailable(job)) { - iterator.remove(); - setGroupIdUnavailable(job); - return job; - } - } - - return null; - } - - private boolean isJobActive(@NonNull Job job) { - return job.getRetryUntil() > 0 && job.getRunIteration() > 0; - } - - private boolean isGroupIdAvailable(@NonNull Job requester) { - String groupId = requester.getGroupId(); - return groupId == null || !activeGroupIds.containsKey(groupId) || activeGroupIds.get(groupId).equals(requester); - } - - private void setGroupIdUnavailable(@NonNull Job job) { - String groupId = job.getGroupId(); - if (groupId != null) { - activeGroupIds.put(groupId, job); - } - } -} diff --git a/src/org/thoughtcrime/securesms/jobmanager/SafeData.java b/src/org/thoughtcrime/securesms/jobmanager/SafeData.java new file mode 100644 index 0000000000..642ab84e0e --- /dev/null +++ b/src/org/thoughtcrime/securesms/jobmanager/SafeData.java @@ -0,0 +1,80 @@ +package org.thoughtcrime.securesms.jobmanager; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import androidx.work.Data; + +/** + * A wrapper around {@link Data} that does its best to throw an exception whenever a key isn't + * present in the {@link Data} object. + */ +public class SafeData { + + private final static int INVALID_INT = Integer.MIN_VALUE; + private final static long INVALID_LONG = Long.MIN_VALUE; + + private final Data data; + + public SafeData(@NonNull Data data) { + this.data = data; + } + + public int getInt(@NonNull String key) { + int value = data.getInt(key, INVALID_INT); + + if (value == INVALID_INT) { + throw new IllegalStateException("Missing key: " + key); + } + + return value; + } + + public long getLong(@NonNull String key) { + long value = data.getLong(key, INVALID_LONG); + + if (value == INVALID_LONG) { + throw new IllegalStateException("Missing key: " + key); + } + + return value; + } + + public @NonNull String getString(@NonNull String key) { + String value = data.getString(key); + + if (value == null) { + throw new IllegalStateException("Missing key: " + key); + } + + return value; + } + + public @Nullable String getNullableString(@NonNull String key) { + return data.getString(key); + } + + public @NonNull String[] getStringArray(@NonNull String key) { + String[] value = data.getStringArray(key); + + if (value == null) { + throw new IllegalStateException("Missing key: " + key); + } + + return value; + } + + public @NonNull long[] getLongArray(@NonNull String key) { + long[] value = data.getLongArray(key); + + if (value == null) { + throw new IllegalStateException("Missing key: " + key); + } + + return value; + } + + public boolean getBoolean(@NonNull String key, boolean defaultValue) { + return data.getBoolean(key, defaultValue); + } +} diff --git a/src/org/thoughtcrime/securesms/jobmanager/dependencies/AggregateDependencyInjector.java b/src/org/thoughtcrime/securesms/jobmanager/dependencies/AggregateDependencyInjector.java deleted file mode 100644 index c855314b7c..0000000000 --- a/src/org/thoughtcrime/securesms/jobmanager/dependencies/AggregateDependencyInjector.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.dependencies; - -import android.content.Context; - -import org.thoughtcrime.securesms.jobmanager.Job; -import org.thoughtcrime.securesms.jobmanager.requirements.Requirement; - -public class AggregateDependencyInjector { - - private final DependencyInjector dependencyInjector; - - public AggregateDependencyInjector(DependencyInjector dependencyInjector) { - this.dependencyInjector = dependencyInjector; - } - - public void injectDependencies(Context context, Job job) { - if (job instanceof ContextDependent) { - ((ContextDependent)job).setContext(context); - } - - for (Requirement requirement : job.getRequirements()) { - if (requirement instanceof ContextDependent) { - ((ContextDependent)requirement).setContext(context); - } - } - - if (dependencyInjector != null) { - dependencyInjector.injectDependencies(job); - - for (Requirement requirement : job.getRequirements()) { - dependencyInjector.injectDependencies(requirement); - } - } - } - -} diff --git a/src/org/thoughtcrime/securesms/jobmanager/persistence/PersistentStorage.java b/src/org/thoughtcrime/securesms/jobmanager/persistence/PersistentStorage.java index 7bd9ed6904..4da766f77f 100644 --- a/src/org/thoughtcrime/securesms/jobmanager/persistence/PersistentStorage.java +++ b/src/org/thoughtcrime/securesms/jobmanager/persistence/PersistentStorage.java @@ -16,7 +16,6 @@ */ package org.thoughtcrime.securesms.jobmanager.persistence; -import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; @@ -24,7 +23,6 @@ import android.database.sqlite.SQLiteOpenHelper; import org.thoughtcrime.securesms.jobmanager.EncryptionKeys; import org.thoughtcrime.securesms.jobmanager.Job; -import org.thoughtcrime.securesms.jobmanager.dependencies.AggregateDependencyInjector; import org.thoughtcrime.securesms.logging.Log; import java.io.IOException; @@ -43,38 +41,18 @@ public class PersistentStorage { private static final String DATABASE_CREATE = String.format("CREATE TABLE %s (%s INTEGER PRIMARY KEY, %s TEXT NOT NULL, %s INTEGER DEFAULT 0);", TABLE_NAME, ID, ITEM, ENCRYPTED); - private final Context context; - private final DatabaseHelper databaseHelper; - private final JobSerializer jobSerializer; - private final AggregateDependencyInjector dependencyInjector; + private final DatabaseHelper databaseHelper; + private final JobSerializer jobSerializer; - public PersistentStorage(Context context, String name, - JobSerializer serializer, - AggregateDependencyInjector dependencyInjector) - { + public PersistentStorage(Context context, String name, JobSerializer serializer) { this.databaseHelper = new DatabaseHelper(context, "_jobqueue-" + name); - this.context = context; this.jobSerializer = serializer; - this.dependencyInjector = dependencyInjector; - } - - public void store(Job job) throws IOException { - ContentValues contentValues = new ContentValues(); - contentValues.put(ITEM, jobSerializer.serialize(job)); - contentValues.put(ENCRYPTED, job.getEncryptionKeys() != null); - - long id = databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues); - job.setPersistentId(id); } public List getAllUnencrypted() { return getJobs(null, ENCRYPTED + " = 0"); } - public List getAllEncrypted(EncryptionKeys keys) { - return getJobs(keys, ENCRYPTED + " = 1"); - } - private List getJobs(EncryptionKeys keys, String where) { List results = new LinkedList<>(); SQLiteDatabase database = databaseHelper.getReadableDatabase(); @@ -90,11 +68,6 @@ public class PersistentStorage { try{ Job job = jobSerializer.deserialize(keys, encrypted, item); - - job.setPersistentId(id); - job.setEncryptionKeys(keys); - dependencyInjector.injectDependencies(context, job); - results.add(job); } catch (IOException e) { Log.w("PersistentStore", e); diff --git a/src/org/thoughtcrime/securesms/jobmanager/requirements/BackoffReceiver.java b/src/org/thoughtcrime/securesms/jobmanager/requirements/BackoffReceiver.java deleted file mode 100644 index 203c93aeb7..0000000000 --- a/src/org/thoughtcrime/securesms/jobmanager/requirements/BackoffReceiver.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.requirements; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.support.annotation.NonNull; - -import org.thoughtcrime.securesms.ApplicationContext; -import org.thoughtcrime.securesms.BuildConfig; -import org.thoughtcrime.securesms.logging.Log; - -import java.util.UUID; - -public class BackoffReceiver extends BroadcastReceiver { - - private static final String TAG = BackoffReceiver.class.getSimpleName(); - - @Override - public void onReceive(Context context, Intent intent) { - Log.i(TAG, "Received an alarm to retry a job with ID: " + intent.getAction()); - ApplicationContext.getInstance(context).getJobManager().onRequirementStatusChanged(); - } - - public static void setUniqueAlarm(@NonNull Context context, long time) { - AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - Intent intent = new Intent(context, BackoffReceiver.class); - - intent.setAction(BuildConfig.APPLICATION_ID + UUID.randomUUID().toString()); - alarmManager.set(AlarmManager.RTC_WAKEUP, time, PendingIntent.getBroadcast(context, 0, intent, 0)); - - Log.i(TAG, "Set an alarm to retry a job in " + (time - System.currentTimeMillis()) + " ms with ID: " + intent.getAction()); - } -} diff --git a/src/org/thoughtcrime/securesms/jobmanager/requirements/NetworkBackoffRequirement.java b/src/org/thoughtcrime/securesms/jobmanager/requirements/NetworkBackoffRequirement.java index 5c5667cbc2..147f4342b7 100644 --- a/src/org/thoughtcrime/securesms/jobmanager/requirements/NetworkBackoffRequirement.java +++ b/src/org/thoughtcrime/securesms/jobmanager/requirements/NetworkBackoffRequirement.java @@ -31,15 +31,6 @@ public class NetworkBackoffRequirement implements Requirement, ContextDependent @Override public void onRetry(@NonNull Job job) { - Log.i(TAG, "onRetry()"); - - if (!(new NetworkRequirement(context).isPresent())) { - Log.i(TAG, "No network. Resetting run stats."); - job.resetRunStats(); - return; - } - - BackoffReceiver.setUniqueAlarm(context, NetworkBackoffRequirement.calculateNextRunTime(job)); } @Override @@ -48,9 +39,6 @@ public class NetworkBackoffRequirement implements Requirement, ContextDependent } private static long calculateNextRunTime(@NonNull Job job) { - long targetTime = job.getLastRunTime() + (long) (Math.pow(2, job.getRunIteration() - 1) * 1000); - long furthestTime = System.currentTimeMillis() + MAX_WAIT; - - return Math.min(targetTime, Math.min(furthestTime, job.getRetryUntil())); + return 0; } } diff --git a/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java index 6099abad0b..deebfc252d 100644 --- a/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java @@ -1,8 +1,11 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.greenrobot.eventbus.EventBus; @@ -15,8 +18,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.events.PartProgressEvent; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.util.AttachmentUtil; @@ -36,24 +37,34 @@ import java.io.InputStream; import javax.inject.Inject; +import androidx.work.Data; + public class AttachmentDownloadJob extends MasterSecretJob implements InjectableType { private static final long serialVersionUID = 2L; private static final int MAX_ATTACHMENT_SIZE = 150 * 1024 * 1024; private static final String TAG = AttachmentDownloadJob.class.getSimpleName(); + private static final String KEY_MESSAGE_ID = "message_id"; + private static final String KEY_PART_ROW_ID = "part_row_id"; + private static final String KEY_PAR_UNIQUE_ID = "part_unique_id"; + private static final String KEY_MANUAL = "part_manual"; + @Inject transient SignalServiceMessageReceiver messageReceiver; - private final long messageId; - private final long partRowId; - private final long partUniqueId; - private final boolean manual; + private long messageId; + private long partRowId; + private long partUniqueId; + private boolean manual; + + public AttachmentDownloadJob() { + super(null, null); + } public AttachmentDownloadJob(Context context, long messageId, AttachmentId attachmentId, boolean manual) { super(context, JobParameters.newBuilder() .withGroupId(AttachmentDownloadJob.class.getCanonicalName()) - .withRequirement(new MasterSecretRequirement(context)) - .withRequirement(new NetworkRequirement(context)) - .withPersistence() + .withMasterSecretRequirement() + .withNetworkRequirement() .create()); this.messageId = messageId; @@ -62,6 +73,23 @@ public class AttachmentDownloadJob extends MasterSecretJob implements Injectable this.manual = manual; } + @Override + protected void initialize(@NonNull SafeData data) { + messageId = data.getLong(KEY_MESSAGE_ID); + partRowId = data.getLong(KEY_PART_ROW_ID); + partUniqueId = data.getLong(KEY_PAR_UNIQUE_ID); + manual = data.getBoolean(KEY_MANUAL, false); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putLong(KEY_MESSAGE_ID, messageId) + .putLong(KEY_PART_ROW_ID, partRowId) + .putLong(KEY_PAR_UNIQUE_ID, partUniqueId) + .putBoolean(KEY_MANUAL, manual) + .build(); + } + @Override public void onAdded() { Log.i(TAG, "onAdded() messageId: " + messageId + " partRowId: " + partRowId + " partUniqueId: " + partUniqueId + " manual: " + manual); diff --git a/src/org/thoughtcrime/securesms/jobs/AttachmentFileNameJob.java b/src/org/thoughtcrime/securesms/jobs/AttachmentFileNameJob.java deleted file mode 100644 index a7d30e29f9..0000000000 --- a/src/org/thoughtcrime/securesms/jobs/AttachmentFileNameJob.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.thoughtcrime.securesms.jobs; - - -import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import org.thoughtcrime.securesms.attachments.Attachment; -import org.thoughtcrime.securesms.attachments.AttachmentId; -import org.thoughtcrime.securesms.attachments.DatabaseAttachment; -import org.thoughtcrime.securesms.crypto.AsymmetricMasterCipher; -import org.thoughtcrime.securesms.crypto.AsymmetricMasterSecret; -import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.thoughtcrime.securesms.crypto.MasterSecretUtil; -import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; -import org.thoughtcrime.securesms.mms.IncomingMediaMessage; -import org.whispersystems.libsignal.InvalidMessageException; - -import java.io.IOException; -import java.util.Arrays; - -public class AttachmentFileNameJob extends MasterSecretJob { - - private static final long serialVersionUID = 1L; - - private final long attachmentRowId; - private final long attachmentUniqueId; - private final String encryptedFileName; - - public AttachmentFileNameJob(@NonNull Context context, @NonNull AsymmetricMasterSecret asymmetricMasterSecret, - @NonNull DatabaseAttachment attachment, @NonNull IncomingMediaMessage message) - { - super(context, new JobParameters.Builder().withPersistence() - .withRequirement(new MasterSecretRequirement(context)) - .create()); - - this.attachmentRowId = attachment.getAttachmentId().getRowId(); - this.attachmentUniqueId = attachment.getAttachmentId().getUniqueId(); - this.encryptedFileName = getEncryptedFileName(asymmetricMasterSecret, attachment, message); - } - - @Override - public void onRun(MasterSecret masterSecret) throws IOException, InvalidMessageException { - if (encryptedFileName == null) return; - - AttachmentId attachmentId = new AttachmentId(attachmentRowId, attachmentUniqueId); - String plaintextFileName = new AsymmetricMasterCipher(MasterSecretUtil.getAsymmetricMasterSecret(context, masterSecret)).decryptBody(encryptedFileName); - - DatabaseFactory.getAttachmentDatabase(context).updateAttachmentFileName(attachmentId, plaintextFileName); - } - - @Override - public boolean onShouldRetryThrowable(Exception exception) { - return false; - } - - @Override - public void onAdded() { - - } - - @Override - public void onCanceled() { - - } - - private @Nullable String getEncryptedFileName(@NonNull AsymmetricMasterSecret asymmetricMasterSecret, - @NonNull DatabaseAttachment attachment, - @NonNull IncomingMediaMessage mediaMessage) - { - for (Attachment messageAttachment : mediaMessage.getAttachments()) { - if (mediaMessage.getAttachments().size() == 1 || - (messageAttachment.getDigest() != null && Arrays.equals(messageAttachment.getDigest(), attachment.getDigest()))) - { - if (messageAttachment.getFileName() == null) return null; - else return new AsymmetricMasterCipher(asymmetricMasterSecret).encryptBody(messageAttachment.getFileName()); - } - } - - return null; - } - - -} diff --git a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java index 327504f1e5..3a07f1f079 100644 --- a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java @@ -10,8 +10,7 @@ import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel; import org.thoughtcrime.securesms.util.BitmapDecodingException; @@ -30,6 +29,8 @@ import java.io.InputStream; import javax.inject.Inject; +import androidx.work.Data; + public class AvatarDownloadJob extends MasterSecretJob implements InjectableType { private static final int MAX_AVATAR_SIZE = 20 * 1024 * 1024; @@ -37,22 +38,38 @@ public class AvatarDownloadJob extends MasterSecretJob implements InjectableType private static final String TAG = AvatarDownloadJob.class.getSimpleName(); + private static final String KEY_GROUP_ID = "group_id"; + @Inject transient SignalServiceMessageReceiver receiver; - private final byte[] groupId; + private byte[] groupId; + + public AvatarDownloadJob() { + super(null, null); + } public AvatarDownloadJob(Context context, @NonNull byte[] groupId) { super(context, JobParameters.newBuilder() - .withRequirement(new MasterSecretRequirement(context)) - .withRequirement(new NetworkRequirement(context)) - .withPersistence() + .withMasterSecretRequirement() + .withNetworkRequirement() .create()); this.groupId = groupId; } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + try { + groupId = GroupUtil.getDecodedId(data.getString(KEY_GROUP_ID)); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putString(KEY_GROUP_ID, GroupUtil.getEncodedId(groupId, false)).build(); + } @Override public void onRun(MasterSecret masterSecret) throws IOException { diff --git a/src/org/thoughtcrime/securesms/jobs/CleanPreKeysJob.java b/src/org/thoughtcrime/securesms/jobs/CleanPreKeysJob.java index a78379584e..618567e6f8 100644 --- a/src/org/thoughtcrime/securesms/jobs/CleanPreKeysJob.java +++ b/src/org/thoughtcrime/securesms/jobs/CleanPreKeysJob.java @@ -1,13 +1,15 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.PreKeyUtil; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; import org.whispersystems.libsignal.InvalidKeyIdException; import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyStore; @@ -24,6 +26,8 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; +import androidx.work.Data; + import static org.thoughtcrime.securesms.dependencies.AxolotlStorageModule.SignedPreKeyStoreFactory; public class CleanPreKeysJob extends MasterSecretJob implements InjectableType { @@ -35,17 +39,25 @@ public class CleanPreKeysJob extends MasterSecretJob implements InjectableType { @Inject transient SignalServiceAccountManager accountManager; @Inject transient SignedPreKeyStoreFactory signedPreKeyStoreFactory; + public CleanPreKeysJob() { + super(null, null); + } + public CleanPreKeysJob(Context context) { super(context, JobParameters.newBuilder() .withGroupId(CleanPreKeysJob.class.getSimpleName()) - .withRequirement(new MasterSecretRequirement(context)) + .withMasterSecretRequirement() .withRetryCount(5) .create()); } @Override - public void onAdded() { + protected void initialize(@NonNull SafeData data) { + } + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); } @Override diff --git a/src/org/thoughtcrime/securesms/jobs/CreateSignedPreKeyJob.java b/src/org/thoughtcrime/securesms/jobs/CreateSignedPreKeyJob.java index 153564872b..6e377b9d31 100644 --- a/src/org/thoughtcrime/securesms/jobs/CreateSignedPreKeyJob.java +++ b/src/org/thoughtcrime/securesms/jobs/CreateSignedPreKeyJob.java @@ -1,14 +1,14 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.PreKeyUtil; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.IdentityKeyPair; @@ -20,6 +20,8 @@ import java.io.IOException; import javax.inject.Inject; +import androidx.work.Data; + public class CreateSignedPreKeyJob extends MasterSecretJob implements InjectableType { private static final long serialVersionUID = 1L; @@ -28,17 +30,26 @@ public class CreateSignedPreKeyJob extends MasterSecretJob implements Injectable @Inject transient SignalServiceAccountManager accountManager; + public CreateSignedPreKeyJob() { + super(null, null); + } + public CreateSignedPreKeyJob(Context context) { super(context, JobParameters.newBuilder() - .withPersistence() - .withRequirement(new NetworkRequirement(context)) - .withRequirement(new MasterSecretRequirement(context)) + .withNetworkRequirement() + .withMasterSecretRequirement() .withGroupId(CreateSignedPreKeyJob.class.getSimpleName()) .create()); } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); + } @Override public void onRun(MasterSecret masterSecret) throws IOException { diff --git a/src/org/thoughtcrime/securesms/jobs/DirectoryRefreshJob.java b/src/org/thoughtcrime/securesms/jobs/DirectoryRefreshJob.java index f03362461d..20409eaa01 100644 --- a/src/org/thoughtcrime/securesms/jobs/DirectoryRefreshJob.java +++ b/src/org/thoughtcrime/securesms/jobs/DirectoryRefreshJob.java @@ -1,26 +1,36 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; -import android.os.PowerManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; + +import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.DirectoryHelper; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; import java.io.IOException; +import androidx.work.Data; + public class DirectoryRefreshJob extends ContextJob { private static final String TAG = DirectoryRefreshJob.class.getSimpleName(); + private static final String KEY_ADDRESS = "address"; + private static final String KEY_NOTIFY_OF_NEW_USERS = "notify_of_new_users"; + @Nullable private transient Recipient recipient; private transient boolean notifyOfNewUsers; + public DirectoryRefreshJob() { + super(null, null); + } + public DirectoryRefreshJob(@NonNull Context context, boolean notifyOfNewUsers) { this(context, null, notifyOfNewUsers); } @@ -31,7 +41,7 @@ public class DirectoryRefreshJob extends ContextJob { { super(context, JobParameters.newBuilder() .withGroupId(DirectoryRefreshJob.class.getSimpleName()) - .withRequirement(new NetworkRequirement(context)) + .withNetworkRequirement() .create()); this.recipient = recipient; @@ -39,23 +49,29 @@ public class DirectoryRefreshJob extends ContextJob { } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + String serializedAddress = data.getNullableString(KEY_ADDRESS); + Address address = serializedAddress != null ? Address.fromSerialized(serializedAddress) : null; + + recipient = address != null ? Recipient.from(context, address, true) : null; + notifyOfNewUsers = data.getBoolean(KEY_NOTIFY_OF_NEW_USERS, false); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putString(KEY_ADDRESS, recipient != null ? recipient.getAddress().serialize() : null) + .putBoolean(KEY_NOTIFY_OF_NEW_USERS, notifyOfNewUsers) + .build(); + } @Override public void onRun() throws IOException { Log.i(TAG, "DirectoryRefreshJob.onRun()"); - PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Directory Refresh"); - try { - wakeLock.acquire(); - if (recipient == null) { - DirectoryHelper.refreshDirectory(context, notifyOfNewUsers); - } else { - DirectoryHelper.refreshDirectoryFor(context, recipient); - } - } finally { - if (wakeLock.isHeld()) wakeLock.release(); + if (recipient == null) { + DirectoryHelper.refreshDirectory(context, notifyOfNewUsers); + } else { + DirectoryHelper.refreshDirectoryFor(context, recipient); } } diff --git a/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java b/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java index 11663b51eb..561014dcfa 100644 --- a/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java +++ b/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java @@ -21,7 +21,10 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.graphics.BitmapFactory; +import android.support.annotation.NonNull; import android.support.v4.app.NotificationCompat; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import com.google.android.gms.common.ConnectionResult; @@ -32,7 +35,6 @@ import org.thoughtcrime.securesms.PlayServicesProblemActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.util.guava.Optional; @@ -41,6 +43,8 @@ import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulRespons import javax.inject.Inject; +import androidx.work.Data; + public class GcmRefreshJob extends ContextJob implements InjectableType { private static final String TAG = GcmRefreshJob.class.getSimpleName(); @@ -49,15 +53,27 @@ public class GcmRefreshJob extends ContextJob implements InjectableType { @Inject transient SignalServiceAccountManager textSecureAccountManager; + public GcmRefreshJob() { + super(null, null); + } + public GcmRefreshJob(Context context) { super(context, JobParameters.newBuilder() - .withRequirement(new NetworkRequirement(context)) + .withGroupId(GcmRefreshJob.class.getSimpleName()) + .withDuplicatesIgnored(true) + .withNetworkRequirement() .withRetryCount(1) .create()); } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); + } @Override public void onRun() throws Exception { diff --git a/src/org/thoughtcrime/securesms/jobs/LocalBackupJob.java b/src/org/thoughtcrime/securesms/jobs/LocalBackupJob.java index d8faf1fd84..72d1558e4f 100644 --- a/src/org/thoughtcrime/securesms/jobs/LocalBackupJob.java +++ b/src/org/thoughtcrime/securesms/jobs/LocalBackupJob.java @@ -4,6 +4,8 @@ package org.thoughtcrime.securesms.jobs; import android.Manifest; import android.content.Context; import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.R; @@ -24,21 +26,32 @@ import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -import java.util.concurrent.TimeUnit; + +import androidx.work.Data; public class LocalBackupJob extends ContextJob { private static final String TAG = LocalBackupJob.class.getSimpleName(); + public LocalBackupJob() { + super(null, null); + } + public LocalBackupJob(@NonNull Context context) { super(context, JobParameters.newBuilder() .withGroupId("__LOCAL_BACKUP__") - .withWakeLock(true, 10, TimeUnit.SECONDS) + .withDuplicatesIgnored(true) .create()); } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); + } @Override public void onRun() throws NoExternalStorageException, IOException { diff --git a/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java index 23b38f8ad3..fa50125167 100644 --- a/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java @@ -2,7 +2,10 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; import android.net.Uri; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import com.google.android.mms.pdu_alt.CharacterSets; @@ -20,8 +23,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult; import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; import org.thoughtcrime.securesms.mms.ApnUnavailableException; import org.thoughtcrime.securesms.mms.CompatMmsConnection; import org.thoughtcrime.securesms.mms.IncomingMediaMessage; @@ -45,7 +46,8 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; -import java.util.concurrent.TimeUnit; + +import androidx.work.Data; public class MmsDownloadJob extends MasterSecretJob { @@ -53,17 +55,23 @@ public class MmsDownloadJob extends MasterSecretJob { private static final String TAG = MmsDownloadJob.class.getSimpleName(); - private final long messageId; - private final long threadId; - private final boolean automatic; + private static final String KEY_MESSAGE_ID = "message_id"; + private static final String KEY_THREAD_ID = "thread_id"; + private static final String KEY_AUTOMATIC = "automatic"; + + private long messageId; + private long threadId; + private boolean automatic; + + public MmsDownloadJob() { + super(null, null); + } public MmsDownloadJob(Context context, long messageId, long threadId, boolean automatic) { super(context, JobParameters.newBuilder() - .withPersistence() - .withRequirement(new MasterSecretRequirement(context)) - .withRequirement(new NetworkRequirement(context)) + .withMasterSecretRequirement() + .withMasterSecretRequirement() .withGroupId("mms-operation") - .withWakeLock(true, 30, TimeUnit.SECONDS) .create()); this.messageId = messageId; @@ -71,6 +79,21 @@ public class MmsDownloadJob extends MasterSecretJob { this.automatic = automatic; } + @Override + protected void initialize(@NonNull SafeData data) { + messageId = data.getLong(KEY_MESSAGE_ID); + threadId = data.getLong(KEY_THREAD_ID); + automatic = data.getBoolean(KEY_AUTOMATIC, false); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putLong(KEY_MESSAGE_ID, messageId) + .putLong(KEY_THREAD_ID, threadId) + .putBoolean(KEY_AUTOMATIC, automatic) + .build(); + } + @Override public void onAdded() { if (automatic && KeyCachingService.getMasterSecret(context) == null) { diff --git a/src/org/thoughtcrime/securesms/jobs/MmsReceiveJob.java b/src/org/thoughtcrime/securesms/jobs/MmsReceiveJob.java index 5efa378ce0..18e6f1a1bf 100644 --- a/src/org/thoughtcrime/securesms/jobs/MmsReceiveJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MmsReceiveJob.java @@ -1,7 +1,11 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; + +import android.support.annotation.NonNull; import android.util.Pair; import com.google.android.mms.pdu_alt.GenericPdu; @@ -15,29 +19,51 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.jobmanager.JobParameters; import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.Util; +import java.io.IOException; + +import androidx.work.Data; + public class MmsReceiveJob extends ContextJob { private static final long serialVersionUID = 1L; private static final String TAG = MmsReceiveJob.class.getSimpleName(); - private final byte[] data; - private final int subscriptionId; + private static final String KEY_DATA = "data"; + private static final String KEY_SUBSCRIPTION_ID = "subscription_id"; + + private byte[] data; + private int subscriptionId; + + public MmsReceiveJob() { + super(null, null); + } public MmsReceiveJob(Context context, byte[] data, int subscriptionId) { - super(context, JobParameters.newBuilder() - .withWakeLock(true) - .withPersistence().create()); + super(context, JobParameters.newBuilder().create()); this.data = data; this.subscriptionId = subscriptionId; } @Override - public void onAdded() { + protected void initialize(@NonNull SafeData data) { + try { + this.data = Base64.decode(data.getString(KEY_DATA)); + } catch (IOException e) { + throw new AssertionError(e); + } + subscriptionId = data.getInt(KEY_SUBSCRIPTION_ID); + } + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putString(KEY_DATA, Base64.encodeBytes(data)) + .putInt(KEY_SUBSCRIPTION_ID, subscriptionId) + .build(); } @Override diff --git a/src/org/thoughtcrime/securesms/jobs/MmsSendJob.java b/src/org/thoughtcrime/securesms/jobs/MmsSendJob.java index c203237efa..0c6d70b800 100644 --- a/src/org/thoughtcrime/securesms/jobs/MmsSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MmsSendJob.java @@ -1,7 +1,10 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import android.text.TextUtils; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import android.webkit.MimeTypeMap; @@ -27,8 +30,6 @@ import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; import org.thoughtcrime.securesms.mms.CompatMmsConnection; import org.thoughtcrime.securesms.mms.MediaConstraints; import org.thoughtcrime.securesms.mms.MmsException; @@ -49,28 +50,41 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; +import androidx.work.Data; + public class MmsSendJob extends SendJob { private static final long serialVersionUID = 0L; private static final String TAG = MmsSendJob.class.getSimpleName(); - private final long messageId; + private static final String KEY_MESSAGE_ID = "message_id"; + + private long messageId; + + public MmsSendJob() { + super(null, null); + } public MmsSendJob(Context context, long messageId) { super(context, JobParameters.newBuilder() .withGroupId("mms-operation") - .withRequirement(new NetworkRequirement(context)) - .withRequirement(new MasterSecretRequirement(context)) - .withPersistence() + .withNetworkRequirement() + .withMasterSecretRequirement() + .withRetryCount(15) .create()); this.messageId = messageId; } @Override - public void onAdded() { - Log.i(TAG, "onAdded() messageId: " + messageId); + protected void initialize(@NonNull SafeData data) { + messageId = data.getLong(KEY_MESSAGE_ID); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putLong(KEY_MESSAGE_ID, messageId).build(); } @Override diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java index 93a1e8ca4a..25c7f70ab2 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; @@ -8,8 +9,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientReader; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.GroupUtil; import org.whispersystems.signalservice.api.SignalServiceMessageSender; @@ -24,6 +24,8 @@ import java.util.List; import javax.inject.Inject; +import androidx.work.Data; + public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements InjectableType { private static final long serialVersionUID = 1L; @@ -32,15 +34,27 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje @Inject transient SignalServiceMessageSender messageSender; + public MultiDeviceBlockedUpdateJob() { + super(null, null); + } + public MultiDeviceBlockedUpdateJob(Context context) { super(context, JobParameters.newBuilder() - .withRequirement(new NetworkRequirement(context)) - .withRequirement(new MasterSecretRequirement(context)) + .withNetworkRequirement() + .withMasterSecretRequirement() .withGroupId(MultiDeviceBlockedUpdateJob.class.getSimpleName()) - .withPersistence() .create()); } + @Override + protected void initialize(@NonNull SafeData data) { + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); + } + @Override public void onRun(MasterSecret masterSecret) throws IOException, UntrustedIdentityException @@ -71,11 +85,6 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje return false; } - @Override - public void onAdded() { - - } - @Override public void onCanceled() { diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java index 9a11b4b08d..bef0c9ac65 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java @@ -20,8 +20,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.IdentityDatabase; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.recipients.Recipient; @@ -50,6 +49,8 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; +import androidx.work.Data; + public class MultiDeviceContactUpdateJob extends MasterSecretJob implements InjectableType { private static final long serialVersionUID = 2L; @@ -58,12 +59,19 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje private static final long FULL_SYNC_TIME = TimeUnit.HOURS.toMillis(6); + private static final String KEY_ADDRESS = "address"; + private static final String KEY_FORCE_SYNC = "force_sync"; + @Inject transient SignalServiceMessageSender messageSender; - private final @Nullable String address; + private @Nullable String address; private boolean forceSync; + public MultiDeviceContactUpdateJob() { + super(null, null); + } + public MultiDeviceContactUpdateJob(@NonNull Context context) { this(context, false); } @@ -78,10 +86,9 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address address, boolean forceSync) { super(context, JobParameters.newBuilder() - .withRequirement(new NetworkRequirement(context)) - .withRequirement(new MasterSecretRequirement(context)) + .withNetworkRequirement() + .withMasterSecretRequirement() .withGroupId(MultiDeviceContactUpdateJob.class.getSimpleName()) - .withPersistence() .create()); this.forceSync = forceSync; @@ -90,6 +97,19 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje else this.address = null; } + @Override + protected void initialize(@NonNull SafeData data) { + address = data.getNullableString(KEY_ADDRESS); + forceSync = data.getBoolean(KEY_FORCE_SYNC, false); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putString(KEY_ADDRESS, address) + .putBoolean(KEY_FORCE_SYNC, forceSync) + .build(); + } + @Override public void onRun(MasterSecret masterSecret) throws IOException, UntrustedIdentityException, NetworkException @@ -201,11 +221,6 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje return false; } - @Override - public void onAdded() { - - } - @Override public void onCanceled() { diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceGroupUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceGroupUpdateJob.java index 3d1119b0ff..ca7de5f49d 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceGroupUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceGroupUpdateJob.java @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import org.thoughtcrime.securesms.crypto.MasterSecret; @@ -8,12 +9,11 @@ import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.dependencies.InjectableType; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; @@ -34,6 +34,8 @@ import java.util.List; import javax.inject.Inject; +import androidx.work.Data; + public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements InjectableType { private static final long serialVersionUID = 1L; @@ -41,15 +43,27 @@ public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements Inject @Inject transient SignalServiceMessageSender messageSender; + public MultiDeviceGroupUpdateJob() { + super(null, null); + } + public MultiDeviceGroupUpdateJob(Context context) { super(context, JobParameters.newBuilder() - .withRequirement(new NetworkRequirement(context)) - .withRequirement(new MasterSecretRequirement(context)) + .withNetworkRequirement() + .withMasterSecretRequirement() .withGroupId(MultiDeviceGroupUpdateJob.class.getSimpleName()) - .withPersistence() .create()); } + @Override + protected void initialize(@NonNull SafeData data) { + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); + } + @Override public void onRun(MasterSecret masterSecret) throws Exception { File contactDataFile = createTempFile("multidevice-contact-update"); @@ -102,11 +116,6 @@ public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements Inject return false; } - @Override - public void onAdded() { - - } - @Override public void onCanceled() { diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob.java index 897c9131d4..270e22653d 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob.java @@ -2,13 +2,15 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageSender; @@ -27,6 +29,8 @@ import java.io.IOException; import javax.inject.Inject; +import androidx.work.Data; + public class MultiDeviceProfileKeyUpdateJob extends MasterSecretJob implements InjectableType { private static final long serialVersionUID = 1L; @@ -34,14 +38,26 @@ public class MultiDeviceProfileKeyUpdateJob extends MasterSecretJob implements I @Inject transient SignalServiceMessageSender messageSender; + public MultiDeviceProfileKeyUpdateJob() { + super(null, null); + } + public MultiDeviceProfileKeyUpdateJob(Context context) { super(context, JobParameters.newBuilder() - .withRequirement(new NetworkRequirement(context)) - .withPersistence() + .withNetworkRequirement() .withGroupId(MultiDeviceProfileKeyUpdateJob.class.getSimpleName()) .create()); } + @Override + protected void initialize(@NonNull SafeData data) { + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); + } + @Override public void onRun(MasterSecret masterSecret) throws IOException, UntrustedIdentityException { if (!TextSecurePreferences.isMultiDevice(getContext())) { @@ -79,11 +95,6 @@ public class MultiDeviceProfileKeyUpdateJob extends MasterSecretJob implements I return false; } - @Override - public void onAdded() { - - } - @Override public void onCanceled() { Log.w(TAG, "Profile key sync failed!"); diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceReadReceiptUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceReadReceiptUpdateJob.java index e5bf04ce63..f0ae033109 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceReadReceiptUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceReadReceiptUpdateJob.java @@ -2,10 +2,11 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageSender; @@ -18,28 +19,42 @@ import java.io.IOException; import javax.inject.Inject; +import androidx.work.Data; + public class MultiDeviceReadReceiptUpdateJob extends ContextJob implements InjectableType { private static final long serialVersionUID = 1L; private static final String TAG = MultiDeviceReadReceiptUpdateJob.class.getSimpleName(); + private static final String KEY_ENABLED = "enabled"; + @Inject transient SignalServiceMessageSender messageSender; - private final boolean enabled; + private boolean enabled; + + public MultiDeviceReadReceiptUpdateJob() { + super(null, null); + } public MultiDeviceReadReceiptUpdateJob(Context context, boolean enabled) { super(context, JobParameters.newBuilder() - .withPersistence() .withGroupId("__MULTI_DEVICE_READ_RECEIPT_UPDATE_JOB__") - .withRequirement(new NetworkRequirement(context)) + .withNetworkRequirement() .create()); this.enabled = enabled; } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + enabled = data.getBoolean(KEY_ENABLED, false); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putBoolean(KEY_ENABLED, enabled).build(); + } @Override public void onRun() throws IOException, UntrustedIdentityException { diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceReadUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceReadUpdateJob.java index 764817b671..a2cf7fafd0 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceReadUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceReadUpdateJob.java @@ -1,14 +1,18 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.util.JsonUtils; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; @@ -18,25 +22,33 @@ import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException import java.io.IOException; import java.io.Serializable; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import javax.inject.Inject; +import androidx.work.Data; + public class MultiDeviceReadUpdateJob extends MasterSecretJob implements InjectableType { private static final long serialVersionUID = 1L; private static final String TAG = MultiDeviceReadUpdateJob.class.getSimpleName(); - private final List messageIds; + private static final String KEY_MESSAGE_IDS = "message_ids"; + + private List messageIds; @Inject transient SignalServiceMessageSender messageSender; + public MultiDeviceReadUpdateJob() { + super(null, null); + } + public MultiDeviceReadUpdateJob(Context context, List messageIds) { super(context, JobParameters.newBuilder() - .withRequirement(new NetworkRequirement(context)) - .withRequirement(new MasterSecretRequirement(context)) - .withPersistence() + .withNetworkRequirement() + .withMasterSecretRequirement() .create()); this.messageIds = new LinkedList<>(); @@ -46,6 +58,34 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta } } + @Override + protected void initialize(@NonNull SafeData data) { + String[] ids = data.getStringArray(KEY_MESSAGE_IDS); + + messageIds = new ArrayList<>(ids.length); + for (String id : ids) { + try { + messageIds.add(JsonUtils.fromJson(id, SerializableSyncMessageId.class)); + } catch (IOException e) { + throw new AssertionError(e); + } + } + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + String[] ids = new String[messageIds.size()]; + + for (int i = 0; i < ids.length; i++) { + try { + ids[i] = JsonUtils.toJson(messageIds.get(i)); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + return dataBuilder.putStringArray(KEY_MESSAGE_IDS, ids).build(); + } @Override public void onRun(MasterSecret masterSecret) throws IOException, UntrustedIdentityException { @@ -68,11 +108,6 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta return exception instanceof PushNetworkException; } - @Override - public void onAdded() { - - } - @Override public void onCanceled() { @@ -82,10 +117,13 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta private static final long serialVersionUID = 1L; + @JsonProperty private final String sender; + + @JsonProperty private final long timestamp; - private SerializableSyncMessageId(String sender, long timestamp) { + private SerializableSyncMessageId(@JsonProperty("sender") String sender, @JsonProperty("timestamp") long timestamp) { this.sender = sender; this.timestamp = timestamp; } diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceVerifiedUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceVerifiedUpdateJob.java index aaf4a687e2..0a3c7ed709 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceVerifiedUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceVerifiedUpdateJob.java @@ -2,13 +2,16 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; +import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.InvalidKeyException; @@ -22,24 +25,34 @@ import java.io.IOException; import javax.inject.Inject; +import androidx.work.Data; + public class MultiDeviceVerifiedUpdateJob extends ContextJob implements InjectableType { private static final long serialVersionUID = 1L; private static final String TAG = MultiDeviceVerifiedUpdateJob.class.getSimpleName(); + private static final String KEY_DESTINATION = "destination"; + private static final String KEY_IDENTITY_KEY = "identity_key"; + private static final String KEY_VERIFIED_STATUS = "verified_status"; + private static final String KEY_TIMESTAMP = "timestamp"; + @Inject transient SignalServiceMessageSender messageSender; - private final String destination; - private final byte[] identityKey; - private final VerifiedStatus verifiedStatus; - private final long timestamp; + private String destination; + private byte[] identityKey; + private VerifiedStatus verifiedStatus; + private long timestamp; + + public MultiDeviceVerifiedUpdateJob() { + super(null, null); + } public MultiDeviceVerifiedUpdateJob(Context context, Address destination, IdentityKey identityKey, VerifiedStatus verifiedStatus) { super(context, JobParameters.newBuilder() - .withRequirement(new NetworkRequirement(context)) - .withPersistence() + .withNetworkRequirement() .withGroupId("__MULTI_DEVICE_VERIFIED_UPDATE__") .create()); @@ -49,6 +62,28 @@ public class MultiDeviceVerifiedUpdateJob extends ContextJob implements Injectab this.timestamp = System.currentTimeMillis(); } + @Override + protected void initialize(@NonNull SafeData data) { + destination = data.getString(KEY_DESTINATION); + verifiedStatus = VerifiedStatus.forState(data.getInt(KEY_VERIFIED_STATUS)); + timestamp = data.getLong(KEY_TIMESTAMP); + + try { + identityKey = Base64.decode(data.getString(KEY_IDENTITY_KEY)); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putString(KEY_DESTINATION, destination) + .putString(KEY_IDENTITY_KEY, Base64.encodeBytes(identityKey)) + .putInt(KEY_VERIFIED_STATUS, verifiedStatus.toInt()) + .putLong(KEY_TIMESTAMP, timestamp) + .build(); + } + @Override public void onRun() throws IOException, UntrustedIdentityException { try { @@ -90,11 +125,6 @@ public class MultiDeviceVerifiedUpdateJob extends ContextJob implements Injectab return exception instanceof PushNetworkException; } - @Override - public void onAdded() { - - } - @Override public void onCanceled() { diff --git a/src/org/thoughtcrime/securesms/jobs/PushContentReceiveJob.java b/src/org/thoughtcrime/securesms/jobs/PushContentReceiveJob.java index 393a77798b..bd9aa10d58 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushContentReceiveJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushContentReceiveJob.java @@ -1,6 +1,9 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.jobmanager.JobParameters; @@ -10,12 +13,20 @@ import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import java.io.IOException; +import androidx.work.Data; + public class PushContentReceiveJob extends PushReceivedJob { private static final long serialVersionUID = 5685475456901715638L; private static final String TAG = PushContentReceiveJob.class.getSimpleName(); - private final String data; + private static final String KEY_DATA = "data"; + + private String data; + + public PushContentReceiveJob() { + super(null, null); + } public PushContentReceiveJob(Context context) { super(context, JobParameters.newBuilder().create()); @@ -23,16 +34,19 @@ public class PushContentReceiveJob extends PushReceivedJob { } public PushContentReceiveJob(Context context, String data) { - super(context, JobParameters.newBuilder() - .withPersistence() - .withWakeLock(true) - .create()); - + super(context, JobParameters.newBuilder().create()); this.data = data; } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + this.data = data.getNullableString(KEY_DATA); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putString(KEY_DATA, data).build(); + } @Override public void onRun() { diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 21df44055e..9487c8cd8a 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -7,6 +7,8 @@ import android.os.Build; import android.support.annotation.NonNull; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import android.util.Pair; @@ -98,7 +100,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.concurrent.TimeUnit; + +import androidx.work.Data; public class PushDecryptJob extends ContextJob { @@ -106,8 +109,15 @@ public class PushDecryptJob extends ContextJob { public static final String TAG = PushDecryptJob.class.getSimpleName(); - private final long messageId; - private final long smsMessageId; + private static final String KEY_MESSAGE_ID = "message_id"; + private static final String KEY_SMS_MESSAGE_ID = "sms_message_id"; + + private long messageId; + private long smsMessageId; + + public PushDecryptJob() { + super(null, null); + } public PushDecryptJob(Context context, long pushMessageId) { this(context, pushMessageId, -1); @@ -115,16 +125,24 @@ public class PushDecryptJob extends ContextJob { public PushDecryptJob(Context context, long pushMessageId, long smsMessageId) { super(context, JobParameters.newBuilder() - .withPersistence() .withGroupId("__PUSH_DECRYPT_JOB__") - .withWakeLock(true, 5, TimeUnit.SECONDS) .create()); this.messageId = pushMessageId; this.smsMessageId = smsMessageId; } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + messageId = data.getLong(KEY_MESSAGE_ID); + smsMessageId = data.getLong(KEY_SMS_MESSAGE_ID); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putLong(KEY_MESSAGE_ID, messageId) + .putLong(KEY_SMS_MESSAGE_ID, smsMessageId) + .build(); + } @Override public void onRun() throws NoSuchMessageException { diff --git a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index 77ef8fa1e6..45f6841bc2 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -16,8 +16,7 @@ import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.documents.NetworkFailure; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkBackoffRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.MediaConstraints; import org.thoughtcrime.securesms.mms.MmsException; @@ -48,6 +47,8 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; +import androidx.work.Data; + public class PushGroupSendJob extends PushSendJob implements InjectableType { private static final long serialVersionUID = 1L; @@ -56,16 +57,22 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType { @Inject transient SignalServiceMessageSender messageSender; - private final long messageId; - private final long filterRecipientId; // Deprecated - private final String filterAddress; + private static final String KEY_MESSAGE_ID = "message_id"; + private static final String KEY_FILTER_ADDRESS = "filter_address"; + + private long messageId; + private long filterRecipientId; // Deprecated + private String filterAddress; + + public PushGroupSendJob() { + super(null, null); + } public PushGroupSendJob(Context context, long messageId, @NonNull Address destination, @Nullable Address filterAddress) { super(context, JobParameters.newBuilder() - .withPersistence() .withGroupId(destination.toGroupString()) - .withRequirement(new MasterSecretRequirement(context)) - .withRequirement(new NetworkBackoffRequirement(context)) + .withMasterSecretRequirement() + .withNetworkRequirement() .withRetryDuration(TimeUnit.DAYS.toMillis(1)) .create()); @@ -75,8 +82,16 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType { } @Override - public void onAdded() { - Log.i(TAG, "onAdded() messageId: " + messageId); + protected void initialize(@NonNull SafeData data) { + messageId = data.getLong(KEY_MESSAGE_ID); + filterAddress = data.getNullableString(KEY_FILTER_ADDRESS); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putLong(KEY_MESSAGE_ID, messageId) + .putString(KEY_FILTER_ADDRESS, filterAddress) + .build(); } @Override diff --git a/src/org/thoughtcrime/securesms/jobs/PushGroupUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/PushGroupUpdateJob.java index 097f171427..c9cf823031 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushGroupUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushGroupUpdateJob.java @@ -2,6 +2,9 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.database.Address; @@ -10,7 +13,6 @@ import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.GroupUtil; import org.whispersystems.libsignal.util.guava.Optional; @@ -28,26 +30,34 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; +import androidx.work.Data; + public class PushGroupUpdateJob extends ContextJob implements InjectableType { private static final String TAG = PushGroupUpdateJob.class.getSimpleName(); private static final long serialVersionUID = 0L; + private static final String KEY_SOURCE = "source"; + private static final String KEY_GROUP_ID = "group_id"; + @Inject transient SignalServiceMessageSender messageSender; - private final String source; - private final byte[] groupId; + private String source; + private byte[] groupId; + public PushGroupUpdateJob() { + super(null, null); + } public PushGroupUpdateJob(Context context, String source, byte[] groupId) { super(context, JobParameters.newBuilder() - .withPersistence() - .withRequirement(new NetworkRequirement(context)) - .withRetryCount(50) + .withNetworkRequirement() + .withRetryDuration(TimeUnit.DAYS.toMillis(1)) .create()); this.source = source; @@ -55,7 +65,21 @@ public class PushGroupUpdateJob extends ContextJob implements InjectableType { } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + source = data.getString(KEY_SOURCE); + try { + groupId = GroupUtil.getDecodedId(data.getString(KEY_GROUP_ID)); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putString(KEY_SOURCE, source) + .putString(KEY_GROUP_ID, GroupUtil.getEncodedId(groupId, false)) + .build(); + } @Override public void onRun() throws IOException, UntrustedIdentityException { diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index 94473aa5da..940d8dfb3e 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -1,6 +1,9 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.ApplicationContext; @@ -32,24 +35,37 @@ import java.util.List; import javax.inject.Inject; +import androidx.work.Data; + public class PushMediaSendJob extends PushSendJob implements InjectableType { private static final long serialVersionUID = 1L; private static final String TAG = PushMediaSendJob.class.getSimpleName(); + private static final String KEY_MESSAGE_ID = "message_id"; + @Inject transient SignalServiceMessageSender messageSender; - private final long messageId; + private long messageId; + + public PushMediaSendJob() { + super(null, null); + } public PushMediaSendJob(Context context, long messageId, Address destination) { - super(context, constructParameters(context, destination)); + super(context, constructParameters(destination)); this.messageId = messageId; } @Override - public void onAdded() { - Log.i(TAG, "onAdded() messageId: " + messageId); + protected void initialize(@NonNull SafeData data) { + messageId = data.getLong(KEY_MESSAGE_ID); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putLong(KEY_MESSAGE_ID, messageId).build(); } @Override diff --git a/src/org/thoughtcrime/securesms/jobs/PushNotificationReceiveJob.java b/src/org/thoughtcrime/securesms/jobs/PushNotificationReceiveJob.java index 87b301462f..a8d4331b2a 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushNotificationReceiveJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushNotificationReceiveJob.java @@ -1,35 +1,47 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.whispersystems.signalservice.api.SignalServiceMessageReceiver; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; import java.io.IOException; -import java.util.concurrent.TimeUnit; import javax.inject.Inject; +import androidx.work.Data; + public class PushNotificationReceiveJob extends PushReceivedJob implements InjectableType { private static final String TAG = PushNotificationReceiveJob.class.getSimpleName(); @Inject transient SignalServiceMessageReceiver receiver; + public PushNotificationReceiveJob() { + super(null, null); + } + public PushNotificationReceiveJob(Context context) { super(context, JobParameters.newBuilder() - .withRequirement(new NetworkRequirement(context)) + .withNetworkRequirement() .withGroupId("__notification_received") - .withWakeLock(true, 30, TimeUnit.SECONDS).create()); + .create()); } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); + } @Override public void onRun() throws IOException { diff --git a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java index 97088d9a71..a74a77d970 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java @@ -15,8 +15,6 @@ import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.events.PartProgressEvent; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkBackoffRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; @@ -49,12 +47,11 @@ public abstract class PushSendJob extends SendJob { super(context, parameters); } - protected static JobParameters constructParameters(Context context, Address destination) { + protected static JobParameters constructParameters(Address destination) { JobParameters.Builder builder = JobParameters.newBuilder(); - builder.withPersistence(); builder.withGroupId(destination.serialize()); - builder.withRequirement(new MasterSecretRequirement(context)); - builder.withRequirement(new NetworkBackoffRequirement(context)); + builder.withMasterSecretRequirement(); + builder.withNetworkRequirement(); builder.withRetryDuration(TimeUnit.DAYS.toMillis(1)); return builder.create(); @@ -80,7 +77,7 @@ public abstract class PushSendJob extends SendJob { super.onRetry(); Log.i(TAG, "onRetry()"); - if (getRunIteration() > 1) { + if (getRunAttemptCount() > 1) { Log.i(TAG, "Scheduling service outage detection job."); ApplicationContext.getInstance(context).getJobManager().add(new ServiceOutageDetectionJob(context)); } diff --git a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index 1b880aa132..1076376674 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -1,6 +1,9 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.ApplicationContext; @@ -26,21 +29,39 @@ import java.io.IOException; import javax.inject.Inject; +import androidx.work.Data; + public class PushTextSendJob extends PushSendJob implements InjectableType { private static final long serialVersionUID = 1L; private static final String TAG = PushTextSendJob.class.getSimpleName(); + private static final String KEY_MESSAGE_ID = "message_id"; + @Inject transient SignalServiceMessageSender messageSender; - private final long messageId; + private long messageId; + + public PushTextSendJob() { + super(null, null); + } public PushTextSendJob(Context context, long messageId, Address destination) { - super(context, constructParameters(context, destination)); + super(context, constructParameters(destination)); this.messageId = messageId; } + @Override + protected void initialize(@NonNull SafeData data) { + messageId = data.getLong(KEY_MESSAGE_ID); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putLong(KEY_MESSAGE_ID, messageId).build(); + } + @Override public void onAdded() { Log.i(TAG, "onAdded() messageId: " + messageId); diff --git a/src/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java b/src/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java index 7227e5c81b..70952e881b 100644 --- a/src/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java +++ b/src/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java @@ -1,20 +1,23 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.push.exceptions.NetworkFailureException; import java.io.IOException; -import java.util.concurrent.TimeUnit; import javax.inject.Inject; +import androidx.work.Data; + public class RefreshAttributesJob extends ContextJob implements InjectableType { public static final long serialVersionUID = 1L; @@ -23,17 +26,25 @@ public class RefreshAttributesJob extends ContextJob implements InjectableType { @Inject transient SignalServiceAccountManager signalAccountManager; + public RefreshAttributesJob() { + super(null, null); + } + public RefreshAttributesJob(Context context) { super(context, JobParameters.newBuilder() - .withPersistence() - .withRequirement(new NetworkRequirement(context)) - .withWakeLock(true, 30, TimeUnit.SECONDS) + .withNetworkRequirement() .withGroupId(RefreshAttributesJob.class.getName()) .create()); } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); + } @Override public void onRun() throws IOException { diff --git a/src/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java b/src/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java index 1ebd5243c4..67723201c1 100644 --- a/src/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java +++ b/src/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; @@ -8,8 +9,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.PreKeyUtil; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.IdentityKeyPair; @@ -24,6 +24,8 @@ import java.util.List; import javax.inject.Inject; +import androidx.work.Data; + public class RefreshPreKeysJob extends MasterSecretJob implements InjectableType { private static final String TAG = RefreshPreKeysJob.class.getSimpleName(); @@ -32,18 +34,26 @@ public class RefreshPreKeysJob extends MasterSecretJob implements InjectableType @Inject transient SignalServiceAccountManager accountManager; + public RefreshPreKeysJob() { + super(null, null); + } + public RefreshPreKeysJob(Context context) { super(context, JobParameters.newBuilder() .withGroupId(RefreshPreKeysJob.class.getSimpleName()) - .withRequirement(new NetworkRequirement(context)) - .withRequirement(new MasterSecretRequirement(context)) + .withNetworkRequirement() + .withMasterSecretRequirement() .withRetryCount(5) .create()); } @Override - public void onAdded() { + protected void initialize(@NonNull SafeData data) { + } + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); } @Override diff --git a/src/org/thoughtcrime/securesms/jobs/RequestGroupInfoJob.java b/src/org/thoughtcrime/securesms/jobs/RequestGroupInfoJob.java index 290de287d7..7846d971f7 100644 --- a/src/org/thoughtcrime/securesms/jobs/RequestGroupInfoJob.java +++ b/src/org/thoughtcrime/securesms/jobs/RequestGroupInfoJob.java @@ -5,7 +5,8 @@ import android.support.annotation.NonNull; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; +import org.thoughtcrime.securesms.util.GroupUtil; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; @@ -18,21 +19,29 @@ import java.io.IOException; import javax.inject.Inject; +import androidx.work.Data; + public class RequestGroupInfoJob extends ContextJob implements InjectableType { private static final String TAG = RequestGroupInfoJob.class.getSimpleName(); private static final long serialVersionUID = 0L; + private static final String KEY_SOURCE = "source"; + private static final String KEY_GROUP_ID = "group_id"; + @Inject transient SignalServiceMessageSender messageSender; - private final String source; - private final byte[] groupId; + private String source; + private byte[] groupId; + + public RequestGroupInfoJob() { + super(null, null); + } public RequestGroupInfoJob(@NonNull Context context, @NonNull String source, @NonNull byte[] groupId) { super(context, JobParameters.newBuilder() - .withRequirement(new NetworkRequirement(context)) - .withPersistence() + .withNetworkRequirement() .withRetryCount(50) .create()); @@ -41,7 +50,21 @@ public class RequestGroupInfoJob extends ContextJob implements InjectableType { } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + source = data.getString(KEY_SOURCE); + try { + groupId = GroupUtil.getDecodedId(data.getString(KEY_GROUP_ID)); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putString(KEY_SOURCE, source) + .putString(KEY_GROUP_ID, GroupUtil.getEncodedId(groupId, false)) + .build(); + } @Override public void onRun() throws IOException, UntrustedIdentityException { diff --git a/src/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java b/src/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java index 5ef2c7d1e9..7d8ee23711 100644 --- a/src/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java +++ b/src/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java @@ -2,14 +2,17 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import android.text.TextUtils; + +import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; import org.thoughtcrime.securesms.profiles.AvatarHelper; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.Util; @@ -23,21 +26,31 @@ import java.io.InputStream; import javax.inject.Inject; +import androidx.work.Data; + public class RetrieveProfileAvatarJob extends ContextJob implements InjectableType { private static final String TAG = RetrieveProfileAvatarJob.class.getSimpleName(); private static final int MAX_PROFILE_SIZE_BYTES = 20 * 1024 * 1024; + private static final String KEY_PROFILE_AVATAR = "profile_avatar"; + private static final String KEY_ADDRESS = "address"; + @Inject SignalServiceMessageReceiver receiver; - private final String profileAvatar; - private final Recipient recipient; + private String profileAvatar; + private Recipient recipient; + + public RetrieveProfileAvatarJob() { + super(null, null); + } public RetrieveProfileAvatarJob(Context context, Recipient recipient, String profileAvatar) { super(context, JobParameters.newBuilder() .withGroupId(RetrieveProfileAvatarJob.class.getSimpleName() + recipient.getAddress().serialize()) - .withRequirement(new NetworkRequirement(context)) + .withDuplicatesIgnored(true) + .withNetworkRequirement() .create()); this.recipient = recipient; @@ -45,7 +58,17 @@ public class RetrieveProfileAvatarJob extends ContextJob implements InjectableTy } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + profileAvatar = data.getString(KEY_PROFILE_AVATAR); + recipient = Recipient.from(context, Address.fromSerialized(data.getString(KEY_ADDRESS)), true); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putString(KEY_PROFILE_AVATAR, profileAvatar) + .putString(KEY_ADDRESS, recipient.getAddress().serialize()) + .build(); + } @Override public void onRun() throws IOException { diff --git a/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java b/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java index 96b6f26962..baf554299a 100644 --- a/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java +++ b/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java @@ -4,6 +4,9 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; import android.support.annotation.NonNull; import android.text.TextUtils; + +import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.ApplicationContext; @@ -29,16 +32,25 @@ import java.util.List; import javax.inject.Inject; +import androidx.work.Data; + public class RetrieveProfileJob extends ContextJob implements InjectableType { private static final String TAG = RetrieveProfileJob.class.getSimpleName(); + private static final String KEY_ADDRESS = "address"; + @Inject transient SignalServiceMessageReceiver receiver; - private final Recipient recipient; + private Recipient recipient; + + public RetrieveProfileJob() { + super(null, null); + } public RetrieveProfileJob(Context context, Recipient recipient) { super(context, JobParameters.newBuilder() + .withNetworkRequirement() .withRetryCount(3) .create()); @@ -46,7 +58,14 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType { } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + recipient = Recipient.from(context, Address.fromSerialized(data.getString(KEY_ADDRESS)), true); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putString(KEY_ADDRESS, recipient.getAddress().serialize()).build(); + } @Override public void onRun() throws IOException, InvalidKeyException { diff --git a/src/org/thoughtcrime/securesms/jobs/RotateSignedPreKeyJob.java b/src/org/thoughtcrime/securesms/jobs/RotateSignedPreKeyJob.java index c23bd42bfb..2ecef2e7ba 100644 --- a/src/org/thoughtcrime/securesms/jobs/RotateSignedPreKeyJob.java +++ b/src/org/thoughtcrime/securesms/jobs/RotateSignedPreKeyJob.java @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; @@ -9,8 +10,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.PreKeyUtil; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.IdentityKeyPair; @@ -20,23 +20,33 @@ import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException import javax.inject.Inject; +import androidx.work.Data; + public class RotateSignedPreKeyJob extends MasterSecretJob implements InjectableType { private static final String TAG = RotateSignedPreKeyJob.class.getName(); @Inject transient SignalServiceAccountManager accountManager; + public RotateSignedPreKeyJob() { + super(null, null); + } + public RotateSignedPreKeyJob(Context context) { super(context, JobParameters.newBuilder() - .withRequirement(new NetworkRequirement(context)) - .withRequirement(new MasterSecretRequirement(context)) + .withNetworkRequirement() + .withMasterSecretRequirement() .withRetryCount(5) .create()); } @Override - public void onAdded() { + protected void initialize(@NonNull SafeData data) { + } + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); } @Override diff --git a/src/org/thoughtcrime/securesms/jobs/SendReadReceiptJob.java b/src/org/thoughtcrime/securesms/jobs/SendReadReceiptJob.java index 41333b2339..bed3982340 100644 --- a/src/org/thoughtcrime/securesms/jobs/SendReadReceiptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/SendReadReceiptJob.java @@ -2,11 +2,12 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.signalservice.api.SignalServiceMessageSender; @@ -16,26 +17,36 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import javax.inject.Inject; +import androidx.work.Data; + public class SendReadReceiptJob extends ContextJob implements InjectableType { private static final long serialVersionUID = 1L; private static final String TAG = SendReadReceiptJob.class.getSimpleName(); + private static final String KEY_ADDRESS = "address"; + private static final String KEY_MESSAGE_IDS = "message_ids"; + private static final String KEY_TIMESTAMP = "timestamp"; + @Inject transient SignalServiceMessageSender messageSender; - private final String address; - private final List messageIds; - private final long timestamp; + private String address; + private List messageIds; + private long timestamp; + + public SendReadReceiptJob() { + super(null, null); + } public SendReadReceiptJob(Context context, Address address, List messageIds) { super(context, JobParameters.newBuilder() - .withRequirement(new NetworkRequirement(context)) - .withPersistence() + .withNetworkRequirement() .create()); this.address = address.serialize(); @@ -44,7 +55,29 @@ public class SendReadReceiptJob extends ContextJob implements InjectableType { } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + address = data.getString(KEY_ADDRESS); + timestamp = data.getLong(KEY_TIMESTAMP); + + long[] ids = data.getLongArray(KEY_MESSAGE_IDS); + messageIds = new ArrayList<>(ids.length); + for (long id : ids) { + messageIds.add(id); + } + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + long[] ids = new long[messageIds.size()]; + for (int i = 0; i < ids.length; i++) { + ids[i] = messageIds.get(i); + } + + return dataBuilder.putString(KEY_ADDRESS, address) + .putLongArray(KEY_MESSAGE_IDS, ids) + .putLong(KEY_TIMESTAMP, timestamp) + .build(); + } @Override public void onRun() throws IOException, UntrustedIdentityException { diff --git a/src/org/thoughtcrime/securesms/jobs/ServiceOutageDetectionJob.java b/src/org/thoughtcrime/securesms/jobs/ServiceOutageDetectionJob.java index 4735669127..4a4c1a511a 100644 --- a/src/org/thoughtcrime/securesms/jobs/ServiceOutageDetectionJob.java +++ b/src/org/thoughtcrime/securesms/jobs/ServiceOutageDetectionJob.java @@ -1,12 +1,13 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import org.greenrobot.eventbus.EventBus; import org.thoughtcrime.securesms.BuildConfig; import org.thoughtcrime.securesms.events.ReminderUpdateEvent; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.util.TextSecurePreferences; @@ -14,6 +15,8 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences; import java.net.InetAddress; import java.net.UnknownHostException; +import androidx.work.Data; + public class ServiceOutageDetectionJob extends ContextJob { private static final String TAG = ServiceOutageDetectionJob.class.getSimpleName(); @@ -22,16 +25,26 @@ public class ServiceOutageDetectionJob extends ContextJob { private static final String IP_FAILURE = "127.0.0.2"; private static final long CHECK_TIME = 1000 * 60; + public ServiceOutageDetectionJob() { + super(null, null); + } + public ServiceOutageDetectionJob(Context context) { super(context, new JobParameters.Builder() .withGroupId(ServiceOutageDetectionJob.class.getSimpleName()) - .withRequirement(new NetworkRequirement(context)) + .withDuplicatesIgnored(true) + .withNetworkRequirement() .withRetryCount(5) .create()); } @Override - public void onAdded() { + protected void initialize(@NonNull SafeData data) { + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); } @Override diff --git a/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java b/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java index f11113580e..83d0aecb3a 100644 --- a/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java +++ b/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java @@ -4,36 +4,47 @@ import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.telephony.SmsMessage; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult; import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobs.requirements.SqlCipherMigrationRequirement; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.sms.IncomingTextMessage; +import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.util.guava.Optional; +import java.io.IOException; import java.util.LinkedList; import java.util.List; +import androidx.work.Data; + public class SmsReceiveJob extends ContextJob { private static final long serialVersionUID = 1L; private static final String TAG = SmsReceiveJob.class.getSimpleName(); - private final @Nullable Object[] pdus; - private final int subscriptionId; + private static final String KEY_PDUS = "pdus"; + private static final String KEY_SUBSCRIPTION_ID = "subscription_id"; + + private @Nullable Object[] pdus; + + private int subscriptionId; + + public SmsReceiveJob() { + super(null, null); + } public SmsReceiveJob(@NonNull Context context, @Nullable Object[] pdus, int subscriptionId) { super(context, JobParameters.newBuilder() - .withPersistence() - .withWakeLock(true) - .withRequirement(new SqlCipherMigrationRequirement(context)) + .withSqlCipherRequirement() .create()); this.pdus = pdus; @@ -41,7 +52,31 @@ public class SmsReceiveJob extends ContextJob { } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + String[] encoded = data.getStringArray(KEY_PDUS); + pdus = new Object[encoded.length]; + try { + for (int i = 0; i < encoded.length; i++) { + pdus[i] = Base64.decode(encoded[i]); + } + } catch (IOException e) { + throw new AssertionError(e); + } + + subscriptionId = data.getInt(KEY_SUBSCRIPTION_ID); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + String[] encoded = new String[pdus.length]; + for (int i = 0; i < pdus.length; i++) { + encoded[i] = Base64.encodeBytes((byte[]) pdus[i]); + } + + return dataBuilder.putStringArray(KEY_PDUS, encoded) + .putInt(KEY_SUBSCRIPTION_ID, subscriptionId) + .build(); + } @Override public void onRun() throws MigrationPendingException { diff --git a/src/org/thoughtcrime/securesms/jobs/SmsSendJob.java b/src/org/thoughtcrime/securesms/jobs/SmsSendJob.java index f01d613056..0452924ec5 100644 --- a/src/org/thoughtcrime/securesms/jobs/SmsSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/SmsSendJob.java @@ -5,8 +5,11 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; +import android.support.annotation.NonNull; import android.telephony.PhoneNumberUtils; import android.telephony.SmsManager; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.crypto.MasterSecret; @@ -14,9 +17,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.database.model.SmsMessageRecord; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; -import org.thoughtcrime.securesms.jobs.requirements.NetworkOrServiceRequirement; -import org.thoughtcrime.securesms.jobs.requirements.ServiceRequirement; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.SmsDeliveryListener; @@ -27,18 +27,35 @@ import org.thoughtcrime.securesms.jobmanager.JobParameters; import java.util.ArrayList; +import androidx.work.Data; + public class SmsSendJob extends SendJob { private static final long serialVersionUID = -5118520036244759718L; private static final String TAG = SmsSendJob.class.getSimpleName(); + private static final String KEY_MESSAGE_ID = "message_id"; - private final long messageId; + private long messageId; + + public SmsSendJob() { + super(null, null); + } public SmsSendJob(Context context, long messageId, String name) { - super(context, constructParameters(context, name)); + super(context, constructParameters(name)); this.messageId = messageId; } + @Override + protected void initialize(@NonNull SafeData data) { + messageId = data.getLong(KEY_MESSAGE_ID); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putLong(KEY_MESSAGE_ID, messageId).build(); + } + @Override public void onAdded() { Log.i(TAG, "onAdded() messageId: " + messageId); @@ -190,19 +207,11 @@ public class SmsSendJob extends SendJob { } } - private static JobParameters constructParameters(Context context, String name) { + private static JobParameters constructParameters(String name) { JobParameters.Builder builder = JobParameters.newBuilder() - .withPersistence() - .withRequirement(new MasterSecretRequirement(context)) + .withMasterSecretRequirement() .withRetryCount(15) .withGroupId(name); - - if (TextSecurePreferences.isWifiSmsEnabled(context)) { - builder.withRequirement(new NetworkOrServiceRequirement(context)); - } else { - builder.withRequirement(new ServiceRequirement(context)); - } - return builder.create(); } diff --git a/src/org/thoughtcrime/securesms/jobs/SmsSentJob.java b/src/org/thoughtcrime/securesms/jobs/SmsSentJob.java index a086d7d45d..b335022448 100644 --- a/src/org/thoughtcrime/securesms/jobs/SmsSentJob.java +++ b/src/org/thoughtcrime/securesms/jobs/SmsSentJob.java @@ -2,7 +2,10 @@ package org.thoughtcrime.securesms.jobs; import android.app.Activity; import android.content.Context; +import android.support.annotation.NonNull; import android.telephony.SmsManager; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.ApplicationContext; @@ -12,23 +15,31 @@ import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.database.model.SmsMessageRecord; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.service.SmsDeliveryListener; +import androidx.work.Data; + public class SmsSentJob extends MasterSecretJob { private static final long serialVersionUID = -2624694558755317560L; private static final String TAG = SmsSentJob.class.getSimpleName(); - private final long messageId; - private final String action; - private final int result; + private static final String KEY_MESSAGE_ID = "message_id"; + private static final String KEY_ACTION = "action"; + private static final String KEY_RESULT = "result"; + + private long messageId; + private String action; + private int result; + + public SmsSentJob() { + super(null, null); + } public SmsSentJob(Context context, long messageId, String action, int result) { super(context, JobParameters.newBuilder() - .withPersistence() - .withRequirement(new MasterSecretRequirement(context)) + .withMasterSecretRequirement() .create()); this.messageId = messageId; @@ -37,8 +48,18 @@ public class SmsSentJob extends MasterSecretJob { } @Override - public void onAdded() { + protected void initialize(@NonNull SafeData data) { + messageId = data.getLong(KEY_MESSAGE_ID); + action = data.getString(KEY_ACTION); + result = data.getInt(KEY_RESULT); + } + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putLong(KEY_MESSAGE_ID, messageId) + .putString(KEY_ACTION, action) + .putInt(KEY_RESULT, result) + .build(); } @Override diff --git a/src/org/thoughtcrime/securesms/jobs/TrimThreadJob.java b/src/org/thoughtcrime/securesms/jobs/TrimThreadJob.java index 15c843ed3b..790eef6142 100644 --- a/src/org/thoughtcrime/securesms/jobs/TrimThreadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/TrimThreadJob.java @@ -17,29 +17,42 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; +import android.support.annotation.NonNull; import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.JobParameters; +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.util.TextSecurePreferences; -public class TrimThreadJob extends Job { +import androidx.work.Data; + +public class TrimThreadJob extends ContextJob { private static final String TAG = TrimThreadJob.class.getSimpleName(); - private final Context context; - private final long threadId; + private static final String KEY_THREAD_ID = "thread_id"; + + private long threadId; + + public TrimThreadJob() { + super(null, null); + } public TrimThreadJob(Context context, long threadId) { - super(JobParameters.newBuilder().withGroupId(TrimThreadJob.class.getSimpleName()).create()); + super(context, JobParameters.newBuilder().withGroupId(TrimThreadJob.class.getSimpleName()).create()); this.context = context; this.threadId = threadId; } @Override - public void onAdded() { + protected void initialize(@NonNull SafeData data) { + threadId = data.getLong(KEY_THREAD_ID); + } + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putLong(KEY_THREAD_ID, threadId).build(); } @Override diff --git a/src/org/thoughtcrime/securesms/jobs/UpdateApkJob.java b/src/org/thoughtcrime/securesms/jobs/UpdateApkJob.java index 9650e750ed..c435bb501b 100644 --- a/src/org/thoughtcrime/securesms/jobs/UpdateApkJob.java +++ b/src/org/thoughtcrime/securesms/jobs/UpdateApkJob.java @@ -9,14 +9,16 @@ import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.Build; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; + +import org.thoughtcrime.securesms.jobmanager.SafeData; import org.thoughtcrime.securesms.logging.Log; import com.fasterxml.jackson.annotation.JsonProperty; import org.thoughtcrime.securesms.BuildConfig; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement; import org.thoughtcrime.securesms.service.UpdateApkReadyListener; import org.thoughtcrime.securesms.util.FileUtils; import org.thoughtcrime.securesms.util.Hex; @@ -26,8 +28,8 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences; import java.io.FileInputStream; import java.io.IOException; import java.security.MessageDigest; -import java.util.concurrent.TimeUnit; +import androidx.work.Data; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -36,17 +38,26 @@ public class UpdateApkJob extends ContextJob { private static final String TAG = UpdateApkJob.class.getSimpleName(); + public UpdateApkJob() { + super(null, null); + } + public UpdateApkJob(Context context) { super(context, JobParameters.newBuilder() .withGroupId(UpdateApkJob.class.getSimpleName()) - .withRequirement(new NetworkRequirement(context)) - .withWakeLock(true, 30, TimeUnit.SECONDS) + .withNetworkRequirement() .withRetryCount(2) .create()); } @Override - public void onAdded() {} + protected void initialize(@NonNull SafeData data) { + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.build(); + } @Override public void onRun() throws IOException, PackageManager.NameNotFoundException {