Migrate legacy color palette.
We don't store non-user-selected colors in the database. That means that when we update the palette, we still have to hash based off of the legacy palette when generating a color if we want to migrate to a similar-looking color. Unfortunately, because the new palette is smaller, some colors are "overloaded", meaning that when we hash based off of the legacy palette, some colors will be more/less common than others. To fix this, we simply persist all current colors in the database, then switch our hashing list to what we really want.master
parent
5eec3c9541
commit
547b7a3c6f
|
@ -30,6 +30,8 @@ import org.thoughtcrime.securesms.jobmanager.Job;
|
|||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.JavaJobSerializer;
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.PersistentStorage;
|
||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColorsLegacy;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
|
@ -50,6 +52,7 @@ import org.thoughtcrime.securesms.jobs.PushDecryptJob;
|
|||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.FileUtils;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
@ -91,6 +94,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||
public static final int BAD_IMPORT_CLEANUP = 373;
|
||||
public static final int IMAGE_CACHE_CLEANUP = 406;
|
||||
public static final int WORKMANAGER_MIGRATION = 408;
|
||||
public static final int COLOR_MIGRATION = 412;
|
||||
|
||||
private static final SortedSet<Integer> UPGRADE_VERSIONS = new TreeSet<Integer>() {{
|
||||
add(NO_MORE_KEY_EXCHANGE_PREFIX_VERSION);
|
||||
|
@ -115,6 +119,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||
add(BAD_IMPORT_CLEANUP);
|
||||
add(IMAGE_CACHE_CLEANUP);
|
||||
add(WORKMANAGER_MIGRATION);
|
||||
add(COLOR_MIGRATION);
|
||||
}};
|
||||
|
||||
private MasterSecret masterSecret;
|
||||
|
@ -337,6 +342,22 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||
}
|
||||
}
|
||||
|
||||
if (params[0] < COLOR_MIGRATION) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
DatabaseFactory.getRecipientDatabase(context).updateSystemContactColors((name, color) -> {
|
||||
if (color != null) {
|
||||
try {
|
||||
return MaterialColor.fromSerialized(color);
|
||||
} catch (MaterialColor.UnknownColorException e) {
|
||||
Log.w(TAG, "Encountered an unknown color during legacy color migration.", e);
|
||||
return ContactColorsLegacy.generateFor(name);
|
||||
}
|
||||
}
|
||||
return ContactColorsLegacy.generateFor(name);
|
||||
});
|
||||
Log.i(TAG, "Color migration took " + (System.currentTimeMillis() - startTime) + " ms");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ public enum MaterialColor {
|
|||
|
||||
private static final Map<String, MaterialColor> COLOR_MATCHES = new HashMap<String, MaterialColor>() {{
|
||||
put("red", CRIMSON);
|
||||
put("deep_orange", VERMILLION);
|
||||
put("deep_orange", CRIMSON);
|
||||
put("orange", VERMILLION);
|
||||
put("amber", VERMILLION);
|
||||
put("brown", BURLAP);
|
||||
|
|
|
@ -5,35 +5,30 @@ import android.support.annotation.NonNull;
|
|||
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||
import org.thoughtcrime.securesms.color.MaterialColors;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ContactColors {
|
||||
|
||||
public static final MaterialColor UNKNOWN_COLOR = MaterialColor.STEEL;
|
||||
|
||||
private static final String[] LEGACY_PALETTE = new String[] {
|
||||
"red",
|
||||
"pink",
|
||||
"purple",
|
||||
"deep_purple",
|
||||
"indigo",
|
||||
"blue",
|
||||
"light_blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"green",
|
||||
"light_green",
|
||||
"orange",
|
||||
"deep_orange",
|
||||
"amber",
|
||||
"blue_grey"
|
||||
};
|
||||
private static final List<MaterialColor> CONVERSATION_PALETTE = new ArrayList<>(Arrays.asList(
|
||||
MaterialColor.PLUM,
|
||||
MaterialColor.CRIMSON,
|
||||
MaterialColor.VERMILLION,
|
||||
MaterialColor.VIOLET,
|
||||
MaterialColor.BLUE,
|
||||
MaterialColor.INDIGO,
|
||||
MaterialColor.FOREST,
|
||||
MaterialColor.WINTERGREEN,
|
||||
MaterialColor.TEAL,
|
||||
MaterialColor.BURLAP,
|
||||
MaterialColor.TAUPE,
|
||||
MaterialColor.STEEL
|
||||
));
|
||||
|
||||
public static MaterialColor generateFor(@NonNull String name) {
|
||||
String serialized = LEGACY_PALETTE[Math.abs(name.hashCode()) % LEGACY_PALETTE.length];
|
||||
try {
|
||||
return MaterialColor.fromSerialized(serialized);
|
||||
} catch (MaterialColor.UnknownColorException e) {
|
||||
return MaterialColors.CONVERSATION_PALETTE.get(Math.abs(name.hashCode()) % MaterialColors.CONVERSATION_PALETTE.size());
|
||||
}
|
||||
return CONVERSATION_PALETTE.get(Math.abs(name.hashCode()) % CONVERSATION_PALETTE.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package org.thoughtcrime.securesms.contacts.avatars;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||
import org.thoughtcrime.securesms.color.MaterialColors;
|
||||
|
||||
/**
|
||||
* Used for migrating legacy colors to modern colors. For normal color generation, use
|
||||
* {@link ContactColors}.
|
||||
*/
|
||||
public class ContactColorsLegacy {
|
||||
|
||||
private static final String[] LEGACY_PALETTE = new String[] {
|
||||
"red",
|
||||
"pink",
|
||||
"purple",
|
||||
"deep_purple",
|
||||
"indigo",
|
||||
"blue",
|
||||
"light_blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"green",
|
||||
"light_green",
|
||||
"orange",
|
||||
"deep_orange",
|
||||
"amber",
|
||||
"blue_grey"
|
||||
};
|
||||
|
||||
public static MaterialColor generateFor(@NonNull String name) {
|
||||
String serialized = LEGACY_PALETTE[Math.abs(name.hashCode()) % LEGACY_PALETTE.length];
|
||||
try {
|
||||
return MaterialColor.fromSerialized(serialized);
|
||||
} catch (MaterialColor.UnknownColorException e) {
|
||||
return ContactColors.generateFor(name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class RecipientDatabase extends Database {
|
||||
|
||||
|
@ -150,7 +151,6 @@ public class RecipientDatabase extends Database {
|
|||
return new RecipientReader(context, cursor);
|
||||
}
|
||||
|
||||
|
||||
public Optional<RecipientSettings> getRecipientSettings(@NonNull Address address) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
|
@ -410,6 +410,35 @@ public class RecipientDatabase extends Database {
|
|||
return results;
|
||||
}
|
||||
|
||||
public void updateSystemContactColors(@NonNull ColorUpdater updater) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Map<Address, MaterialColor> updates = new HashMap<>();
|
||||
|
||||
db.beginTransaction();
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS, COLOR, SYSTEM_DISPLAY_NAME}, SYSTEM_DISPLAY_NAME + " IS NOT NULL AND " + SYSTEM_DISPLAY_NAME + " != \"\"", null, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
MaterialColor newColor = updater.update(cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_DISPLAY_NAME)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(COLOR)));
|
||||
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(COLOR, newColor.serialize());
|
||||
db.update(TABLE_NAME, contentValues, ADDRESS + " = ?", new String[]{address.serialize()});
|
||||
|
||||
updates.put(address, newColor);
|
||||
}
|
||||
} finally {
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
Stream.of(updates.entrySet()).forEach(entry -> {
|
||||
Recipient.applyCached(entry.getKey(), recipient -> {
|
||||
recipient.setColor(entry.getValue());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// XXX This shouldn't be here, and is just a temporary workaround
|
||||
public RegisteredState isRegistered(@NonNull Address address) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
|
@ -472,6 +501,10 @@ public class RecipientDatabase extends Database {
|
|||
}
|
||||
}
|
||||
|
||||
public interface ColorUpdater {
|
||||
MaterialColor update(@NonNull String name, @Nullable String color);
|
||||
}
|
||||
|
||||
public static class RecipientSettings {
|
||||
private final boolean blocked;
|
||||
private final long muteUntil;
|
||||
|
@ -633,7 +666,7 @@ public class RecipientDatabase extends Database {
|
|||
}
|
||||
|
||||
public @Nullable Recipient getNext() {
|
||||
if (!cursor.moveToNext()) {
|
||||
if (cursor != null && !cursor.moveToNext()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue