Upgrade Kotlin, AGP, Gradle versions and bring in kotlinx-serialization for use with navigation-compose.

This commit is contained in:
Alex Hart
2025-09-17 12:41:18 -03:00
committed by Greyson Parrelli
parent 957ddc82b5
commit 736811393f
25 changed files with 1209 additions and 5 deletions

View File

@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.audio;
import android.annotation.SuppressLint;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaCodec;
@@ -191,6 +192,7 @@ public class AudioCodec implements Recorder {
return adtsHeader;
}
@SuppressLint("MissingPermission")
private AudioRecord createAudioRecord(int bufferSize) {
return new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,

View File

@@ -1,16 +1,20 @@
package org.thoughtcrime.securesms.backup;
import android.Manifest;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.PackageManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import org.signal.core.util.PendingIntentFlags;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
import org.thoughtcrime.securesms.notifications.NotificationCancellationHelper;
@@ -26,6 +30,7 @@ public enum BackupFileIOError {
ATTACHMENT_TOO_LARGE(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_your_backup_contains_a_very_large_file),
UNKNOWN(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_tap_to_manage_backups);
private static final String TAG = Log.tag(BackupFileIOError.class);
private static final short BACKUP_FAILED_ID = 31321;
private final @StringRes int titleId;
@@ -41,6 +46,11 @@ public enum BackupFileIOError {
}
public void postNotification(@NonNull Context context) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "postNotification: Notification permission is not granted.");
return;
}
PendingIntent pendingIntent = PendingIntent.getActivity(context, -1, AppSettingsActivity.backups(context), PendingIntentFlags.mutable());
Notification backupFailedNotification = new NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_signal_backup)

View File

@@ -1,13 +1,17 @@
package org.thoughtcrime.securesms.components.settings.app.subscription.errors
import android.Manifest
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import org.signal.core.util.PendingIntentFlags
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
import org.thoughtcrime.securesms.help.HelpFragment
@@ -18,7 +22,15 @@ import org.thoughtcrime.securesms.notifications.NotificationIds
* Donation-related push notifications.
*/
object DonationErrorNotifications {
private val TAG = Log.tag(DonationErrorNotifications::class)
fun displayErrorNotification(context: Context, donationError: DonationError) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "Permission to post notifications is not granted.")
return
}
val parameters = DonationErrorParams.create(context, donationError, NotificationCallback)
val notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_notification)

View File

@@ -1,15 +1,19 @@
package org.thoughtcrime.securesms.components.webrtc;
import android.Manifest;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import org.signal.core.util.PendingIntentFlags;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.webrtc.v2.CallIntent;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
@@ -20,12 +24,18 @@ import org.thoughtcrime.securesms.recipients.Recipient;
*/
public final class GroupCallSafetyNumberChangeNotificationUtil {
public static final String TAG = Log.tag(GroupCallSafetyNumberChangeNotificationUtil.class);
public static final String GROUP_CALLING_NOTIFICATION_TAG = "group_calling";
private GroupCallSafetyNumberChangeNotificationUtil() {
}
public static void showNotification(@NonNull Context context, @NonNull Recipient recipient) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "showNotification: Notification permission is not granted.");
return;
}
Intent contentIntent = new Intent(context, CallIntent.getActivityClass());
contentIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

View File

@@ -1,12 +1,15 @@
package org.thoughtcrime.securesms.gcm
import android.Manifest
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import org.signal.core.util.PendingIntentFlags.mutable
import org.signal.core.util.concurrent.SignalExecutors
import org.signal.core.util.logging.Log
@@ -83,6 +86,11 @@ object FcmFetchManager {
return
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "Missing permission to post notifications.")
return
}
Log.w(TAG, "Notifying the user that they may have new messages.")
val mayHaveMessagesNotification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().ADDITIONAL_MESSAGE_NOTIFICATIONS)

View File

@@ -5,11 +5,14 @@
package org.thoughtcrime.securesms.jobs
import android.Manifest
import android.app.Notification
import android.app.PendingIntent
import android.content.Intent
import android.content.pm.PackageManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import org.signal.core.util.EventTimer
import org.signal.core.util.PendingIntentFlags
import org.signal.core.util.Stopwatch
@@ -364,6 +367,10 @@ class ArchiveAttachmentReconciliationJob private constructor(
return
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
return
}
val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("[Internal-only] Archive reconciliation found an error!")

View File

@@ -5,11 +5,14 @@
package org.thoughtcrime.securesms.jobs
import android.Manifest
import android.app.Notification
import android.app.PendingIntent
import android.content.Intent
import android.content.pm.PackageManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import org.signal.core.util.PendingIntentFlags
import org.signal.core.util.Stopwatch
import org.signal.core.util.isNotNullOrBlank
@@ -440,6 +443,10 @@ class BackupMessagesJob private constructor(
return
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
return
}
val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("[Internal-only] Unexpected remote key missing!")

View File

@@ -4,11 +4,14 @@
*/
package org.thoughtcrime.securesms.jobs
import android.Manifest
import android.app.Notification
import android.app.PendingIntent
import android.content.Intent
import android.content.pm.PackageManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import org.greenrobot.eventbus.EventBus
import org.signal.core.util.Base64.decodeBase64OrThrow
import org.signal.core.util.PendingIntentFlags
@@ -471,6 +474,11 @@ class RestoreAttachmentJob private constructor(
return
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "maybePostFailedToDownloadFromArchiveNotification: Notification permission is not granted.")
return
}
val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("[Internal-only] Failed to restore attachment from Archive CDN!")
@@ -486,6 +494,11 @@ class RestoreAttachmentJob private constructor(
return
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "maybePostFailedToDownloadFromArchiveAndTransitNotification: Notification permission is not granted.")
return
}
val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("[Internal-only] Completely failed to restore attachment!")

View File

@@ -1,12 +1,15 @@
package org.thoughtcrime.securesms.mediapreview
import android.Manifest
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModel
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Completable
@@ -164,6 +167,11 @@ class MediaPreviewV2ViewModel : ViewModel() {
return
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "maybePostInvalidMacErrorNotification: Notification permission is not granted.")
return
}
val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("[Internal-only] Bad incrementalMac!")

View File

@@ -144,7 +144,7 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
.execute();
}
@SuppressLint("RestrictedApi")
@SuppressLint({"RestrictedApi", "MissingPermission"})
private void beginCameraRecording() {
cameraXModePolicy.setToVideo(cameraController);
this.cameraController.setZoomRatio(getDefaultVideoZoomRatio());

View File

@@ -5,12 +5,15 @@
package org.thoughtcrime.securesms.messages
import android.Manifest
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import org.signal.core.util.PendingIntentFlags
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
@@ -40,6 +43,11 @@ object GroupSendEndorsementInternalNotifier {
return
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "maybePostGroupSendFallbackError: Notification permission is not granted.")
return
}
Log.internal().w(TAG, "Group send with GSE failed, GSE was likely out of date or incorrect", Throwable())
val now = System.currentTimeMillis().milliseconds
@@ -67,6 +75,11 @@ object GroupSendEndorsementInternalNotifier {
return
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "maybePostMissingGroupSendEndorsement: Notification permission is not granted.")
return
}
Log.internal().w(TAG, "GSE missing for recipient", Throwable())
val now = System.currentTimeMillis().milliseconds

View File

@@ -1,11 +1,14 @@
package org.thoughtcrime.securesms.messages
import android.Manifest
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import com.squareup.wire.internal.toUnmodifiableList
import org.signal.core.util.PendingIntentFlags
import org.signal.core.util.isAbsent
@@ -44,7 +47,6 @@ import org.thoughtcrime.securesms.jobs.PreKeysSyncJob
import org.thoughtcrime.securesms.jobs.SendRetryReceiptJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogActivity
import org.thoughtcrime.securesms.messages.MessageDecryptor.FollowUpOperation
import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.hasGroupContext
import org.thoughtcrime.securesms.messages.protocol.BufferedProtocolStore
import org.thoughtcrime.securesms.notifications.NotificationChannels
@@ -430,6 +432,11 @@ object MessageDecryptor {
}
private fun postDecryptionErrorNotification(context: Context) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "postDecryptionErrorNotification: Notification permission is not granted.")
return
}
val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("[Internal-only] Failed to decrypt a message!")
@@ -441,6 +448,11 @@ object MessageDecryptor {
}
private fun postInvalidMessageNotification(context: Context, message: String) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "postInvalidMessageNotification: Notification permission is not granted.")
return
}
val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("[Internal-only] Received an invalid message!")

View File

@@ -1,14 +1,17 @@
package org.thoughtcrime.securesms.migrations;
import android.Manifest;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.PackageManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.app.TaskStackBuilder;
import androidx.core.content.ContextCompat;
import org.signal.core.util.SetUtil;
import org.signal.core.util.logging.Log;
@@ -95,6 +98,11 @@ public class UserNotificationMigrationJob extends MigrationJob {
return;
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "Notification permission is not granted. Skipping.");
return;
}
String message = context.getResources().getQuantityString(R.plurals.UserNotificationMigrationJob_d_contacts_are_on_signal,
registeredSystemContacts.size(),
registeredSystemContacts.size());

View File

@@ -6,6 +6,7 @@
package org.thoughtcrime.securesms.registration.ui
import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
@@ -123,6 +124,7 @@ class RegistrationViewModel : ViewModel() {
}
}
@SuppressLint("MissingPermission")
fun maybePrefillE164(context: Context) {
Log.v(TAG, "maybePrefillE164()")
if (Permissions.hasAll(context, Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_PHONE_NUMBERS)) {

View File

@@ -6,6 +6,7 @@
package org.thoughtcrime.securesms.registrationv3.ui
import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
@@ -150,6 +151,7 @@ class RegistrationViewModel : ViewModel() {
}
}
@SuppressLint("MissingPermission")
fun maybePrefillE164(context: Context) {
Log.v(TAG, "maybePrefillE164()")
if (Permissions.hasAll(context, Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_PHONE_NUMBERS)) {

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.serialization
import android.net.Uri
import android.os.Bundle
import androidx.navigation.NavType
import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json
/**
* NavType for JSON Serializable types using KotlinX Serialization.
*
* This only needs to be used if there are embedded serializers (using `@Serializable(with = ...)`) as the
* native NavType serialization support doesn't handle these objects gracefully.
*/
class JsonSerializableNavType<T : Any>(
private val serializer: KSerializer<T>
) : NavType<T>(false) {
override fun get(bundle: Bundle, key: String): T? {
return Json.Default.decodeFromString(serializer, bundle.getString(key)!!)
}
override fun parseValue(value: String): T {
return Json.Default.decodeFromString(serializer, value)
}
override fun put(bundle: Bundle, key: String, value: T) {
bundle.putString(key, Json.Default.encodeToString(serializer, value))
}
override fun serializeAsValue(value: T): String {
return Uri.encode(Json.Default.encodeToString(serializer, value))
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.serialization
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import org.thoughtcrime.securesms.recipients.RecipientId
/**
* Kotlinx Serialization serializer for [RecipientId] objects.
*/
class RecipientIdSerializer : KSerializer<RecipientId> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("RecipientId", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: RecipientId) {
encoder.encodeString(value.serialize())
}
override fun deserialize(decoder: Decoder): RecipientId {
return RecipientId.from(decoder.decodeString())
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.serialization
import android.net.Uri
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
/**
* Kotlinx Serialization serializer for Android [Uri] objects.
*/
class UriSerializer : KSerializer<Uri> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Uri", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: Uri) {
encoder.encodeString(value.toString())
}
override fun deserialize(decoder: Decoder): Uri {
return Uri.parse(decoder.decodeString())
}
}

View File

@@ -5,13 +5,16 @@
package org.thoughtcrime.securesms.service
import android.Manifest
import android.annotation.SuppressLint
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import org.signal.core.util.PendingIntentFlags
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.MainActivity
@@ -111,6 +114,11 @@ class BackupProgressService : SafeForegroundService() {
BackupProgressService.progress = progress
BackupProgressService.indeterminate = indeterminate
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "Cannot update notification due to missing permission.")
return@withLock
}
if (NotificationManagerCompat.from(context).activeNotifications.any { n -> n.id == NotificationIds.BACKUP_PROGRESS }) {
NotificationManagerCompat.from(context).notify(NotificationIds.BACKUP_PROGRESS, getForegroundNotification(context))
}

View File

@@ -6,6 +6,7 @@
package org.thoughtcrime.securesms.service.webrtc
import android.Manifest
import android.annotation.SuppressLint
import android.app.Notification
import android.app.PendingIntent
import android.content.BroadcastReceiver
@@ -177,6 +178,7 @@ class ActiveCallManager(
}
}
@SuppressLint("MissingPermission")
fun update(type: Int, recipientId: RecipientId, isVideoCall: Boolean) {
Log.i(TAG, "update $type $recipientId $isVideoCall")
previousNotificationDisposable.dispose()

View File

@@ -1,8 +1,10 @@
package org.thoughtcrime.securesms.util;
import android.Manifest;
import android.app.PendingIntent;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.hardware.Camera.CameraInfo;
import android.net.Uri;
import android.os.Build;
@@ -13,6 +15,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import org.greenrobot.eventbus.EventBus;
@@ -900,6 +903,11 @@ public class TextSecurePreferences {
}
private static void notifyUnregisteredReceived(Context context) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "notifyUnregisteredReceived: Notification permission is not granted.");
return;
}
PendingIntent reRegistrationIntent = PendingIntent.getActivity(context,
0,
RegistrationActivity.newIntentForReRegistration(context),

View File

@@ -1,6 +1,8 @@
package org.thoughtcrime.securesms.util.dualsim;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -8,6 +10,7 @@ import android.telephony.TelephonyManager;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
@@ -99,6 +102,11 @@ public final class SubscriptionManagerCompat {
return Collections.emptyList();
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "Missing READ_PHONE_STATE permission.");
return Collections.emptyList();
}
List<SubscriptionInfo> list = subscriptionManager.getActiveSubscriptionInfoList();
return list != null? list : Collections.emptyList();