Clear out checks for SDK < 23 as they're no longer relevant.

This commit is contained in:
Alex Hart
2025-10-31 12:50:47 -03:00
committed by Michelle Tang
parent ab9c8626c0
commit 1d7ae669b6
57 changed files with 137 additions and 387 deletions

View File

@@ -38,11 +38,7 @@ class BiometricDeviceAuthentication(
} }
private fun isDeviceSecure(context: Context): Boolean { private fun isDeviceSecure(context: Context): Boolean {
return if (Build.VERSION.SDK_INT > 23) { return ServiceUtil.getKeyguardManager(context).isDeviceSecure
ServiceUtil.getKeyguardManager(context).isDeviceSecure
} else {
ServiceUtil.getKeyguardManager(context).isKeyguardSecure
}
} }
/** /**

View File

@@ -29,9 +29,11 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.BoxWithConstraintsScope import androidx.compose.foundation.layout.BoxWithConstraintsScope
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.displayCutoutPadding import androidx.compose.foundation.layout.displayCutoutPadding
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@@ -125,7 +127,6 @@ import org.thoughtcrime.securesms.main.MainToolbarMode
import org.thoughtcrime.securesms.main.MainToolbarState import org.thoughtcrime.securesms.main.MainToolbarState
import org.thoughtcrime.securesms.main.MainToolbarViewModel import org.thoughtcrime.securesms.main.MainToolbarViewModel
import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder
import org.thoughtcrime.securesms.main.NavigationBarSpacerCompat
import org.thoughtcrime.securesms.main.SnackbarState import org.thoughtcrime.securesms.main.SnackbarState
import org.thoughtcrime.securesms.main.callNavGraphBuilder import org.thoughtcrime.securesms.main.callNavGraphBuilder
import org.thoughtcrime.securesms.main.chatNavGraphBuilder import org.thoughtcrime.securesms.main.chatNavGraphBuilder
@@ -514,7 +515,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
) )
if (!windowSizeClass.isSplitPane()) { if (!windowSizeClass.isSplitPane()) {
NavigationBarSpacerCompat() Spacer(Modifier.navigationBarsPadding())
} }
} }
} }

View File

@@ -7,7 +7,6 @@ package org.thoughtcrime.securesms.attachments
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.os.Build
import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log
import org.signal.core.util.mebiBytes import org.signal.core.util.mebiBytes
import org.signal.protos.resumableuploads.ResumableUpload import org.signal.protos.resumableuploads.ResumableUpload
@@ -93,11 +92,6 @@ object AttachmentUploadUtil {
return attachment.blurHash.hash return attachment.blurHash.hash
} }
if (Build.VERSION.SDK_INT < 23) {
Log.w(TAG, "Video thumbnails not supported...")
return null
}
return MediaUtil.getVideoThumbnail(context, Objects.requireNonNull(attachment.uri), 1000)?.let { bitmap -> return MediaUtil.getVideoThumbnail(context, Objects.requireNonNull(attachment.uri), 1000)?.let { bitmap ->
val thumb = Bitmap.createScaledBitmap(bitmap, 100, 100, false) val thumb = Bitmap.createScaledBitmap(bitmap, 100, 100, false)
bitmap.recycle() bitmap.recycle()

View File

@@ -4,7 +4,6 @@ import android.content.Context
import android.net.Uri import android.net.Uri
import android.util.LruCache import android.util.LruCache
import androidx.annotation.AnyThread import androidx.annotation.AnyThread
import androidx.annotation.RequiresApi
import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import io.reactivex.rxjava3.subjects.SingleSubject import io.reactivex.rxjava3.subjects.SingleSubject
@@ -24,7 +23,6 @@ import kotlin.concurrent.write
* *
* Maintains an in-memory cache of recently requested wave forms. * Maintains an in-memory cache of recently requested wave forms.
*/ */
@RequiresApi(23)
object AudioWaveForms { object AudioWaveForms {
private val TAG = Log.tag(AudioWaveForms::class.java) private val TAG = Log.tag(AudioWaveForms::class.java)

View File

@@ -10,7 +10,6 @@ import android.content.res.ColorStateList
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Build
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.airbnb.lottie.SimpleColorFilter import com.airbnb.lottie.SimpleColorFilter
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
@@ -58,9 +57,7 @@ class FallbackAvatarDrawable(
) )
resourceIcon.bounds = iconBounds resourceIcon.bounds = iconBounds
if (Build.VERSION.SDK_INT >= 23) { resourceIcon.setLayoutDirection(layoutDirection)
resourceIcon.setLayoutDirection(layoutDirection)
}
resourceIcon resourceIcon
} }

View File

@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.backup; package org.thoughtcrime.securesms.backup;
import android.content.Context; import android.content.Context;
import android.os.Build;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@@ -24,8 +23,8 @@ public final class BackupPassphrase {
String passphrase = TextSecurePreferences.getBackupPassphrase(context); String passphrase = TextSecurePreferences.getBackupPassphrase(context);
String encryptedPassphrase = TextSecurePreferences.getEncryptedBackupPassphrase(context); String encryptedPassphrase = TextSecurePreferences.getEncryptedBackupPassphrase(context);
if (Build.VERSION.SDK_INT < 23 || (passphrase == null && encryptedPassphrase == null)) { if (passphrase == null && encryptedPassphrase == null) {
return stripSpaces(passphrase); return null;
} }
if (encryptedPassphrase == null) { if (encryptedPassphrase == null) {
@@ -40,8 +39,8 @@ public final class BackupPassphrase {
} }
public static void set(@NonNull Context context, @Nullable String passphrase) { public static void set(@NonNull Context context, @Nullable String passphrase) {
if (passphrase == null || Build.VERSION.SDK_INT < 23) { if (passphrase == null) {
TextSecurePreferences.setBackupPassphrase(context, passphrase); TextSecurePreferences.setBackupPassphrase(context, null);
TextSecurePreferences.setEncryptedBackupPassphrase(context, null); TextSecurePreferences.setEncryptedBackupPassphrase(context, null);
} else { } else {
KeyStoreHelper.SealedData encryptedPassphrase = KeyStoreHelper.seal(passphrase.getBytes()); KeyStoreHelper.SealedData encryptedPassphrase = KeyStoreHelper.seal(passphrase.getBytes());

View File

@@ -6,7 +6,6 @@
package org.thoughtcrime.securesms.banner.banners package org.thoughtcrime.securesms.banner.banners
import android.content.Context import android.content.Context
import android.os.Build
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -27,17 +26,13 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
class DozeBanner(private val context: Context, private val onDismissListener: () -> Unit) : Banner<Unit>() { class DozeBanner(private val context: Context, private val onDismissListener: () -> Unit) : Banner<Unit>() {
override val enabled: Boolean override val enabled: Boolean
get() = Build.VERSION.SDK_INT >= 23 && !SignalStore.account.fcmEnabled && !TextSecurePreferences.hasPromptedOptimizeDoze(context) && !ServiceUtil.getPowerManager(context).isIgnoringBatteryOptimizations(context.packageName) get() = !SignalStore.account.fcmEnabled && !TextSecurePreferences.hasPromptedOptimizeDoze(context) && !ServiceUtil.getPowerManager(context).isIgnoringBatteryOptimizations(context.packageName)
override val dataFlow: Flow<Unit> override val dataFlow: Flow<Unit>
get() = flowOf(Unit) get() = flowOf(Unit)
@Composable @Composable
override fun DisplayBanner(model: Unit, contentPadding: PaddingValues) { override fun DisplayBanner(model: Unit, contentPadding: PaddingValues) {
if (Build.VERSION.SDK_INT < 23) {
throw IllegalStateException("Showing a Doze banner for an OS prior to Android 6.0")
}
Banner( Banner(
contentPadding = contentPadding, contentPadding = contentPadding,
onDismissListener = { onDismissListener = {

View File

@@ -219,28 +219,21 @@ public final class AudioView extends FrameLayout {
if (seekBar instanceof WaveFormSeekBarView) { if (seekBar instanceof WaveFormSeekBarView) {
WaveFormSeekBarView waveFormView = (WaveFormSeekBarView) seekBar; WaveFormSeekBarView waveFormView = (WaveFormSeekBarView) seekBar;
waveFormView.setColors(waveFormPlayedBarsColor, waveFormUnplayedBarsColor, waveFormThumbTint); waveFormView.setColors(waveFormPlayedBarsColor, waveFormUnplayedBarsColor, waveFormThumbTint);
if (android.os.Build.VERSION.SDK_INT >= 23) { if (audioSlide == null || !Objects.equals(audioSlide.getUri(), audio.getUri())) {
if (audioSlide == null || !Objects.equals(audioSlide.getUri(), audio.getUri())) { disposable.dispose();
disposable.dispose(); disposable = AudioWaveForms.getWaveForm(getContext(), audio.asAttachment())
disposable = AudioWaveForms.getWaveForm(getContext(), audio.asAttachment()) .observeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread()) .subscribe(
.subscribe( data -> {
data -> { durationMillis = data.getDuration(TimeUnit.MILLISECONDS);
durationMillis = data.getDuration(TimeUnit.MILLISECONDS); updateProgress(0, 0);
updateProgress(0, 0); if (!forceHideDuration && duration != null) {
if (!forceHideDuration && duration != null) { duration.setVisibility(VISIBLE);
duration.setVisibility(VISIBLE); }
} waveFormView.setWaveData(data.getWaveForm());
waveFormView.setWaveData(data.getWaveForm()); },
}, t -> waveFormView.setWaveMode(false)
t -> waveFormView.setWaveMode(false) );
);
}
} else {
waveFormView.setWaveMode(false);
if (duration != null) {
duration.setVisibility(GONE);
}
} }
} }

View File

@@ -18,7 +18,6 @@ import androidx.lifecycle.Lifecycle
import org.signal.core.util.concurrent.LifecycleDisposable import org.signal.core.util.concurrent.LifecycleDisposable
import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.DebugLogsPromptDialogFragment.Purpose.entries
import org.thoughtcrime.securesms.databinding.PromptLogsBottomSheetBinding import org.thoughtcrime.securesms.databinding.PromptLogsBottomSheetBinding
import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.keyvalue.SignalStore
@@ -159,11 +158,7 @@ class DebugLogsPromptDialogFragment : FixedRoundedCornerBottomSheetDialogFragmen
} }
private fun batteryOptimizationsString(): String { private fun batteryOptimizationsString(): String {
return if (Build.VERSION.SDK_INT < 23) { return PowerManagerCompat.isIgnoringBatteryOptimizations(requireContext()).toString()
"N/A (API < 23)"
} else {
PowerManagerCompat.isIgnoringBatteryOptimizations(requireContext()).toString()
}
} }
private fun backgroundRestrictedString(): String { private fun backgroundRestrictedString(): String {

View File

@@ -135,7 +135,7 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
protected void onAttachedToWindow() { protected void onAttachedToWindow() {
super.onAttachedToWindow(); super.onAttachedToWindow();
rotation = getDeviceRotation(); rotation = getDeviceRotation();
if (Build.VERSION.SDK_INT >= 23 && getRootWindowInsets() != null) { if (getRootWindowInsets() != null) {
int bottomInset; int bottomInset;
WindowInsets windowInsets = getRootWindowInsets(); WindowInsets windowInsets = getRootWindowInsets();

View File

@@ -9,7 +9,6 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
@@ -23,7 +22,6 @@ import org.thoughtcrime.securesms.util.BottomSheetUtil
import org.thoughtcrime.securesms.util.LocalMetrics import org.thoughtcrime.securesms.util.LocalMetrics
import org.thoughtcrime.securesms.util.PowerManagerCompat import org.thoughtcrime.securesms.util.PowerManagerCompat
@RequiresApi(23)
class PromptBatterySaverDialogFragment : FixedRoundedCornerBottomSheetDialogFragment() { class PromptBatterySaverDialogFragment : FixedRoundedCornerBottomSheetDialogFragment() {
companion object { companion object {

View File

@@ -604,9 +604,7 @@ public class ThumbnailView extends FrameLayout {
.downsample(SignalDownsampleStrategy.CENTER_OUTSIDE_NO_UPSCALE) .downsample(SignalDownsampleStrategy.CENTER_OUTSIDE_NO_UPSCALE)
.transition(withCrossFade())); .transition(withCrossFade()));
boolean doNotShowMissingThumbnailImage = Build.VERSION.SDK_INT < 23; if (slide.isInProgress()) {
if (slide.isInProgress() || doNotShowMissingThumbnailImage) {
return requestBuilder; return requestBuilder;
} else { } else {
return requestBuilder.apply(RequestOptions.errorOf(R.drawable.missing_thumbnail)); return requestBuilder.apply(RequestOptions.errorOf(R.drawable.missing_thumbnail));

View File

@@ -116,16 +116,12 @@ public class EmojiEditText extends AppCompatEditText {
ClipData clipData = ServiceUtil.getClipboardManager(getContext()).getPrimaryClip(); ClipData clipData = ServiceUtil.getClipboardManager(getContext()).getPrimaryClip();
if (clipData != null) { if (clipData != null) {
CharSequence label = clipData.getDescription().getLabel(); CharSequence label = clipData.getDescription().getLabel();
CharSequence pendingPaste = getTextFromClipData(clipData);
if (TextUtils.equals(Util.COPY_LABEL, label) && shouldPersistSignalStylingWhenPasting()) { if (TextUtils.equals(Util.COPY_LABEL, label) && shouldPersistSignalStylingWhenPasting()) {
return super.onTextContextMenuItem(id); return super.onTextContextMenuItem(id);
} else if (Build.VERSION.SDK_INT >= 23) { } else {
return super.onTextContextMenuItem(android.R.id.pasteAsPlainText); return super.onTextContextMenuItem(android.R.id.pasteAsPlainText);
} else if (pendingPaste != null) {
Util.copyToClipboard(getContext(), pendingPaste.toString());
return super.onTextContextMenuItem(id);
} }
} }
} else if (id == android.R.id.copy || id == android.R.id.cut) { } else if (id == android.R.id.copy || id == android.R.id.cut) {

View File

@@ -10,7 +10,6 @@ import android.widget.Toast
import androidx.activity.result.ActivityResultCallback import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContract import androidx.activity.result.contract.ActivityResultContract
import androidx.annotation.RequiresApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@@ -238,7 +237,6 @@ open class DefaultNotificationsSettingsCallbacks(
viewModel.setMessageNotificationPrivacy(selection) viewModel.setMessageNotificationPrivacy(selection)
} }
@RequiresApi(23)
override fun onTroubleshootNotificationsClick() { override fun onTroubleshootNotificationsClick() {
PromptBatterySaverDialogFragment.show(activity.supportFragmentManager) PromptBatterySaverDialogFragment.show(activity.supportFragmentManager)
} }

View File

@@ -6,7 +6,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Build
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@@ -106,7 +105,7 @@ object DonationErrorNotifications {
context, context,
0, 0,
actionIntent, actionIntent,
if (Build.VERSION.SDK_INT >= 23) PendingIntentFlags.oneShot() else PendingIntentFlags.mutable() PendingIntentFlags.oneShot()
) )
} }
) )

View File

@@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.crypto;
import android.content.Context; import android.content.Context;
import android.os.Build;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -60,25 +59,17 @@ public class AttachmentSecretProvider {
{ {
AttachmentSecret attachmentSecret = AttachmentSecret.fromString(unencryptedSecret); AttachmentSecret attachmentSecret = AttachmentSecret.fromString(unencryptedSecret);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(attachmentSecret.serialize().getBytes());
return attachmentSecret;
} else {
KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(attachmentSecret.serialize().getBytes());
TextSecurePreferences.setAttachmentEncryptedSecret(context, encryptedSecret.serialize()); TextSecurePreferences.setAttachmentEncryptedSecret(context, encryptedSecret.serialize());
TextSecurePreferences.setAttachmentUnencryptedSecret(context, null); TextSecurePreferences.setAttachmentUnencryptedSecret(context, null);
return attachmentSecret; return attachmentSecret;
}
} }
private AttachmentSecret getEncryptedAttachmentSecret(@NonNull String serializedEncryptedSecret) { private AttachmentSecret getEncryptedAttachmentSecret(@NonNull String serializedEncryptedSecret) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.SealedData.fromString(serializedEncryptedSecret);
throw new AssertionError("OS downgrade not supported. KeyStore sealed data exists on platform < M!"); return AttachmentSecret.fromString(new String(KeyStoreHelper.unseal(encryptedSecret)));
} else {
KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.SealedData.fromString(serializedEncryptedSecret);
return AttachmentSecret.fromString(new String(KeyStoreHelper.unseal(encryptedSecret)));
}
} }
private AttachmentSecret createAndStoreAttachmentSecret(@NonNull Context context) { private AttachmentSecret createAndStoreAttachmentSecret(@NonNull Context context) {
@@ -93,12 +84,7 @@ public class AttachmentSecretProvider {
} }
private void storeAttachmentSecret(@NonNull Context context, @NonNull AttachmentSecret attachmentSecret) { private void storeAttachmentSecret(@NonNull Context context, @NonNull AttachmentSecret attachmentSecret) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(attachmentSecret.serialize().getBytes());
KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(attachmentSecret.serialize().getBytes()); TextSecurePreferences.setAttachmentEncryptedSecret(context, encryptedSecret.serialize());
TextSecurePreferences.setAttachmentEncryptedSecret(context, encryptedSecret.serialize());
} else {
TextSecurePreferences.setAttachmentUnencryptedSecret(context, attachmentSecret.serialize());
}
} }
} }

View File

@@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.crypto;
import android.content.Context; import android.content.Context;
import android.os.Build;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -48,28 +47,20 @@ public final class DatabaseSecretProvider {
try { try {
DatabaseSecret databaseSecret = new DatabaseSecret(unencryptedSecret); DatabaseSecret databaseSecret = new DatabaseSecret(unencryptedSecret);
if (Build.VERSION.SDK_INT < 23) { KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(databaseSecret.asBytes());
return databaseSecret;
} else {
KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(databaseSecret.asBytes());
TextSecurePreferences.setDatabaseEncryptedSecret(context, encryptedSecret.serialize()); TextSecurePreferences.setDatabaseEncryptedSecret(context, encryptedSecret.serialize());
TextSecurePreferences.setDatabaseUnencryptedSecret(context, null); TextSecurePreferences.setDatabaseUnencryptedSecret(context, null);
return databaseSecret; return databaseSecret;
}
} catch (IOException e) { } catch (IOException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
private static @NonNull DatabaseSecret getEncryptedDatabaseSecret(@NonNull String serializedEncryptedSecret) { private static @NonNull DatabaseSecret getEncryptedDatabaseSecret(@NonNull String serializedEncryptedSecret) {
if (Build.VERSION.SDK_INT < 23) { KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.SealedData.fromString(serializedEncryptedSecret);
throw new AssertionError("OS downgrade not supported. KeyStore sealed data exists on platform < M!"); return new DatabaseSecret(KeyStoreHelper.unseal(encryptedSecret));
} else {
KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.SealedData.fromString(serializedEncryptedSecret);
return new DatabaseSecret(KeyStoreHelper.unseal(encryptedSecret));
}
} }
private static @NonNull DatabaseSecret createAndStoreDatabaseSecret(@NonNull Context context) { private static @NonNull DatabaseSecret createAndStoreDatabaseSecret(@NonNull Context context) {
@@ -79,12 +70,8 @@ public final class DatabaseSecretProvider {
DatabaseSecret databaseSecret = new DatabaseSecret(secret); DatabaseSecret databaseSecret = new DatabaseSecret(secret);
if (Build.VERSION.SDK_INT >= 23) { KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(databaseSecret.asBytes());
KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(databaseSecret.asBytes()); TextSecurePreferences.setDatabaseEncryptedSecret(context, encryptedSecret.serialize());
TextSecurePreferences.setDatabaseEncryptedSecret(context, encryptedSecret.serialize());
} else {
TextSecurePreferences.setDatabaseUnencryptedSecret(context, databaseSecret.asString());
}
return databaseSecret; return databaseSecret;
} }

View File

@@ -51,7 +51,6 @@ public final class KeyStoreHelper {
private static final String KEY_ALIAS = "SignalSecret"; private static final String KEY_ALIAS = "SignalSecret";
private static final Executor executor = Executors.newSingleThreadExecutor(); private static final Executor executor = Executors.newSingleThreadExecutor();
@RequiresApi(23)
public static SealedData seal(@NonNull byte[] input) { public static SealedData seal(@NonNull byte[] input) {
CountDownLatch latch = new CountDownLatch(1); CountDownLatch latch = new CountDownLatch(1);
AtomicReference<SealedData> result = new AtomicReference<>(); AtomicReference<SealedData> result = new AtomicReference<>();
@@ -83,7 +82,6 @@ public final class KeyStoreHelper {
return result.get(); return result.get();
} }
@RequiresApi(23)
public static byte[] unseal(@NonNull SealedData sealedData) { public static byte[] unseal(@NonNull SealedData sealedData) {
CountDownLatch latch = new CountDownLatch(1); CountDownLatch latch = new CountDownLatch(1);
AtomicReference<byte[]> result = new AtomicReference<>(); AtomicReference<byte[]> result = new AtomicReference<>();

View File

@@ -22,7 +22,6 @@ import android.database.Cursor
import android.media.MediaDataSource import android.media.MediaDataSource
import android.os.Parcelable import android.os.Parcelable
import android.text.TextUtils import android.text.TextUtils
import androidx.annotation.RequiresApi
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import androidx.core.content.contentValuesOf import androidx.core.content.contentValuesOf
@@ -2150,7 +2149,6 @@ class AttachmentTable(
.run() .run()
} }
@RequiresApi(23)
fun mediaDataSourceFor(attachmentId: AttachmentId, allowReadingFromTempFile: Boolean): MediaDataSource? { fun mediaDataSourceFor(attachmentId: AttachmentId, allowReadingFromTempFile: Boolean): MediaDataSource? {
val dataInfo = getDataFileInfo(attachmentId) val dataInfo = getDataFileInfo(attachmentId)
if (dataInfo != null) { if (dataInfo != null) {

View File

@@ -5,7 +5,6 @@
package org.thoughtcrime.securesms.jobs package org.thoughtcrime.securesms.jobs
import android.os.Build
import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log
import org.signal.protos.resumableuploads.ResumableUpload import org.signal.protos.resumableuploads.ResumableUpload
import org.thoughtcrime.securesms.attachments.AttachmentId import org.thoughtcrime.securesms.attachments.AttachmentId
@@ -263,7 +262,7 @@ class ArchiveThumbnailUploadJob private constructor(
return if (MediaUtil.isImageType(attachment.contentType)) { return if (MediaUtil.isImageType(attachment.contentType)) {
compress(uri, attachment.contentType ?: "") compress(uri, attachment.contentType ?: "")
} else if (Build.VERSION.SDK_INT >= 23 && MediaUtil.isVideoType(attachment.contentType)) { } else if (MediaUtil.isVideoType(attachment.contentType)) {
MediaUtil.getVideoThumbnail(context, attachment.uri)?.let { MediaUtil.getVideoThumbnail(context, attachment.uri)?.let {
compress(uri, attachment.contentType ?: "") compress(uri, attachment.contentType ?: "")
} }

View File

@@ -1,7 +1,5 @@
package org.thoughtcrime.securesms.jobs package org.thoughtcrime.securesms.jobs
import android.os.Build
import androidx.annotation.RequiresApi
import org.signal.core.util.concurrent.safeBlockingGet import org.signal.core.util.concurrent.safeBlockingGet
import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.attachments.AttachmentId import org.thoughtcrime.securesms.attachments.AttachmentId
@@ -28,11 +26,7 @@ class GenerateAudioWaveFormJob private constructor(private val attachmentId: Att
@JvmStatic @JvmStatic
fun enqueue(attachmentId: AttachmentId) { fun enqueue(attachmentId: AttachmentId) {
if (Build.VERSION.SDK_INT < 23) { AppDependencies.jobManager.add(GenerateAudioWaveFormJob(attachmentId))
Log.i(TAG, "Unable to generate waveform on this version of Android")
} else {
AppDependencies.jobManager.add(GenerateAudioWaveFormJob(attachmentId))
}
} }
} }
@@ -53,7 +47,6 @@ class GenerateAudioWaveFormJob private constructor(private val attachmentId: Att
override fun getFactoryKey(): String = KEY override fun getFactoryKey(): String = KEY
@RequiresApi(23)
override fun onRun() { override fun onRun() {
val attachment: DatabaseAttachment? = SignalDatabase.attachments.getAttachment(attachmentId) val attachment: DatabaseAttachment? = SignalDatabase.attachments.getAttachment(attachmentId)

View File

@@ -1,12 +1,11 @@
package org.thoughtcrime.securesms.logging; package org.thoughtcrime.securesms.logging;
import android.content.Context; import android.content.Context;
import android.os.Build;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.crypto.KeyStoreHelper;
import org.signal.core.util.Base64; import org.signal.core.util.Base64;
import org.thoughtcrime.securesms.crypto.KeyStoreHelper;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.io.IOException; import java.io.IOException;
@@ -32,12 +31,8 @@ public class LogSecretProvider {
} }
private static byte[] parseEncryptedSecret(String secret) { private static byte[] parseEncryptedSecret(String secret) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.SealedData.fromString(secret);
KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.SealedData.fromString(secret); return KeyStoreHelper.unseal(encryptedSecret);
return KeyStoreHelper.unseal(encryptedSecret);
} else {
throw new AssertionError("OS downgrade not supported. KeyStore sealed data exists on platform < M!");
}
} }
private static byte[] createAndStoreSecret(@NonNull Context context) { private static byte[] createAndStoreSecret(@NonNull Context context) {
@@ -45,12 +40,8 @@ public class LogSecretProvider {
byte[] secret = new byte[32]; byte[] secret = new byte[32];
random.nextBytes(secret); random.nextBytes(secret);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(secret);
KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(secret); TextSecurePreferences.setLogEncryptedSecret(context, encryptedSecret.serialize());
TextSecurePreferences.setLogEncryptedSecret(context, encryptedSecret.serialize());
} else {
TextSecurePreferences.setLogUnencryptedSecret(context, Base64.encodeWithPadding(secret));
}
return secret; return secret;
} }

View File

@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.logsubmit package org.thoughtcrime.securesms.logsubmit
import android.content.Context import android.content.Context
import android.os.Build
import org.signal.core.util.MemoryTracker import org.signal.core.util.MemoryTracker
import org.signal.core.util.bytes import org.signal.core.util.bytes
import org.signal.core.util.kibiBytes import org.signal.core.util.kibiBytes
@@ -28,20 +27,18 @@ class LogSectionMemory : LogSection {
Low Memory? : ${nativeMemory.lowMemory} Low Memory? : ${nativeMemory.lowMemory}
""".trimIndent() """.trimIndent()
if (Build.VERSION.SDK_INT >= 23) { val detailedMemory = MemoryTracker.getDetailedMemoryStats()
val detailedMemory = MemoryTracker.getDetailedMemoryStats()
base += "\n\n" base += "\n\n"
base += """ base += """
-- Detailed Memory (API 23+) -- Detailed Memory (API 23+)
App JVM Heap Usage : ${detailedMemory.appJavaHeapUsageKb?.kbDisplay()} App JVM Heap Usage : ${detailedMemory.appJavaHeapUsageKb?.kbDisplay()}
App Native Heap Usage: ${detailedMemory.appNativeHeapUsageKb?.kbDisplay()} App Native Heap Usage: ${detailedMemory.appNativeHeapUsageKb?.kbDisplay()}
Code Usage : ${detailedMemory.codeUsageKb?.kbDisplay()} Code Usage : ${detailedMemory.codeUsageKb?.kbDisplay()}
Graphics Usage : ${detailedMemory.graphicsUsageKb?.kbDisplay()} Graphics Usage : ${detailedMemory.graphicsUsageKb?.kbDisplay()}
Stack Usage : ${detailedMemory.stackUsageKb?.kbDisplay()} Stack Usage : ${detailedMemory.stackUsageKb?.kbDisplay()}
Other Usage : ${detailedMemory.appOtherUsageKb?.kbDisplay()} Other Usage : ${detailedMemory.appOtherUsageKb?.kbDisplay()}
""".trimIndent() """.trimIndent()
}
return base return base
} }

View File

@@ -1,32 +0,0 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.main
import android.os.Build
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import org.signal.core.util.DimensionUnit
import org.thoughtcrime.securesms.util.ViewUtil
@Composable
fun NavigationBarSpacerCompat() {
if (Build.VERSION.SDK_INT >= 23) {
Spacer(Modifier.navigationBarsPadding())
} else {
val resources = LocalContext.current.resources
val navigationBarHeight = remember(resources) {
DimensionUnit.PIXELS.toDp(ViewUtil.getNavigationBarHeight(resources).toFloat()).dp
}
Spacer(Modifier.height(navigationBarHeight))
}
}

View File

@@ -1,14 +1,12 @@
package org.thoughtcrime.securesms.mediasend package org.thoughtcrime.securesms.mediasend
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log
@@ -161,7 +159,6 @@ class VideoEditorFragment : Fragment(), PositionDragListener, MediaSendPageFragm
} }
} }
@RequiresApi(23)
private fun bindVideoTimeline(data: VideoTrimData) { private fun bindVideoTimeline(data: VideoTrimData) {
val autoplay = isVideoGif val autoplay = isVideoGif
val slide = VideoSlide(requireContext(), uri, 0, autoplay) val slide = VideoSlide(requireContext(), uri, 0, autoplay)
@@ -213,10 +210,8 @@ class VideoEditorFragment : Fragment(), PositionDragListener, MediaSendPageFragm
} }
private fun startPositionUpdates() { private fun startPositionUpdates() {
if (Build.VERSION.SDK_INT >= 23) { stopPositionUpdates()
stopPositionUpdates() handler.post(updatePosition)
handler.post(updatePosition)
}
} }
private fun stopPositionUpdates() { private fun stopPositionUpdates() {
@@ -250,7 +245,6 @@ class VideoEditorFragment : Fragment(), PositionDragListener, MediaSendPageFragm
hud.showPlayButton() hud.showPlayButton()
} }
@RequiresApi(23)
private fun onEditVideoDuration(data: VideoTrimData, editingComplete: Boolean) { private fun onEditVideoDuration(data: VideoTrimData, editingComplete: Boolean) {
if (editingComplete) { if (editingComplete) {
isInEdit = false isInEdit = false

View File

@@ -19,7 +19,6 @@ package org.thoughtcrime.securesms.mms;
import android.content.Context; import android.content.Context;
import android.content.res.Resources.Theme; import android.content.res.Resources.Theme;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import androidx.annotation.DrawableRes; import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -56,7 +55,7 @@ public class VideoSlide extends Slide {
@Override @Override
public boolean hasPlayOverlay() { public boolean hasPlayOverlay() {
return !(isVideoGif() && GiphyMp4PlaybackPolicy.autoplay()) || Build.VERSION.SDK_INT < 23; return !(isVideoGif() && GiphyMp4PlaybackPolicy.autoplay());
} }
@Override @Override

View File

@@ -9,14 +9,13 @@ import android.os.Build;
import android.provider.ContactsContract; import android.provider.ContactsContract;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.WorkerThread; import androidx.annotation.WorkerThread;
import org.signal.core.util.CursorUtil;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.signal.core.util.CursorUtil;
import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.ServiceUtil;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -31,8 +30,6 @@ public final class DoNotDisturbUtil {
@WorkerThread @WorkerThread
@SuppressLint("SwitchIntDef") @SuppressLint("SwitchIntDef")
public static boolean shouldDisturbUserWithCall(@NonNull Context context) { public static boolean shouldDisturbUserWithCall(@NonNull Context context) {
if (Build.VERSION.SDK_INT <= 23) return true;
NotificationManager notificationManager = ServiceUtil.getNotificationManager(context); NotificationManager notificationManager = ServiceUtil.getNotificationManager(context);
switch (notificationManager.getCurrentInterruptionFilter()) { switch (notificationManager.getCurrentInterruptionFilter()) {
@@ -47,8 +44,6 @@ public final class DoNotDisturbUtil {
@WorkerThread @WorkerThread
@SuppressLint("SwitchIntDef") @SuppressLint("SwitchIntDef")
public static boolean shouldDisturbUserWithCall(@NonNull Context context, @NonNull Recipient recipient) { public static boolean shouldDisturbUserWithCall(@NonNull Context context, @NonNull Recipient recipient) {
if (Build.VERSION.SDK_INT <= 23) return true;
NotificationManager notificationManager = ServiceUtil.getNotificationManager(context); NotificationManager notificationManager = ServiceUtil.getNotificationManager(context);
switch (notificationManager.getCurrentInterruptionFilter()) { switch (notificationManager.getCurrentInterruptionFilter()) {
@@ -65,7 +60,6 @@ public final class DoNotDisturbUtil {
} }
} }
@RequiresApi(23)
private static boolean handlePriority(@NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull Recipient recipient) { private static boolean handlePriority(@NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull Recipient recipient) {
if (Build.VERSION.SDK_INT < 28 && !notificationManager.isNotificationPolicyAccessGranted()) { if (Build.VERSION.SDK_INT < 28 && !notificationManager.isNotificationPolicyAccessGranted()) {
Log.w(TAG, "Notification Policy is not granted"); Log.w(TAG, "Notification Policy is not granted");

View File

@@ -14,8 +14,8 @@ import com.annimon.stream.Stream;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.dependencies.AppDependencies; import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.notifications.v2.DefaultMessageNotifier;
import org.thoughtcrime.securesms.notifications.v2.ConversationId; import org.thoughtcrime.securesms.notifications.v2.ConversationId;
import org.thoughtcrime.securesms.notifications.v2.DefaultMessageNotifier;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.BubbleUtil; import org.thoughtcrime.securesms.util.BubbleUtil;
import org.thoughtcrime.securesms.util.ConversationUtil; import org.thoughtcrime.securesms.util.ConversationUtil;
@@ -53,31 +53,27 @@ public final class NotificationCancellationHelper {
* bubble notifications that do not have unread messages in them. * bubble notifications that do not have unread messages in them.
*/ */
public static void cancelAllMessageNotifications(@NonNull Context context, @NonNull Set<Integer> stickyNotifications) { public static void cancelAllMessageNotifications(@NonNull Context context, @NonNull Set<Integer> stickyNotifications) {
if (Build.VERSION.SDK_INT >= 23) { try {
try { NotificationManager notifications = ServiceUtil.getNotificationManager(context);
NotificationManager notifications = ServiceUtil.getNotificationManager(context); StatusBarNotification[] activeNotifications = notifications.getActiveNotifications();
StatusBarNotification[] activeNotifications = notifications.getActiveNotifications(); int activeCount = 0;
int activeCount = 0;
for (StatusBarNotification activeNotification : activeNotifications) { for (StatusBarNotification activeNotification : activeNotifications) {
if (isSingleThreadNotification(activeNotification)) { if (isSingleThreadNotification(activeNotification)) {
activeCount++; activeCount++;
if (!stickyNotifications.contains(activeNotification.getId()) && cancel(context, activeNotification.getId())) { if (!stickyNotifications.contains(activeNotification.getId()) && cancel(context, activeNotification.getId())) {
activeCount--; activeCount--;
}
} }
} }
if (activeCount == 0) {
cancelLegacy(context, NotificationIds.MESSAGE_SUMMARY);
}
} catch (Throwable e) {
// XXX Appears to be a ROM bug, see #6043
Log.w(TAG, "Canceling all notifications.", e);
ServiceUtil.getNotificationManager(context).cancelAll();
} }
} else {
cancelLegacy(context, NotificationIds.MESSAGE_SUMMARY); if (activeCount == 0) {
cancelLegacy(context, NotificationIds.MESSAGE_SUMMARY);
}
} catch (Throwable e) {
// XXX Appears to be a ROM bug, see #6043
Log.w(TAG, "Canceling all notifications.", e);
ServiceUtil.getNotificationManager(context).cancelAll();
} }
} }
@@ -110,7 +106,6 @@ public final class NotificationCancellationHelper {
/** /**
* @return whether this is a non-summary notification that is a member of the NOTIFICATION_GROUP group. * @return whether this is a non-summary notification that is a member of the NOTIFICATION_GROUP group.
*/ */
@RequiresApi(23)
private static boolean isSingleThreadNotification(@NonNull StatusBarNotification statusBarNotification) { private static boolean isSingleThreadNotification(@NonNull StatusBarNotification statusBarNotification) {
return statusBarNotification.getId() != NotificationIds.MESSAGE_SUMMARY && return statusBarNotification.getId() != NotificationIds.MESSAGE_SUMMARY &&
Objects.equals(statusBarNotification.getNotification().getGroup(), DefaultMessageNotifier.NOTIFICATION_GROUP); Objects.equals(statusBarNotification.getNotification().getGroup(), DefaultMessageNotifier.NOTIFICATION_GROUP);

View File

@@ -5,7 +5,6 @@
package org.thoughtcrime.securesms.notifications package org.thoughtcrime.securesms.notifications
import android.os.Build
import android.text.TextUtils import android.text.TextUtils
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log
@@ -76,10 +75,6 @@ object SlowNotificationHeuristics {
@JvmStatic @JvmStatic
fun shouldPromptBatterySaver(): Boolean { fun shouldPromptBatterySaver(): Boolean {
if (Build.VERSION.SDK_INT < 23) {
return false
}
val remoteEnabled = LocaleRemoteConfig.isBatterySaverPromptEnabled() || LocaleRemoteConfig.isDelayedNotificationPromptEnabled() val remoteEnabled = LocaleRemoteConfig.isBatterySaverPromptEnabled() || LocaleRemoteConfig.isDelayedNotificationPromptEnabled()
if (!remoteEnabled || SignalStore.uiHints.hasDismissedBatterySaverPrompt()) { if (!remoteEnabled || SignalStore.uiHints.hasDismissedBatterySaverPrompt()) {
return false return false

View File

@@ -6,7 +6,6 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.provider.Settings; import android.provider.Settings;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.view.Display; import android.view.Display;
@@ -16,7 +15,6 @@ import android.view.WindowManager;
import androidx.annotation.DrawableRes; import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
@@ -52,10 +50,6 @@ public class Permissions {
return new PermissionsBuilder(new FragmentPermissionObject(fragment)); return new PermissionsBuilder(new FragmentPermissionObject(fragment));
} }
public static boolean isRuntimePermissionsRequired() {
return Build.VERSION.SDK_INT >= 23;
}
public static class PermissionsBuilder { public static class PermissionsBuilder {
private final PermissionObject permissionObject; private final PermissionObject permissionObject;
@@ -277,14 +271,12 @@ public class Permissions {
} }
public static boolean hasAny(@NonNull Context context, String... permissions) { public static boolean hasAny(@NonNull Context context, String... permissions) {
return !isRuntimePermissionsRequired() || return Stream.of(permissions).anyMatch(permission -> ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED);
Stream.of(permissions).anyMatch(permission -> ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED);
} }
public static boolean hasAll(@NonNull Context context, String... permissions) { public static boolean hasAll(@NonNull Context context, String... permissions) {
return !isRuntimePermissionsRequired() || return Stream.of(permissions).allMatch(permission -> ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED);
Stream.of(permissions).allMatch(permission -> ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED);
} }

View File

@@ -10,7 +10,6 @@ import androidx.annotation.AnyThread;
import androidx.annotation.IntRange; import androidx.annotation.IntRange;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread; import androidx.annotation.WorkerThread;
@@ -155,7 +154,6 @@ public class BlobProvider {
position)); position));
} }
@RequiresApi(23)
public synchronized @NonNull MediaDataSource getMediaDataSource(@NonNull Context context, @NonNull Uri uri) throws IOException { public synchronized @NonNull MediaDataSource getMediaDataSource(@NonNull Context context, @NonNull Uri uri) throws IOException {
waitUntilInitialized(); waitUntilInitialized();
return getBlobRepresentation(context, return getBlobRepresentation(context,

View File

@@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.push
import android.content.Context import android.content.Context
import android.net.ConnectivityManager import android.net.ConnectivityManager
import android.os.Build
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.google.i18n.phonenumbers.PhoneNumberUtil import com.google.i18n.phonenumbers.PhoneNumberUtil
import okhttp3.CipherSuite import okhttp3.CipherSuite
@@ -33,7 +32,6 @@ import org.whispersystems.signalservice.internal.configuration.SignalStorageUrl
import org.whispersystems.signalservice.internal.configuration.SignalSvr2Url import org.whispersystems.signalservice.internal.configuration.SignalSvr2Url
import java.io.IOException import java.io.IOException
import java.util.Optional import java.util.Optional
import android.net.Proxy as AndroidProxy
/** /**
* Provides a [SignalServiceConfiguration] to be used with our service layer. * Provides a [SignalServiceConfiguration] to be used with our service layer.
@@ -142,24 +140,13 @@ class SignalServiceNetworkAccess(context: Context) {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
private fun getSystemHttpProxy(context: Context): HttpProxy? { private fun getSystemHttpProxy(context: Context): HttpProxy? {
return if (Build.VERSION.SDK_INT >= 23) { val connectivityManager = ContextCompat.getSystemService(context, ConnectivityManager::class.java) ?: return null
val connectivityManager = ContextCompat.getSystemService(context, ConnectivityManager::class.java) ?: return null
connectivityManager return connectivityManager
.activeNetwork .activeNetwork
?.let { connectivityManager.getLinkProperties(it)?.httpProxy } ?.let { connectivityManager.getLinkProperties(it)?.httpProxy }
?.takeIf { !it.exclusionList.contains(BuildConfig.SIGNAL_URL.stripProtocol()) } ?.takeIf { !it.exclusionList.contains(BuildConfig.SIGNAL_URL.stripProtocol()) }
?.let { proxy -> HttpProxy(proxy.host, proxy.port) } ?.let { proxy -> HttpProxy(proxy.host, proxy.port) }
} else {
val host: String? = AndroidProxy.getHost(context)
val port: Int = AndroidProxy.getPort(context)
if (host != null) {
HttpProxy(host, port)
} else {
null
}
}
} }
} }
@@ -298,9 +285,11 @@ class SignalServiceNetworkAccess(context: Context) {
SettingsValues.CensorshipCircumventionEnabled.ENABLED -> { SettingsValues.CensorshipCircumventionEnabled.ENABLED -> {
censorshipConfiguration[countryCode] ?: defaultCensoredConfiguration censorshipConfiguration[countryCode] ?: defaultCensoredConfiguration
} }
SettingsValues.CensorshipCircumventionEnabled.DISABLED -> { SettingsValues.CensorshipCircumventionEnabled.DISABLED -> {
uncensoredConfiguration uncensoredConfiguration
} }
SettingsValues.CensorshipCircumventionEnabled.DEFAULT -> { SettingsValues.CensorshipCircumventionEnabled.DEFAULT -> {
if (defaultCensoredCountryCodes.contains(countryCode)) { if (defaultCensoredCountryCodes.contains(countryCode)) {
censorshipConfiguration[countryCode] ?: defaultCensoredConfiguration censorshipConfiguration[countryCode] ?: defaultCensoredConfiguration

View File

@@ -55,12 +55,7 @@ public final class SignalStrengthPhoneStateListener extends PhoneStateListener
} }
private boolean isLowLevel(@NonNull SignalStrength signalStrength) { private boolean isLowLevel(@NonNull SignalStrength signalStrength) {
if (Build.VERSION.SDK_INT >= 23) { return signalStrength.getLevel() == 0;
return signalStrength.getLevel() == 0;
} else {
//noinspection deprecation: False lint warning, deprecated by 29, but this else block is for < 23
return signalStrength.getGsmSignalStrength() == 0;
}
} }
public interface Callback { public interface Callback {

View File

@@ -8,7 +8,6 @@ package org.thoughtcrime.securesms.registration.ui.permissions
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@@ -28,7 +27,6 @@ import org.thoughtcrime.securesms.util.BackupUtil
/** /**
* Screen in account registration that provides rationales for the suggested runtime permissions. * Screen in account registration that provides rationales for the suggested runtime permissions.
*/ */
@RequiresApi(23)
class GrantPermissionsFragment : ComposeFragment() { class GrantPermissionsFragment : ComposeFragment() {
companion object { companion object {

View File

@@ -19,7 +19,6 @@ import org.thoughtcrime.securesms.LoggingFragment
import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.ViewBinderDelegate import org.thoughtcrime.securesms.components.ViewBinderDelegate
import org.thoughtcrime.securesms.databinding.FragmentRegistrationWelcomeV3Binding import org.thoughtcrime.securesms.databinding.FragmentRegistrationWelcomeV3Binding
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView
import org.thoughtcrime.securesms.registration.fragments.WelcomePermissions import org.thoughtcrime.securesms.registration.fragments.WelcomePermissions
import org.thoughtcrime.securesms.registration.ui.RegistrationCheckpoint import org.thoughtcrime.securesms.registration.ui.RegistrationCheckpoint
@@ -75,23 +74,21 @@ class WelcomeFragment : LoggingFragment(R.layout.fragment_registration_welcome_v
} }
} }
if (Permissions.isRuntimePermissionsRequired()) { parentFragmentManager.setFragmentResultListener(GrantPermissionsFragment.REQUEST_KEY, viewLifecycleOwner) { requestKey, bundle ->
parentFragmentManager.setFragmentResultListener(GrantPermissionsFragment.REQUEST_KEY, viewLifecycleOwner) { requestKey, bundle -> if (requestKey == GrantPermissionsFragment.REQUEST_KEY) {
if (requestKey == GrantPermissionsFragment.REQUEST_KEY) { when (val userSelection = bundle.getSerializableCompat(GrantPermissionsFragment.REQUEST_KEY, WelcomeUserSelection::class.java)) {
when (val userSelection = bundle.getSerializableCompat(GrantPermissionsFragment.REQUEST_KEY, WelcomeUserSelection::class.java)) { WelcomeUserSelection.RESTORE_WITH_OLD_PHONE,
WelcomeUserSelection.RESTORE_WITH_OLD_PHONE, WelcomeUserSelection.RESTORE_WITH_NO_PHONE -> navigateToNextScreenViaRestore(userSelection)
WelcomeUserSelection.RESTORE_WITH_NO_PHONE -> navigateToNextScreenViaRestore(userSelection) WelcomeUserSelection.CONTINUE -> navigateToNextScreenViaContinue()
WelcomeUserSelection.CONTINUE -> navigateToNextScreenViaContinue() WelcomeUserSelection.LINK -> navigateToLinkDevice()
WelcomeUserSelection.LINK -> navigateToLinkDevice() null -> Unit
null -> Unit
}
} }
} }
} }
} }
private fun onLinkDeviceClicked() { private fun onLinkDeviceClicked() {
if (Permissions.isRuntimePermissionsRequired() && !hasAllPermissions()) { if (!hasAllPermissions()) {
findNavController().safeNavigate(WelcomeFragmentDirections.actionWelcomeFragmentToGrantPermissionsFragment(WelcomeUserSelection.LINK)) findNavController().safeNavigate(WelcomeFragmentDirections.actionWelcomeFragmentToGrantPermissionsFragment(WelcomeUserSelection.LINK))
} else { } else {
navigateToLinkDevice() navigateToLinkDevice()
@@ -108,7 +105,7 @@ class WelcomeFragment : LoggingFragment(R.layout.fragment_registration_welcome_v
} }
private fun onContinueClicked() { private fun onContinueClicked() {
if (Permissions.isRuntimePermissionsRequired() && !hasAllPermissions()) { if (!hasAllPermissions()) {
findNavController().safeNavigate(WelcomeFragmentDirections.actionWelcomeFragmentToGrantPermissionsFragment(WelcomeUserSelection.CONTINUE)) findNavController().safeNavigate(WelcomeFragmentDirections.actionWelcomeFragmentToGrantPermissionsFragment(WelcomeUserSelection.CONTINUE))
} else { } else {
navigateToNextScreenViaContinue() navigateToNextScreenViaContinue()
@@ -129,7 +126,7 @@ class WelcomeFragment : LoggingFragment(R.layout.fragment_registration_welcome_v
} }
private fun afterRestoreOrTransferClicked(userSelection: WelcomeUserSelection) { private fun afterRestoreOrTransferClicked(userSelection: WelcomeUserSelection) {
if (Permissions.isRuntimePermissionsRequired() && !hasAllPermissions()) { if (!hasAllPermissions()) {
findNavController().safeNavigate(WelcomeFragmentDirections.actionWelcomeFragmentToGrantPermissionsFragment(userSelection)) findNavController().safeNavigate(WelcomeFragmentDirections.actionWelcomeFragmentToGrantPermissionsFragment(userSelection))
} else { } else {
navigateToNextScreenViaRestore(userSelection) navigateToNextScreenViaRestore(userSelection)

View File

@@ -24,7 +24,6 @@ import android.app.Service;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Binder; import android.os.Binder;
import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.os.SystemClock; import android.os.SystemClock;
@@ -313,11 +312,7 @@ public class KeyCachingService extends Service {
} }
private static int getPendingIntentFlags() { private static int getPendingIntentFlags() {
if (Build.VERSION.SDK_INT >= 23) { return PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT;
return PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT;
} else {
return PendingIntent.FLAG_UPDATE_CURRENT;
}
} }
@Override @Override

View File

@@ -4,7 +4,6 @@ import android.media.MediaDataSource;
import android.media.MediaMetadataRetriever; import android.media.MediaMetadataRetriever;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import java.io.IOException; import java.io.IOException;
@@ -16,7 +15,6 @@ public final class MediaMetadataRetrieverUtil {
* {@link MediaMetadataRetriever#setDataSource(MediaDataSource)} tends to crash in native code on * {@link MediaMetadataRetriever#setDataSource(MediaDataSource)} tends to crash in native code on
* specific devices, so this just a wrapper to convert that into an {@link IOException}. * specific devices, so this just a wrapper to convert that into an {@link IOException}.
*/ */
@RequiresApi(23)
public static void setDataSource(@NonNull MediaMetadataRetriever retriever, public static void setDataSource(@NonNull MediaMetadataRetriever retriever,
@NonNull MediaDataSource dataSource) @NonNull MediaDataSource dataSource)
throws IOException throws IOException

View File

@@ -12,7 +12,6 @@ import android.media.MediaDataSource;
import android.media.MediaMetadataRetriever; import android.media.MediaMetadataRetriever;
import android.media.ThumbnailUtils; import android.media.ThumbnailUtils;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Pair; import android.util.Pair;
@@ -20,7 +19,6 @@ import android.webkit.MimeTypeMap;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.WorkerThread; import androidx.annotation.WorkerThread;
import androidx.exifinterface.media.ExifInterface; import androidx.exifinterface.media.ExifInterface;
@@ -431,7 +429,7 @@ public class MediaUtil {
return false; return false;
} }
if (BlobProvider.isAuthority(uri) && MediaUtil.isVideo(BlobProvider.getMimeType(uri)) && Build.VERSION.SDK_INT >= 23) { if (BlobProvider.isAuthority(uri) && MediaUtil.isVideo(BlobProvider.getMimeType(uri))) {
return true; return true;
} }
@@ -476,8 +474,7 @@ public class MediaUtil {
MediaUtil.isVideo(URLConnection.guessContentTypeFromName(uri.toString()))) { MediaUtil.isVideo(URLConnection.guessContentTypeFromName(uri.toString()))) {
return ThumbnailUtils.createVideoThumbnail(uri.toString().replace("file://", ""), return ThumbnailUtils.createVideoThumbnail(uri.toString().replace("file://", ""),
MediaStore.Video.Thumbnails.MINI_KIND); MediaStore.Video.Thumbnails.MINI_KIND);
} else if (Build.VERSION.SDK_INT >= 23 && } else if (BlobProvider.isAuthority(uri) &&
BlobProvider.isAuthority(uri) &&
MediaUtil.isVideo(BlobProvider.getMimeType(uri))) MediaUtil.isVideo(BlobProvider.getMimeType(uri)))
{ {
try { try {
@@ -486,8 +483,7 @@ public class MediaUtil {
} catch (IOException e) { } catch (IOException e) {
Log.w(TAG, "Failed to extract frame for URI: " + uri, e); Log.w(TAG, "Failed to extract frame for URI: " + uri, e);
} }
} else if (Build.VERSION.SDK_INT >= 23 && } else if (PartAuthority.isAttachmentUri(uri) &&
PartAuthority.isAttachmentUri(uri) &&
MediaUtil.isVideoType(PartAuthority.getAttachmentContentType(context, uri))) MediaUtil.isVideoType(PartAuthority.getAttachmentContentType(context, uri)))
{ {
try { try {
@@ -502,7 +498,6 @@ public class MediaUtil {
return null; return null;
} }
@RequiresApi(23)
private static @Nullable Bitmap extractFrame(@Nullable MediaDataSource dataSource, long timeUs) throws IOException { private static @Nullable Bitmap extractFrame(@Nullable MediaDataSource dataSource, long timeUs) throws IOException {
if (dataSource == null) { if (dataSource == null) {
return null; return null;

View File

@@ -89,17 +89,13 @@ public final class NetworkUtil {
public static @NonNull NetworkStatus getNetworkStatus(@NonNull Context context) { public static @NonNull NetworkStatus getNetworkStatus(@NonNull Context context) {
ConnectivityManager connectivityManager = ServiceUtil.getConnectivityManager(context); ConnectivityManager connectivityManager = ServiceUtil.getConnectivityManager(context);
if (Build.VERSION.SDK_INT >= 23) { Network network = connectivityManager.getActiveNetwork();
Network network = connectivityManager.getActiveNetwork(); NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
boolean onVpn = capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN); boolean onVpn = capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
boolean isNotMetered = capabilities == null || capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); boolean isNotMetered = capabilities == null || capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
return new NetworkStatus(onVpn, !isNotMetered); return new NetworkStatus(onVpn, !isNotMetered);
} else {
return new NetworkStatus(false, false);
}
} }
private static boolean useLowDataCalling(@NonNull Context context, @NonNull PeerConnection.AdapterType networkAdapter) { private static boolean useLowDataCalling(@NonNull Context context, @NonNull PeerConnection.AdapterType networkAdapter) {

View File

@@ -3,30 +3,21 @@ package org.thoughtcrime.securesms.util;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.PowerManager; import android.os.PowerManager;
import android.provider.Settings; import android.provider.Settings;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
public class PowerManagerCompat { public class PowerManagerCompat {
public static boolean isDeviceIdleMode(@NonNull PowerManager powerManager) { public static boolean isDeviceIdleMode(@NonNull PowerManager powerManager) {
if (Build.VERSION.SDK_INT >= 23) { return powerManager.isDeviceIdleMode();
return powerManager.isDeviceIdleMode();
}
return false;
} }
public static boolean isIgnoringBatteryOptimizations(@NonNull Context context) { public static boolean isIgnoringBatteryOptimizations(@NonNull Context context) {
if (Build.VERSION.SDK_INT < 23) {
return true;
}
return ServiceUtil.getPowerManager(context).isIgnoringBatteryOptimizations(context.getPackageName()); return ServiceUtil.getPowerManager(context).isIgnoringBatteryOptimizations(context.getPackageName());
} }
@RequiresApi(api = 23)
public static void requestIgnoreBatteryOptimizations(@NonNull Context context) { public static void requestIgnoreBatteryOptimizations(@NonNull Context context) {
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Uri.parse("package:" + context.getPackageName())); Uri.parse("package:" + context.getPackageName()));

View File

@@ -659,11 +659,7 @@ public class TextSecurePreferences {
@Deprecated @Deprecated
public static boolean isCallNotificationVibrateEnabled(Context context) { public static boolean isCallNotificationVibrateEnabled(Context context) {
boolean defaultValue = true; boolean defaultValue = (Settings.System.getInt(context.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 1) == 1);
if (Build.VERSION.SDK_INT >= 23) {
defaultValue = (Settings.System.getInt(context.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 1) == 1);
}
return getBooleanPreference(context, CALL_VIBRATE_PREF, defaultValue); return getBooleanPreference(context, CALL_VIBRATE_PREF, defaultValue);
} }

View File

@@ -62,8 +62,6 @@ public final class WindowUtil {
} }
public static void setLightStatusBarFromTheme(@NonNull Activity activity) { public static void setLightStatusBarFromTheme(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT < 23) return;
final boolean isLightStatusBar = ThemeUtil.getThemedBoolean(activity, android.R.attr.windowLightStatusBar); final boolean isLightStatusBar = ThemeUtil.getThemedBoolean(activity, android.R.attr.windowLightStatusBar);
if (isLightStatusBar) setLightStatusBar(activity.getWindow()); if (isLightStatusBar) setLightStatusBar(activity.getWindow());
@@ -71,14 +69,10 @@ public final class WindowUtil {
} }
public static void clearLightStatusBar(@NonNull Window window) { public static void clearLightStatusBar(@NonNull Window window) {
if (Build.VERSION.SDK_INT < 23) return;
clearSystemUiFlags(window, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); clearSystemUiFlags(window, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} }
public static void setLightStatusBar(@NonNull Window window) { public static void setLightStatusBar(@NonNull Window window) {
if (Build.VERSION.SDK_INT < 23) return;
setSystemUiFlags(window, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); setSystemUiFlags(window, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} }

View File

@@ -2,11 +2,8 @@ package org.thoughtcrime.securesms.video;
import android.media.MediaDataSource; import android.media.MediaDataSource;
import androidx.annotation.RequiresApi;
import java.io.IOException; import java.io.IOException;
@RequiresApi(23)
public class ByteArrayMediaDataSource extends MediaDataSource { public class ByteArrayMediaDataSource extends MediaDataSource {
private byte[] data; private byte[] data;

View File

@@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.video;
import android.media.MediaDataSource; import android.media.MediaDataSource;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import org.thoughtcrime.securesms.crypto.AttachmentSecret; import org.thoughtcrime.securesms.crypto.AttachmentSecret;
import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream; import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream;
@@ -13,7 +12,6 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@RequiresApi(23)
final class ClassicEncryptedMediaDataSource extends MediaDataSource { final class ClassicEncryptedMediaDataSource extends MediaDataSource {
private final AttachmentSecret attachmentSecret; private final AttachmentSecret attachmentSecret;

View File

@@ -4,13 +4,11 @@ import android.media.MediaDataSource;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import org.thoughtcrime.securesms.crypto.AttachmentSecret; import org.thoughtcrime.securesms.crypto.AttachmentSecret;
import java.io.File; import java.io.File;
@RequiresApi(23)
public final class EncryptedMediaDataSource { public final class EncryptedMediaDataSource {
public static MediaDataSource createFor(@NonNull AttachmentSecret attachmentSecret, @NonNull File mediaFile, @Nullable byte[] random, long length) { public static MediaDataSource createFor(@NonNull AttachmentSecret attachmentSecret, @NonNull File mediaFile, @Nullable byte[] random, long length) {

View File

@@ -4,7 +4,6 @@ import android.media.MediaDataSource;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import org.thoughtcrime.securesms.crypto.AttachmentSecret; import org.thoughtcrime.securesms.crypto.AttachmentSecret;
import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream; import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream;
@@ -22,7 +21,6 @@ import java.io.InputStream;
* It is "modern" compared to the {@link ClassicEncryptedMediaDataSource}. And "modern" refers to * It is "modern" compared to the {@link ClassicEncryptedMediaDataSource}. And "modern" refers to
* the presence of a random part of the key supplied in the constructor. * the presence of a random part of the key supplied in the constructor.
*/ */
@RequiresApi(23)
final class ModernEncryptedMediaDataSource extends InputStreamMediaDataSource { final class ModernEncryptedMediaDataSource extends InputStreamMediaDataSource {
private final AttachmentSecret attachmentSecret; private final AttachmentSecret attachmentSecret;

View File

@@ -172,33 +172,26 @@ public abstract class AudioManagerCompat {
audioManager.clearCommunicationDevice(); audioManager.clearCommunicationDevice();
} }
@RequiresApi(23)
public void registerAudioDeviceCallback(@NonNull AudioDeviceCallback deviceCallback, @NonNull Handler handler) { public void registerAudioDeviceCallback(@NonNull AudioDeviceCallback deviceCallback, @NonNull Handler handler) {
audioManager.registerAudioDeviceCallback(deviceCallback, handler); audioManager.registerAudioDeviceCallback(deviceCallback, handler);
} }
@RequiresApi(23)
public void unregisterAudioDeviceCallback(@NonNull AudioDeviceCallback deviceCallback) { public void unregisterAudioDeviceCallback(@NonNull AudioDeviceCallback deviceCallback) {
audioManager.unregisterAudioDeviceCallback(deviceCallback); audioManager.unregisterAudioDeviceCallback(deviceCallback);
} }
@SuppressLint("WrongConstant") @SuppressLint("WrongConstant")
public boolean isWiredHeadsetOn() { public boolean isWiredHeadsetOn() {
if (Build.VERSION.SDK_INT < 23) { AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
//noinspection deprecation for (AudioDeviceInfo device : devices) {
return audioManager.isWiredHeadsetOn(); final int type = device.getType();
} else { if (type == AudioDeviceInfo.TYPE_WIRED_HEADSET) {
AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL); return true;
for (AudioDeviceInfo device : devices) { } else if (type == AudioDeviceInfo.TYPE_USB_DEVICE) {
final int type = device.getType(); return true;
if (type == AudioDeviceInfo.TYPE_WIRED_HEADSET) {
return true;
} else if (type == AudioDeviceInfo.TYPE_USB_DEVICE) {
return true;
}
} }
return false;
} }
return false;
} }
public float ringVolumeWithMinimum() { public float ringVolumeWithMinimum() {

View File

@@ -9,7 +9,6 @@ import android.app.ActivityManager
import android.content.Context import android.content.Context
import android.os.Debug import android.os.Debug
import android.os.Handler import android.os.Handler
import androidx.annotation.RequiresApi
import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.concurrent.SignalExecutors
import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
@@ -89,7 +88,6 @@ object MemoryTracker {
* This gives us details stats, but it takes an appreciable amount of time. On an emulator, it can take ~30ms. * This gives us details stats, but it takes an appreciable amount of time. On an emulator, it can take ~30ms.
* As a result, we don't want to be calling this regularly for most users. * As a result, we don't want to be calling this regularly for most users.
*/ */
@RequiresApi(23)
fun getDetailedMemoryStats(): DetailedMemoryStats { fun getDetailedMemoryStats(): DetailedMemoryStats {
Debug.getMemoryInfo(debugMemoryInfo) Debug.getMemoryInfo(debugMemoryInfo)

View File

@@ -42,6 +42,6 @@ object PendingIntentFlags {
@JvmStatic @JvmStatic
fun immutable(): Int { fun immutable(): Int {
return if (Build.VERSION.SDK_INT >= 23) PendingIntent.FLAG_IMMUTABLE else 0 return PendingIntent.FLAG_IMMUTABLE
} }
} }

View File

@@ -86,7 +86,7 @@ public class MainActivity extends AppCompatActivity {
findViewById(R.id.stop).setOnClickListener(v -> DeviceToDeviceTransferService.stop(this)); findViewById(R.id.stop).setOnClickListener(v -> DeviceToDeviceTransferService.stop(this));
findViewById(R.id.enable_permission).setOnClickListener(v -> { findViewById(R.id.enable_permission).setOnClickListener(v -> {
if (Build.VERSION.SDK_INT >= 23 && checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 420); requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 420);
} }
}); });

View File

@@ -92,13 +92,13 @@ public final class WifiDirect {
if (Build.VERSION.SDK_INT >= 33 && context.checkSelfPermission(Manifest.permission.NEARBY_WIFI_DEVICES) != PackageManager.PERMISSION_GRANTED) { if (Build.VERSION.SDK_INT >= 33 && context.checkSelfPermission(Manifest.permission.NEARBY_WIFI_DEVICES) != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "Nearby Wifi permission required"); Log.i(TAG, "Nearby Wifi permission required");
return AvailableStatus.REQUIRED_PERMISSION_NOT_GRANTED; return AvailableStatus.REQUIRED_PERMISSION_NOT_GRANTED;
} else if (Build.VERSION.SDK_INT < 33 && Build.VERSION.SDK_INT >= 23 && context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { } else if (Build.VERSION.SDK_INT < 33 && context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "Fine location permission required"); Log.i(TAG, "Fine location permission required");
return AvailableStatus.REQUIRED_PERMISSION_NOT_GRANTED; return AvailableStatus.REQUIRED_PERMISSION_NOT_GRANTED;
} }
return Build.VERSION.SDK_INT <= 23 || wifiManager.isP2pSupported() ? AvailableStatus.AVAILABLE return wifiManager.isP2pSupported() ? AvailableStatus.AVAILABLE
: AvailableStatus.WIFI_DIRECT_NOT_AVAILABLE; : AvailableStatus.WIFI_DIRECT_NOT_AVAILABLE;
} }
WifiDirect(@NonNull Context context) { WifiDirect(@NonNull Context context) {

View File

@@ -2,7 +2,6 @@ package org.signal.qrtest
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.graphics.Bitmap import android.graphics.Bitmap
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.EditText import android.widget.EditText
@@ -73,9 +72,7 @@ class QrMainActivity : AppCompatActivity() {
text = findViewById(R.id.log) text = findViewById(R.id.log)
if (Build.VERSION.SDK_INT >= 23) { requestPermissions(arrayOf(android.Manifest.permission.CAMERA), 1)
requestPermissions(arrayOf(android.Manifest.permission.CAMERA), 1)
}
val scanner = findViewById<QrScannerView>(R.id.scanner) val scanner = findViewById<QrScannerView>(R.id.scanner)
scanner.start(this) scanner.start(this)

View File

@@ -29,9 +29,9 @@ import androidx.annotation.StringDef;
import androidx.annotation.WorkerThread; import androidx.annotation.WorkerThread;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.video.videoconverter.exceptions.EncodingException;
import org.thoughtcrime.securesms.video.interfaces.MediaInput; import org.thoughtcrime.securesms.video.interfaces.MediaInput;
import org.thoughtcrime.securesms.video.interfaces.Muxer; import org.thoughtcrime.securesms.video.interfaces.Muxer;
import org.thoughtcrime.securesms.video.videoconverter.exceptions.EncodingException;
import org.thoughtcrime.securesms.video.videoconverter.muxer.StreamingMuxer; import org.thoughtcrime.securesms.video.videoconverter.muxer.StreamingMuxer;
import java.io.File; import java.io.File;
@@ -142,7 +142,6 @@ public final class MediaConverter {
* @return The total content size of the MP4 mdat box. * @return The total content size of the MP4 mdat box.
*/ */
@WorkerThread @WorkerThread
@RequiresApi(23)
public long convert() throws EncodingException, IOException { public long convert() throws EncodingException, IOException {
// Exception that may be thrown during release. // Exception that may be thrown during release.
Exception exception = null; Exception exception = null;

View File

@@ -14,7 +14,6 @@ import android.view.Surface;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.video.interfaces.MediaInput; import org.thoughtcrime.securesms.video.interfaces.MediaInput;
@@ -78,7 +77,6 @@ final class VideoTrackConverter {
private Muxer mMuxer; private Muxer mMuxer;
@RequiresApi(23)
static @Nullable VideoTrackConverter create( static @Nullable VideoTrackConverter create(
final @NonNull MediaInput input, final @NonNull MediaInput input,
final long timeFrom, final long timeFrom,
@@ -97,7 +95,6 @@ final class VideoTrackConverter {
} }
@RequiresApi(23)
private VideoTrackConverter( private VideoTrackConverter(
final @NonNull MediaExtractor videoExtractor, final @NonNull MediaExtractor videoExtractor,
final int videoInputTrack, final int videoInputTrack,

View File

@@ -6,14 +6,12 @@
package org.thoughtcrime.securesms.video.videoconverter.mediadatasource package org.thoughtcrime.securesms.video.videoconverter.mediadatasource
import android.media.MediaDataSource import android.media.MediaDataSource
import androidx.annotation.RequiresApi
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
/** /**
* Extend this class in order to be able to use the system media framework with any arbitrary [InputStream] of bytes. * Extend this class in order to be able to use the system media framework with any arbitrary [InputStream] of bytes.
*/ */
@RequiresApi(23)
abstract class InputStreamMediaDataSource : MediaDataSource() { abstract class InputStreamMediaDataSource : MediaDataSource() {
@Throws(IOException::class) @Throws(IOException::class)
override fun readAt(position: Long, bytes: ByteArray?, offset: Int, length: Int): Int { override fun readAt(position: Long, bytes: ByteArray?, offset: Int, length: Int): Int {

View File

@@ -7,14 +7,12 @@ package org.thoughtcrime.securesms.video.videoconverter.mediadatasource
import android.media.MediaDataSource import android.media.MediaDataSource
import android.media.MediaExtractor import android.media.MediaExtractor
import androidx.annotation.RequiresApi
import org.thoughtcrime.securesms.video.interfaces.MediaInput import org.thoughtcrime.securesms.video.interfaces.MediaInput
import java.io.IOException import java.io.IOException
/** /**
* [MediaInput] implementation that adds support for the system framework's media data source. * [MediaInput] implementation that adds support for the system framework's media data source.
*/ */
@RequiresApi(23)
class MediaDataSourceMediaInput(private val mediaDataSource: MediaDataSource) : MediaInput { class MediaDataSourceMediaInput(private val mediaDataSource: MediaDataSource) : MediaInput {
@Throws(IOException::class) @Throws(IOException::class)
override fun createExtractor(): MediaExtractor { override fun createExtractor(): MediaExtractor {

View File

@@ -10,7 +10,6 @@ import android.media.MediaCodecInfo.CodecProfileLevel
import android.media.MediaCodecList import android.media.MediaCodecList
import android.media.MediaFormat import android.media.MediaFormat
import android.os.Build import android.os.Build
import androidx.annotation.RequiresApi
import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log
import java.io.IOException import java.io.IOException
@@ -77,9 +76,7 @@ object MediaCodecCompat {
// dolby vision profile 04/08: Base layer is H.265 Main10 High Profile, Rec709/HLG/HDR10 // dolby vision profile 04/08: Base layer is H.265 Main10 High Profile, Rec709/HLG/HDR10
mediaFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_HEVC) mediaFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_HEVC)
mediaFormat.setInteger(MediaFormat.KEY_PROFILE, CodecProfileLevel.HEVCProfileMain10) mediaFormat.setInteger(MediaFormat.KEY_PROFILE, CodecProfileLevel.HEVCProfileMain10)
if (Build.VERSION.SDK_INT >= 23) { mediaFormat.setBaseCodecLevelFromDolbyVisionLevel()
mediaFormat.setBaseCodecLevelFromDolbyVisionLevel()
}
return findDecoder(mediaFormat) return findDecoder(mediaFormat)
} }
@@ -87,9 +84,7 @@ object MediaCodecCompat {
// dolby vision profile 09: Base layer is H.264 High/Progressive/Constrained Profile, Rec 709 // dolby vision profile 09: Base layer is H.264 High/Progressive/Constrained Profile, Rec 709
mediaFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_AVC) mediaFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_AVC)
mediaFormat.setInteger(MediaFormat.KEY_PROFILE, CodecProfileLevel.AVCProfileHigh) mediaFormat.setInteger(MediaFormat.KEY_PROFILE, CodecProfileLevel.AVCProfileHigh)
if (Build.VERSION.SDK_INT >= 23) { mediaFormat.setBaseCodecLevelFromDolbyVisionLevel()
mediaFormat.setBaseCodecLevelFromDolbyVisionLevel()
}
return findDecoder(mediaFormat) return findDecoder(mediaFormat)
} }
@@ -100,7 +95,6 @@ object MediaCodecCompat {
} }
} }
@RequiresApi(23)
private fun MediaFormat.setBaseCodecLevelFromDolbyVisionLevel(): Boolean { private fun MediaFormat.setBaseCodecLevelFromDolbyVisionLevel(): Boolean {
val mimeType = this.getString(MediaFormat.KEY_MIME) ?: return false val mimeType = this.getString(MediaFormat.KEY_MIME) ?: return false
try { try {