Enable key transparency for internal users.

This commit is contained in:
Michelle Tang
2026-02-02 17:46:19 -05:00
parent e9f2580bb8
commit 1ddde6ab92
9 changed files with 45 additions and 38 deletions

View File

@@ -299,7 +299,7 @@ private fun AdvancedPrivacySettingsScreen(
)
}
if (RemoteConfig.keyTransparency) {
if (RemoteConfig.internalUser) {
item {
Dividers.Default()
}

View File

@@ -663,7 +663,6 @@ class ConversationFragment :
presentGroupConversationSubtitle(createGroupSubtitleString(viewModel.titleViewParticipantsSnapshot))
presentActionBarMenu()
presentStoryRing()
presentVerifyAutomaticallySheet()
observeConversationThread()
@@ -1417,12 +1416,6 @@ class ConversationFragment :
}
}
private fun presentVerifyAutomaticallySheet() {
if (RemoteConfig.keyTransparency && SignalStore.settings.automaticVerificationEnabled && !SignalStore.uiHints.hasSeenVerifyAutomaticallySheet() && viewModel.recipientSnapshot?.isIndividual == true) {
VerifyAutomaticallyEducationSheet.show(parentFragmentManager)
}
}
private fun presentInputReadyState(inputReadyState: InputReadyState) {
presentConversationTitle(inputReadyState.conversationRecipient)
@@ -1454,6 +1447,17 @@ class ConversationFragment :
private fun presentIdentityRecordsState(identityRecordsState: IdentityRecordsState) {
binding.conversationTitleView.root.setVerified(identityRecordsState.isVerified)
if (RemoteConfig.internalUser && SignalStore.settings.automaticVerificationEnabled && !SignalStore.uiHints.hasSeenVerifyAutomaticallySheet() && viewModel.recipientSnapshot?.isIndividual == true) {
VerifyAutomaticallyEducationSheet.show(parentFragmentManager)
parentFragmentManager.setFragmentResultListener(VerifyAutomaticallyEducationSheet.RESULT_KEY, requireActivity()) { _, bundle ->
val shouldVerify = bundle.getBoolean(VerifyAutomaticallyEducationSheet.RESULT_KEY, false)
if (shouldVerify) {
VerifyIdentityActivity.startOrShowExchangeMessagesDialog(requireContext(), identityRecordsState.identityRecords.identityRecords.first())
}
}
}
if (identityRecordsState.isUnverified) {
binding.conversationBanner.showUnverifiedBanner(identityRecordsState.identityRecords)
} else {

View File

@@ -84,7 +84,7 @@ class CheckKeyTransparencyJob private constructor(
}
private fun canRunJob(): Boolean {
return if (!RemoteConfig.keyTransparency) {
return if (!RemoteConfig.internalUser) {
Log.i(TAG, "Remote config is not on. Exiting.")
false
} else if (!SignalStore.account.isRegistered) {

View File

@@ -1226,18 +1226,6 @@ object RemoteConfig {
hotSwappable = true
)
/**
* Whether or not to show any UI related to key transparency
*/
@JvmStatic
@get:JvmName("keyTransparency")
val keyTransparency: Boolean by remoteBoolean(
key = "android.keyTransparency",
active = false,
defaultValue = false,
hotSwappable = true
)
/**
* Whether or not the new UX for unified local backups is enabled
*/

View File

@@ -18,7 +18,9 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.core.os.bundleOf
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.setFragmentResult
import org.signal.core.ui.compose.BottomSheets
import org.signal.core.ui.compose.Buttons
import org.signal.core.ui.compose.DayNightPreviews
@@ -27,6 +29,7 @@ import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.BottomSheetUtil
import org.thoughtcrime.securesms.util.CommunicationActions
/**
* Education sheet explaining that conversations now have auto verification
@@ -37,6 +40,8 @@ class VerifyAutomaticallyEducationSheet : ComposeBottomSheetDialogFragment() {
companion object {
const val RESULT_KEY = "verify_result_key"
@JvmStatic
fun show(fragmentManager: FragmentManager) {
VerifyAutomaticallyEducationSheet().show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
@@ -51,8 +56,13 @@ class VerifyAutomaticallyEducationSheet : ComposeBottomSheetDialogFragment() {
@Composable
override fun SheetContent() {
VerifyEducationSheet(
onVerify = {}, // TODO(michelle): Plug in to verify fragment
onLearnMore = {} // TODO(michelle): Update with support url
onVerify = {
setFragmentResult(RESULT_KEY, bundleOf(RESULT_KEY to true))
dismissAllowingStateLoss()
},
onLearnMore = {
CommunicationActions.openBrowserLink(requireContext(), getString(R.string.verify_display_fragment__link))
}
)
}
}

View File

@@ -75,7 +75,7 @@ class VerifyDisplayFragment : Fragment() {
updateVerifyButton(requireArguments().getBoolean(VERIFIED_STATE, false), false)
binding.automaticVerification.visible = RemoteConfig.keyTransparency && SignalStore.settings.automaticVerificationEnabled
binding.automaticVerification.visible = RemoteConfig.internalUser && SignalStore.settings.automaticVerificationEnabled
binding.safetyQrView.verifyButton.setOnClickListener { updateVerifyButton(!currentVerifiedState, true) }
binding.toolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
binding.toolbar.setTitle(R.string.AndroidManifest__verify_safety_number)
@@ -119,18 +119,22 @@ class VerifyDisplayFragment : Fragment() {
}
private fun animateStatus(status: AutomaticVerificationStatus) {
binding.autoVerifyContainer.animate()
.alpha(0f)
.setDuration(FADE_TIME)
.withEndAction {
updateStatus(status)
if (status == AutomaticVerificationStatus.NONE || status == AutomaticVerificationStatus.UNAVAILABLE_PERMANENT) {
updateStatus(status)
} else {
binding.autoVerifyContainer.animate()
.alpha(0f)
.setDuration(FADE_TIME)
.withEndAction {
updateStatus(status)
binding.autoVerifyContainer.animate()
.alpha(1f)
.setDuration(FADE_TIME)
.start()
}
.start()
binding.autoVerifyContainer.animate()
.alpha(1f)
.setDuration(FADE_TIME)
.start()
}
.start()
}
}
private fun updateStatus(status: AutomaticVerificationStatus) {

View File

@@ -53,7 +53,7 @@ class VerifySafetyNumberViewModel(
}
private fun checkAutomaticVerificationEligibility() {
if (recipient.get().e164.isEmpty || recipient.get().aci.isEmpty) {
if (recipient.get().e164.isEmpty || recipient.get().aci.isEmpty || SignalStore.misc.hasKeyTransparencyFailure) {
automaticVerificationLiveData.postValue(AutomaticVerificationStatus.UNAVAILABLE_PERMANENT)
}
}

View File

@@ -231,10 +231,11 @@
<com.google.android.material.button.MaterialButton
android:id="@+id/verify_button"
style="@style/Signal.Widget.Button.Base.Tonal"
android:backgroundTint="@color/signal_colorSurface1"
android:backgroundTint="@color/core_white"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:textColor="@color/signal_light_colorOnSurface"
android:text="@string/verify_display_fragment__mark_as_verified"
app:layout_constraintTop_toBottomOf="@id/number_table"
app:layout_constraintStart_toStartOf="parent"

View File

@@ -3848,7 +3848,7 @@
<string name="verify_display_fragment__encryption_unavailable">Auto-verification unavailable</string>
<!-- Caption text explaining more about automatic verification -->
<string name="verify_display_fragment__auto_verify_not_available">Auto-verification is not available for all chats.</string>
<string name="verify_display_fragment__link" translatable="false">https://signal.org/redirect/safety-numbers</string>
<string name="verify_display_fragment__link" translatable="false">https://support.signal.org/hc/articles/10223569377562</string>
<!-- Bottom sheet title when encryption is auto-verified -->
<string name="EncryptionVerifiedSheet__title_success">Encryption was auto-verified for this chat</string>