mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-21 02:08:40 +00:00
Route system camera quick restore qr scan into Signal camera.
This commit is contained in:
committed by
jeffrey-signal
parent
8783d69406
commit
87e56bf4bf
@@ -934,6 +934,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
|
||||
handleSignalMeIntent(intent)
|
||||
handleCallLinkInIntent(intent)
|
||||
handleDonateReturnIntent(intent)
|
||||
handleQuickRestoreIntent(intent)
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@@ -990,6 +991,14 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleQuickRestoreIntent(intent: Intent) {
|
||||
intent.data?.let { data ->
|
||||
CommunicationActions.handlePotentialQuickRestoreUrl(this, data.toString()) {
|
||||
onCameraClick(MainNavigationListLocation.CHATS, isForQuickRestore = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNotificationProfileStatus(notificationProfiles: List<NotificationProfile>) {
|
||||
val activeProfile = NotificationProfiles.getActiveProfile(notificationProfiles)
|
||||
if (activeProfile != null) {
|
||||
@@ -1028,6 +1037,39 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
|
||||
}
|
||||
}
|
||||
|
||||
private fun onCameraClick(destination: MainNavigationListLocation, isForQuickRestore: Boolean) {
|
||||
val onGranted = {
|
||||
val intent = if (isForQuickRestore) {
|
||||
MediaSelectionActivity.cameraForQuickRestore(context = this@MainActivity)
|
||||
} else {
|
||||
MediaSelectionActivity.camera(
|
||||
context = this@MainActivity,
|
||||
isStory = destination == MainNavigationListLocation.STORIES
|
||||
)
|
||||
}
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
if (CameraXUtil.isSupported()) {
|
||||
onGranted()
|
||||
} else {
|
||||
Permissions.with(this@MainActivity)
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.ifNecessary()
|
||||
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.CameraXFragment_to_capture_photos_and_video_allow_camera), R.drawable.symbol_camera_24)
|
||||
.withPermanentDenialDialog(
|
||||
getString(R.string.CameraXFragment_signal_needs_camera_access_capture_photos),
|
||||
null,
|
||||
R.string.CameraXFragment_allow_access_camera,
|
||||
R.string.CameraXFragment_to_capture_photos_videos,
|
||||
supportFragmentManager
|
||||
)
|
||||
.onAllGranted(onGranted)
|
||||
.onAnyDenied { Toast.makeText(this@MainActivity, R.string.CameraXFragment_signal_needs_camera_access_capture_photos, Toast.LENGTH_LONG).show() }
|
||||
.execute()
|
||||
}
|
||||
}
|
||||
|
||||
inner class ToolbarCallback : MainToolbarCallback {
|
||||
|
||||
override fun onNewGroupClick() {
|
||||
@@ -1125,33 +1167,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
|
||||
}
|
||||
|
||||
override fun onCameraClick(destination: MainNavigationListLocation) {
|
||||
val onGranted = {
|
||||
startActivity(
|
||||
MediaSelectionActivity.camera(
|
||||
context = this@MainActivity,
|
||||
isStory = destination == MainNavigationListLocation.STORIES
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (CameraXUtil.isSupported()) {
|
||||
onGranted()
|
||||
} else {
|
||||
Permissions.with(this@MainActivity)
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.ifNecessary()
|
||||
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.CameraXFragment_to_capture_photos_and_video_allow_camera), R.drawable.symbol_camera_24)
|
||||
.withPermanentDenialDialog(
|
||||
getString(R.string.CameraXFragment_signal_needs_camera_access_capture_photos),
|
||||
null,
|
||||
R.string.CameraXFragment_allow_access_camera,
|
||||
R.string.CameraXFragment_to_capture_photos_videos,
|
||||
supportFragmentManager
|
||||
)
|
||||
.onAllGranted(onGranted)
|
||||
.onAnyDenied { Toast.makeText(this@MainActivity, R.string.CameraXFragment_signal_needs_camera_access_capture_photos, Toast.LENGTH_LONG).show() }
|
||||
.execute()
|
||||
}
|
||||
onCameraClick(destination, false)
|
||||
}
|
||||
|
||||
override fun onMegaphoneVisible(megaphone: Megaphone) {
|
||||
|
||||
@@ -183,6 +183,10 @@ class MediaSelectionActivity :
|
||||
.subscribe(this::handleError)
|
||||
|
||||
onBackPressedDispatcher.addCallback(OnBackPressed())
|
||||
|
||||
if (savedInstanceState == null && intent.getBooleanExtra(IS_FOR_QUICK_RESTORE, false)) {
|
||||
QuickRestoreInfoDialog.show(supportFragmentManager)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleError(error: MediaValidator.FilterError) {
|
||||
@@ -385,6 +389,7 @@ class MediaSelectionActivity :
|
||||
private const val IS_STORY = "is_story"
|
||||
private const val AS_TEXT_STORY = "as_text_story"
|
||||
private const val IS_ADD_TO_GROUP_STORY_FLOW = "is_add_to_group_story_flow"
|
||||
private const val IS_FOR_QUICK_RESTORE = "is_for_quick_restore"
|
||||
|
||||
@JvmStatic
|
||||
fun camera(context: Context): Intent {
|
||||
@@ -400,6 +405,14 @@ class MediaSelectionActivity :
|
||||
)
|
||||
}
|
||||
|
||||
fun cameraForQuickRestore(context: Context): Intent {
|
||||
return buildIntent(
|
||||
context = context,
|
||||
startAction = R.id.action_directly_to_mediaCaptureFragment,
|
||||
isForQuickRestore = true
|
||||
)
|
||||
}
|
||||
|
||||
fun addToGroupStory(
|
||||
context: Context,
|
||||
recipientId: RecipientId
|
||||
@@ -508,7 +521,8 @@ class MediaSelectionActivity :
|
||||
isReply: Boolean = false,
|
||||
isStory: Boolean = false,
|
||||
asTextStory: Boolean = false,
|
||||
isAddToGroupStoryFlow: Boolean = false
|
||||
isAddToGroupStoryFlow: Boolean = false,
|
||||
isForQuickRestore: Boolean = false
|
||||
): Intent {
|
||||
return Intent(context, MediaSelectionActivity::class.java).apply {
|
||||
putExtra(START_ACTION, startAction)
|
||||
@@ -520,6 +534,7 @@ class MediaSelectionActivity :
|
||||
putExtra(IS_STORY, isStory)
|
||||
putExtra(AS_TEXT_STORY, asTextStory)
|
||||
putExtra(IS_ADD_TO_GROUP_STORY_FLOW, isAddToGroupStoryFlow)
|
||||
putExtra(IS_FOR_QUICK_RESTORE, isForQuickRestore)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package org.thoughtcrime.securesms.mediasend.v2
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import org.signal.core.ui.compose.BottomSheets
|
||||
import org.signal.core.ui.compose.Buttons
|
||||
import org.signal.core.ui.compose.DayNightPreviews
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.util.BottomSheetUtil
|
||||
|
||||
/**
|
||||
* Bottom sheet dialog displayed when users scan a quick restore with the system camera and then
|
||||
* follow the prompt into the Signal camera to scan the qr code a second time from within Signal.
|
||||
*/
|
||||
class QuickRestoreInfoDialog : ComposeBottomSheetDialogFragment() {
|
||||
|
||||
companion object {
|
||||
fun show(fragmentManager: FragmentManager) {
|
||||
QuickRestoreInfoDialog().show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
|
||||
}
|
||||
}
|
||||
|
||||
override val peekHeightPercentage: Float = 1f
|
||||
|
||||
@Composable
|
||||
override fun SheetContent() {
|
||||
InfoSheet(this::dismissAllowingStateLoss)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InfoSheet(onClick: () -> Unit) {
|
||||
return Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
BottomSheets.Handle()
|
||||
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.quick_restore),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(top = 14.dp, bottom = 24.dp)
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.QuickRestoreInfoDialog__scan_qr_code),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
modifier = Modifier.padding(bottom = 8.dp)
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.QuickRestoreInfoDialog__use_this_device_to_scan_qr_code),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(bottom = 28.dp)
|
||||
)
|
||||
Buttons.LargeTonal(
|
||||
onClick = onClick,
|
||||
modifier = Modifier.defaultMinSize(minWidth = 220.dp)
|
||||
) {
|
||||
Text(stringResource(id = R.string.QuickRestoreInfoDialog__okay))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DayNightPreviews
|
||||
@Composable
|
||||
fun InfoSheetPreview() {
|
||||
Previews.BottomSheetPreview {
|
||||
InfoSheet(onClick = {})
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
|
||||
import org.whispersystems.signalservice.api.push.UsernameLinkComponents;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -343,6 +344,26 @@ public class CommunicationActions {
|
||||
startVideoCall(new ActivityCallContext(activity), linkParseResult.getRootKey(), linkParseResult.getEpoch(), onUserAlreadyInAnotherCall);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the url is a quick restore link it will handle it.
|
||||
* Otherwise returns false, indicating it was not a quick restore link.
|
||||
*/
|
||||
public static boolean handlePotentialQuickRestoreUrl(@NonNull FragmentActivity activity, @NonNull String potentialQuickRestoreUrl, @NonNull Runnable onContinue) {
|
||||
URI uri = URI.create(potentialQuickRestoreUrl);
|
||||
|
||||
if ("sgnl".equalsIgnoreCase(uri.getScheme()) && "rereg".equalsIgnoreCase(uri.getHost())) {
|
||||
new MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.CommunicationActions__transfer_dialog_title)
|
||||
.setMessage(R.string.CommunicationActions__transfer_dialog_message)
|
||||
.setPositiveButton(R.string.DeviceProvisioningActivity_continue, (d, w) -> onContinue.run())
|
||||
.setNegativeButton(R.string.CommunicationActions__dont_transfer, null)
|
||||
.show();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to start a video call for the given call link via root key. This will insert a call link into
|
||||
* the user's database if one does not already exist.
|
||||
|
||||
Reference in New Issue
Block a user