Move StickerRecord into core-util.

This commit is contained in:
Alex Hart
2026-07-30 14:29:48 -03:00
parent 0182ee3ac3
commit ed754c1d30
27 changed files with 138 additions and 50 deletions
@@ -36,6 +36,7 @@ import org.signal.aesgcmprovider.AesGcmProvider;
import org.signal.core.util.AppForegroundObserver;
import org.signal.core.util.DiskUtil;
import org.signal.core.util.MemoryTracker;
import org.signal.core.util.PartAuthorityUris;
import org.signal.core.util.Util;
import org.signal.core.util.concurrent.AnrDetector;
import org.signal.core.util.concurrent.SignalExecutors;
@@ -166,6 +167,8 @@ public class ApplicationContext extends Application implements AppForegroundObse
@Override
public void onCreate() {
PartAuthorityUris.init(BuildConfig.APPLICATION_ID);
Tracer.getInstance().start("Application#onCreate()");
AppStartup.getInstance().onApplicationCreate();
SignalLocalMetrics.ColdStart.start();
@@ -8,8 +8,8 @@ package org.thoughtcrime.securesms.attachments
import android.net.Uri
import android.os.Parcel
import androidx.core.os.ParcelCompat
import org.signal.core.models.database.StickerRecord
import org.thoughtcrime.securesms.database.AttachmentTable
import org.thoughtcrime.securesms.database.model.StickerRecord
import org.thoughtcrime.securesms.mms.StickerSlide
import org.thoughtcrime.securesms.stickers.StickerLocator
import java.security.SecureRandom
@@ -38,6 +38,7 @@ import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.signal.core.models.database.StickerRecord;
import org.signal.core.ui.view.Stub;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.concurrent.ListenableFuture;
@@ -61,7 +62,6 @@ import org.thoughtcrime.securesms.database.model.MessageId;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.database.model.Quote;
import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.thoughtcrime.securesms.keyboard.KeyboardPage;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
@@ -12,7 +12,7 @@ import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.signal.core.models.database.StickerRecord;
import org.signal.glide.decryptableuri.DecryptableUri;
import java.util.ArrayList;
@@ -109,6 +109,7 @@ import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.signal.core.models.database.StickerRecord
import org.signal.core.models.media.Media
import org.signal.core.models.media.TransformProperties
import org.signal.core.ui.BottomSheetUtil
@@ -257,7 +258,6 @@ import org.thoughtcrime.securesms.database.model.MessageId
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.Quote
import org.thoughtcrime.securesms.database.model.StickerRecord
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
import org.thoughtcrime.securesms.databinding.V2ConversationFragmentBinding
import org.thoughtcrime.securesms.dependencies.AppDependencies
@@ -24,6 +24,7 @@ import io.reactivex.rxjava3.core.Maybe
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.core.SingleEmitter
import io.reactivex.rxjava3.schedulers.Schedulers
import org.signal.core.models.database.StickerRecord
import org.signal.core.util.DrawableUtil
import org.signal.core.util.StreamUtil
import org.signal.core.util.Util
@@ -62,7 +63,6 @@ import org.thoughtcrime.securesms.database.model.MessageId
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.ReactionRecord
import org.thoughtcrime.securesms.database.model.StickerRecord
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras
import org.thoughtcrime.securesms.database.model.databaseprotos.PinnedMessage
@@ -44,6 +44,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx3.asFlow
import org.signal.core.models.ServiceId
import org.signal.core.models.database.StickerRecord
import org.signal.core.util.concurrent.SignalDispatchers
import org.signal.core.util.logging.Log
import org.signal.core.util.orNull
@@ -74,7 +75,6 @@ import org.thoughtcrime.securesms.database.model.MessageId
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.ReactionRecord
import org.thoughtcrime.securesms.database.model.StickerRecord
import org.thoughtcrime.securesms.database.model.StoryViewState
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
import org.thoughtcrime.securesms.dependencies.AppDependencies
@@ -8,7 +8,7 @@ package org.thoughtcrime.securesms.conversation.v2
import androidx.lifecycle.ViewModel
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.processors.BehaviorProcessor
import org.thoughtcrime.securesms.database.model.StickerRecord
import org.signal.core.models.database.StickerRecord
import org.thoughtcrime.securesms.stickers.StickerSearchRepository
class StickerSuggestionsViewModel(
@@ -4,6 +4,7 @@ import android.content.Context
import android.database.Cursor
import androidx.core.content.contentValuesOf
import org.greenrobot.eventbus.EventBus
import org.signal.core.models.database.StickerRecord
import org.signal.core.util.Base64
import org.signal.core.util.Hex
import org.signal.core.util.SqlUtil
@@ -40,7 +41,6 @@ import org.thoughtcrime.securesms.database.model.StickerPackId
import org.thoughtcrime.securesms.database.model.StickerPackKey
import org.thoughtcrime.securesms.database.model.StickerPackRecord
import org.thoughtcrime.securesms.database.model.StickerPackSyncRecord
import org.thoughtcrime.securesms.database.model.StickerRecord
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob
import org.thoughtcrime.securesms.stickers.BlessedPacks
@@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.database.model
import android.net.Uri
import org.signal.core.models.database.StickerRecord
import org.signal.core.util.orNull
import org.thoughtcrime.securesms.stickers.StickerUrl
import org.whispersystems.signalservice.api.storage.StorageId
@@ -3,11 +3,11 @@ package org.thoughtcrime.securesms.jobs;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.models.database.StickerRecord;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.StickerTables;
import org.thoughtcrime.securesms.database.model.IncomingSticker;
import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
import org.thoughtcrime.securesms.jobmanager.Job;
@@ -6,10 +6,10 @@ import android.widget.ImageView
import android.widget.TextView
import com.bumptech.glide.RequestManager
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import org.signal.core.models.database.StickerRecord
import org.signal.glide.apng.ApngOptions
import org.signal.glide.decryptableuri.DecryptableUri
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.database.model.StickerRecord
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel
@@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.keyboard.sticker
import android.net.Uri
import org.signal.core.models.database.StickerRecord
import org.signal.core.util.concurrent.SignalExecutors
import org.signal.core.util.nullIfBlank
import org.thoughtcrime.securesms.R
@@ -8,7 +9,6 @@ import org.thoughtcrime.securesms.database.StickerTables
import org.thoughtcrime.securesms.database.StickerTables.StickerPackRecordReader
import org.thoughtcrime.securesms.database.StickerTables.StickerRecordReader
import org.thoughtcrime.securesms.database.model.StickerPackRecord
import org.thoughtcrime.securesms.database.model.StickerRecord
import java.util.function.Consumer
private const val RECENT_LIMIT = 24
@@ -1,12 +1,12 @@
package org.thoughtcrime.securesms.keyboard.sticker
import androidx.annotation.WorkerThread
import org.signal.core.models.database.StickerRecord
import org.thoughtcrime.securesms.components.emoji.EmojiUtil
import org.thoughtcrime.securesms.database.EmojiSearchTable
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.StickerTables
import org.thoughtcrime.securesms.database.StickerTables.StickerRecordReader
import org.thoughtcrime.securesms.database.model.StickerRecord
private const val RECENT_LIMIT = 24
private const val EMOJI_SEARCH_RESULTS_LIMIT = 20
@@ -6,6 +6,7 @@ import com.mobilecoin.lib.exceptions.SerializationException
import okio.ByteString.Companion.toByteString
import org.signal.core.models.ServiceId
import org.signal.core.models.ServiceId.ACI
import org.signal.core.models.database.StickerRecord
import org.signal.core.util.Base64
import org.signal.core.util.Hex
import org.signal.core.util.UuidUtil
@@ -40,7 +41,6 @@ import org.thoughtcrime.securesms.database.model.ParentStoryId
import org.thoughtcrime.securesms.database.model.ParentStoryId.DirectReply
import org.thoughtcrime.securesms.database.model.ParentStoryId.GroupReply
import org.thoughtcrime.securesms.database.model.ReactionRecord
import org.thoughtcrime.securesms.database.model.StickerRecord
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras
@@ -14,7 +14,7 @@ import androidx.core.provider.DocumentsContractCompat;
import org.signal.core.models.database.AttachmentId;
import org.signal.core.models.media.TransformProperties;
import org.thoughtcrime.securesms.BuildConfig;
import org.signal.core.util.PartAuthorityUris;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.avatar.AvatarPickerStorage;
import org.thoughtcrime.securesms.database.SignalDatabase;
@@ -28,18 +28,6 @@ import java.io.InputStream;
public class PartAuthority {
private static final String AUTHORITY = BuildConfig.APPLICATION_ID;
private static final String PART_URI_STRING = "content://" + AUTHORITY + "/part";
private static final String PART_THUMBNAIL_STRING = "content://" + AUTHORITY + "/thumbnail";
private static final String STICKER_URI_STRING = "content://" + AUTHORITY + "/sticker";
private static final String EMOJI_URI_STRING = "content://" + AUTHORITY + "/emoji";
private static final String AVATAR_PICKER_URI_STRING = "content://" + AUTHORITY + "/avatar_picker";
private static final Uri PART_CONTENT_URI = Uri.parse(PART_URI_STRING);
private static final Uri PART_THUMBNAIL_URI = Uri.parse(PART_THUMBNAIL_STRING);
private static final Uri STICKER_CONTENT_URI = Uri.parse(STICKER_URI_STRING);
private static final Uri EMOJI_CONTENT_URI = Uri.parse(EMOJI_URI_STRING);
private static final Uri AVATAR_PICKER_CONTENT_URI = Uri.parse(AVATAR_PICKER_URI_STRING);
private static final int PART_ROW = 1;
private static final int BLOB_ROW = 3;
private static final int STICKER_ROW = 4;
@@ -51,13 +39,15 @@ public class PartAuthority {
private static final UriMatcher uriMatcher;
static {
String authority = PartAuthorityUris.getAuthority();
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "part/#", PART_ROW);
uriMatcher.addURI(AUTHORITY, "thumbnail/#", THUMBNAIL_ROW);
uriMatcher.addURI(AUTHORITY, "sticker/#", STICKER_ROW);
uriMatcher.addURI(AUTHORITY, "wallpaper/*", WALLPAPER_ROW);
uriMatcher.addURI(AUTHORITY, "emoji/*", EMOJI_ROW);
uriMatcher.addURI(AUTHORITY, "avatar_picker/*", AVATAR_PICKER_ROW);
uriMatcher.addURI(authority, PartAuthorityUris.PATH_PART + "/#", PART_ROW);
uriMatcher.addURI(authority, PartAuthorityUris.PATH_THUMBNAIL + "/#", THUMBNAIL_ROW);
uriMatcher.addURI(authority, PartAuthorityUris.PATH_STICKER + "/#", STICKER_ROW);
uriMatcher.addURI(authority, PartAuthorityUris.PATH_WALLPAPER + "/*", WALLPAPER_ROW);
uriMatcher.addURI(authority, PartAuthorityUris.PATH_EMOJI + "/*", EMOJI_ROW);
uriMatcher.addURI(authority, PartAuthorityUris.PATH_AVATAR_PICKER + "/*", AVATAR_PICKER_ROW);
uriMatcher.addURI(AppDependencies.getBlobs().getAuthority(), AppDependencies.getBlobs().PATH, BLOB_ROW);
}
@@ -164,35 +154,35 @@ public class PartAuthority {
}
public static Uri getAttachmentDataUri(AttachmentId attachmentId) {
return ContentUris.withAppendedId(PART_CONTENT_URI, attachmentId.id);
return PartAuthorityUris.getAttachmentDataUri(attachmentId);
}
public static Uri getAttachmentThumbnailUri(AttachmentId attachmentId) {
return ContentUris.withAppendedId(PART_THUMBNAIL_URI, attachmentId.id);
return PartAuthorityUris.getAttachmentThumbnailUri(attachmentId);
}
public static Uri getStickerUri(long id) {
return ContentUris.withAppendedId(STICKER_CONTENT_URI, id);
return PartAuthorityUris.getStickerUri(id);
}
public static Uri getAvatarPickerUri(String filename) {
return Uri.withAppendedPath(AVATAR_PICKER_CONTENT_URI, filename);
return PartAuthorityUris.getAvatarPickerUri(filename);
}
public static Uri getEmojiUri(String sprite) {
return Uri.withAppendedPath(EMOJI_CONTENT_URI, sprite);
return PartAuthorityUris.getEmojiUri(sprite);
}
public static String getWallpaperFilename(Uri uri) {
return uri.getPathSegments().get(1);
return PartAuthorityUris.getFilename(uri);
}
public static String getEmojiFilename(Uri uri) {
return uri.getPathSegments().get(1);
return PartAuthorityUris.getFilename(uri);
}
public static String getAvatarPickerFilename(Uri uri) {
return uri.getPathSegments().get(1);
return PartAuthorityUris.getFilename(uri);
}
public static boolean isLocalUri(final @NonNull Uri uri) {
@@ -14,6 +14,7 @@ import android.database.Cursor
import android.graphics.Bitmap
import android.net.Uri
import android.os.ParcelFileDescriptor
import org.signal.core.util.PartAuthorityUris
import org.signal.core.util.concurrent.SignalExecutors
import org.signal.core.util.contentproviders.BaseContentProvider
import org.signal.core.util.crypto.AttachmentSecretProvider
@@ -71,6 +72,8 @@ class AvatarProvider : BaseContentProvider() {
private fun init(): Application? {
val application = context as? ApplicationContext ?: return null
PartAuthorityUris.init(BuildConfig.APPLICATION_ID)
SqlCipherLibraryLoader.load()
SignalDatabase.init(
application,
@@ -14,11 +14,11 @@ import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import org.signal.core.models.database.StickerRecord;
import org.signal.core.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.thoughtcrime.securesms.keyboard.KeyboardPage;
import org.thoughtcrime.securesms.keyboard.sticker.StickerKeyboardPageFragment;
import org.thoughtcrime.securesms.keyboard.sticker.StickerSearchDialogFragment;
@@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.stickers;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.signal.core.models.database.StickerRecord;
public interface StickerEventListener {
void onStickerSelected(@NonNull StickerRecord sticker);
@@ -5,8 +5,8 @@
package org.thoughtcrime.securesms.stickers
import org.signal.core.models.database.StickerRecord
import org.thoughtcrime.securesms.database.model.StickerPackRecord
import org.thoughtcrime.securesms.database.model.StickerRecord
import org.thoughtcrime.securesms.stickers.manage.AvailableStickerPack
import org.thoughtcrime.securesms.stickers.manage.InstalledStickerPack
import java.util.UUID
@@ -5,13 +5,13 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import org.signal.core.models.database.StickerRecord;
import org.signal.core.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.components.emoji.EmojiUtil;
import org.thoughtcrime.securesms.database.AttachmentTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.StickerTables;
import org.thoughtcrime.securesms.database.StickerTables.StickerRecordReader;
import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.thoughtcrime.securesms.emoji.EmojiSource;
import java.util.ArrayList;
@@ -7,13 +7,13 @@ import androidx.annotation.WorkerThread;
import java.util.stream.Collectors;
import org.signal.core.models.database.StickerRecord;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.InvalidMessageException;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.StickerTables;
import org.thoughtcrime.securesms.database.model.StickerPackRecord;
import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.signal.core.util.Hex;
import org.thoughtcrime.securesms.stickers.StickerManifest;
@@ -17,11 +17,11 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.signal.core.models.database.StickerRecord
import org.signal.core.util.Hex
import org.signal.core.util.deleteAll
import org.thoughtcrime.securesms.database.model.IncomingSticker
import org.thoughtcrime.securesms.database.model.StickerPackId
import org.thoughtcrime.securesms.database.model.StickerRecord
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.testutil.RecipientTestRule
import org.thoughtcrime.securesms.util.RemoteConfig
@@ -8,6 +8,8 @@ package org.thoughtcrime.securesms.testutil
import androidx.test.core.app.ApplicationProvider
import io.mockk.clearMocks
import org.junit.rules.ExternalResource
import org.signal.core.util.PartAuthorityUris
import org.thoughtcrime.securesms.BuildConfig
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
import kotlin.reflect.KVisibility
@@ -36,6 +38,8 @@ class MockAppDependenciesRule : ExternalResource() {
.filterNot { skipList.contains(it.name) }
override fun before() {
PartAuthorityUris.init(BuildConfig.APPLICATION_ID)
if (!AppDependencies.isInitialized) {
AppDependencies.init(ApplicationProvider.getApplicationContext(), MockApplicationDependencyProvider())
}
@@ -11,6 +11,8 @@ import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.unmockkObject
import org.junit.rules.ExternalResource
import org.signal.core.util.PartAuthorityUris
import org.thoughtcrime.securesms.BuildConfig
import org.thoughtcrime.securesms.database.DatabaseTable
import org.thoughtcrime.securesms.database.RemappedRecordsTestHelper
import org.thoughtcrime.securesms.database.SQLiteDatabase
@@ -32,6 +34,8 @@ class SignalDatabaseRule : ExternalResource() {
get() = signalDatabase.signalWritableDatabase
override fun before() {
PartAuthorityUris.init(BuildConfig.APPLICATION_ID)
RecipientId.clearCache()
RemappedRecordsTestHelper.resetInstance()
DatabaseTable.clearTableReferencesForTests()
@@ -1,10 +1,10 @@
package org.thoughtcrime.securesms.database.model
package org.signal.core.models.database
import android.net.Uri
import org.thoughtcrime.securesms.mms.PartAuthority
import org.signal.core.util.PartAuthorityUris
/**
* Represents a record for a sticker pack in the [org.thoughtcrime.securesms.database.StickerTables].
* Represents a record for a sticker pack in the sticker tables.
*/
data class StickerRecord(
@JvmField val rowId: Long,
@@ -17,5 +17,5 @@ data class StickerRecord(
@JvmField val isCover: Boolean
) {
@JvmField
val uri: Uri = PartAuthority.getStickerUri(rowId)
val uri: Uri = PartAuthorityUris.getStickerUri(rowId)
}
@@ -0,0 +1,83 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.signal.core.util
import android.content.ContentUris
import android.net.Uri
import androidx.core.net.toUri
import org.signal.core.models.database.AttachmentId
/**
* Builds and parses the content uris served by the application, so that models outside of the app
* module can reference them without depending on the app module's PartAuthority.
*/
object PartAuthorityUris {
const val PATH_PART = "part"
const val PATH_THUMBNAIL = "thumbnail"
const val PATH_STICKER = "sticker"
const val PATH_WALLPAPER = "wallpaper"
const val PATH_EMOJI = "emoji"
const val PATH_AVATAR_PICKER = "avatar_picker"
private lateinit var uris: Uris
/**
* Must be called with the application id before any uri is built or parsed. Intentionally not tied
* to [CoreUtilDependencies] so that uris are available from the very start of [android.app.Application.onCreate].
*/
@JvmStatic
fun init(authority: String) {
if (this::uris.isInitialized) {
return
}
uris = Uris(authority)
}
@JvmStatic
val authority: String
get() = uris.authority
@JvmStatic
fun getAttachmentDataUri(attachmentId: AttachmentId): Uri {
return ContentUris.withAppendedId(uris.part, attachmentId.id)
}
@JvmStatic
fun getAttachmentThumbnailUri(attachmentId: AttachmentId): Uri {
return ContentUris.withAppendedId(uris.partThumbnail, attachmentId.id)
}
@JvmStatic
fun getStickerUri(id: Long): Uri {
return ContentUris.withAppendedId(uris.sticker, id)
}
@JvmStatic
fun getEmojiUri(sprite: String): Uri {
return Uri.withAppendedPath(uris.emoji, sprite)
}
@JvmStatic
fun getAvatarPickerUri(filename: String): Uri {
return Uri.withAppendedPath(uris.avatarPicker, filename)
}
/** The filename component of a single-segment uri, e.g. the sprite name of an emoji uri. */
@JvmStatic
fun getFilename(uri: Uri): String {
return uri.pathSegments[1]
}
private class Uris(val authority: String) {
val part: Uri = "content://$authority/$PATH_PART".toUri()
val partThumbnail: Uri = "content://$authority/$PATH_THUMBNAIL".toUri()
val sticker: Uri = "content://$authority/$PATH_STICKER".toUri()
val emoji: Uri = "content://$authority/$PATH_EMOJI".toUri()
val avatarPicker: Uri = "content://$authority/$PATH_AVATAR_PICKER".toUri()
}
}