From 9e3a6ce97707f185ba183db346614a03de35cb04 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Fri, 6 Sep 2019 11:49:02 +1000 Subject: [PATCH 1/6] Added Identicon --- .../securesms/ConversationListActivity.java | 3 +- .../securesms/components/AvatarImageView.java | 3 +- .../loki/identicon/IdenticonDrawable.kt | 58 ++++++++ .../loki/identicon/JazzIdenticonDrawable.kt | 130 ++++++++++++++++++ .../securesms/loki/identicon/RNG.kt | 29 ++++ .../widgets/ProfilePreference.java | 3 +- 6 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 src/org/thoughtcrime/securesms/loki/identicon/IdenticonDrawable.kt create mode 100644 src/org/thoughtcrime/securesms/loki/identicon/JazzIdenticonDrawable.kt create mode 100644 src/org/thoughtcrime/securesms/loki/identicon/RNG.kt diff --git a/src/org/thoughtcrime/securesms/ConversationListActivity.java b/src/org/thoughtcrime/securesms/ConversationListActivity.java index 42c4d4bbd..1b7095613 100644 --- a/src/org/thoughtcrime/securesms/ConversationListActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationListActivity.java @@ -46,6 +46,7 @@ import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo; import org.thoughtcrime.securesms.lock.RegistrationLockDialog; +import org.thoughtcrime.securesms.loki.identicon.JazzIdenticonDrawable; import org.thoughtcrime.securesms.notifications.MarkReadReceiver; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.permissions.Permissions; @@ -204,7 +205,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit int height = profilePictureImageView.getHeight(); if (width == 0 || height == 0) return true; profilePictureImageView.getViewTreeObserver().removeOnPreDrawListener(this); - ClassicIdenticonDrawable identicon = new ClassicIdenticonDrawable(width, height, recipient.getAddress().serialize().hashCode()); + JazzIdenticonDrawable identicon = new JazzIdenticonDrawable(width, height, recipient.getAddress().serialize()); profilePictureImageView.setImageDrawable(identicon); return true; } diff --git a/src/org/thoughtcrime/securesms/components/AvatarImageView.java b/src/org/thoughtcrime/securesms/components/AvatarImageView.java index ce0fffb72..b9a762726 100644 --- a/src/org/thoughtcrime/securesms/components/AvatarImageView.java +++ b/src/org/thoughtcrime/securesms/components/AvatarImageView.java @@ -17,6 +17,7 @@ import android.view.ViewOutlineProvider; import com.lelloman.identicon.drawable.ClassicIdenticonDrawable; import network.loki.messenger.R; +import org.thoughtcrime.securesms.loki.identicon.JazzIdenticonDrawable; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientExporter; @@ -97,7 +98,7 @@ public class AvatarImageView extends AppCompatImageView { protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (w == 0 || h == 0 || recipient == null) { return; } - ClassicIdenticonDrawable identicon = new ClassicIdenticonDrawable(w, h, recipient.getAddress().serialize().hashCode()); + JazzIdenticonDrawable identicon = new JazzIdenticonDrawable(w, h, recipient.getAddress().serialize()); setImageDrawable(identicon); } diff --git a/src/org/thoughtcrime/securesms/loki/identicon/IdenticonDrawable.kt b/src/org/thoughtcrime/securesms/loki/identicon/IdenticonDrawable.kt new file mode 100644 index 000000000..257b4bf40 --- /dev/null +++ b/src/org/thoughtcrime/securesms/loki/identicon/IdenticonDrawable.kt @@ -0,0 +1,58 @@ +package org.thoughtcrime.securesms.loki.identicon + +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.ColorFilter +import android.graphics.Paint +import android.graphics.Rect +import android.graphics.drawable.Drawable + +/** + * Basically a [Bitmap] wrapper, the [Bitmap] size must be known when instantiating it + * but when drawing it will draw the [Bitmap] to fit the canvas. + */ +abstract class IdenticonDrawable( + width: Int, + height: Int, + hash: Long +) : Drawable() { + + private val bitmapRect: Rect = Rect(0, 0, width, height) + private val destinationRect: Rect = Rect(0, 0, width, height) + private val bitmap: Bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + private val canvas: Canvas = Canvas(bitmap) + private val bitmapPaint = Paint(Paint.ANTI_ALIAS_FLAG) + + var hash: Long = hash + set(value) { + field = value + onSetHash(value) + invalidateBitmap() + } + + protected fun invalidateBitmap() { + drawBitmap(canvas) + invalidateSelf() + } + + protected abstract fun drawBitmap(canvas: Canvas) + + protected open fun onSetHash(newHash: Long) = Unit + + override fun draw(canvas: Canvas) { + destinationRect.set(0, 0, canvas.width, canvas.height) + canvas.drawBitmap(bitmap, bitmapRect, destinationRect, bitmapPaint) + } + + override fun setAlpha(i: Int) { + bitmapPaint.alpha = i + } + + override fun setColorFilter(colorFilter: ColorFilter?) { + bitmapPaint.colorFilter = colorFilter + } + + override fun getOpacity(): Int { + return bitmapPaint.alpha + } +} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/identicon/JazzIdenticonDrawable.kt b/src/org/thoughtcrime/securesms/loki/identicon/JazzIdenticonDrawable.kt new file mode 100644 index 000000000..06c5fc618 --- /dev/null +++ b/src/org/thoughtcrime/securesms/loki/identicon/JazzIdenticonDrawable.kt @@ -0,0 +1,130 @@ +package org.thoughtcrime.securesms.loki.identicon + +import android.graphics.* +import kotlin.math.* + +class JazzIdenticonDrawable(width: Int, height: Int, hash: Long) : IdenticonDrawable(width, height, hash) { + + constructor(width: Int, height: Int, hashString: String): this(width, height, 0) { + val hexRegex = Regex("^[0-9A-Fa-f]+\$") + if (hashString.length >= 12 && hashString.matches(hexRegex)) { + hash = hashString.substring(0 until 12).toLong(16) + } + } + + companion object { + var colors = listOf( + "#01888c", // teal + "#fc7500", // bright orange + "#034f5d", // dark teal + "#E784BA", // light pink + "#81C8B6", // bright green + "#c7144c", // raspberry + "#f3c100", // goldenrod + "#1598f2", // lightning blue + "#2465e1", // sail blue + "#f19e02" // gold + ).map{ Color.parseColor(it) } + } + + private var generator: RNG = RNG(hash) + private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.FILL } + + // Settings + private val wobble: Float = 30f + private val shapeCount = 4 + + init { + invalidateBitmap() + } + + override fun onSetHash(newHash: Long) { + super.onSetHash(newHash) + generator = RNG(newHash) + invalidateBitmap() + } + + override fun drawBitmap(canvas: Canvas) { + generator.reset() + + val newColors = hueShift(colors) + val shuffled = shuffleList(newColors) + + canvas.drawColor(shuffled[0]) + for (i in 0 until shapeCount) { + drawSquare(canvas, shuffled[i + 1], i, shapeCount - 1) + } + } + + private fun drawSquare(canvas: Canvas, color: Int, index: Int, total: Int) { + val size = min(canvas.width, canvas.height) + val center = (size / 2).toFloat() + val firstRotation = generator.nextFloat() + val angle = PI * 2 * firstRotation + + val a = size / total.toFloat() + val b = generator.nextFloat() + val c = index.toFloat() * a + val velocity = a * b + c + + val tx = cos(angle) * velocity + val ty = sin(angle) * velocity + + // Third random is a shape rotation on top of all that + val secondRotation = generator.nextFloat() + val rotation = (firstRotation * 360f) + (secondRotation * 180f) + + // Paint it! + canvas.save() + + paint.color = color + canvas.translate(tx.toFloat(), ty.toFloat()) + canvas.rotate(rotation.round(1), center, center) + canvas.drawRect(0f, 0f, canvas.width.toFloat(), canvas.height.toFloat(), paint) + + canvas.restore() + } + + private fun hueShift(colors: List): List { + val amount = generator.nextFloat() * 30 - wobble / 2 + + return colors.map { color -> + val red = Color.red(color) + val green = Color.green(color) + val blue = Color.blue(color) + + val hsv = FloatArray(3) + Color.RGBToHSV(red, green, blue, hsv) + + // Normalise between 0 and 360 + var newHue = hsv[0] + round(amount) + if (newHue < 0) { newHue += 360 } + if (newHue > 360) { newHue -= 360 } + + hsv[0] = newHue + Color.HSVToColor(hsv) + } + } + + private fun shuffleList(list: List): List { + var currentIndex = list.count() + val newList = list.toMutableList() + while (currentIndex > 0) { + val randomIndex = generator.next().toInt() % currentIndex + currentIndex -= 1 + + // Swap + val temp = newList[currentIndex] + newList[currentIndex] = newList[randomIndex] + newList[randomIndex] = temp + } + + return newList + } +} + +private fun Float.round(decimals: Int): Float { + var multiplier = 1f + repeat(decimals) { multiplier *= 10 } + return round(this * multiplier) / multiplier +} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/identicon/RNG.kt b/src/org/thoughtcrime/securesms/loki/identicon/RNG.kt new file mode 100644 index 000000000..6e43ecaeb --- /dev/null +++ b/src/org/thoughtcrime/securesms/loki/identicon/RNG.kt @@ -0,0 +1,29 @@ +package org.thoughtcrime.securesms.loki.identicon + +class RNG(hash: Long) { + + private var seed: Long + private val initial: Long + + init { + seed = hash % 2147483647 + if (seed <= 0) { + seed = 2147483646 + } + initial = seed + } + + public fun next(): Long { + val newSeed = (seed * 16807) % 2147483647 + seed = newSeed + return seed + } + + public fun nextFloat(): Float { + return (next() - 1).toFloat() / 2147483646 + } + + public fun reset() { + seed = initial + } +} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java b/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java index c67d6c0d1..2838bfc0b 100644 --- a/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java +++ b/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java @@ -21,6 +21,7 @@ import android.widget.Toast; import com.lelloman.identicon.drawable.ClassicIdenticonDrawable; import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.loki.identicon.JazzIdenticonDrawable; import org.thoughtcrime.securesms.util.TextSecurePreferences; import network.loki.messenger.R; @@ -101,7 +102,7 @@ public class ProfilePreference extends Preference { int height = avatarView.getHeight(); if (width == 0 || height == 0) return true; avatarView.getViewTreeObserver().removeOnPreDrawListener(this); - ClassicIdenticonDrawable identicon = new ClassicIdenticonDrawable(width, height, userHexEncodedPublicKey.hashCode()); + JazzIdenticonDrawable identicon = new JazzIdenticonDrawable(width, height, userHexEncodedPublicKey); avatarView.setImageDrawable(identicon); return true; } From e054740ce0f15021d20b03bc20e1ea998e627486 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Fri, 6 Sep 2019 14:08:46 +1000 Subject: [PATCH 2/6] Disable identicon generation for groups. --- .../securesms/components/AvatarImageView.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/components/AvatarImageView.java b/src/org/thoughtcrime/securesms/components/AvatarImageView.java index b9a762726..dfaf053a0 100644 --- a/src/org/thoughtcrime/securesms/components/AvatarImageView.java +++ b/src/org/thoughtcrime/securesms/components/AvatarImageView.java @@ -6,10 +6,12 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Outline; import android.graphics.Paint; +import android.graphics.drawable.Drawable; import android.provider.ContactsContract; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.widget.AppCompatImageView; +import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; @@ -17,11 +19,16 @@ import android.view.ViewOutlineProvider; import com.lelloman.identicon.drawable.ClassicIdenticonDrawable; import network.loki.messenger.R; +import org.thoughtcrime.securesms.color.MaterialColor; +import org.thoughtcrime.securesms.contacts.avatars.ContactColors; +import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto; import org.thoughtcrime.securesms.loki.identicon.JazzIdenticonDrawable; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientExporter; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.ThemeUtil; +import org.whispersystems.libsignal.util.guava.Optional; public class AvatarImageView extends AppCompatImageView { @@ -98,8 +105,23 @@ public class AvatarImageView extends AppCompatImageView { protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (w == 0 || h == 0 || recipient == null) { return; } - JazzIdenticonDrawable identicon = new JazzIdenticonDrawable(w, h, recipient.getAddress().serialize()); - setImageDrawable(identicon); + + Drawable image; + if (recipient.isGroupRecipient()) { + Context context = this.getContext(); + + String name = Optional.fromNullable(recipient.getName()).or(Optional.fromNullable(TextSecurePreferences.getProfileName(context))).or(""); + MaterialColor fallbackColor = recipient.getColor(); + + if (fallbackColor == ContactColors.UNKNOWN_COLOR && !TextUtils.isEmpty(name)) { + fallbackColor = ContactColors.generateFor(name); + } + + image = new GeneratedContactPhoto(name, R.drawable.ic_profile_default).asDrawable(context, fallbackColor.toAvatarColor(context)); + } else { + image = new JazzIdenticonDrawable(w, h, recipient.getAddress().serialize()); + } + setImageDrawable(image); } public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) { From 7ff27b572f34d72e1d7c0d7aa49de7a1798ae102 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Fri, 6 Sep 2019 16:18:26 +1000 Subject: [PATCH 3/6] Fix identicons for public chats --- src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt index a5c57e31f..e1053d38b 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt @@ -94,7 +94,7 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) val x2 = SignalServiceDataMessage(message.timestamp, x1, null, message.body) val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" - val x3 = SignalServiceContent(x2, senderDisplayName, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) + val x3 = SignalServiceContent(x2, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) } fun processOutgoingMessage(message: LokiGroupMessage) { From 842be4378a81cf5b32ea0b66a99e64491d4beb88 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 9 Sep 2019 12:53:31 +1000 Subject: [PATCH 4/6] Show correct names on public chats. --- .../conversation/ConversationItem.java | 20 +++++++------- .../database/helpers/SQLCipherOpenHelper.java | 10 +++++-- .../securesms/loki/LokiGroupChatPoller.kt | 5 +++- .../securesms/loki/LokiUserDatabase.kt | 26 ++++++++++++++++++- .../securesms/util/GroupUtil.java | 6 ++++- 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java index c089c50f1..35b1be25d 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -99,15 +99,7 @@ import org.thoughtcrime.securesms.mms.TextSlide; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.stickers.StickerUrl; -import org.thoughtcrime.securesms.util.DateUtils; -import org.thoughtcrime.securesms.util.DynamicTheme; -import org.thoughtcrime.securesms.util.LongClickCopySpan; -import org.thoughtcrime.securesms.util.LongClickMovementMethod; -import org.thoughtcrime.securesms.util.SearchUtil; -import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.thoughtcrime.securesms.util.ThemeUtil; -import org.thoughtcrime.securesms.util.Util; -import org.thoughtcrime.securesms.util.ViewUtil; +import org.thoughtcrime.securesms.util.*; import org.thoughtcrime.securesms.util.views.Stub; import org.whispersystems.libsignal.util.guava.Optional; @@ -883,7 +875,15 @@ public class ConversationItem extends LinearLayout @SuppressLint("SetTextI18n") private void setGroupMessageStatus(MessageRecord messageRecord, Recipient recipient) { if (groupThread && !messageRecord.isOutgoing()) { - this.groupSender.setText(recipient.toShortString()); + // Show custom display names for group chats + String displayName = recipient.toShortString(); + try { + String serverId = GroupUtil.getDecodedStringId(conversationRecipient.getAddress().serialize()); + String senderDisplayName = DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(serverId, recipient.getAddress().serialize()); + if (senderDisplayName != null) { displayName = senderDisplayName; } + } catch (Exception e) {} + + this.groupSender.setText(displayName); if (recipient.getName() == null && !TextUtils.isEmpty(recipient.getProfileName())) { this.groupSenderProfileName.setText("~" + recipient.getProfileName()); diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index 5c54f7d13..31ca0310e 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -73,8 +73,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final int JOBMANAGER_STRIKES_BACK = 20; private static final int STICKERS = 21; private static final int lokiV1 = 22; + private static final int lokiV2 = 23; - private static final int DATABASE_VERSION = lokiV1; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes + private static final int DATABASE_VERSION = lokiV2; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes private static final String DATABASE_NAME = "signal.db"; private final Context context; @@ -134,7 +135,8 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(LokiMessageDatabase.getCreateTableCommand()); db.execSQL(LokiThreadDatabase.getCreateFriendRequestTableCommand()); db.execSQL(LokiThreadDatabase.getCreateSessionResetTableCommand()); - db.execSQL(LokiUserDatabase.getCreateTableCommand()); + db.execSQL(LokiUserDatabase.getCreateDisplayNameTableCommand()); + db.execSQL(LokiUserDatabase.getCreateServerDisplayNameTableCommand()); executeStatements(db, SmsDatabase.CREATE_INDEXS); executeStatements(db, MmsDatabase.CREATE_INDEXS); @@ -493,6 +495,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(LokiAPIDatabase.getCreateLastDeletionServerIDTableCommand()); } + if (oldVersion < lokiV2) { + db.execSQL(LokiUserDatabase.getCreateServerDisplayNameTableCommand()); + } + db.setTransactionSuccessful(); } finally { db.endTransaction(); diff --git a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt index e1053d38b..b0e6fcb59 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt @@ -93,9 +93,12 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG val id = group.id.toByteArray() val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) val x2 = SignalServiceDataMessage(message.timestamp, x1, null, message.body) - val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" val x3 = SignalServiceContent(x2, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) + PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) + + val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" + DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) } fun processOutgoingMessage(message: LokiGroupMessage) { val messageServerID = message.serverID ?: return diff --git a/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt b/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt index 50a2faee8..fd71896a0 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.loki import android.content.ContentValues import android.content.Context +import android.database.sqlite.SQLiteDatabase import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.Database import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper @@ -13,9 +14,12 @@ class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database companion object { private val displayNameTable = "loki_user_display_name_database" + private val serverDisplayNameTable = "loki_user_server_display_name_database" private val hexEncodedPublicKey = "hex_encoded_public_key" private val displayName = "display_name" - @JvmStatic val createTableCommand = "CREATE TABLE $displayNameTable ($hexEncodedPublicKey TEXT PRIMARY KEY, $displayName TEXT);" + private val serverId = "server_id" + @JvmStatic val createDisplayNameTableCommand = "CREATE TABLE $displayNameTable ($hexEncodedPublicKey TEXT PRIMARY KEY, $displayName TEXT);" + @JvmStatic val createServerDisplayNameTableCommand = "CREATE TABLE $serverDisplayNameTable ($hexEncodedPublicKey TEXT, $serverId TEXT, $displayName TEXT, PRIMARY KEY ($hexEncodedPublicKey, $serverId));" } override fun getDisplayName(hexEncodedPublicKey: String): String? { @@ -37,4 +41,24 @@ class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database database.insertOrUpdate(displayNameTable, row, "${Companion.hexEncodedPublicKey} = ?", arrayOf( hexEncodedPublicKey )) Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false).notifyListeners() } + + fun getServerDisplayName(serverId: String, hexEncodedPublicKey: String): String? { + val database = databaseHelper.readableDatabase + return database.get(serverDisplayNameTable, "${Companion.hexEncodedPublicKey} = ? AND ${Companion.serverId} = ?", arrayOf(hexEncodedPublicKey, serverId)) { cursor -> + cursor.getString(cursor.getColumnIndexOrThrow(displayName)) + } + } + + fun setServerDisplayName(serverId: String, hexEncodedPublicKey: String, displayName: String) { + val database = databaseHelper.writableDatabase + val values = ContentValues(3) + values.put(Companion.serverId, serverId) + values.put(Companion.hexEncodedPublicKey, hexEncodedPublicKey) + values.put(Companion.displayName, displayName) + try { + database.insertWithOnConflict(serverDisplayNameTable, null, values, SQLiteDatabase.CONFLICT_REPLACE) + } catch (e: Exception) { + print(e) + } + } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/util/GroupUtil.java b/src/org/thoughtcrime/securesms/util/GroupUtil.java index 6b83304ee..224887fb0 100644 --- a/src/org/thoughtcrime/securesms/util/GroupUtil.java +++ b/src/org/thoughtcrime/securesms/util/GroupUtil.java @@ -15,7 +15,6 @@ import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; -import org.thoughtcrime.securesms.sms.MessageSender; import org.whispersystems.libsignal.util.guava.Optional; import java.io.IOException; @@ -43,6 +42,11 @@ public class GroupUtil { return Hex.fromStringCondensed(groupId.split("!", 2)[1]); } + public static String getDecodedStringId(String groupId) throws IOException { + byte[] id = getDecodedId(groupId); + return new String(id); + } + public static boolean isEncodedGroup(@NonNull String groupId) { return groupId.startsWith(ENCODED_SIGNAL_GROUP_PREFIX) || groupId.startsWith(ENCODED_MMS_GROUP_PREFIX); } From 7c6c551b32df42f68168c64d3e9dca5c73d3f9e1 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 9 Sep 2019 13:20:59 +1000 Subject: [PATCH 5/6] Fix order of execution. --- src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt | 4 ++-- src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt index b0e6fcb59..3a5c94f36 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt @@ -95,10 +95,10 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG val x2 = SignalServiceDataMessage(message.timestamp, x1, null, message.body) val x3 = SignalServiceContent(x2, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) - PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) - val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) + + PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) } fun processOutgoingMessage(message: LokiGroupMessage) { val messageServerID = message.serverID ?: return diff --git a/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt b/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt index fd71896a0..4b16d8432 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt @@ -57,6 +57,7 @@ class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database values.put(Companion.displayName, displayName) try { database.insertWithOnConflict(serverDisplayNameTable, null, values, SQLiteDatabase.CONFLICT_REPLACE) + Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false).notifyListeners() } catch (e: Exception) { print(e) } From fd389a637a8f7e607b789695eb1e6a06bfb81ea8 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 10 Sep 2019 13:50:59 +1000 Subject: [PATCH 6/6] Clean --- .../securesms/ConversationListActivity.java | 4 +--- .../securesms/components/AvatarImageView.java | 7 +++--- .../conversation/ConversationItem.java | 4 +++- .../loki/{identicon => }/IdenticonDrawable.kt | 15 +++--------- .../{identicon => }/JazzIdenticonDrawable.kt | 6 +++-- .../securesms/loki/LokiGroupChatPoller.kt | 2 -- .../securesms/loki/LokiUserDatabase.kt | 24 +++++++++++-------- .../securesms/loki/{identicon => }/RNG.kt | 9 ++++--- .../widgets/ProfilePreference.java | 4 +--- 9 files changed, 33 insertions(+), 42 deletions(-) rename src/org/thoughtcrime/securesms/loki/{identicon => }/IdenticonDrawable.kt (79%) rename src/org/thoughtcrime/securesms/loki/{identicon => }/JazzIdenticonDrawable.kt (96%) rename src/org/thoughtcrime/securesms/loki/{identicon => }/RNG.kt (72%) diff --git a/src/org/thoughtcrime/securesms/ConversationListActivity.java b/src/org/thoughtcrime/securesms/ConversationListActivity.java index 1b7095613..ddd3ad3df 100644 --- a/src/org/thoughtcrime/securesms/ConversationListActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationListActivity.java @@ -37,8 +37,6 @@ import android.view.ViewTreeObserver; import android.widget.ImageView; import android.widget.Toast; -import com.lelloman.identicon.drawable.ClassicIdenticonDrawable; - import org.thoughtcrime.securesms.components.RatingManager; import org.thoughtcrime.securesms.components.SearchToolbar; import org.thoughtcrime.securesms.conversation.ConversationActivity; @@ -46,7 +44,7 @@ import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo; import org.thoughtcrime.securesms.lock.RegistrationLockDialog; -import org.thoughtcrime.securesms.loki.identicon.JazzIdenticonDrawable; +import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable; import org.thoughtcrime.securesms.notifications.MarkReadReceiver; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.permissions.Permissions; diff --git a/src/org/thoughtcrime/securesms/components/AvatarImageView.java b/src/org/thoughtcrime/securesms/components/AvatarImageView.java index dfaf053a0..5a3db4bbc 100644 --- a/src/org/thoughtcrime/securesms/components/AvatarImageView.java +++ b/src/org/thoughtcrime/securesms/components/AvatarImageView.java @@ -16,13 +16,10 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; -import com.lelloman.identicon.drawable.ClassicIdenticonDrawable; - -import network.loki.messenger.R; import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.contacts.avatars.ContactColors; import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto; -import org.thoughtcrime.securesms.loki.identicon.JazzIdenticonDrawable; +import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientExporter; @@ -30,6 +27,8 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.ThemeUtil; import org.whispersystems.libsignal.util.guava.Optional; +import network.loki.messenger.R; + public class AvatarImageView extends AppCompatImageView { private static final String TAG = AvatarImageView.class.getSimpleName(); diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java index 35b1be25d..6dc4cf67c 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -881,7 +881,9 @@ public class ConversationItem extends LinearLayout String serverId = GroupUtil.getDecodedStringId(conversationRecipient.getAddress().serialize()); String senderDisplayName = DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(serverId, recipient.getAddress().serialize()); if (senderDisplayName != null) { displayName = senderDisplayName; } - } catch (Exception e) {} + } catch (Exception e) { + // Do nothing + } this.groupSender.setText(displayName); diff --git a/src/org/thoughtcrime/securesms/loki/identicon/IdenticonDrawable.kt b/src/org/thoughtcrime/securesms/loki/IdenticonDrawable.kt similarity index 79% rename from src/org/thoughtcrime/securesms/loki/identicon/IdenticonDrawable.kt rename to src/org/thoughtcrime/securesms/loki/IdenticonDrawable.kt index 257b4bf40..86d69ce99 100644 --- a/src/org/thoughtcrime/securesms/loki/identicon/IdenticonDrawable.kt +++ b/src/org/thoughtcrime/securesms/loki/IdenticonDrawable.kt @@ -1,22 +1,13 @@ -package org.thoughtcrime.securesms.loki.identicon +package org.thoughtcrime.securesms.loki -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.ColorFilter -import android.graphics.Paint -import android.graphics.Rect +import android.graphics.* import android.graphics.drawable.Drawable /** * Basically a [Bitmap] wrapper, the [Bitmap] size must be known when instantiating it * but when drawing it will draw the [Bitmap] to fit the canvas. */ -abstract class IdenticonDrawable( - width: Int, - height: Int, - hash: Long -) : Drawable() { - +abstract class IdenticonDrawable(width: Int, height: Int, hash: Long) : Drawable() { private val bitmapRect: Rect = Rect(0, 0, width, height) private val destinationRect: Rect = Rect(0, 0, width, height) private val bitmap: Bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) diff --git a/src/org/thoughtcrime/securesms/loki/identicon/JazzIdenticonDrawable.kt b/src/org/thoughtcrime/securesms/loki/JazzIdenticonDrawable.kt similarity index 96% rename from src/org/thoughtcrime/securesms/loki/identicon/JazzIdenticonDrawable.kt rename to src/org/thoughtcrime/securesms/loki/JazzIdenticonDrawable.kt index 06c5fc618..ff678db54 100644 --- a/src/org/thoughtcrime/securesms/loki/identicon/JazzIdenticonDrawable.kt +++ b/src/org/thoughtcrime/securesms/loki/JazzIdenticonDrawable.kt @@ -1,6 +1,8 @@ -package org.thoughtcrime.securesms.loki.identicon +package org.thoughtcrime.securesms.loki -import android.graphics.* +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint import kotlin.math.* class JazzIdenticonDrawable(width: Int, height: Int, hash: Long) : IdenticonDrawable(width, height, hash) { diff --git a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt index 3a5c94f36..bf8c86458 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt @@ -94,10 +94,8 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) val x2 = SignalServiceDataMessage(message.timestamp, x1, null, message.body) val x3 = SignalServiceContent(x2, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) - val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) - PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) } fun processOutgoingMessage(message: LokiGroupMessage) { diff --git a/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt b/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt index 4b16d8432..5b907f8be 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiUserDatabase.kt @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.loki import android.content.ContentValues import android.content.Context import android.database.sqlite.SQLiteDatabase +import android.util.Log import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.Database import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper @@ -13,13 +14,16 @@ import org.whispersystems.signalservice.loki.messaging.LokiUserDatabaseProtocol class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiUserDatabaseProtocol { companion object { - private val displayNameTable = "loki_user_display_name_database" - private val serverDisplayNameTable = "loki_user_server_display_name_database" - private val hexEncodedPublicKey = "hex_encoded_public_key" + // Shared private val displayName = "display_name" - private val serverId = "server_id" + // Display name cache + private val displayNameTable = "loki_user_display_name_database" + private val hexEncodedPublicKey = "hex_encoded_public_key" @JvmStatic val createDisplayNameTableCommand = "CREATE TABLE $displayNameTable ($hexEncodedPublicKey TEXT PRIMARY KEY, $displayName TEXT);" - @JvmStatic val createServerDisplayNameTableCommand = "CREATE TABLE $serverDisplayNameTable ($hexEncodedPublicKey TEXT, $serverId TEXT, $displayName TEXT, PRIMARY KEY ($hexEncodedPublicKey, $serverId));" + // Server display name cache + private val serverDisplayNameTable = "loki_user_server_display_name_database" + private val serverID = "server_id" + @JvmStatic val createServerDisplayNameTableCommand = "CREATE TABLE $serverDisplayNameTable ($hexEncodedPublicKey TEXT, $serverID TEXT, $displayName TEXT, PRIMARY KEY ($hexEncodedPublicKey, $serverID));" } override fun getDisplayName(hexEncodedPublicKey: String): String? { @@ -42,24 +46,24 @@ class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false).notifyListeners() } - fun getServerDisplayName(serverId: String, hexEncodedPublicKey: String): String? { + fun getServerDisplayName(serverID: String, hexEncodedPublicKey: String): String? { val database = databaseHelper.readableDatabase - return database.get(serverDisplayNameTable, "${Companion.hexEncodedPublicKey} = ? AND ${Companion.serverId} = ?", arrayOf(hexEncodedPublicKey, serverId)) { cursor -> + return database.get(serverDisplayNameTable, "${Companion.hexEncodedPublicKey} = ? AND ${Companion.serverID} = ?", arrayOf(hexEncodedPublicKey, serverID)) { cursor -> cursor.getString(cursor.getColumnIndexOrThrow(displayName)) } } - fun setServerDisplayName(serverId: String, hexEncodedPublicKey: String, displayName: String) { + fun setServerDisplayName(serverID: String, hexEncodedPublicKey: String, displayName: String) { val database = databaseHelper.writableDatabase val values = ContentValues(3) - values.put(Companion.serverId, serverId) + values.put(Companion.serverID, serverID) values.put(Companion.hexEncodedPublicKey, hexEncodedPublicKey) values.put(Companion.displayName, displayName) try { database.insertWithOnConflict(serverDisplayNameTable, null, values, SQLiteDatabase.CONFLICT_REPLACE) Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false).notifyListeners() } catch (e: Exception) { - print(e) + Log.d("Loki", "Couldn't save server display name due to exception: $e.") } } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/identicon/RNG.kt b/src/org/thoughtcrime/securesms/loki/RNG.kt similarity index 72% rename from src/org/thoughtcrime/securesms/loki/identicon/RNG.kt rename to src/org/thoughtcrime/securesms/loki/RNG.kt index 6e43ecaeb..208414785 100644 --- a/src/org/thoughtcrime/securesms/loki/identicon/RNG.kt +++ b/src/org/thoughtcrime/securesms/loki/RNG.kt @@ -1,7 +1,6 @@ -package org.thoughtcrime.securesms.loki.identicon +package org.thoughtcrime.securesms.loki class RNG(hash: Long) { - private var seed: Long private val initial: Long @@ -13,17 +12,17 @@ class RNG(hash: Long) { initial = seed } - public fun next(): Long { + fun next(): Long { val newSeed = (seed * 16807) % 2147483647 seed = newSeed return seed } - public fun nextFloat(): Float { + fun nextFloat(): Float { return (next() - 1).toFloat() / 2147483646 } - public fun reset() { + fun reset() { seed = initial } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java b/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java index 2838bfc0b..49e60e1f9 100644 --- a/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java +++ b/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java @@ -18,10 +18,8 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; -import com.lelloman.identicon.drawable.ClassicIdenticonDrawable; - import org.thoughtcrime.securesms.database.Address; -import org.thoughtcrime.securesms.loki.identicon.JazzIdenticonDrawable; +import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable; import org.thoughtcrime.securesms.util.TextSecurePreferences; import network.loki.messenger.R;