Make the message trimming behaviour consistent across platform (#936)

* refactor: remove old trim behaviour and create new defaults

* refactor: add in trimming by before time

* refactor: remove old trim thread job, remove message processor scheduling trim thread

* refactor: remove spacing

* refactor: enable trimming by default

* refactor: remove trim now option in chat preference
pull/967/head
Harris 2 years ago committed by GitHub
parent 7d186c198e
commit 919bb01d58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -162,8 +162,8 @@ public class MmsSmsDatabase extends Database {
}
}
public int getConversationCount(long threadId) {
int count = DatabaseComponent.get(context).smsDatabase().getMessageCountForThread(threadId);
public long getConversationCount(long threadId) {
long count = DatabaseComponent.get(context).smsDatabase().getMessageCountForThread(threadId);
count += DatabaseComponent.get(context).mmsDatabase().getMessageCountForThread(threadId);
return count;

@ -201,11 +201,6 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
messageID = result.messageId
}
}
val threadID = message.threadID
// open group trim thread job is scheduled after processing in OpenGroupPollerV2
if (openGroupID.isNullOrEmpty() && threadID != null && threadID >= 0 && TextSecurePreferences.isThreadLengthTrimmingEnabled(context)) {
JobQueue.shared.queueThreadForTrim(threadID)
}
message.serverHash?.let { serverHash ->
messageID?.let { id ->
DatabaseComponent.get(context).lokiMessageDatabase().setMessageServerHash(id, serverHash)
@ -701,6 +696,18 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
threadDB.trimThread(threadID, threadLimit)
}
override fun trimThreadBefore(threadID: Long, timestamp: Long) {
val threadDB = DatabaseComponent.get(context).threadDatabase()
threadDB.trimThreadBefore(threadID, timestamp)
}
override fun getMessageCount(threadID: Long): Long {
val mmsSmsDb = DatabaseComponent.get(context).mmsSmsDatabase()
return mmsSmsDb.getConversationCount(threadID)
}
override fun getAttachmentDataUri(attachmentId: AttachmentId): Uri {
return PartAuthority.getAttachmentDataUri(attachmentId)
}

@ -281,6 +281,14 @@ public class ThreadDatabase extends Database {
}
}
public void trimThreadBefore(long threadId, long timestamp) {
Log.i("ThreadDatabase", "Trimming thread: " + threadId + " before :"+timestamp);
DatabaseComponent.get(context).smsDatabase().deleteMessagesInThreadBeforeDate(threadId, timestamp);
DatabaseComponent.get(context).mmsDatabase().deleteMessagesInThreadBeforeDate(threadId, timestamp);
update(threadId, false);
notifyConversationListeners(threadId);
}
public List<MarkedMessageInfo> setRead(long threadId, boolean lastSeen) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(READ, 1);

@ -31,7 +31,6 @@ public final class JobManagerFactories {
put(AvatarDownloadJob.KEY, new AvatarDownloadJob.Factory());
put(LocalBackupJob.KEY, new LocalBackupJob.Factory());
put(RetrieveProfileAvatarJob.KEY, new RetrieveProfileAvatarJob.Factory(application));
put(TrimThreadJob.KEY, new TrimThreadJob.Factory());
put(UpdateApkJob.KEY, new UpdateApkJob.Factory());
put(PrepareAttachmentAudioExtrasJob.KEY, new PrepareAttachmentAudioExtrasJob.Factory());
}};

@ -1,84 +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 <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.jobs;
import androidx.annotation.NonNull;
import org.session.libsession.messaging.utilities.Data;
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsignal.utilities.Log;
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
import org.thoughtcrime.securesms.jobmanager.Job;
public class TrimThreadJob extends BaseJob {
public static final String KEY = "TrimThreadJob";
private static final String TAG = TrimThreadJob.class.getSimpleName();
private static final String KEY_THREAD_ID = "thread_id";
private long threadId;
public TrimThreadJob(long threadId) {
this(new Job.Parameters.Builder().setQueue("TrimThreadJob").build(), threadId);
}
private TrimThreadJob(@NonNull Job.Parameters parameters, long threadId) {
super(parameters);
this.threadId = threadId;
}
@Override
public @NonNull
Data serialize() {
return new Data.Builder().putLong(KEY_THREAD_ID, threadId).build();
}
@Override
public @NonNull String getFactoryKey() {
return KEY;
}
@Override
public void onRun() {
boolean trimmingEnabled = TextSecurePreferences.isThreadLengthTrimmingEnabled(context);
int threadLengthLimit = TextSecurePreferences.getThreadTrimLength(context);
if (!trimmingEnabled)
return;
DatabaseComponent.get(context).threadDatabase().trimThread(threadId, threadLengthLimit);
}
@Override
public boolean onShouldRetry(@NonNull Exception exception) {
return false;
}
@Override
public void onCanceled() {
Log.w(TAG, "Canceling trim attempt: " + threadId);
}
public static final class Factory implements Job.Factory<TrimThreadJob> {
@Override
public @NonNull TrimThreadJob create(@NonNull Parameters parameters, @NonNull Data data) {
return new TrimThreadJob(parameters, data.getLong(KEY_THREAD_ID));
}
}
}

@ -1,18 +1,11 @@
package org.thoughtcrime.securesms.preferences;
import android.content.DialogInterface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.EditTextPreference;
import androidx.preference.Preference;
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsignal.utilities.Log;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.Trimmer;
import network.loki.messenger.R;
@ -22,12 +15,6 @@ public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment {
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
findPreference(TextSecurePreferences.THREAD_TRIM_NOW)
.setOnPreferenceClickListener(new TrimNowClickListener());
findPreference(TextSecurePreferences.THREAD_TRIM_LENGTH)
.setOnPreferenceChangeListener(new TrimLengthValidationListener());
}
@Override
@ -50,57 +37,4 @@ public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
private class TrimNowClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
final int threadLengthLimit = TextSecurePreferences.getThreadTrimLength(getActivity());
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.ApplicationPreferencesActivity_delete_all_old_messages_now);
builder.setMessage(getResources().getQuantityString(R.plurals.ApplicationPreferencesActivity_this_will_immediately_trim_all_conversations_to_the_d_most_recent_messages,
threadLengthLimit, threadLengthLimit));
builder.setPositiveButton(R.string.ApplicationPreferencesActivity_delete,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Trimmer.trimAllThreads(getActivity(), threadLengthLimit);
}
});
builder.setNegativeButton(android.R.string.cancel, null);
builder.show();
return true;
}
}
private class TrimLengthValidationListener implements Preference.OnPreferenceChangeListener {
public TrimLengthValidationListener() {
EditTextPreference preference = findPreference(TextSecurePreferences.THREAD_TRIM_LENGTH);
onPreferenceChange(preference, preference.getText());
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (newValue == null || ((String)newValue).trim().length() == 0) {
return false;
}
int value;
try {
value = Integer.parseInt((String)newValue);
} catch (NumberFormatException nfe) {
Log.w(TAG, nfe);
return false;
}
if (value < 1) {
return false;
}
preference.setSummary(getResources().getQuantityString(R.plurals.ApplicationPreferencesActivity_messages_per_conversation, value, value));
return true;
}
}
}

@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!-- <PreferenceCategory android:key="media_download" android:title="@string/preferences_chats__media_auto_download">
@ -73,19 +71,6 @@
android:summary="@string/preferences__automatically_delete_older_messages_once_a_conversation_exceeds_a_specified_length"
android:title="@string/preferences__delete_old_messages" />
<EditTextPreference
android:defaultValue="500"
android:key="pref_trim_length"
android:title="@string/preferences__conversation_length_limit"
android:inputType="number"
android:dependency="pref_trim_threads" />
<Preference
android:key="pref_trim_now"
android:title="@string/preferences__trim_all_conversations_now"
android:summary="@string/preferences__scan_through_all_conversations_and_enforce_conversation_length_limits"
android:dependency="pref_trim_threads" />
</PreferenceCategory>
<!-- <PreferenceCategory android:layout="@layout/preference_divider" />

@ -151,6 +151,8 @@ interface StorageProtocol {
fun getThreadIdForMms(mmsId: Long): Long
fun getLastUpdated(threadID: Long): Long
fun trimThread(threadID: Long, threadLimit: Int)
fun trimThreadBefore(threadID: Long, timestamp: Long)
fun getMessageCount(threadID: Long): Long
// Contacts
fun getContactWithSessionID(sessionID: String): Contact?

@ -31,7 +31,6 @@ class JobQueue : JobDelegate {
private val scope = CoroutineScope(Dispatchers.Default) + SupervisorJob()
private val queue = Channel<Job>(UNLIMITED)
private val pendingJobIds = mutableSetOf<String>()
private val pendingTrimThreadIds = mutableSetOf<Long>()
private val openGroupChannels = mutableMapOf<String, Channel<Job>>()
@ -115,15 +114,6 @@ class JobQueue : JobDelegate {
val openGroupJob = processWithOpenGroupDispatcher(openGroupQueue, openGroupDispatcher, "openGroup")
while (isActive) {
if (queue.isEmpty && pendingTrimThreadIds.isNotEmpty()) {
// process trim thread jobs
val pendingThreads = pendingTrimThreadIds.toList()
pendingTrimThreadIds.clear()
for (thread in pendingThreads) {
Log.d("Loki", "Trimming thread $thread")
queue.trySend(TrimThreadJob(thread, null))
}
}
when (val job = queue.receive()) {
is NotifyPNServerJob, is AttachmentUploadJob, is MessageSendJob -> {
txQueue.send(job)
@ -165,10 +155,6 @@ class JobQueue : JobDelegate {
val shared: JobQueue by lazy { JobQueue() }
}
fun queueThreadForTrim(threadId: Long) {
pendingTrimThreadIds += threadId
}
fun add(job: Job) {
addWithoutExecuting(job)
queue.trySend(job) // offer always called on unlimited capacity

@ -15,14 +15,19 @@ class TrimThreadJob(val threadId: Long, val openGroupId: String?) : Job {
const val KEY: String = "TrimThreadJob"
const val THREAD_ID = "thread_id"
const val OPEN_GROUP_ID = "open_group"
const val TRIM_TIME_LIMIT = 15552000000L // trim messages older than this
const val THREAD_LENGTH_TRIGGER_SIZE = 2000
}
override fun execute() {
val context = MessagingModuleConfiguration.shared.context
val trimmingEnabled = TextSecurePreferences.isThreadLengthTrimmingEnabled(context)
val threadLengthLimit = TextSecurePreferences.getThreadTrimLength(context)
if (trimmingEnabled) {
MessagingModuleConfiguration.shared.storage.trimThread(threadId, threadLengthLimit)
val storage = MessagingModuleConfiguration.shared.storage
val messageCount = storage.getMessageCount(threadId)
if (trimmingEnabled && !openGroupId.isNullOrEmpty() && messageCount >= THREAD_LENGTH_TRIGGER_SIZE) {
val oldestMessageTime = System.currentTimeMillis() - TRIM_TIME_LIMIT
storage.trimThreadBefore(threadId, oldestMessageTime)
}
delegate?.handleJobSucceeded(this)
}

@ -117,7 +117,6 @@ interface TextSecurePreferences {
fun getNotificationLedPattern(): String?
fun getNotificationLedPatternCustom(): String?
fun isThreadLengthTrimmingEnabled(): Boolean
fun getThreadTrimLength(): Int
fun isSystemEmojiPreferred(): Boolean
fun getMobileMediaDownloadAllowed(): Set<String>?
fun getWifiMediaDownloadAllowed(): Set<String>?
@ -175,7 +174,6 @@ interface TextSecurePreferences {
const val DISABLE_PASSPHRASE_PREF = "pref_disable_passphrase"
const val LANGUAGE_PREF = "pref_language"
const val THREAD_TRIM_LENGTH = "pref_trim_length"
const val THREAD_TRIM_NOW = "pref_trim_now"
const val LAST_VERSION_CODE_PREF = "last_version_code"
const val RINGTONE_PREF = "pref_key_ringtone"
@ -705,12 +703,7 @@ interface TextSecurePreferences {
@JvmStatic
fun isThreadLengthTrimmingEnabled(context: Context): Boolean {
return getBooleanPreference(context, THREAD_TRIM_ENABLED, false)
}
@JvmStatic
fun getThreadTrimLength(context: Context): Int {
return getStringPreference(context, THREAD_TRIM_LENGTH, "500")!!.toInt()
return getBooleanPreference(context, THREAD_TRIM_ENABLED, true)
}
@JvmStatic
@ -1329,11 +1322,7 @@ class AppTextSecurePreferences @Inject constructor(
}
override fun isThreadLengthTrimmingEnabled(): Boolean {
return getBooleanPreference(TextSecurePreferences.THREAD_TRIM_ENABLED, false)
}
override fun getThreadTrimLength(): Int {
return getStringPreference(TextSecurePreferences.THREAD_TRIM_LENGTH, "500")!!.toInt()
return getBooleanPreference(TextSecurePreferences.THREAD_TRIM_ENABLED, true)
}
override fun isSystemEmojiPreferred(): Boolean {

Loading…
Cancel
Save