Skip to content

Commit

Permalink
Join recipient preferences into thread query for faster lookup
Browse files Browse the repository at this point in the history
// FREEBIE
  • Loading branch information
moxie0 committed Aug 28, 2017
1 parent 375207f commit a02f223
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 66 deletions.
10 changes: 8 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath files('libs/gradle-witness.jar')
classpath 'me.tatarka:gradle-retrolambda:3.7.0'
}
}

apply plugin: 'com.android.application'
apply plugin: 'witness'
apply plugin: 'me.tatarka.retrolambda'

repositories {
maven {
Expand Down Expand Up @@ -99,6 +101,8 @@ dependencies {
exclude group: 'com.squareup.okhttp', module: 'okhttp'
exclude group: 'com.squareup.okhttp', module: 'okhttp-urlconnection'
}
compile 'com.annimon:stream:1.1.8'


testCompile 'junit:junit:4.12'
testCompile 'org.assertj:assertj-core:1.7.1'
Expand Down Expand Up @@ -160,6 +164,7 @@ dependencyVerification {
'cn.carbswang.android:NumberPickerView:18b3c316d62c7c277978a8d4ed57a5b8f4e943762264960f579a8a549c756729',
'com.tomergoldst.android:tooltips:4c56697dd1ad64b8066535c61f961a6d901e7ae5d97ae27084ba40ad620349b6',
'com.klinkerapps:android-smsmms:e7c3328a0f3a8dd44daa8129de4e99996f3057a4546e47891b036b81e0ebf1d1',
'com.annimon:stream:5da6e2e3e0551d61a3ea7014f04312276549e3dd739cf637996e4cf43c5535b9',
'com.android.support:support-v4:ed4cda7c752f51d33f9bbdfff3422b425b323d356cd1bdc9786aa413c912e594',
'com.android.support:support-vector-drawable:2697503d3e8e709023ae176ba5db7f98ca0aa0b4e6290aedcb3c371904806bf7',
'com.android.support:animated-vector-drawable:6d05cb63d1f68900220f85c56dfe1066a9bb19cb0ec1247cc68fc2ba32f6b4a7',
Expand Down Expand Up @@ -222,8 +227,8 @@ android {
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

packagingOptions {
Expand Down Expand Up @@ -257,6 +262,7 @@ android {
'proguard-retrofit.pro',
'proguard-webrtc.pro',
'proguard-klinker.pro',
'proguard-retrolambda.pro',
'proguard.cfg'
testProguardFiles 'proguard-automation.pro',
'proguard.cfg'
Expand Down
2 changes: 2 additions & 0 deletions proguard-retrolambda.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-dontwarn java.lang.invoke.*
-dontwarn **$$Lambda$*
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.Button;
Expand Down Expand Up @@ -92,7 +93,7 @@ private void initializeResources() {
public void onClick(View v) {
Intent intent = new Intent(DatabaseMigrationActivity.this, ApplicationMigrationService.class);
intent.setAction(ApplicationMigrationService.MIGRATE_DATABASE);
intent.putExtra("master_secret", getIntent().getParcelableExtra("master_secret"));
intent.putExtra("master_secret", (Parcelable)getIntent().getParcelableExtra("master_secret"));
startService(intent);

promptLayout.setVisibility(View.GONE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,22 @@
import android.support.annotation.Nullable;
import android.util.Log;

import com.annimon.stream.Stream;

import org.greenrobot.eventbus.EventBus;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.whispersystems.libsignal.util.guava.Optional;

import java.util.List;

public class RecipientPreferenceDatabase extends Database {

private static final String TAG = RecipientPreferenceDatabase.class.getSimpleName();
private static final String RECIPIENT_PREFERENCES_URI = "content://textsecure/recipients/";

private static final String TABLE_NAME = "recipient_preferences";
static final String TABLE_NAME = "recipient_preferences";
private static final String ID = "_id";
private static final String ADDRESS = "recipient_ids";
private static final String BLOCK = "block";
Expand All @@ -33,6 +37,14 @@ public class RecipientPreferenceDatabase extends Database {
private static final String DEFAULT_SUBSCRIPTION_ID = "default_subscription_id";
private static final String EXPIRE_MESSAGES = "expire_messages";

private static final String[] RECIPIENT_PROJECTION = new String[] {
BLOCK, NOTIFICATION, VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES
};

static final List<String> TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION)
.map(columnName -> TABLE_NAME + "." + columnName)
.toList();

public enum VibrateState {
DEFAULT(0), ENABLED(1), DISABLED(2);

Expand Down Expand Up @@ -91,31 +103,7 @@ public Optional<RecipientsPreferences> getRecipientsPreferences(@NonNull Address
cursor = database.query(TABLE_NAME, null, ADDRESS + " = ?", new String[] {address.serialize()}, null, null, null);

if (cursor != null && cursor.moveToNext()) {
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCK)) == 1;
String notification = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION));
int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(VIBRATE));
long muteUntil = cursor.getLong(cursor.getColumnIndexOrThrow(MUTE_UNTIL));
String serializedColor = cursor.getString(cursor.getColumnIndexOrThrow(COLOR));
Uri notificationUri = notification == null ? null : Uri.parse(notification);
boolean seenInviteReminder = cursor.getInt(cursor.getColumnIndexOrThrow(SEEN_INVITE_REMINDER)) == 1;
int defaultSubscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(DEFAULT_SUBSCRIPTION_ID));
int expireMessages = cursor.getInt(cursor.getColumnIndexOrThrow(EXPIRE_MESSAGES));

MaterialColor color;

try {
color = serializedColor == null ? null : MaterialColor.fromSerialized(serializedColor);
} catch (MaterialColor.UnknownColorException e) {
Log.w(TAG, e);
color = null;
}

Log.w(TAG, "Muted until: " + muteUntil);

return Optional.of(new RecipientsPreferences(blocked, muteUntil,
VibrateState.fromId(vibrateState),
notificationUri, color, seenInviteReminder,
defaultSubscriptionId, expireMessages));
return Optional.of(getRecipientPreferences(cursor));
}

return Optional.absent();
Expand All @@ -124,6 +112,32 @@ public Optional<RecipientsPreferences> getRecipientsPreferences(@NonNull Address
}
}

RecipientsPreferences getRecipientPreferences(@NonNull Cursor cursor) {
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCK)) == 1;
String notification = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION));
int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(VIBRATE));
long muteUntil = cursor.getLong(cursor.getColumnIndexOrThrow(MUTE_UNTIL));
String serializedColor = cursor.getString(cursor.getColumnIndexOrThrow(COLOR));
Uri notificationUri = notification == null ? null : Uri.parse(notification);
boolean seenInviteReminder = cursor.getInt(cursor.getColumnIndexOrThrow(SEEN_INVITE_REMINDER)) == 1;
int defaultSubscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(DEFAULT_SUBSCRIPTION_ID));
int expireMessages = cursor.getInt(cursor.getColumnIndexOrThrow(EXPIRE_MESSAGES));

MaterialColor color;

try {
color = serializedColor == null ? null : MaterialColor.fromSerialized(serializedColor);
} catch (MaterialColor.UnknownColorException e) {
Log.w(TAG, e);
color = null;
}

return new RecipientsPreferences(blocked, muteUntil,
VibrateState.fromId(vibrateState),
notificationUri, color, seenInviteReminder,
defaultSubscriptionId, expireMessages);
}

public void setColor(Recipient recipient, MaterialColor color) {
ContentValues values = new ContentValues();
values.put(COLOR, color.serialize());
Expand Down
80 changes: 54 additions & 26 deletions src/org/thoughtcrime/securesms/database/ThreadDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@
import android.text.TextUtils;
import android.util.Log;

import com.annimon.stream.Stream;

import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterCipher;
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
import org.thoughtcrime.securesms.database.model.DisplayRecord;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
Expand Down Expand Up @@ -83,6 +86,19 @@ public class ThreadDatabase extends Database {
"CREATE INDEX IF NOT EXISTS archived_count_index ON " + TABLE_NAME + " (" + ARCHIVED + ", " + MESSAGE_COUNT + ");",
};

private static final String[] THREAD_PROJECTION = {
ID, DATE, MESSAGE_COUNT, ADDRESS, SNIPPET, SNIPPET_CHARSET, READ, TYPE, ERROR, SNIPPET_TYPE,
SNIPPET_URI, ARCHIVED, STATUS, RECEIPT_COUNT, EXPIRES_IN, LAST_SEEN
};

private static final List<String> TYPED_THREAD_PROJECTION = Stream.of(THREAD_PROJECTION)
.map(columnName -> TABLE_NAME + "." + columnName)
.toList();

private static final List<String> COMBINED_THREAD_RECIPIENT_PROJECTION = Stream.concat(Stream.of(TYPED_THREAD_PROJECTION),
Stream.of(RecipientPreferenceDatabase.TYPED_RECIPIENT_PROJECTION))
.toList();

public ThreadDatabase(Context context, SQLiteOpenHelper databaseHelper) {
super(context, databaseHelper);
}
Expand Down Expand Up @@ -316,26 +332,37 @@ public Cursor getFilteredConversationList(List<Address> filter) {
}

public Cursor getConversationList() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, null, ARCHIVED + " = ? AND " + MESSAGE_COUNT + " != 0", new String[] {"0"}, null, null, DATE + " DESC");

setNotifyConverationListListeners(cursor);

return cursor;
return getConversationList("0");
}

public Cursor getArchivedConversationList() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, null, ARCHIVED + " = ? AND " + MESSAGE_COUNT + " != 0", new String[] {"1"}, null, null, DATE + " DESC");
return getConversationList("1");
}

private Cursor getConversationList(String archived) {
String projection = Util.join(COMBINED_THREAD_RECIPIENT_PROJECTION, ",");
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT " + projection + " FROM " + TABLE_NAME +
" LEFT OUTER JOIN " + RecipientPreferenceDatabase.TABLE_NAME +
" ON " + TABLE_NAME + "." + ADDRESS + " = " + RecipientPreferenceDatabase.TABLE_NAME + "." + ADDRESS +
" WHERE " + ARCHIVED + " = ? AND " + MESSAGE_COUNT + " != 0" +
" ORDER BY " + TABLE_NAME + "." + DATE + " DESC",
new String[] {archived});

setNotifyConverationListListeners(cursor);

return cursor;
}

public Cursor getDirectShareList() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
return db.query(TABLE_NAME, null, null, null, null, null, DATE + " DESC");
SQLiteDatabase db = databaseHelper.getReadableDatabase();
String projection = Util.join(COMBINED_THREAD_RECIPIENT_PROJECTION, ",");

return db.rawQuery("SELECT " + projection + " FROM " + TABLE_NAME +
" LEFT OUTER JOIN " + RecipientPreferenceDatabase.TABLE_NAME +
" ON " + TABLE_NAME + "." + ADDRESS + " = " + RecipientPreferenceDatabase.TABLE_NAME + "." + ADDRESS +
" ORDER BY " + TABLE_NAME + "." + DATE + " DESC",
null);
}

public int getArchivedConversationListCount() {
Expand Down Expand Up @@ -574,22 +601,23 @@ public ThreadRecord getNext() {
}

public ThreadRecord getCurrent() {
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.ADDRESS)));
Recipient recipient = RecipientFactory.getRecipientFor(context, address, true);

DisplayRecord.Body body = getPlaintextBody(cursor);
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
long count = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.MESSAGE_COUNT));
long read = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.READ));
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
int distributionType = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.TYPE));
boolean archived = cursor.getInt(cursor.getColumnIndex(ThreadDatabase.ARCHIVED)) != 0;
int status = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.STATUS));
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.RECEIPT_COUNT));
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.EXPIRES_IN));
long lastSeen = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.LAST_SEEN));
Uri snippetUri = getSnippetUri(cursor);
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.ADDRESS)));
RecipientsPreferences preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientPreferences(cursor);
Recipient recipient = RecipientFactory.getRecipientFor(context, address, preferences, true);

DisplayRecord.Body body = getPlaintextBody(cursor);
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
long count = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.MESSAGE_COUNT));
long read = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.READ));
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
int distributionType = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.TYPE));
boolean archived = cursor.getInt(cursor.getColumnIndex(ThreadDatabase.ARCHIVED)) != 0;
int status = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.STATUS));
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.RECEIPT_COUNT));
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.EXPIRES_IN));
long lastSeen = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.LAST_SEEN));
Uri snippetUri = getSnippetUri(cursor);

return new ThreadRecord(context, body, snippetUri, recipient, date, count, read == 1,
threadId, receiptCount, status, type, distributionType, archived,
Expand Down
10 changes: 9 additions & 1 deletion src/org/thoughtcrime/securesms/recipients/RecipientFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import android.support.annotation.NonNull;

import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
import org.whispersystems.libsignal.util.guava.Optional;

public class RecipientFactory {

Expand All @@ -30,7 +33,12 @@ public class RecipientFactory {

public static @NonNull Recipient getRecipientFor(@NonNull Context context, @NonNull Address address, boolean asynchronous) {
if (address == null) throw new AssertionError(address);
return provider.getRecipient(context, address, asynchronous);
return provider.getRecipient(context, address, Optional.absent(), asynchronous);
}

public static @NonNull Recipient getRecipientFor(@NonNull Context context, @NonNull Address address, @NonNull RecipientsPreferences preferences, boolean asynchronous) {
if (address == null) throw new AssertionError(address);
return provider.getRecipient(context, address, Optional.of(preferences), asynchronous);
}

public static void clearCache(Context context) {
Expand Down
Loading

0 comments on commit a02f223

Please sign in to comment.